Yii2图片上传功能异常:无法获取扩展名且saveAs()触发空值错误
Yii2多图上传功能故障修复方案
问题现象
Yii2框架中多图上传功能异常,存在两个核心问题:
- 无法获取
$addImgFile->extension属性; - 手动指定
.png后缀时,触发错误:Exception 'Error' with message 'Call to a member function saveAs() on null'
现有代码
控制器代码
public function actionMultipleImg() { $this->enableCsrfValidation = false; if (\Yii::$app->request->isPost) { $post = \Yii::$app->request->post(); $dir = \Yii::getAlias('@productImgPath') . '/additional-image/'; $result_link = str_replace('administrator', '', Url::home(true)) . 'storage/additional-image/'; $addImgFile = UploadedFile::getInstanceByName('ProductImage[attachment]'); $modelProductImage = new ProductImage(); $modelProductImage->filename = strtotime('now') . '_' . \Yii::$app->getSecurity()->generateRandomString(6) . '.'.$addImgFile->extension; $modelProductImage->load($post); $modelProductImage->validate(); if ($modelProductImage->hasErrors()) { $result = ['error' => $modelProductImage->getFirstError('addImgFile')]; } else { if ($addImgFile->saveAs($dir . $modelProductImage->filename)) { $imag = \Yii::$app->image->load($dir . $modelProductImage->filename); $imag->save($dir . $modelProductImage->filename, 90); $result = ['filelink' => $result_link . $modelProductImage->filename, 'filename' => $modelProductImage->filename]; } else { $result = ['error' => 'Ошибка']; }//else }//else $modelProductImage->save(); \Yii::$app->response->format = Response::FORMAT_JSON; return $result; } else { throw new BadRequestHttpException('Only POST is allowed'); } }//action multiple img
视图表单代码
<?php echo FileInput::widget([ 'name' => 'ProductImage[attachment]', 'options' => ['accept' => 'image/*','multiple' => true], 'pluginOptions' => [ 'deleteUrl' => Url::toRoute(['/product/delete-image']), 'initialPreview' => $model->imagesLinks, 'initialPreviewAsData'=>true, 'overwriteInitial' => false, 'initialPreviewConfig' => $model->imagesLinksData, 'uploadUrl' => Url::to(['/product/multiple-img']), 'uploadExtraData' => [ 'ProductImage[product_id]' => $model->id, ], 'maxFileCount' => 10 ], 'pluginEvents' => [ 'filesorted' => new JsExpression('function(event, params){ $.post("' . Url::toRoute(["/product/sort-image", "id"=>$model->id]) . '", {position:params}); }') ], ]);?>
问题根源
- 多文件上传字段名错误:表单开启了
multiple => true,但字段名未使用数组格式ProductImage[attachment][],导致控制器无法正确接收文件; - 单文件获取方法不匹配:使用
UploadedFile::getInstanceByName()只能获取单个文件,无法处理多文件上传场景; - 空值未校验:未判断
$addImgFile是否为null就直接调用其属性/方法,触发致命错误; - 错误字段名不匹配:模型验证错误中使用的
addImgFile字段不存在,应该对应表单的attachment字段。
修复方案
1. 修改视图表单字段名
将name属性改为数组格式,适配多文件上传:
'name' => 'ProductImage[attachment][]',
2. 重构控制器代码
调整为循环处理多文件,增加空值校验,修正错误字段名,优化逻辑:
public function actionMultipleImg() { $this->enableCsrfValidation = false; if (\Yii::$app->request->isPost) { $post = \Yii::$app->request->post(); $dir = \Yii::getAlias('@productImgPath') . '/additional-image/'; $result_link = str_replace('administrator', '', Url::home(true)) . 'storage/additional-image/'; // 获取所有上传的文件 $addImgFiles = UploadedFile::getInstancesByName('ProductImage[attachment]'); $results = []; if (empty($addImgFiles)) { \Yii::$app->response->format = Response::FORMAT_JSON; return ['error' => '未选择任何文件']; } foreach ($addImgFiles as $addImgFile) { // 校验文件是否有效 if (!$addImgFile instanceof UploadedFile) { $results[] = ['error' => '无效的上传文件']; continue; } $modelProductImage = new ProductImage(); // 生成带正确后缀的文件名 $filename = strtotime('now') . '_' . \Yii::$app->getSecurity()->generateRandomString(6) . '.' . $addImgFile->extension; $modelProductImage->filename = $filename; $modelProductImage->load($post); if ($modelProductImage->validate()) { // 确保目录存在 if (!file_exists($dir)) { mkdir($dir, 0755, true); } // 保存文件并处理图片 if ($addImgFile->saveAs($dir . $filename)) { $imag = \Yii::$app->image->load($dir . $filename); $imag->save($dir . $filename, 90); $modelProductImage->save(); $results[] = [ 'filelink' => $result_link . $filename, 'filename' => $filename ]; } else { $results[] = ['error' => '文件保存失败']; } } else { $results[] = ['error' => $modelProductImage->getFirstError('attachment')]; } } \Yii::$app->response->format = Response::FORMAT_JSON; return $results; } else { throw new BadRequestHttpException('仅允许POST请求'); } }
额外注意事项
- 确保
@productImgPath别名已正确配置,且目标目录有写入权限; - 若使用的
FileInput插件版本较旧,需确认多文件上传的参数传递逻辑是否兼容; - 可根据需求增加文件大小、类型的额外校验逻辑。
内容的提问来源于stack exchange,提问作者Dimon Fre
相关产品推荐
相关产品推荐

