ImageUploadService.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <?php
  2. namespace Longyi\ImageUpload\Services;
  3. use Illuminate\Http\UploadedFile;
  4. use Illuminate\Support\Facades\Storage;
  5. use Illuminate\Support\Str;
  6. use Intervention\Image\ImageManager;
  7. use Exception;
  8. use Aws\S3\S3Client;
  9. use Aws\Exception\AwsException;
  10. class ImageUploadService
  11. {
  12. /**
  13. * Upload an image to the configured storage disk.
  14. *
  15. * @param UploadedFile $file
  16. * @param string|null $directory Custom directory path
  17. * @return array
  18. * @throws Exception
  19. */
  20. public function upload(UploadedFile $file, ?string $directory = null): array
  21. {
  22. // Validate the file
  23. $this->validateFile($file);
  24. // Determine the disk to use
  25. $disk = config('image_upload.default_disk', 's3');
  26. // Generate directory path
  27. $uploadDirectory = $directory ?? config('image_upload.upload_directory', 'images/uploads');
  28. $path = $uploadDirectory . '/' . date('Ym/d');
  29. // Process and store the image
  30. if (Str::contains($file->getMimeType(), 'image')) {
  31. return $this->processAndStoreImage($file, $path, $disk);
  32. } else {
  33. return $this->storeFile($file, $path, $disk);
  34. }
  35. }
  36. /**
  37. * Upload multiple images.
  38. *
  39. * @param array $files
  40. * @param string|null $directory
  41. * @return array
  42. */
  43. public function uploadMultiple(array $files, ?string $directory = null): array
  44. {
  45. $results = [];
  46. foreach ($files as $file) {
  47. if ($file instanceof UploadedFile) {
  48. try {
  49. $results[] = $this->upload($file, $directory);
  50. } catch (Exception $e) {
  51. $results[] = [
  52. 'success' => false,
  53. 'error' => $e->getMessage(),
  54. 'original_name' => $file->getClientOriginalName(),
  55. ];
  56. }
  57. }
  58. }
  59. return $results;
  60. }
  61. /**
  62. * Validate the uploaded file.
  63. *
  64. * @param UploadedFile $file
  65. * @throws Exception
  66. */
  67. protected function validateFile(UploadedFile $file): void
  68. {
  69. // Check file size
  70. $maxSize = config('image_upload.max_size', 5120) * 1024; // Convert KB to bytes
  71. if ($file->getSize() > $maxSize) {
  72. throw new Exception(__('The file size exceeds the maximum allowed size of :size KB.', [
  73. 'size' => config('image_upload.max_size', 5120)
  74. ]));
  75. }
  76. // Check file type
  77. $allowedTypes = config('image_upload.allowed_types', []);
  78. if (!in_array($file->getMimeType(), $allowedTypes)) {
  79. throw new Exception(__('The file type is not allowed. Allowed types: :types', [
  80. 'types' => implode(', ', $allowedTypes)
  81. ]));
  82. }
  83. }
  84. /**
  85. * Process and store an image file.
  86. *
  87. * @param UploadedFile $file
  88. * @param string $path
  89. * @param string $disk
  90. * @return array
  91. */
  92. protected function processAndStoreImage(UploadedFile $file, string $path, string $disk): array
  93. {
  94. $manager = new ImageManager();
  95. $image = $manager->make($file)->encode('webp');
  96. $fileName = Str::random(40) . '.webp';
  97. $fullPath = $path . '/' . $fileName;
  98. // 方式一:使用原生 AWS SDK 绕过 Laravel Storage
  99. $s3Client = new S3Client([
  100. 'version' => 'latest',
  101. 'region' => env('AWS_DEFAULT_REGION'),
  102. 'credentials' => [
  103. 'key' => env('AWS_ACCESS_KEY_ID'),
  104. 'secret' => env('AWS_SECRET_ACCESS_KEY'),
  105. ],
  106. 'http' => [
  107. 'verify' => false, // 临时禁用 SSL 验证用于测试
  108. ],
  109. ]);
  110. $result = $s3Client->putObject([
  111. 'Bucket' => env('AWS_BUCKET'),
  112. 'Key' => $fullPath,
  113. 'Body' => (string) $image,
  114. 'ContentType' => 'image/webp',
  115. ]);
  116. return [
  117. 'success' => true,
  118. 'path' => $fullPath,
  119. 'url' => Storage::disk($disk)->url($fullPath),
  120. 'original_name' => $file->getClientOriginalName(),
  121. 'mime_type' => $file->getMimeType(),
  122. 'size' => $file->getSize(),
  123. 'disk' => $disk,
  124. ];
  125. }
  126. /**
  127. * Store a non-image file.
  128. *
  129. * @param UploadedFile $file
  130. * @param string $path
  131. * @param string $disk
  132. * @return array
  133. */
  134. protected function storeFile(UploadedFile $file, string $path, string $disk): array
  135. {
  136. try {
  137. $fileName = Str::random(40) . '.' . $file->getClientOriginalExtension();
  138. $fullPath = $path . '/' . $fileName;
  139. Storage::disk($disk)->putFileAs($path, $file, $fileName);
  140. return [
  141. 'success' => true,
  142. 'path' => $fullPath,
  143. 'url' => Storage::disk($disk)->url($fullPath),
  144. 'original_name' => $file->getClientOriginalName(),
  145. 'mime_type' => $file->getMimeType(),
  146. 'size' => $file->getSize(),
  147. 'disk' => $disk,
  148. ];
  149. } catch (Exception $e) {
  150. throw new Exception(__('Failed to store file: :error', ['error' => $e->getMessage()]));
  151. }
  152. }
  153. /**
  154. * Delete an image from storage.
  155. *
  156. * @param string $path
  157. * @param string|null $disk
  158. * @return bool
  159. */
  160. public function delete(string $path, ?string $disk = null): bool
  161. {
  162. $disk = $disk ?? config('image_upload.default_disk', 's3');
  163. return Storage::disk($disk)->delete($path);
  164. }
  165. /**
  166. * Get the URL for a stored image.
  167. *
  168. * @param string $path
  169. * @param string|null $disk
  170. * @return string
  171. */
  172. public function getUrl(string $path, ?string $disk = null): string
  173. {
  174. $disk = $disk ?? config('image_upload.default_disk', 's3');
  175. return Storage::disk($disk)->url($path);
  176. }
  177. }