PHP文件上传失败主因是配置错误:file_uploads必须On;upload_max_filesize和post_max_size需合理设置并重启服务;upload_tmp_dir权限、磁盘空间及SELinux等也需检查;ThinkPHP中应先用getError()获取原生错误码,再moveTo。

上传失败提示 UPLOAD_ERR_NO_FILE 或直接空白?先查 PHP 配置项
ThinkPHP 里文件没传进来,不一定是框架问题,大概率是 PHP 底层关了上传开关。重点盯三个配置:
-
file_uploads = On—— 必须为On,否则整个上传功能被禁用 -
upload_max_filesize = 2M—— 这个值要 ≥ 你实际想传的文件大小,比如传 5MB 图片就至少设成8M -
post_max_size = 8M—— 它必须 ≥upload_max_filesize,否则 POST 数据体还没进 PHP 就被截断,连错误都不报,页面直接空白
改完记得重启 Web 服务(php-fpm 或 Apache),用 phpinfo() 页面确认生效,别只改了 php.ini 却忘了生效路径。
上传后报错 UPLOAD_ERR_CANT_WRITE?检查临时目录权限和磁盘空间
PHP 接收文件后会先写到临时目录(由 upload_tmp_dir 指定,默认是系统 /tmp),再由 ThinkPHP 移走。这里卡住常见于:
-
upload_tmp_dir目录不存在,或 PHP 进程用户(如www-data、nginx)无写权限 - 磁盘已满,
df -h看一眼/tmp所在分区 - SELinux 或 AppArmor 开启时拦截了写操作(Linux 服务器常见,
ausearch -m avc -ts recent可查)
临时解决可显式设置:upload_tmp_dir = /var/tmp,然后 chown www-data:www-data /var/tmp && chmod 1733 /var/tmp(注意 sticky bit)。
立即学习“PHP免费学习笔记(深入)”;
ThinkPHP 的 validate 或 moveTo 报错?别跳过原始错误码
框架封装后容易掩盖底层原因。比如 $file->validate(['size'=>1024*1024]) 失败,你以为是超限,其实可能是 $file->getError() 返回 UPLOAD_ERR_NO_TMP_DIR —— 说明临时目录根本没配。
- 务必在调用
moveTo前检查$file->getError(),它返回的是原生 PHP 错误码字符串,不是布尔值 -
$file->getInfo()返回的数组里,error字段才是关键,name和tmp_name为空往往意味着前置环节已失败 - Windows 下路径分隔符问题:
moveTo('uploads\'. $file->hash())可能因反斜杠被误解析,统一用/或DIRECTORY_SEPARATOR
本地能传、线上 500?重点关注 CGI/FPM 模式下 php.ini 加载差异
Apache + mod_php 和 Nginx + php-fpm 用的不是同一份 php.ini。常见坑:
- Nginx 场景下,
php-fpm的pool配置(如/etc/php/8.1/fpm/pool.d/www.conf)可能通过php_admin_value[upload_max_filesize]覆盖全局配置,优先级更高 - Docker 容器里,
php.ini可能挂载在只读层,修改不生效;或者镜像用了alpine,/tmp是内存盘,容量极小 - 宝塔、AMH 等面板会自动生成多份配置,得进面板「PHP 设置」里改,而不是直接编辑文件
最稳的办法:在出问题的控制器里加一行 var_dump(ini_get('upload_max_filesize'), ini_get('upload_tmp_dir'));,眼见为实。



















