Yii2文件上传需自动清理旧文件:在upload()方法中先检查并删除$oldPath旧文件;数据库绑定场景须存file_path字段并联动更新;临时文件用定时任务扫描孤立文件清理。

Yii2项目中文件上传后需自动清理旧文件,避免磁盘空间被历史文件持续占用,尤其在用户反复上传同名或相似内容时,旧文件若未及时移除将堆积成冗余数据。
配置UploadForm模型启用自动清理
在上传模型中显式定义清理逻辑,确保每次新文件保存前先删除关联的旧文件路径。这一步必须写在upload()方法内,不能仅靠外部脚本延后处理——否则存在窗口期,导致新旧文件同时存在。
打开你的上传模型(如app\models\UploadForm.php),在upload()方法中插入清理动作:
调用unlink()前先检查文件是否存在,避免PHP警告:if (file_exists($oldPath)) { unlink($oldPath); }。
【$oldPath必须与新文件保存路径逻辑一致,否则删错文件不可逆】
修改后的upload()示例:
public function upload()
{
if ($this->validate()) {
$basePath = 'uploads/';
$oldPath = $basePath . $this->oldFileName; // 该字段需在表单提交时传入,或从数据库查出
if (file_exists($oldPath)) {
unlink($oldPath);
}
$newPath = $basePath . $this->imageFile->baseName . '.' . $this->imageFile->extension;
$this->imageFile->saveAs($newPath);
return true;
} else {
return false;
}
}
使用数据库记录旧文件路径并联动清理
当上传文件与某条记录强绑定(如用户头像、商品主图),旧文件路径应持久化存储,便于精准清理。
第一步:在对应数据表中新增字段file_path VARCHAR(255),用于存档上次上传的完整相对路径。
第二步:在控制器actionUpdate或actionCreate中,执行上传前先查出当前记录的file_path值。
第三步:调用upload()成功后,立即执行unlink()并更新数据库中的file_path为新路径。
注意:若旧路径为空或为默认占位图(如/images/default.png),跳过unlink(),防止误删公共资源。
这一步操作起来很简单,直接把文件拖进去就行。
定时任务清理孤立文件(无数据库关联的上传)
针对未绑定数据库记录的临时上传(如富文本编辑器图片、前端直传附件),需定期扫描uploads/目录下无数据库引用的文件。
方法一:编写控制台命令CleanOrphanFilesController
在app\commands\下新建CleanOrphanFilesController.php,继承yii\console\Controller:
定义actionRun(),遍历uploads/目录所有文件,对每个文件计算其文件名(不含扩展名)是否出现在任意一张表的file_name字段中;未命中则unlink()。
方法二:用shell脚本配合find + grep(仅Linux环境)
在项目根目录下建clean_orphan.sh,内容为:
find ./uploads -type f -mtime +30 -name "*.jpg" -o -name "*.png" | while read f; do
if ! mysql -u root -p'pass' mydb -e "SELECT COUNT(*) FROM article WHERE image LIKE '%$(basename "$f" | cut -d. -f1)%'" | grep -q "0"; then
rm "$f"
fi
done
【此脚本需测试后再上线,grep匹配逻辑易漏判或误删】
方法三:用Yii内置FileHelper递归扫描(推荐)
在actionRun()中使用Yii::getAlias('@webroot/uploads')获取绝对路径,调用FileHelper::findFiles()获取全部文件列表,再用ActiveRecord::find()->select('file_name')->column()拉取所有已知文件名,做array_diff后批量unlink。


















