Yii2中Jodit富文本编辑器上传时修改文件名的实现
解决Jodit WYSIWYG上传同名文件覆盖问题:自定义文件名
我最近在搭建Jodit富文本编辑器时,也碰到了上传同名文件到根目录会覆盖旧文件的麻烦,而且官方文档确实有点晦涩,折腾了一阵终于搞定了修改上传文件名的功能,分享给同样遇到这个问题的朋友:
问题分析
调试过程中发现,上传的文件信息存储在$files = $_FILES[$source->defaultFilesKey];变量里,核心的上传逻辑就在move方法中。要避免文件覆盖,关键就是在文件移动到目标目录前,修改$files['name']字段的文件名。
实现步骤
在move方法的开头,添加一段遍历$files['name']数组的代码,给每个文件名加上唯一标识(比如时间戳),确保文件名全局唯一。
修改后的完整move方法代码
public function move(Config $source) { $files = $_FILES[$source->defaultFilesKey]; // 核心修改:遍历文件名,添加时间戳前缀避免重复 foreach ($files['name'] as $i => $file) { // 用当前时间戳(精确到秒)作为前缀,确保文件名唯一 $files['name'][$i] = round(microtime(true)) . $files['name'][$i]; } /** * @var $output File[] */ $output = []; try { if (isset($files) and is_array($files) and isset($files['name']) and is_array($files['name']) and count($files['name'])) { foreach ($files['name'] as $i => $file) { if ($files['error'][$i]) { throw new \Exception(isset(Helper::$upload_errors[$files['error'][$i]]) ? Helper::$upload_errors[$files['error'][$i]] : 'Error', $files['error'][$i]); } $path = $source->getPath(); $tmp_name = $files['tmp_name'][$i]; $new_path = $path . Helper::makeSafe($files['name'][$i]); if (!move_uploaded_file($tmp_name, $new_path)) { if (!is_writable($path)) { throw new \Exception('Destination directory is not writeble', Consts::ERROR_CODE_IS_NOT_WRITEBLE); } throw new \Exception('No files have been uploaded', Consts::ERROR_CODE_NO_FILES_UPLOADED); } $file = new File($new_path); try { $this->accessControl->checkPermission($this->getUserRole(), $this->action, $source->getRoot(), pathinfo($file->getPath(), PATHINFO_EXTENSION)); } catch (\Exception $e) { $file->remove(); throw $e; } if (!$file->isGoodFile($source)) { $file->remove(); throw new \Exception('File type is not in white list', Consts::ERROR_CODE_FORBIDDEN); } if ($source->maxFileSize and $file->getSize() > Helper::convertToBytes($source->maxFileSize)) { $file->remove(); throw new \Exception('File size exceeds the allowable', Consts::ERROR_CODE_FORBIDDEN); } $output[] = $file; } } } catch (\Exception $e) { foreach ($output as $file) { $file->remove(); } throw $e; } return $output; }
代码说明
- 我们通过
round(microtime(true))生成当前时间戳(精确到秒),将其拼接到原文件名前面,这样即使上传相同名称的文件,最终的文件名也会带有唯一的时间戳,彻底避免了文件覆盖的问题。 - 你也可以根据需求替换成其他唯一标识,比如UUID,不过时间戳的实现方式简单且足够满足大多数场景的需求。
内容的提问来源于stack exchange,提问作者Chonjaroen Chauynoo




