Yii2中实现安全可控的文件上传功能需定义UploadForm模型,通过file验证器校验类型与大小,使用UploadedFile::getInstance绑定文件,enctype="multipart/form-data"确保表单提交,支持单/多文件、远程URL下载、日期分层存储及数据库关联。

你需要在Yii2项目中实现安全、可控、可扩展的文件上传功能,包括单文件上传、多文件上传、远程URL图片下载、类型与大小校验、自定义保存路径和数据库关联存储。
创建基础上传模型
新建 app/models/UploadForm.php,定义一个仅接收单个文件的模型:
声明 【$imageFile 属性必须为 public 且不带类型提示】,否则 UploadedFile::getInstance 无法正确绑定;使用 file 验证器强制限制扩展名和 MIME 类型,避免仅靠前端判断带来的安全隐患。
public $imageFile;
public function rules() { return [ [['imageFile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'jpg, jpeg, png, gif', 'mimeTypes' => 'image/jpeg, image/png, image/gif', 'maxSize' => 2097152 // 2MB ], ]; }
public function upload() { if ($this->validate()) { $extension = $this->imageFile->extension; $fileName = md5(uniqid() . time()) . '.' . $extension; $this->imageFile->saveAs('uploads/' . $fileName); return $fileName; } return false; }
在控制器中处理上传请求
在 app/controllers/SiteController.php 中添加 actionUpload 方法:
先实例化模型,再调用 UploadedFile::getInstance 获取上传对象——这一步不能省略,否则 validate() 将始终失败。
$model = new UploadForm(); if (Yii::$app->request->isPost) { $model->imageFile = UploadedFile::getInstance($model, 'imageFile'); if ($model->upload()) { Yii::$app->session->setFlash('success', '文件上传成功'); return $this->refresh(); } }
注意:UploadedFile::getInstance 第二个参数必须与模型属性名完全一致(区分大小写),否则返回 null 导致后续操作崩溃。
渲染带 enctype 的表单视图
在 views/site/upload.php 中编写表单代码:
ActiveForm 必须显式设置 【enctype="multipart/form-data"】,否则浏览器不会发送文件二进制流,后端永远收不到 $_FILES 数据。
['enctype' => 'multipart/form-data']]); ?>
= $form->field($model, 'imageFile')->fileInput(['accept' => 'image/*']) ?>
实现多文件上传
方法一:复用 UploadForm 模型,仅修改 rules 和 upload 方法
将 $imageFile 改为 $files,并设为数组类型;rules 中启用 maxFiles 参数并允许空文件(因部分浏览器可能提交空项):
public $files;
public function rules() { return [ [['files'], 'file', 'skipOnEmpty' => true, 'extensions' => 'pdf, doc, docx', 'maxFiles' => 5, 'maxSize' => 5242880 // 5MB ], ]; }
upload() 方法需遍历处理:
if ($this->validate()) { foreach ($this->files as $file) { $fileName = uniqid() . '_' . $file->baseName . '.' . $file->extension; $file->saveAs('uploads/multi/' . $fileName); } return true; }
方法二:使用 UploadedFile::getInstances 直接获取全部文件对象,绕过模型验证(适用于需完全自控流程的场景):
$uploadedFiles = UploadedFile::getInstancesByName('UploadForm[files]');
这行代码依赖 HTML input name 属性格式,若表单字段名为 files 则必须写成 UploadForm[files][] 才能被正确识别为数组。
远程图片 URL 上传
安装扩展:composer require igogo5yo/yii2-upload-from-url
在模型中引入验证器并配置规则:
[['remoteImage'], 'igogo5yo\uploadfromurl\FileFromUrlValidator', 'extensions' => 'jpg, png, webp', 'mimeTypes' => 'image/*', 'maxSize' => 3145728]
控制器中调用:
$file = UploadFromUrl::getInstance($model, 'remoteImage'); $savedPath = 'uploads/remote/' . md5($model->remoteImage) . '.png'; $file->saveAs($savedPath, true);
注意:saveAs 第二个参数为 true 时,会自动将 $savedPath 写入模型对应属性,省去手动赋值步骤。
保存路径按日期自动分层
第一步:在 upload() 方法内生成时间路径
$datePath = date('Y/m/d'); $uploadDir = 'uploads/' . $datePath;
第二步:确保目录存在
if (!is_dir($uploadDir)) { mkdir($uploadDir, 0755, true); }
第三步:拼接完整路径并保存
$fileName = uniqid() . '.' . $this->imageFile->extension; $this->imageFile->saveAs($uploadDir . '/' . $fileName);
这样上传的文件将存放在 uploads/2026/08/07/xxx.png,避免单目录下文件过多导致系统性能下降。
关联数据库存储文件信息
假设你有一张 article 表,其中 image 字段用于记录文件路径:
在控制器中完成上传后,立即更新模型的 image 属性:
$article = Article::findOne($id); $article->image = 'uploads/' . $fileName; $article->save(false);
save(false) 表示跳过模型验证,防止因其他字段未填写而中断保存。务必确认 image 字段允许为空或已提供默认值,否则数据库约束会报错。











