目录已存在且可获取临时文件,为何move_uploaded_file()上传失败?
move_uploaded_file转存失败排查方案
最高概率问题:目录权限不匹配
你创建上传目录时使用的系统用户,和实际运行PHP服务的用户(通常是www-data、apache、nginx)不是同一账号,哪怕目录确实存在,PHP进程没有写入权限就会直接导致转存失败。
- 在PHP脚本顶部加上
echo 'PHP运行身份:' . exec('whoami');,访问页面拿到实际运行PHP的系统用户 - 执行授权命令(将
www-data替换成你查到的实际用户):sudo chown -R www-data:www-data /var/www/html/uploads/user/test_uploads - 临时排查可先给目录开全权限测试:
sudo chmod -R 777 /var/www/html/uploads/user/test_uploads,如果此时能上传成功即可确认是权限问题,生产环境记得将权限改回安全的755规则,禁止长期使用777权限。
核心排查步骤:不要盲试,先拿明确错误
现有代码只输出笼统的“上传失败”,没有定位真实原因,首先要读取$_FILES['file']['error']字段获取明确错误码,对照下表排查:
- 0:上传流程无基础错误
- 1:文件大小超过php.ini的
upload_max_filesize配置上限 - 2:文件大小超过前端表单设置的
MAX_FILE_SIZE值 - 3:文件仅部分被上传
- 4:没有选择有效上传文件
- 6:PHP临时目录不存在或无读取权限
- 7:磁盘写入失败
- 8:PHP扩展中断了上传流程
其他高频踩坑点
- open_basedir限制:如果php.ini配置了
open_basedir规则,会限制PHP可访问的目录范围,若你的目标上传目录不在允许列表内,转存会直接失败。在脚本中加echo 'open_basedir配置:' . ini_get('open_basedir');即可查看当前规则,要么把上传目录加入允许范围,要么调整open_basedir配置。 - 文件名安全处理:不要直接使用原始上传文件名拼接路径,万一文件名包含
../这类特殊字符,会导致路径错误甚至安全漏洞。用basename($fileName)过滤掉路径部分,仅保留纯文件名再拼接目标路径。 - 磁盘空间检查:执行
df -h /var/www/html/查看对应分区是否已满,空间不足会直接导致写入失败。 - 上传合法性校验:
move_uploaded_file仅能识别PHP通过POST流程生成的合法临时文件,调用前先用is_uploaded_file($fileTmpLoc)校验,避免伪造临时文件路径导致的失败。
可直接定位问题的修正版上传代码
<?php // 先打印基础上传错误,快速排除流程问题 if ($_FILES['file']['error'] !== UPLOAD_ERR_OK) { echo "上传失败,错误码:" . $_FILES['file']['error']; exit; } $fileName = $_FILES["file"]["name"]; $fileTmpLoc = $_FILES["file"]["tmp_name"]; // 校验临时文件合法性 if (!is_uploaded_file($fileTmpLoc)) { echo "非法的上传临时文件"; exit; } // 过滤路径字符,避免遍历漏洞 $safeFileName = basename($fileName); $targetDir = "/var/www/html/uploads/user/test_uploads/"; $targetPath = $targetDir . $safeFileName; // 校验目录写入权限 if (!is_writable($targetDir)) { echo "目标目录无写入权限"; exit; } if (move_uploaded_file($fileTmpLoc, $targetPath)){ echo "$safeFileName 上传成功。"; } else { echo "转存失败,请检查磁盘空间、open_basedir限制"; } ?>
内容的提问来源于stack exchange,提问作者Stacie T.
相关产品推荐
相关产品推荐

