You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动