diff --git a/app/Http/Controllers/Api/H5UploadController.php b/app/Http/Controllers/Api/H5UploadController.php index 7f4ca0c..277f62b 100644 --- a/app/Http/Controllers/Api/H5UploadController.php +++ b/app/Http/Controllers/Api/H5UploadController.php @@ -2,15 +2,19 @@ namespace App\Http\Controllers\Api; +use App\Http\Controllers\Concerns\EnsuresPublicDiskWritable; use App\Http\Controllers\Controller; use App\Models\WechatUser; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; use Throwable; class H5UploadController extends Controller { + use EnsuresPublicDiskWritable; + public function store(Request $request): JsonResponse { $user = $request->user(); @@ -18,6 +22,10 @@ class H5UploadController extends Controller abort(403, '仅微信用户可上传'); } + if ($early = $this->ensurePublicDiskReady()) { + return $early; + } + if (!$request->hasFile('file')) { return response()->json(['message' => '未收到文件'], 422); } @@ -32,15 +40,30 @@ class H5UploadController extends Controller ]); try { + Storage::disk('public')->makeDirectory('uploads/h5'); $path = Storage::disk('public')->putFile('uploads/h5', $data['file']); } catch (Throwable $e) { report($e); + Log::error('h5_upload_putfile_failed', [ + 'message' => $e->getMessage(), + 'public_path' => storage_path('app/public'), + ]); - return response()->json(['message' => '文件保存失败'], 500); + return response()->json([ + 'message' => '文件保存失败', + 'detail' => config('app.debug') ? $e->getMessage() : null, + ], 500); } if ($path === false) { - return response()->json(['message' => '文件保存失败'], 500); + Log::error('h5_upload_putfile_returned_false', [ + 'public_path' => storage_path('app/public'), + ]); + + return response()->json([ + 'message' => '文件保存失败(写入返回失败)', + 'detail' => config('app.debug') ? 'Storage::putFile 返回 false' : null, + ], 500); } $safePath = str_replace('\\', '/', $path); diff --git a/app/Http/Controllers/Api/UploadController.php b/app/Http/Controllers/Api/UploadController.php index 6888451..c216325 100644 --- a/app/Http/Controllers/Api/UploadController.php +++ b/app/Http/Controllers/Api/UploadController.php @@ -2,16 +2,24 @@ namespace App\Http\Controllers\Api; +use App\Http\Controllers\Concerns\EnsuresPublicDiskWritable; use App\Http\Controllers\Controller; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; use Throwable; class UploadController extends Controller { + use EnsuresPublicDiskWritable; + public function store(Request $request): JsonResponse { + if ($early = $this->ensurePublicDiskReady()) { + return $early; + } + if (!$request->hasFile('file')) { return response()->json([ 'message' => '未收到文件,请使用 multipart 表单字段名 file。', @@ -30,18 +38,29 @@ class UploadController extends Controller ]); try { + Storage::disk('public')->makeDirectory('uploads'); $path = Storage::disk('public')->putFile('uploads', $data['file']); } 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' => '文件保存失败', + 'message' => '文件保存失败(写入返回失败)', + 'detail' => config('app.debug') ? 'Storage::putFile 返回 false,多为磁盘 public 配置或权限问题' : null, ], 500); } diff --git a/app/Http/Controllers/Concerns/EnsuresPublicDiskWritable.php b/app/Http/Controllers/Concerns/EnsuresPublicDiskWritable.php new file mode 100644 index 0000000..1f56111 --- /dev/null +++ b/app/Http/Controllers/Concerns/EnsuresPublicDiskWritable.php @@ -0,0 +1,41 @@ +json([ + 'message' => '无法创建存储目录 storage/app/public', + 'detail' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + + if (!is_writable($dir)) { + Log::error('upload_public_dir_not_writable', ['path' => $dir]); + + return response()->json([ + 'message' => '存储目录不可写,请在线上为 PHP 运行用户开放 storage 与 bootstrap/cache 写权限', + 'hint' => '示例:chmod -R ug+rwx storage bootstrap/cache && chown -R www-data:www-data storage bootstrap/cache(用户以实际 php-fpm 用户为准)', + ], 500); + } + + return null; + } +}