validateFile($file); // Determine the disk to use $disk = config('image_upload.default_disk', 's3'); // Generate directory path $uploadDirectory = $directory ?? config('image_upload.upload_directory', 'images/uploads'); $path = $uploadDirectory . '/' . date('Ym/d'); // Process and store the image if (Str::contains($file->getMimeType(), 'image')) { return $this->processAndStoreImage($file, $path, $disk); } else { return $this->storeFile($file, $path, $disk); } } /** * Upload multiple images. * * @param array $files * @param string|null $directory * @return array */ public function uploadMultiple(array $files, ?string $directory = null): array { $results = []; foreach ($files as $file) { if ($file instanceof UploadedFile) { try { $results[] = $this->upload($file, $directory); } catch (Exception $e) { $results[] = [ 'success' => false, 'error' => $e->getMessage(), 'original_name' => $file->getClientOriginalName(), ]; } } } return $results; } /** * Validate the uploaded file. * * @param UploadedFile $file * @throws Exception */ protected function validateFile(UploadedFile $file): void { // Check file size $maxSize = config('image_upload.max_size', 5120) * 1024; // Convert KB to bytes if ($file->getSize() > $maxSize) { throw new Exception(__('The file size exceeds the maximum allowed size of :size KB.', [ 'size' => config('image_upload.max_size', 5120) ])); } // Check file type $allowedTypes = config('image_upload.allowed_types', []); if (!in_array($file->getMimeType(), $allowedTypes)) { throw new Exception(__('The file type is not allowed. Allowed types: :types', [ 'types' => implode(', ', $allowedTypes) ])); } } /** * Process and store an image file. * * @param UploadedFile $file * @param string $path * @param string $disk * @return array */ protected function processAndStoreImage(UploadedFile $file, string $path, string $disk): array { $manager = new ImageManager(); $image = $manager->make($file)->encode('webp'); $fileName = Str::random(40) . '.webp'; $fullPath = $path . '/' . $fileName; // 方式一:使用原生 AWS SDK 绕过 Laravel Storage $s3Client = new S3Client([ 'version' => 'latest', 'region' => env('AWS_DEFAULT_REGION'), 'credentials' => [ 'key' => env('AWS_ACCESS_KEY_ID'), 'secret' => env('AWS_SECRET_ACCESS_KEY'), ], 'http' => [ 'verify' => false, // 临时禁用 SSL 验证用于测试 ], ]); $result = $s3Client->putObject([ 'Bucket' => env('AWS_BUCKET'), 'Key' => $fullPath, 'Body' => (string) $image, 'ContentType' => 'image/webp', ]); return [ 'success' => true, 'path' => $fullPath, 'url' => Storage::disk($disk)->url($fullPath), 'original_name' => $file->getClientOriginalName(), 'mime_type' => $file->getMimeType(), 'size' => $file->getSize(), 'disk' => $disk, ]; } /** * Store a non-image file. * * @param UploadedFile $file * @param string $path * @param string $disk * @return array */ protected function storeFile(UploadedFile $file, string $path, string $disk): array { try { $fileName = Str::random(40) . '.' . $file->getClientOriginalExtension(); $fullPath = $path . '/' . $fileName; Storage::disk($disk)->putFileAs($path, $file, $fileName); return [ 'success' => true, 'path' => $fullPath, 'url' => Storage::disk($disk)->url($fullPath), 'original_name' => $file->getClientOriginalName(), 'mime_type' => $file->getMimeType(), 'size' => $file->getSize(), 'disk' => $disk, ]; } catch (Exception $e) { throw new Exception(__('Failed to store file: :error', ['error' => $e->getMessage()])); } } /** * Delete an image from storage. * * @param string $path * @param string|null $disk * @return bool */ public function delete(string $path, ?string $disk = null): bool { $disk = $disk ?? config('image_upload.default_disk', 's3'); return Storage::disk($disk)->delete($path); } /** * Get the URL for a stored image. * * @param string $path * @param string|null $disk * @return string */ public function getUrl(string $path, ?string $disk = null): string { $disk = $disk ?? config('image_upload.default_disk', 's3'); return Storage::disk($disk)->url($path); } }