Yii2文件上传系统需分三阶段演进:基础版实现单机直传与本地存储,进阶版对接七牛云等对象存储,高可用版通过Redis队列解耦上传与异步处理,全程解决并发覆盖、路径隔离、失败重试等问题。

构建一个稳定、可扩展的Yii2文件上传系统,需要从单机上传逐步过渡到分布式存储与异步处理,过程中必须解决并发冲突、文件校验、路径隔离、失败重试等实际问题。
基础版:单服务器直传+本地存储
第一步:在模型中定义 file 属性,并添加 file 验证规则,不加 【required】 会导致空文件绕过校验直接保存空记录。
第二步:控制器中调用 $model->upload(),该方法内部执行 $model->file->saveAs($path) → 确保 $path 包含唯一子目录(如 uploads/2024/06/),否则高并发下可能覆盖同名文件。
第三步:上传成功后,把相对路径存入数据库字段,不要存绝对路径——本地调试和生产环境的根目录往往不同。
进阶版:引入七牛云SDK实现对象存储
方法一:替换 saveAs() 为 QiniuStorage::uploadFile(),需提前配置 accessKey、secretKey 和 bucket。
方法二:封装 QiniuUploadBehavior 行为类,在 afterSave 中触发上传,同时将本地临时文件 【unlink() 必须放在上传成功回调里】,否则失败时文件残留且无日志提示。
方法三:改用 Flysystem 抽象层,注册 qiniu 适配器,统一使用 $filesystem->write($key, $content) 接口,后续切换阿里云OSS只需换适配器,不用动业务逻辑。
高可用版:分离上传与处理流程
第一步:用户上传后,仅生成带签名的临时URL并返回,不等待处理完成。
第二步:将文件元信息(原始名、大小、临时路径、用户ID)推入 Redis List 队列 → 使用 LPUSH upload:queue,避免多个 worker 同时 pop 同一条任务。
第三步:独立的 console 命令监听队列:yii upload/process,每次 pop 一条后立即 BRPOPLPUSH 到 processing 队列,防止进程崩溃导致任务丢失。
第四步:处理逻辑包含病毒扫描(调用 ClamAV CLI)、格式转换(ImageMagick 缩略图)、MD5 校验比对,任一环节失败则标记任务状态为 failed 并写入错误日志。


















