diff --git a/app/controller/admin/system/FileController.php b/app/controller/admin/system/FileController.php index 2f16d34..0d6c2f9 100644 --- a/app/controller/admin/system/FileController.php +++ b/app/controller/admin/system/FileController.php @@ -8,6 +8,7 @@ use app\service\CurdService; use think\db\exception\DbException; use think\exception\FileException; use think\exception\ValidateException; +use think\facade\Filesystem; use think\response\Json; class FileController extends BaseController diff --git a/app/entity/UploadFile.php b/app/entity/UploadFile.php deleted file mode 100644 index 1658822..0000000 --- a/app/entity/UploadFile.php +++ /dev/null @@ -1,18 +0,0 @@ -file = $file; - $this->record = $record; - } -} \ No newline at end of file diff --git a/app/entity/file/UploadResult.php b/app/entity/file/UploadResult.php new file mode 100644 index 0000000..603f754 --- /dev/null +++ b/app/entity/file/UploadResult.php @@ -0,0 +1,21 @@ + $value) { + $this->$key = $value; + } + } +} \ No newline at end of file diff --git a/app/model/SysFileRule.php b/app/model/SysFileRule.php index c7e80bf..ca0a3dc 100644 --- a/app/model/SysFileRule.php +++ b/app/model/SysFileRule.php @@ -9,6 +9,8 @@ use app\BaseModel; * @property string $path_rule 路径规则 * @property string $name_rule 命名规则 * @property string $query Query参数携带 + * @property int $is_close 是否关闭上传权限 + * @property string $url 自定义预览URL * @property string $permissions * #1 文件大小限制(单位:KB) * @property int $rule_file_size_limit_min diff --git a/app/service/FileService.php b/app/service/FileService.php index 9f54667..bad49f4 100644 --- a/app/service/FileService.php +++ b/app/service/FileService.php @@ -2,9 +2,9 @@ namespace app\service; +use app\entity\file\UploadFile; use app\entity\SysFileRecord; use app\entity\SysFileRule; -use app\entity\UploadFile; use app\service\file\FilesystemService; use think\File; use think\Service; @@ -22,29 +22,29 @@ class FileService extends Service $this->app->bind('filesystem', FilesystemService::class); } - public function upload(string $contextId, File $file, SysFileRule $rule): UploadFile - { - $sysFileRecord = new SysFileRecord; - // 存储规则相关 - $sysFileRecord->set('rid', $rule->id); // ruleId - $sysFileRecord->set('disk', $rule->disk); // 存储disk - // 文件信息相关 - $sysFileRecord->set('path', ''); // 文件存储路径 - $sysFileRecord->set('name', ''); // 文件名称 - $sysFileRecord->set('length', (int)$file->getSize()); // 文件大小 - $sysFileRecord->set('content_type', $file->getMime()); // 文件类型(mime) - $sysFileRecord->set('md5', $file->md5());// 文件md5 - $sysFileRecord->set('sha1', $file->sha1()); // 文件sha1 - $sysFileRecord->set('extension', $file->extension()); // 文件扩展名(extension) - $sysFileRecord->set('origin_name', $file->getFilename()); // 文件原始名称 - $sysFileRecord->set('create_time', date('Y-m-d H:i:s')); // 文件记录创建时间 - $sysFileRecord->set('create_date', date('Y-m-d')); // 文件记录创建日期 - // 关联数据相关 - $sysFileRecord->set('context_id', $contextId); // 来源上下文 - - // 返回UploadFile实体类 - $uploadFile = new UploadFile(); - $uploadFile->done($file, $sysFileRecord); - return $uploadFile; - } +// public function upload(string $contextId, File $file, SysFileRule $rule): UploadFile +// { +// $sysFileRecord = new SysFileRecord; +// // 存储规则相关 +// $sysFileRecord->set('rid', $rule->id); // ruleId +// $sysFileRecord->set('disk', $rule->disk); // 存储disk +// // 文件信息相关 +// $sysFileRecord->set('path', ''); // 文件存储路径 +// $sysFileRecord->set('name', ''); // 文件名称 +// $sysFileRecord->set('length', (int)$file->getSize()); // 文件大小 +// $sysFileRecord->set('content_type', $file->getMime()); // 文件类型(mime) +// $sysFileRecord->set('md5', $file->md5());// 文件md5 +// $sysFileRecord->set('sha1', $file->sha1()); // 文件sha1 +// $sysFileRecord->set('extension', $file->extension()); // 文件扩展名(extension) +// $sysFileRecord->set('origin_name', $file->getFilename()); // 文件原始名称 +// $sysFileRecord->set('create_time', date('Y-m-d H:i:s')); // 文件记录创建时间 +// $sysFileRecord->set('create_date', date('Y-m-d')); // 文件记录创建日期 +// // 关联数据相关 +// $sysFileRecord->set('context_id', $contextId); // 来源上下文 +// +// // 返回UploadFile实体类 +// $uploadFile = new UploadFile(); +// $uploadFile->done($file, $sysFileRecord); +// return $uploadFile; +// } } \ No newline at end of file diff --git a/app/service/file/FilesystemService.php b/app/service/file/FilesystemService.php index a3fddc2..f2dc6fb 100644 --- a/app/service/file/FilesystemService.php +++ b/app/service/file/FilesystemService.php @@ -2,6 +2,8 @@ namespace app\service\file; +use app\entity\file\UploadResult; +use app\entity\SysFileRecord; use app\entity\SysFileRule; use app\entity\SysUserFile; use think\facade\Event; @@ -12,6 +14,7 @@ use think\exception\ValidateException; use think\facade\Filesystem; use think\facade\Validate; use think\file\UploadedFile; +use think\filesystem\Driver; use think\helper\Str; class FilesystemService @@ -28,9 +31,9 @@ class FilesystemService * @param int $directory_id 存储的目录位置 * @param int $user_id 用户ID * @param array $vars - * @return array + * @return UploadResult */ - public function upload(UploadedFile $file, int $directory_id, int $user_id, array $vars = []): array + public function upload(UploadedFile $file, int $directory_id, int $user_id, array $vars = []): UploadResult { $rule_id = 1; if ($directory_id > 0) { @@ -42,31 +45,46 @@ class FilesystemService } /* * 文件记录实体 + * filesystem.model */ $filesystem_model = $this->app->config->get('filesystem.model'); if (empty($filesystem_model)) { throw new FileException('File记录模型未定义'); } - /** - * @var SysFileRule $fileRule + /* + * 文件预览接口(用于安全访问模式) + * filesystem.api_url */ - $fileRule = SysFileRule::find($rule_id); - if (empty($fileRule)) { + $filesystem_apiUrl = $this->app->config->get('filesystem.api_url'); + if (empty($filesystem_apiUrl)) { + throw new FileException('请正确配置filesystem.api_url'); + } + if ($filesystem_apiUrl == "#") { + $filesystem_apiUrl = Request::domain(); + } else if (!Validate::url($filesystem_apiUrl)) { + throw new FileException('请正确配置filesystem.api_url'); + } + + /** + * @var SysFileRule|\app\model\SysFileRule $rule + */ + $rule = SysFileRule::find($rule_id); + if (empty($rule)) { throw new ValidateException('Rule: 上传规则不存在'); } - if ($fileRule['is_close']) { + if ($rule->is_close) { throw new ValidateException('Rule: 已关闭上传权限'); } /* * 根据规则校验上传的文件是否符合要求 */ - $this->checkFileRule($fileRule, $file); + $this->checkFileRule($rule, $file); - $putDisk = $fileRule->disk; - $putUrl = $fileRule->url; - $putPath = $fileRule->path_rule; - $nameRule = $fileRule->name_rule; + $putDisk = $rule->disk; + $putUrl = $rule->url ? $rule->url : $filesystem_apiUrl; + $putPath = $rule->path_rule; + $nameRule = $rule->name_rule; $nameRule = $this->replaceName($nameRule, $file, $vars + ['uid' => $user_id]); @@ -77,101 +95,76 @@ class FilesystemService $fileName = pathinfo($savePath, PATHINFO_FILENAME); $filePath = pathinfo($savePath, PATHINFO_DIRNAME); -// dump(['#1', $putPath, $nameRule]); -// dump(['#2', $filePath, $fileName]); - - $filesystemSrv = Filesystem::disk($putDisk); - $uploadPath = $filesystemSrv->putFile($filePath, $file, function () use ($fileName) { - return $fileName; - }); + $disk = Filesystem::disk('public'); + $uploadPath = $this->uploadFile($disk, $filePath, $file, $fileName); if ($uploadPath === false) { throw new FileException('上传失败'); } - $diskConfig = Filesystem::getDiskConfig($putDisk); - $url = $diskConfig['url'] ?? ''; - if ($url && Validate::url($url) === false) { - $url = trim($url, '/'); - $uploadPath = "$url/$uploadPath"; - $url = ""; - } - $filesystem_apiUrl = $this->app->config->get('filesystem.api_url'); - /* - * URL取值优先级为 - * #1 取fileRule中的设置 -> #2 取config中的设置 -> #3 取api_url的配置 #4 取当前域名的配置 - * 注意, fileRule中的permissions配置会把#3,#4做为优先项 - */ - $diskUrl = $putUrl ?: ($url ?: $filesystem_apiUrl ?: Request::domain()); + $uploadPath = $disk->url($uploadPath); + + $fileUrl = $putUrl . '/' . ltrim($uploadPath, '/'); + $uploadSavePath = pathinfo($uploadPath, PATHINFO_DIRNAME); $fileSaveName = pathinfo($uploadPath, PATHINFO_BASENAME); -// dump([$diskUrl, $uploadPath]); -// dump(['#4', $uploadSavePath, $fileSaveName]); - - + // 系统文件上传日志记录 $sysFileRecord = $this->app->invokeClass($filesystem_model); $sysFileRecord->save([ - 'name' => $fileSaveName, - 'origin_name' => $file->getOriginalName(), - 'alias_name' => '', - 'path' => $uploadSavePath, - 'length' => $file->getSize(), + 'rule_id' => $rule->id, + 'name' => $fileSaveName, + 'path' => $uploadSavePath, + 'length' => $file->getSize(), 'extension' => $file->getOriginalExtension(), 'content_type' => mime_content_type($file->getRealPath()) ?: '', 'md5' => $file->md5(), - 'sha1' => $file->sha1(), 'disk' => $putDisk, - 'uid' => $user_id, 'create_user_id' => $user_id, 'context_id' => $this->app->request->contextId, - 'gid' => 0, 'create_date' => date('Y-m-d'), 'create_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s'), 'delete_time' => null, - 'uuid' => guid() ]); - $sysFileRecordData = $sysFileRecord->toArray(); - $fileRuleData = $fileRule->toArray(); - if ($user_id > 0) { - (new SysUserFile)->save([ - 'user_id' => $user_id, - 'name' => $file->getOriginalName(), - 'is_directory' => 0, - 'parent_id' => $directory_id, - 'path' => $uploadPath, - 'length' => $file->getSize(), - 'content_type' => $file->getOriginalMime(), - 'deleted' => 0, - // 磁盘 - 'disk' => $putDisk, - // 存储规则 - 'rule_id' => $rule_id, - 'uuid' => $sysFileRecord->uuid, - 'url' => "$diskUrl/{$uploadPath}", - 'is_anonymous' => 0, - ]); - } + (new SysUserFile)->save([ + 'user_id' => $user_id, + 'name' => $file->getOriginalName(), + 'is_directory' => 0, + 'parent_id' => $directory_id, + 'path' => $uploadPath, + 'length' => $file->getSize(), + 'content_type' => $file->getOriginalMime(), + 'deleted' => 0, + // 磁盘 + 'disk' => $putDisk, + // 存储规则 + 'rule_id' => $rule_id, + 'url' => $fileUrl, + 'is_anonymous' => 0, + ]); // 是否需要安全访问 - if ($fileRule->permissions) { - $uploadPath = "i/" . $sysFileRecord->uuid; - $diskUrl = $filesystem_apiUrl ?: Request::domain(); + if ($rule->permissions) { + $fileId = hashids(12)->encode($sysFileRecord->id); + $uploadPath = "i/" . $fileId; + $fileUrl = $putUrl . '/' . ltrim($uploadPath, '/'); } - $results = [ + + /* + * 上传结果封装 + */ + $results = new UploadResult([ // 文件对外显示URL - 'url' => "$diskUrl/{$uploadPath}", + 'url' => $fileUrl, // 文件对外显示存储路径 'path' => $uploadPath, - // 文件唯一标识符 - 'uuid' => "{$rule_id}@" . $sysFileRecord->uuid, // 文件上传时间戳 'time' => time(), - ]; - // 触发文件上传事件 - Event::trigger('upload', ['results' => $results, 'file' => $file, 'rule' => $fileRuleData, 'model' => $sysFileRecordData, 'directory_id' => $directory_id]); - // 触发磁盘上传事件 - Event::trigger("upload.$putDisk", ['results' => $results, 'file' => $file, 'rule' => $fileRuleData, 'model' => $sysFileRecordData, 'directory_id' => $directory_id]); - // 触发磁盘某个规则的上传事件 - Event::trigger("upload.rule_$rule_id", ['results' => $results, 'file' => $file, 'rule' => $fileRuleData, 'model' => $sysFileRecordData, 'directory_id' => $directory_id]); + ]); + + /* + * 触发上传完成事件 + */ + $this->triggerUploaded($results, $putDisk, $file, $rule, $sysFileRecord); + return $results; } @@ -241,4 +234,33 @@ class FilesystemService ->check(['file' => $file]); } } + + /** + * 触发上传完成事件 + * @param UploadResult $results 上传结果 + * @param string $putDisk 存储磁盘 + * @param UploadedFile $file 上传的文件 + * @param SysFileRule $rule 上传规则 + * @param SysFileRecord $sysFileRecord 文件上传记录 + * @return void + */ + private function triggerUploaded(UploadResult $results, string $putDisk, UploadedFile $file, SysFileRule $rule, SysFileRecord $sysFileRecord): void + { + $eventData = ['results' => $results, 'file' => $file, 'rule' => $rule, 'model' => $sysFileRecord]; + // 触发文件上传事件 + Event::trigger('uploaded', $eventData); + // 触发磁盘上传事件 + Event::trigger("uploaded.$putDisk", $eventData); + // 触发磁盘某个规则的上传事件 + if (!empty($rule->id)) { + Event::trigger("uploaded.rule_{$rule->id}", $eventData); + } + } + + private function uploadFile(Driver $driver, string $filePath, UploadedFile $file, string $fileName): bool|string + { + return $driver->putFile($filePath, $file, function () use ($fileName) { + return $fileName; + }); + } } \ No newline at end of file diff --git a/config/filesystem.php b/config/filesystem.php index a5d664c..1faa237 100644 --- a/config/filesystem.php +++ b/config/filesystem.php @@ -21,5 +21,6 @@ return [ ], // 更多的磁盘配置信息 ], - 'model' => \app\entity\SysFileRecord::class + 'model' => \app\entity\SysFileRecord::class, + 'api_url' => "#", ];