在Yii框架中实现多文件上传需四步:视图启用fileInput(['multiple'=>true])并设enctype为multipart/form-data;模型声明$imageFiles属性及'skipOnEmpty'=>true的file验证规则;控制器用getInstances()接收、validate()校验、遍历saveAs()保存;超限文件需流式上传并手动校验。

在Yii框架中实现用户一次性选择并上传多个文件,需同时满足表单支持多选、后端正确接收实例、验证规则允许批量、保存逻辑遍历处理四个条件,缺一不可。
视图层:启用多文件选择并提交到同一字段
在ActiveForm中使用fileInput(['multiple' => true]),且属性名必须带[]后缀,否则后端无法识别为数组。
确保表单enctype设为multipart/form-data,这是文件上传的硬性前提——没有它,$_FILES将为空,UploadedFile::getInstances()永远返回空数组。
直接写:= $form->field($model, 'imageFiles[]')->fileInput(['multiple' => true, 'accept' => 'image/*']) ?>。
模型层:定义多文件属性与验证规则
声明公共属性public $imageFiles;,类型为UploadedFile[]数组(PHPDoc可标注,非强制但强烈建议)。
在rules()中使用'file'验证器,并显式设置'maxFiles'上限和'extensions'白名单:
【'skipOnEmpty' => true是必须的】——若设为false,验证器会要求至少传一个文件,导致空提交失败;而多文件场景下用户可能暂不选任何文件就点提交。
示例规则:[['imageFiles'], 'file', 'skipOnEmpty' => true, 'extensions' => 'png, jpg, gif', 'maxFiles' => 12]。
控制器层:批量接收、校验与保存
第一步:用UploadedFile::getInstances($model, 'imageFiles')获取全部文件对象,注意参数二是属性名(不含[])。
第二步:调用$model->validate()触发规则检查——这一步必须在saveAs()前执行,否则扩展名、大小等校验失效。
第三步:遍历每个$file,调用$file->saveAs()保存。路径需手动拼接唯一文件名,避免重名覆盖:
$filename = uniqid() . '.' . $file->extension;$file->saveAs('@webroot/uploads/' . $filename);
第四步:保存成功后,可将路径存入数据库或返回前端。若任一文件保存失败,整个操作应中断并回滚,不要部分写入。
安全增强:绕过$_FILES限制上传大文件
当单个文件超2MB时,PHP默认的upload_max_filesize和post_max_size会直接截断请求,getInstances()返回空——此时必须改用流式上传。
方法一:前端用fetch发送PUT请求携带原始二进制流,后端禁用multipart解析器:
'parsers' => ['application/octet-stream' => 'yii\web\BinaryParser'](配置在控制器behaviors()中)。
方法二:在action中直接读取php://input流,分块写入目标文件:
$input = fopen('php://input', 'rb');$output = fopen($targetPath, 'wb');while (!feof($input)) { fwrite($output, fread($input, 8192)); }
【流式上传不经过Yii验证器,所有校验(MIME、magic number、大小)必须手动实现】——例如读取前4字节判断PNG是否以\x89PNG开头。


















