133 lines
3.9 KiB
PHP
133 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace app\controller\api;
|
|
|
|
use app\model\UploadFile;
|
|
use app\service\PermissionService;
|
|
use think\exception\HttpResponseException;
|
|
|
|
class Upload extends BaseApi
|
|
{
|
|
public function upload()
|
|
{
|
|
$user = $this->authUser();
|
|
$file = $this->request->file('file');
|
|
|
|
if (!$file) {
|
|
return $this->error('请选择文件');
|
|
}
|
|
|
|
$mime = $file->getMime() ?: mime_content_type($file->getPathname());
|
|
$fileType = $this->detectFileType($mime);
|
|
|
|
if (!PermissionService::canUpload($user, $fileType)) {
|
|
return $this->error('您没有权限上传此类型文件或功能未开启', 403);
|
|
}
|
|
|
|
$maxSize = PermissionService::getMaxUploadSizeMb($user) * 1024 * 1024;
|
|
if ($file->getSize() > $maxSize) {
|
|
return $this->error('文件大小超出限制');
|
|
}
|
|
|
|
if (!$this->isAllowedMime($mime, $fileType)) {
|
|
return $this->error('不支持的文件类型');
|
|
}
|
|
|
|
$originalName = $file->getOriginalName();
|
|
$fileSize = $file->getSize();
|
|
|
|
$uploadPath = config('upload.path');
|
|
if (!is_dir($uploadPath)) {
|
|
mkdir($uploadPath, 0755, true);
|
|
}
|
|
|
|
$ext = $file->extension() ?: 'bin';
|
|
$subdir = date('Y/m/d');
|
|
$storedBase = uniqid() . '.' . $ext;
|
|
$storedName = $subdir . '/' . $storedBase;
|
|
$fullDir = $uploadPath . '/' . $subdir;
|
|
|
|
if (!is_dir($fullDir)) {
|
|
mkdir($fullDir, 0755, true);
|
|
}
|
|
|
|
$file->move($fullDir, $storedBase);
|
|
|
|
$record = UploadFile::create([
|
|
'user_id' => $user['id'],
|
|
'original_name' => $originalName,
|
|
'stored_name' => $storedBase,
|
|
'file_path' => $storedName,
|
|
'mime_type' => $mime,
|
|
'file_size' => $fileSize,
|
|
'file_type' => $fileType,
|
|
]);
|
|
|
|
return $this->success([
|
|
'id' => $record->id,
|
|
'url' => '/api/uploads/' . urlencode($storedBase),
|
|
'name' => $originalName,
|
|
'type' => $fileType,
|
|
'mime' => $mime,
|
|
'size' => $fileSize,
|
|
]);
|
|
}
|
|
|
|
public function serve($filename)
|
|
{
|
|
$filename = basename($filename);
|
|
$upload = UploadFile::where('stored_name', $filename)
|
|
->whereOr('file_path', 'like', '%/' . $filename)
|
|
->find();
|
|
|
|
if (!$upload) {
|
|
throw new HttpResponseException(json([
|
|
'code' => 1,
|
|
'message' => '文件不存在',
|
|
'data' => null,
|
|
], 404));
|
|
}
|
|
|
|
$path = config('upload.path') . '/' . $upload->file_path;
|
|
if (!is_file($path)) {
|
|
throw new HttpResponseException(json([
|
|
'code' => 1,
|
|
'message' => '文件不存在',
|
|
'data' => null,
|
|
], 404));
|
|
}
|
|
|
|
return download($path, $upload->original_name, true)
|
|
->mimeType($upload->mime_type);
|
|
}
|
|
|
|
private function detectFileType(string $mime): string
|
|
{
|
|
if (str_starts_with($mime, 'image/')) {
|
|
return 'image';
|
|
}
|
|
if (str_starts_with($mime, 'video/')) {
|
|
return 'video';
|
|
}
|
|
if (str_starts_with($mime, 'audio/')) {
|
|
return 'audio';
|
|
}
|
|
if (in_array($mime, config('upload.allowed_documents'), true)) {
|
|
return 'document';
|
|
}
|
|
return 'other';
|
|
}
|
|
|
|
private function isAllowedMime(string $mime, string $fileType): bool
|
|
{
|
|
$config = config('upload');
|
|
return match ($fileType) {
|
|
'image' => in_array($mime, $config['allowed_images'], true),
|
|
'video' => in_array($mime, $config['allowed_videos'], true),
|
|
'audio' => in_array($mime, $config['allowed_audios'], true),
|
|
'document' => in_array($mime, $config['allowed_documents'], true),
|
|
default => false,
|
|
};
|
|
}
|
|
}
|