You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 11:27:39