PHP中PUT请求文件上传失败问题求助
PUT请求下move_uploaded_file失败(错误码0)的排查与解决
问题背景
应用需要支持POST和PUT两种方法上传文件,通过第三方代码生成符合格式的$_FILES数组处理PUT请求后,POST方法上传正常,但PUT方法调用move_uploaded_file时返回false,错误码为0。已确认目标目录权限正常(POST可正常写入),临时JPEG文件可通过exif_get_data()正常读取。
相关代码
function processPhoto($file, $bmid) { $x = explode(".", $file["name"]); $filetype = $x[1]; $fileurl = "https://" . $_SERVER['HTTP_HOST'] . "/assets/img/bm$bmid-" . date('Ymd') . ".$filetype"; $filedir = $_SERVER['DOCUMENT_ROOT'] . "/assets/img"; $filepath = $filedir . "/bm$bmid-" . date('Ymd') . ".$filetype"; if (!is_dir($_SERVER['DOCUMENT_ROOT'] . "/assets")) { return array('result' => false, 'message' => "/assets is not a directory"); } if (!is_dir($_SERVER['DOCUMENT_ROOT'] . "/assets/img")) { return array('result' => false, 'message' => "$filedir is not a directory"); } if (!is_writable($_SERVER['DOCUMENT_ROOT'] . "/assets")) { return array('result' => false, 'message' => "/assets is a directory but is not writeable"); } if (!is_writable($filedir)) { return array('result' => false, 'message' => "$filedir is a directory but is not writeable"); } if (!file_exists($file["tmp_name"])) { return array('result' => false, 'message' => "$file[tmp_name] does not exist"); } clearstatcache(); if (file_exists($filepath)) { chmod($filepath, 0755); unlink($filepath); } $result = move_uploaded_file($file["tmp_name"], $filepath); if (!$result) { return array('result' => false, 'message' => "Unable to upload the photo file from $file[tmp_name] to $filepath (error #$file[error])"); } return array('result' => true, 'filename' => $fileurl); }
排查方向与解决方案
1. 核心原因:move_uploaded_file的机制限制
move_uploaded_file是PHP专门为HTTP POST上传的文件设计的函数,它会验证文件是否由PHP的POST上传机制创建。PUT请求生成的临时文件并非通过POST流程生成,因此即使文件存在、权限正常,该函数也会直接返回false,且错误码保持为$_FILES中手动设置的0。
解决方案:
替换move_uploaded_file为copy()或rename(),这两个函数不检查文件的上传来源,只要文件存在且有读写权限即可完成操作:
// 替换原move_uploaded_file代码段 $result = copy($file["tmp_name"], $filepath); if (!$result) { $lastError = error_get_last(); return array('result' => false, 'message' => "Failed to copy file: " . $lastError['message']); } // 可选:如果临时文件无需保留,可手动删除 unlink($file["tmp_name"]);
2. 临时文件权限与所有权验证
虽然exif_get_data()能读取临时文件,但仍需确认PHP进程是否拥有足够权限操作该文件:
在processPhoto函数开头添加调试代码:
// 打印临时文件权限、PHP进程用户、目标目录所有者 error_log("Temp file permissions: " . decoct(fileperms($file["tmp_name"]))); error_log("PHP process user: " . get_current_user()); error_log("Target dir owner: " . posix_getpwuid(fileowner($filedir))['name']);
若权限或所有者不匹配,需调整临时文件或目标目录的权限设置。
3. 验证$_FILES数组完整性
确认PUT请求生成的$file数组字段是否完全正确,可在函数开头添加日志:
error_log("File array details: " . print_r($file, true));
重点检查tmp_name路径是否真实存在、size是否大于0、error是否确实为0。
内容的提问来源于stack exchange,提问作者Pete
相关产品推荐
相关产品推荐

