直接改 upload_max_filesize 不生效是常态,因 php 文件上传受 web 服务器、php.ini 和应用代码三层拦截;常见原因包括 post_max_size ≤ upload_max_filesize、memory_limit 过小、配置文件路径错误、单位书写错误等。

直接改 upload_max_filesize 不生效是常态,因为 PHP 文件上传受至少三层拦截:Web 服务器(如 Nginx)、PHP 解析层(php.ini)、应用代码($_FILES)。只调其中一层,必然失败。
为什么改了 php.ini 还是 UPLOAD_ERR_INI_SIZE?
这是最典型的“只改一半”现象。错误码 UPLOAD_ERR_INI_SIZE(值为 1)说明请求在 PHP 解析阶段就被拦下了,根本没进你的脚本逻辑。常见原因:
-
post_max_size小于或等于upload_max_filesize→ 整个 POST 请求被截断,哪怕只传一个文件 -
memory_limit小于post_max_size→ PHP 尝试把整个 POST 数据载入内存时爆内存,静默失败 - 改错了配置文件:CLI 和 Web SAPI 加载的
php.ini路径不同,必须通过phpinfo()查 “Loaded Configuration File” - 单位写错:比如
upload_max_filesize = "64M"(带引号)或upload_max_filesize = 64MB(B 被忽略,变成 64 字节)
如何用 $_FILES 做可靠的应用层校验?
$_FILES 的 error 字段是唯一可信入口,但不能只看它——它只反映 PHP 层拦截结果,不反映业务规则。真正可靠的校验要分两步走:
- 先确认上传是否成功:
if ($_FILES['file']['error'] !== UPLOAD_ERR_OK),非 0 就别往下走了 - 再做业务限制:比如只允许 ≤2MB 的图片,就得自己比大小:
if ($_FILES['file']['size'] > 2 * 1024 * 1024) - 注意:不要只信
$_FILES['file']['type'],它由浏览器提供,可伪造;必须用finfo_open(FILEINFO_MIME_TYPE)检测真实 MIME - 临时文件路径
$_FILES['file']['tmp_name']一定要存在且可读,否则move_uploaded_file()会静默失败(error仍为 0)
Nginx + PHP-FPM 环境下必须同步调整 client_max_body_size
即使 php.ini 全部调大,Nginx 在请求抵达 PHP 前就可能把它干掉,返回 413 Request Entity Too Large。这不是 PHP 错误,$_FILES 根本不会出现,表单提交后直接空白或 413 页面。
- 在 Nginx 的
server或location ~ \.php$块中加:client_max_body_size 128M(数值 ≥post_max_size) - 如果用了反向代理(如负载均衡、CDN),上游网关同样要设
client_max_body_size,否则卡在第一道门 - 别忘了超时项:
client_body_timeout 600和proxy_read_timeout 600,防止大文件上传中途断连 - 改完必须
nginx -t && nginx -s reload,reload不等于restart,后者可能中断已有连接
最容易被忽略的是 upload_tmp_dir 权限和空间:PHP 把上传文件先写到这个目录,再交给你处理。如果它不存在、不可写、磁盘满,或挂载在被 systemd-tmpfiles 清理的 /tmp 下,move_uploaded_file() 会失败且不报错——$_FILES['error'] 还是 0,你得手动 is_writable() 和 disk_free_space() 检查。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











