input('scene', 'image'); $file = $request->file('file'); if ($file && $file->isValid()) { $fileName = md5($file->getUploadName() . time()).'.'.$file->getUploadExtension(); $pathUrl = '/uploads/'.$scene.'/'.date('Ymd').'/'.$fileName; $fullPathUrl = public_path() . $pathUrl; $file->move($fullPathUrl); $data = [ 'domain' => getenv('MAIN_DOMAIN'), 'file_url' => $pathUrl, 'full_url' => getenv('MAIN_DOMAIN') . $pathUrl, 'scene' => $scene, ]; // 记录文件信息到数据库 try { $uploadedFilesService = new UploadedFilesService(); $partition = $scene; $category = $request->input('category', 'general'); $fileInfo = [ 'file_name' => basename($fileName), 'file_path' => $pathUrl, 'file_size' => $file->getSize(), 'file_type' => $file->getUploadMimeType(), 'original_name' => $file->getUploadName(), ]; $recordResult = $uploadedFilesService->recordFileInfo($fileInfo, $request, $partition, $category); $data['file_id'] = $recordResult['id']; $data['partition'] = $partition; $data['category'] = $category; } catch (\Throwable $e) { // 记录失败不影响上传结果,只记录日志 Log::error('记录文件信息失败: ' . $e->getMessage()); } return $this->success($data, 'upload success'); } return $this->error('file not found'); } catch (\Throwable $e) { Log::info('uploadFile',[$e->getMessage(),$e->getFile(),$e->getLine()]); return $this->error($e->getMessage()); } } // 上传单文件附件 public function uploadFile(Request $request) { try { $scene = $request->input('scene'); $file = $request->file('file'); if (!$file || !$file->isValid()) { return $this->error('上传失败'); } if (empty($scene)) { // return $this->error('上传场景不能为空'); $sceneUrl = ''; }else{ $sceneUrl = $scene . '/'; } $originalName = $file->getUploadName(); $ossservice = new OssService(); $mimes = $ossservice->getMimeTypes(['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'zip', 'rar', 'MP4', 'MOV', 'M4V', 'WEBM', 'MKV', 'FLV', 'WMV', 'AVI', 'TS']); $result = Storage::adapter('oss') ->path(config('oss.oss_main_dir') . $sceneUrl . date('Ymd')) ->size(1024*1024*50) ->extYes($mimes) ->upload($file); $data = [ 'original_name' => $originalName, 'file_name' => $result->file_name, 'file_url' => $ossservice->generatePrivateUrl($result->file_name) ]; // 记录文件信息到数据库 $category = $request->input('category', 'general'); $res = $this->recordFileInfo($result,$request,$file,$scene,$category); $data = array_merge($data, $res); return $this->success($data); }catch (\Throwable $e){ Log::info('uploadFile',[$e->getMessage(),$e->getFile(),$e->getLine()]); return $this->error($e->getMessage()); } } // 上传单文件图片 public function uploadImage(Request $request) { try { $scene = trim((string)$request->input('scene', '')); $sceneUrl = $scene ? $scene . '/' : ''; $file = $request->file('image'); if (!$file || !$file->isValid()) { return $this->error('上传失败'); } // 允许的 MIME $allowMime = [ 'image/jpeg', 'image/png', 'image/webp', ]; $mime = $file->getMimeType(); if (!in_array($mime, $allowMime, true)) { return $this->error('不支持的图片类型,支持jpeg、png、webp'); } // 临时目录 $tmpDir = runtime_path('upload_tmp'); if (!is_dir($tmpDir)) { mkdir($tmpDir, 0755, true); } $tmpPath = $tmpDir . '/' . uniqid('img_', true); $file->move($tmpPath); // 压缩处理 $finalPath = $this->compressImage($tmpPath, $mime); $result = Storage::adapter('oss') ->path(config('oss.oss_main_dir') . $sceneUrl . date('Ymd')) ->size(1024*1024*30) ->extYes(['image/jpeg','image/png']) ->extNo(['image/gif']) ->upload($file); // 清理临时文件 @unlink($tmpPath); if ($finalPath !== $tmpPath) { @unlink($finalPath); } $ossservice = new OssService(); $data = [ 'href' => $result->file_name, 'alt' => '', 'url' => $ossservice->generatePrivateUrl($result->file_name) ]; // 记录文件信息到数据库 $category = $request->input('category', 'general'); $res = $this->recordFileInfo($result,$request,$file,$scene,$category); $data = array_merge($data, $res); // return json(['errno' => 0, 'data' => $data]); return $this->success($data); } catch (\Throwable $e) { // return json(['errno' => 1, 'message' => $e->getMessage()]); Log::info('uploadFile',[$e->getMessage(),$e->getFile(),$e->getLine()]); return $this->error($e->getMessage()); } } protected function compressImage(string $srcPath, string $mime): string { // 不支持 imagick 直接返回原图 if (!extension_loaded('imagick')) { return $srcPath; } try { $image = new \Imagick(); $image->readImage($srcPath); // 防止超大图 $maxWidth = 2000; $maxHeight = 2000; $image->thumbnailImage($maxWidth, $maxHeight, true); // 自动方向修正(拍照图必备) if (method_exists($image, 'autoOrient')) { $image->autoOrient(); } // PNG / JPEG → WebP if (in_array($mime, ['image/png', 'image/jpeg'], true)) { $image->setImageFormat('webp'); $image->setImageCompressionQuality(80); $dstPath = $srcPath . '.webp'; $image->writeImage($dstPath); } else { // 其他类型直接原样 $dstPath = $srcPath; } $image->clear(); $image->destroy(); return $dstPath; } catch (\Throwable $e) { // 压缩失败直接返回原图 return $srcPath; } } public function recordFileInfo($result, $request, $file, $scene, $category) { try { $uploadedFilesService = new UploadedFilesService(); $partition = $scene; $fileInfo = [ 'file_name' => basename($result->file_name), 'file_path' => $result->file_name, // OSS存储路径 'file_size' => $file->getSize(), 'file_type' => $file->getUploadMimeType(), 'original_name' => $file->getUploadName(), ]; $partition = !empty($partition)?$partition:'other'; $category = !empty($category)?$category:'other'; $recordResult = $uploadedFilesService->recordFileInfo($fileInfo, $request, $partition, $category); $data = []; $data['file_id'] = $recordResult['id']; $data['partition'] = $partition; $data['category'] = $category; return $data; } catch (\Throwable $e) { // 记录失败不影响上传结果,只记录日志 Log::error('记录文件信息失败: ' . $e->getMessage()); return []; } } /** * 获取文件信息 * * @param Request $request * @return \support\Response */ public function getFileInfo(Request $request) { try { $fileId = $request->input('id'); if (!$fileId) { return $this->error('文件ID不能为空'); } $uploadedFilesService = new UploadedFilesService(); $fileInfo = $uploadedFilesService->getFileInfo($fileId); if (!$fileInfo) { return $this->error('文件不存在'); } return $this->success($fileInfo); } catch (\Throwable $e) { return $this->error('获取文件信息失败: ' . $e->getMessage()); } } /** * 删除文件 * * @param Request $request * @return \support\Response */ public function deleteFile(Request $request) { try { $fileId = $request->input('id'); $path = $request->input('path'); $uploadedFilesService = new UploadedFilesService(); if(!empty($path) && empty($fileId)){ $where = ['file_path' => $path]; $file = $uploadedFilesService->getFile($where); $fileId = $file->id; }elseif(empty($path) && !empty($fileId)){ $where = ['id' => $fileId]; $file = $uploadedFilesService->getFile($where); $path = $file->file_path; } if (!$fileId) { return $this->error('文件ID与路径不能为空'); } // 删除 OSS 上的文件 $ossService = new OssService(); $ossService->deleteFile($path); $result = $uploadedFilesService->deleteFile($fileId); if ($result) { return $this->success([], '文件删除成功'); } else { return $this->error('文件删除失败'); } } catch (\Throwable $e) { return $this->error('文件删除失败: ' . $e->getMessage()); } } /** * 获取分区配置 * * @param Request $request * @return \support\Response */ public function getPartitionConfig(Request $request) { try { $uploadedFilesService = new UploadedFilesService(); $config = $uploadedFilesService->getPartitionConfig(); return $this->success($config); } catch (\Throwable $e) { return $this->error('获取分区配置失败: ' . $e->getMessage()); } } public function proxy(Request $request) { $filePath = $request->get('file'); // 原OSS文件路径 try { // 生成签名URL $signedUrl = (new \app\common\service\OssService())->generatePrivateUrl($filePath); // 获取图片数据并返回 $imageData = file_get_contents($signedUrl); // 根据文件类型设置Content-Type $mime = mime_content_type('data://application/octet-stream;base64,'.base64_encode($imageData)); return response($imageData, 200, [ 'Content-Type' => $mime, 'Cache-Control' => 'public, max-age=600' // 客户端缓存10分钟 ]); } catch (\Exception $e) { return response('Image not found '.$e->getMessage(), 404); } } }