PHP开发多文件上传总是丢失首个上传文件问题咨询
PHP多文件上传固定丢失首个文件的排查与解决
问题还原
前端表单、后端处理的代码实现如下:
- 前端表单:
<html> <body> <form action="upload.php" enctype="multipart/form-data" method="post"> <div> <label for='upload'>Add files</label> <input id='upload' name="upload[]" type="file" multiple="multiple" /> </div> <p><input type="submit" name="submit" value="Submit"></p> </form> </body> </html>
- 后端上传逻辑:
<?php if(isset($_POST['submit'])){ if(count($_FILES['upload']['name']) > 0){ for($i=0; $i<count($_FILES['upload']['name']); $i++) { $tmpFilePath = $_FILES['upload']['tmp_name'][$i]; if($tmpFilePath != ""){ $shortname = $_FILES['upload']['name'][$i]; $filePath = $_FILES['upload']['name'][$i]; if(move_uploaded_file($tmpFilePath, $filePath)) { $files[] = $shortname; } } } } echo "<h1>Uploaded:</h1>"; if(is_array($files)){ echo "<ul>"; foreach($files as $file){ echo "<li>$file</li>"; } echo "</ul>"; } } ?>
当前实际运行的异常表现:
- 程序能识别到3个待上传文件
- 最终仅2个文件成功落盘,永远丢失第一个选中待上传的文件
- 全流程无任何错误提示,更换其他网上的多文件上传示例代码,依然复现同样问题
核心根因
这类问题不属于业务代码逻辑bug,是环境配置导致的静默失败,完全匹配当前现象的触发点有两个:
- PHP上传错误被静默拦截
默认配置下move_uploaded_file执行失败仅会返回false,不会抛出明显的警告。第一个文件上传失败的常见场景:- 首个文件大小超过
upload_max_filesize配置限制,PHP在临时文件创建环节就直接失败,tmp_name为空值,被你的$tmpFilePath != ""判断直接跳过 max_file_uploads配置值被修改为2:虽然你能在$_FILES['upload']['name']里拿到3个文件名,但PHP只会为2个文件生成有效的临时文件路径,超出数量限制的文件对应的tmp_name是空值
- 首个文件大小超过
- 落盘路径的权限冲突
你的代码是直接把文件移动到当前PHP脚本所在的根目录,当第一个选中的文件名刚好和目录下已存在的文件重名、且web运行用户对目录没有写入/删除权限时,move_uploaded_file会静默失败,不会抛出权限不足的明显提示。
实操解决步骤
- 先打开全量错误提示,定位真实失败原因
在上传脚本的最顶部加两行代码,强制显示所有错误:
同时直接打印error_reporting(E_ALL); ini_set('display_errors', 1);$_FILES完整结构,查看每个文件对应的error字段值——PHP上传错误码是标准化的,可以直接对应问题:常见上传错误码对照:
- 0:上传成功
- 1:文件大小超过php.ini的
upload_max_filesize限制 - 2:文件大小超过表单设置的
MAX_FILE_SIZE限制 - 3:文件仅部分完成上传
- 4:没有有效文件被上传
- 6:找不到临时存储目录
- 7:文件写入磁盘失败
- 修复代码的固有隐患
不要直接把文件存在脚本运行根目录,指定独立的上传子目录,move之前增加失败日志打印:// 定义固定上传目录,即当前脚本同级的uploads文件夹 $uploadDir = __DIR__ . '/uploads/'; // 自动创建目录,保证写入权限 if(!is_dir($uploadDir)){ mkdir($uploadDir, 0755, true); } // 循环内的上传判断增加错误输出 if(move_uploaded_file($tmpFilePath, $uploadDir . $shortname)) { $files[] = $shortname; } else { echo "文件{$shortname}上传失败,错误码:" . $_FILES['upload']['error'][$i]; } - 核对核心配置项
通过phpinfo()页面确认三个上传相关的配置值是否满足需求:upload_max_filesize:设置为比待上传的最大文件更大的值,比如100Mpost_max_size:要大于单个最大上传文件 * 最大同时上传数的总和,比如300M,避免POST请求体被截断max_file_uploads:设置为比需要同时上传的文件数更大的值,比如20
内容的提问来源于stack exchange,提问作者Telemach
相关产品推荐
相关产品推荐

