php多文件上传时$_files['files']是字段维度嵌套数组,需按索引对齐处理各字段(如name[0]对应tmp_name[0]),遍历name数组获取文件,严格校验error、mime类型和size,重命名+分目录存储,并调大超时配置防卡死。

PHP 多文件上传时 $_FILES 结构怎么读对
PHP 默认把多文件上传当做一个「数组嵌套结构」,不是你想象中每个文件独立一套 $_FILES['file']。如果表单用 <input type="file" name="files[]" multiple>,$_FILES['files'] 会是这种结构:
Array(
'name' => ['a.jpg', 'b.pdf'],
'type' => ['image/jpeg', 'application/pdf'],
'tmp_name' => ['/tmp/php123', '/tmp/php456'],
'error' => [0, 0],
'size' => [12345, 67890]
)
直接遍历 $_FILES['files']['name'] 才能拿到每个文件名;用 foreach ($_FILES['files'] as $file) 会错——那遍历的是字段维度(name/type/tmp_name),不是文件维度。
- 必须按索引对齐处理:比如第 0 个
name对应第 0 个tmp_name和第 0 个error -
move_uploaded_file()只认tmp_name,别传错键名 - 如果漏检查
error === 0就调move_uploaded_file(),可能静默失败或覆盖空文件
上传前必须校验的三个硬性条件
浏览器的 multiple 和前端 JS 校验都不可信,服务端必须重做。重点不是“能不能传”,而是“该不该收”。
-
$_FILES['files']['error'][$i]不为0(如UPLOAD_ERR_INI_SIZE)就跳过,别试图读tmp_name - 用
finfo_open(FILEINFO_MIME_TYPE)检 MIME,别只看$_FILES['files']['type'][$i](浏览器可伪造) - 检查
$_FILES['files']['size'][$i]是否超过你设定的单文件上限(如 10M),upload_max_filesize是 PHP 配置,不是业务规则
move_uploaded_file() 批量调用要注意路径和冲突
每次调用 move_uploaded_file() 都是独立 IO 操作,但并发写同一目录、同名文件会出问题。实际场景里,重命名 + 分目录是刚需。
立即学习“PHP免费学习笔记(深入)”;
- 别直接用原始
$_FILES['files']['name'][$i]当目标文件名——含路径、特殊字符、中文都可能出错 - 建议生成唯一前缀:
$safeName = uniqid() . '_' . preg_replace('/[^\w.-]/', '_', $originalName) - 大文件多时,考虑按哈希分目录(如
uploads/ab/cd/...),避免单目录文件过多影响 inode 查找性能 - 调用后务必检查返回值:
if (!move_uploaded_file($tmp, $dest)) { /* 记录失败原因 */ },否则失败无声无息
大文件或高并发上传时容易卡死的两个点
批量上传不是简单循环就能扛住的。PHP 默认配置和脚本执行方式在真实场景下很容易崩。
-
max_execution_time和max_input_time都要调大——尤其网络慢时,上传本身耗时算在max_input_time里,超时直接截断$_FILES - 别在循环里做耗时操作(如生成缩略图、同步转码),先存再异步处理;否则一个 100MB 文件上传+处理卡住整个请求,其他文件等不到执行
- 如果用 Nginx,记得配
client_max_body_size,它比 PHP 的post_max_size更早拦截请求
真正麻烦的从来不是“怎么把文件挪过去”,而是“怎么确认每个都挪对了、没混、没丢、不拖垮服务器”。边界情况比代码逻辑更花时间。











