PHP上传失败最常见原因是表单enctype未设为multipart/form-data或php.ini中file_uploads=Off;需检查upload_max_filesize、post_max_size及move_uploaded_file()目标目录权限与绝对路径。

PHP上传文件时$_FILES数组为空或报错
最常见原因是表单没设对 enctype 属性,或者 PHP 配置限制了上传。浏览器提交文件必须用 multipart/form-data 编码,否则 $_FILES 里什么都不会有。
- 确认 HTML 表单包含
enctype="multipart/form-data",缺了这句就等于没上传功能 - 检查
php.ini中file_uploads = On、upload_max_filesize(如2M)和post_max_size(需 ≥ upload_max_filesize)是否合理 - 上传失败时,
$_FILES['xxx']['error']会返回数字,比如4表示没选文件,1或2表示超大小,别只看空数组就瞎改代码
move_uploaded_file() 失败的典型原因
move_uploaded_file() 不是万能搬运工,它只接受 $_FILES 里的临时路径,且目标目录必须存在、有写权限,否则直接返回 false。
- 目标路径不能是相对路径如
uploads/,得用绝对路径,推荐__DIR__ . '/uploads/' . $filename - 确保
uploads/目录已创建,并被 Web 服务器用户(如 www-data、apache)可写,Linux 下常要chmod 755或775 - 不要跳过
is_uploaded_file()校验,直接传$_FILES['file']['tmp_name']给move_uploaded_file()前先判断一次,防伪造路径攻击
安全过滤文件名和类型不能只靠前端
前端 <input accept=".jpg,.png"> 和 JS 检查完全不可信,攻击者删掉 HTML 就能传任意后缀。PHP 层必须重验。
- 用
pathinfo($filename, PATHINFO_EXTENSION)提取扩展名,再白名单比对(如in_array(strtolower($ext), ['jpg', 'png', 'pdf'])),别用黑名单 - 避免直接拼接原始文件名,建议用
uniqid() . '.' . $safe_ext生成新名,防止../../../etc/passwd.jpg这类路径遍历 -
$_FILES['file']['type']可被客户端篡改,不能当真;真要验类型,用finfo_open(FILEINFO_MIME_TYPE)读二进制头
大文件上传需要调整超时和分块逻辑
默认 max_execution_time=30 和 max_input_time=60 在上传几十 MB 文件时大概率超时,单纯调大不是最优解。
立即学习“PHP免费学习笔记(深入)”;
- 先在
php.ini中加大max_execution_time、max_input_time、memory_limit(如256M) - 但更稳妥的是前端用分片上传(如使用
axios+Blob.slice()),后端按序接收并合并,避免单次请求卡死 - 上传中刷新页面会导致中断,可用
session_write_close()防止 session 锁阻塞其他请求,尤其在长上传期间还要查进度时
move_uploaded_file() 的权限问题和 $_FILES['x']['error'] 的具体值最容易被忽略,而这两个恰恰决定上传是成功还是静默失败。



















