使用 PHP cURL 将文件上传到 Google 签名 URL

Posted

技术标签:

【中文标题】使用 PHP cURL 将文件上传到 Google 签名 URL【英文标题】:Uploading a file to Google Signed URL with PHP cURL 【发布时间】:2020-10-31 07:48:27 【问题描述】:

我正在尝试使用 php 中的 cURL 将文件上传到 Google 签名 URL。

我有从表单发布的文件,并且可以使用 $_FILES var 访问它。

但是实际上传的文件不是正确的文件,我认为这与我处理 tmp 文件的方式有关。

$file_name = $_FILES['file']['name'];
$temp_name = $_FILES['file']['tmp_name'];

// $file = fopen($temp_name, 'r');
// $file = realpath($temp_name);

$request = curl_init($request_url);

curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
curl_setopt($request, CURLOPT_POSTFIELDS, $file);
curl_setopt($request, CURLOPT_HTTPHEADER, array('Content-Type:text/plain','Authorization:'.$token));
curl_setopt($request, CURLOPT_CUSTOMREQUEST, 'PUT');

$response = curl_exec($request);
$errors = curl_error($request);
curl_close($request);

var_dump($response);
var_dump($errors);

以下内容可以按预期使用内容类型文本而不是音频,即使它是一个 wav 文件。

curl -v -X PUT --upload-file file.wav --header "Content-Type: text/plain" request_url

编辑

我试过这个:

$file = new CurlFile($temp_name,$mime_type,$file_name);

但这只会让我的页面完全崩溃。

我认为这可能与我调用请求的方式有关,所以我想创建一个 cURL 函数,我可以将 url 和数据传递给我的所有请求,如下所示:

$file = new CurlFile($temp_name,$mime_type,$file_name);
$result = curl_request($conn,$signed_url,$file,'text/plain','PUT');

那么我的函数是这样的:

function curl_request($conn,$request_url,$request_data,$content_type,$request_type)
    $api_username = 'API username';
    $stmt = $conn->prepare("SELECT * FROM config WHERE setting=:setting");
    $stmt->bindParam(':setting', $api_username);
    $stmt->execute();
    $result = $stmt->setFetchMode(PDO::FETCH_ASSOC);
    foreach($stmt->fetchAll() as $key=>$row) 
        $username = $row['value'];
    
    $api_key = 'API key';
    $stmt = $conn->prepare("SELECT * FROM config WHERE setting=:setting");
    $stmt->bindParam(':setting', $api_key);
    $stmt->execute();
    $result = $stmt->setFetchMode(PDO::FETCH_ASSOC);
    foreach($stmt->fetchAll() as $key=>$row) 
        $key = $row['value'];
    
    
    $data = array(
        'username' => $username,
        'password' => $key
    );
    $payload = json_encode($data);

    $initial_request = curl_init('https://example.com/auth');
    curl_setopt($initial_request, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($initial_request, CURLOPT_POSTFIELDS, $payload);
    curl_setopt($initial_request, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));

    $initial_response = curl_exec($initial_request);
    $initial_errors = curl_error($initial_request);

    curl_close($initial_request);
    
    $decoded_response = (array)json_decode($initial_response);
    $token = $decoded_response['token'];
    
    $request = curl_init($request_url);
    
    curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($request, CURLOPT_POSTFIELDS, $request_data);
    curl_setopt($request, CURLOPT_HTTPHEADER, array('Content-Type:'.$content_type,'Authorization:'.$token));
    curl_setopt($request, CURLOPT_CUSTOMREQUEST, $request_type);
    
    $response = curl_exec($request);
    $errors = curl_error($request);
    curl_close($request);
    
    if(empty($errors))
        return $response;
    else
        return $errors;
    

这在我有 $file = fopen($temp_name, 'r'); 但上传的文件是一个奇怪的文件时有效。

编辑 2

这是该 API 另一端的人尝试打开文件时的样子。

【问题讨论】:

你能解释一下什么是“奇怪的文件”吗?例如,它是一个完全错误的文件,还是它似乎以某种方式损坏。你能对这两个文件进行二进制比较吗? 嗨 @ChrisHaas 查看我对问题的新编辑以获取屏幕截图 好的。 fopen 打开一个文件进行读取并返回一个资源,而不是文件的内容。为此,您将使用诸如fread 之类的函数。但是,您可能需要查看 @ 语法的 POSTFIELDS ***.com/a/3433581/231316 请注意,我们更喜欢这里的技术写作风格。我们轻轻地劝阻问候,希望你能帮助,谢谢,提前感谢,感谢信,问候,亲切的问候,签名,请你能帮助,聊天材料和缩写 txtspk,恳求,你多久了被卡住、投票建议、元评论等。只需解释您的问题,并展示您尝试过的内容、预期的内容以及实际发生的情况。 好吧curl_setopt($request, CURLOPT_POSTFIELDS, $file); 看起来不对。 $file 应该是一个数组,不是吗?你没有收到错误吗?你甚至隔离了这个问题吗?是在上传吗? 【参考方案1】:

这就是你想要的:完全删除 CURLOPT_POSTFIELDS,将 CURLOPT_CUSTOMREQUEST=>'PUT' 替换为 CURLOPT_UPLOAD=>1,将 'r' 替换为 'rb',并使用 CURLOPT_INFILE(你应该使用 INFILE 而不是 POSTFIELDS),

$fp = fopen($_FILES['file']['tmp_name'], "rb");
curl_setopt_array($ch,array(
CURLOPT_UPLOAD=>1,
CURLOPT_INFILE=>$fp,
CURLOPT_INFILESIZE=>$_FILES['file']['size']
));

这在我有 $file = fopen($temp_name, 'r'); 时有效

永远不要使用r 模式,始终使用rb 模式(“二进制模式”的缩写),如果您曾经在Windows 上使用r 模式,会发生奇怪的事情,r 是“文本”的缩写模式” - 如果你真的想要文本模式,请使用rt(除非你真的知道自己在做什么,否则你永远不需要文本模式,不幸的是它是默认模式),

但上传的文件是一个奇怪的文件。 (...) 这是该 API 另一端的人尝试打开文件时的样子。

你给了 CURLOPT_POSTFIELDS 一个资源。 CURLOPT_POSTFIELDS 接受 2 种参数,#1:数组(用于multipart/form-data 请求),#2:字符串(用于指定原始帖子正文数据时),它不接受资源。

如果 php curl api 设计良好,则在为 CURLOPT_POSTFIELDS 提供资源时,您将收到 InvalidArgumentException 或 TypeError。但它的设计并不好。相反,发生的事情是 curl_setopt 隐式地​​将您的资源转换为字符串,因此 resource id #X ,它与做的一样

curl_setopt($request, CURLOPT_POSTFIELDS, (string) fopen(...));

【讨论】:

以上是关于使用 PHP cURL 将文件上传到 Google 签名 URL的主要内容,如果未能解决你的问题,请参考以下文章

使用 cURL 将 PHP 文件上传到 imageshack

使用 HTML 表单、cURL 和 PHP 将文件上传到 Imageshack API

使用PHP和cURL通过它们的API将文件上传到RapidShare

在邮递员中使用 php curl 将文件上传到 Nextcloud 但上传的文件为空

如何将 curl 上传进度发送到要显示的 ajax

如何使用curl使用php上传文件[关闭]