ensurePublicDiskReady()) { return $early; } if (!$request->hasFile('file')) { return response()->json([ 'message' => '未收到文件,请使用 multipart 表单字段名 file。', ], 422); } $uploaded = $request->file('file'); if (!$uploaded->isValid()) { return response()->json([ 'message' => '上传未通过校验:'.$uploaded->getErrorMessage(), ], 422); } $data = $request->validate([ 'file' => ['required', 'file', 'max:20480'], ]); try { $path = $this->storeUploadedFileAsUniqueName($data['file'], 'uploads'); } catch (Throwable $e) { report($e); Log::error('upload_putfile_failed', [ 'message' => $e->getMessage(), 'public_path' => storage_path('app/public'), ]); return response()->json([ 'message' => '文件保存失败', 'detail' => config('app.debug') ? $e->getMessage() : null, ], 500); } if ($path === false) { Log::error('upload_putfile_returned_false', [ 'public_path' => storage_path('app/public'), ]); return response()->json([ 'message' => '文件保存失败(写入返回失败)', 'detail' => config('app.debug') ? 'Storage::putFile 返回 false,多为磁盘 public 配置或权限问题' : null, ], 500); } $mime = self::jsonSafeString($this->mimeForUploadResponse($data['file'])); return response()->json([ 'path' => $path, 'url' => url('/storage/'.str_replace('\\', '/', $path)), 'mime' => $mime, 'size' => $data['file']->getSize(), ]); } /** 避免 mime 等字段含非法 UTF-8 导致 json_encode 抛错成 500 */ private static function jsonSafeString(string $value): string { if ($value === '') { return ''; } if (function_exists('mb_scrub')) { return mb_scrub($value, 'UTF-8'); } $clean = @iconv('UTF-8', 'UTF-8//IGNORE', $value); return $clean !== false ? $clean : 'application/octet-stream'; } }