You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
2.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Concerns\EnsuresPublicDiskWritable;
use App\Http\Controllers\Concerns\StoresPublicUploadWithoutFileinfo;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Throwable;
class UploadController extends Controller
{
use EnsuresPublicDiskWritable;
use StoresPublicUploadWithoutFileinfo;
public function store(Request $request): JsonResponse
{
if ($early = $this->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';
}
}