上传失败时需先确认$_FILES是否为空,再解析PHP原生错误码:0成功;1为upload_max_filesize超限;2为MAX_FILE_SIZE表单限制;4为未选文件;6/7为临时目录问题;应优先检查enctype、PHP配置及反向代理设置。

当Yii2应用中文件上传失败时,前端只显示“上传失败”四个字,后端日志里却只有UPLOAD_ERR_INI_SIZE或UPLOAD_ERR_FORM_SIZE这类数字代码,开发人员无法快速判断是PHP配置问题、表单限制问题,还是用户上传了非法类型——必须立刻定位错误根源并给出可执行的修复路径。
识别上传错误码来源
Yii2本身不定义上传错误码,它直接透传PHP原生的$_FILES['xxx']['error']值。这个值是整数,不是字符串,且仅在$_FILES非空时才有效。
第一步:在控制器中打印原始错误值——不要跳过这步,很多开发者直接看模型验证失败就去改rules,却忘了先确认底层是否根本没收到文件。
var_dump($_FILES['myFile']['error'] ?? 'no file uploaded');
注意:【若输出NULL或空数组,说明表单未提交或enctype缺失,此时所有后续验证都无效】。必须先解决$_FILES为空的问题,再查错误码。
常见错误码对应关系(PHP官方定义):
0 → 上传成功;1 → UPLOAD_ERR_INI_SIZE(php.ini中upload_max_filesize超限);2 → UPLOAD_ERR_FORM_SIZE(表单MAX_FILE_SIZE隐藏字段超限);3 → UPLOAD_ERR_PARTIAL(仅部分上传);4 → UPLOAD_ERR_NO_FILE(无文件);6/7 → 临时目录缺失或磁盘满。
区分PHP配置级错误与业务逻辑错误
PHP配置级错误(如1、2、6、7)发生在文件进入PHP解析器之前,Yii2模型验证根本不会触发;业务逻辑错误(如类型不符、大小超模型规则)则在$model->validate()之后才暴露。
方法一:用UploadedFile::getInstance()获取实例后立即检查$file->error
这一步必须放在$model->load()之前。如果$file->error !== UPLOAD_ERR_OK,直接返回错误响应,不走模型验证流程。
方法二:在模型rules中添加'checkUploadError' => function ($attribute) { if ($this->$attribute && $this->$attribute->error !== UPLOAD_ERR_OK) { $this->addError($attribute, '文件上传底层失败:'. $this->$attribute->error); } }
此写法能统一捕获,但需注意:它无法区分是PHP配置问题还是服务器环境问题(如tmp目录不可写),仅作兜底。
修复UPLOAD_ERR_INI_SIZE(错误码1)
这是最常被误判为“Yii配置问题”的典型场景。实际是PHP引擎在解析请求体前就拦截了,Yii连request都没收到。
① 修改php.ini中两个关键参数:
upload_max_filesize = 64M
post_max_size = 72M
② 确保post_max_size严格大于upload_max_filesize——否则即使单个文件没超,多个文件+表单字段总和超限也会触发同一错误码。
③ 重启Web服务(Apache/Nginx + PHP-FPM),运行phpinfo()确认生效。不要依赖ini_set(),它对这两个参数无效。
④ 验证:上传一个刚好63MB的文件,观察是否仍报错。若仍失败,检查是否有反向代理(如Nginx)自身设置了client_max_body_size,该值必须同步调大。
拦截UPLOAD_ERR_FORM_SIZE(错误码2)
这个错误完全由HTML表单控制,和PHP配置无关。用户上传文件时,浏览器会先读取表单里的<input type="hidden" name="MAX_FILE_SIZE" value="10485760">,超限时直接拒绝提交。
方法1:删除表单中的MAX_FILE_SIZE字段——让前端完全依赖后端校验,避免前后端不一致。
方法2:在ActiveForm中动态生成该字段:= $form->field($model, 'imageFile')->fileInput(['data-max-size' => $model->maxSize]) ?>,再用JS同步更新隐藏域值。
【注意:MAX_FILE_SIZE只是浏览器提示,可被轻易绕过,绝不能作为唯一校验手段】
方法3:在控制器中主动比对$_SERVER['CONTENT_LENGTH']与预设阈值,超限时直接返回413状态码,不进入Yii生命周期。
处理UPLOAD_ERR_NO_FILE(错误码4)
用户点击提交但未选择任何文件时触发。看似简单,但常因表单编码类型错误导致整个$_FILES为空,而非返回4。
第一步:确认表单属性enctype="multipart/form-data"已设置。缺少它,$_FILES永远为空,错误码也无从谈起。
第二步:检查ActiveForm是否显式声明:ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']])。Yii2默认不自动添加该属性。
第三步:若使用AJAX上传,确保XMLHttpRequest的contentType未被设为application/json——这会覆盖浏览器自动设置的multipart/form-data边界符。
第四步:验证CSRF令牌是否正确嵌入。Yii2默认开启CSRF验证,表单若漏掉<?php echo Html::csrfMetaTags(); ?>或$form->field($model, '_csrf')->hiddenInput(),请求会被拦截,$_FILES同样为空。


















