$_files为空或无数据说明php未接收到文件,首要排查表单是否缺失enctype="multipart/form-data"、input name与$_files键名是否完全一致、是否使用post方法,以及ajax中是否误设content-type;upload_max_filesize修改后需同步调大post_max_size并重启服务,且须确认nginx client_max_body_size、php版本单位大小写等细节。

$_FILES 为空或根本没数据
这是最常被忽略的第一步:PHP 根本没收到文件。不是代码错,是请求压根没把文件送进来。
- 检查
<form></form>是否带enctype="multipart/form-data"—— 缺了这个,$_FILES必然为空 -
<input type="file" name="avatar">的name值,必须和 PHP 里读的键名完全一致(大小写敏感),比如$_FILES['avatar']['error'] - 确认用的是
method="POST",GET 不支持文件上传 - 如果走 AJAX,别手动设
Content-Type,会破坏 multipart boundary;用FormData.append('file', input.files[0])即可
upload_max_filesize 改了但没生效
PHP 8.5.5 对 ini 值解析更严格,改了不生效大概率不是没重启,而是被其他环节卡死了。
-
upload_max_filesize = 256M必须配对调post_max_size = 260M(单位大写,不能写256m或256 M) - 用
php --ini查真实加载路径,再用var_dump(ini_get('upload_max_filesize'))验证是否返回字符串"256M",不是false或空 - Nginx 用户必须同步设
client_max_body_size 256M(在server或location块里),否则 413 错误直接由 Nginx 抛出,PHP 根本收不到请求 - 宝塔用户注意:PHP 设置页改的是全局配置,但站点可能启用了独立 PHP 配置,得进对应站点的 PHP 设置里单独改
move_uploaded_file() 失败但 error === 0
临时文件已存好($_FILES['x']['error'] === 0),但存不到目标位置——问题出在路径、权限或父目录缺失。
-
move_uploaded_file()第一个参数必须是$_FILES['f']['tmp_name'],不是原始文件名或$_FILES['f']['name'] - 目标路径的父目录必须存在,
move_uploaded_file()不会自动创建,得先mkdir(dirname($target), 0755, true) - Linux 下检查 Web 进程用户(如
www-data)对目标目录是否有写权限:ls -ld /path/to/uploads,再chown www-data:www-data /path/to/uploads - 容器环境要确认挂载卷是否设为
rw,Docker Compose 里别漏掉read_only: false
PHP 8.5.5 特别要注意的坑
8.5.5 没新增上传函数,但单位校验变严、错误提示更准,容易暴露旧配置里的“侥幸”写法。
- 单位必须大写:
128M✅,128m❌(会被当 0 处理) -
max_execution_time和max_input_time要一起调大,上传 500MB 文件至少设到600 -
upload_tmp_dir如果自定义了路径,得确保该目录存在且www-data可写,否则报UPLOAD_ERR_NO_TMP_DIR (6) - Cloudflare 或其他 CDN 有自己上传限制(免费版默认 100MB),PHP 和 Nginx 改得再大也没用,得去 CDN 后台调
move_uploaded_file(),而是前面七八个环节里某一个没打通。查的时候按顺序来:表单 → Web 服务器限制 → PHP 配置 → 临时目录 → 目标目录权限。跳步排查,90% 的“上传失败”都能三分钟内定位到具体哪一环断了。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











