上传文件到 Google 签名 URL with PHP cURL
Uploading a file to Google Signed URL with PHP cURL
我正在尝试将文件上传到 Google 已签名 URL,在 PHP 中使用 cURL。
我有从表单发布的文件,可以使用 $_FILES 变量访问它。
但是实际上传的文件不是正确的文件,我认为这与我处理 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 另一端的人试图打开文件时文件的样子。
这就是你想要的:完全删除 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']
));
This works when I had $file = fopen($temp_name, 'r');
永远不要使用r
模式,总是使用rb
模式(“二进制模式”的缩写),如果你在[=上使用r
模式会发生奇怪的事情40=], r
是“文本模式”的缩写 - 如果你真的想要文本模式,请使用 rt
(除非你真的知道你在做什么,否则你不需要文本模式, 不幸的是,它是默认模式),
but the file uploaded was a weird file. (...) This is what the file looks like when the person at the other end of this API tries to open it.
你给了 CURLOPT_POSTFIELDS 一个资源。 CURLOPT_POSTFIELDS 接受 2 种参数,#1:一个数组(用于 multipart/form-data
请求),#2:一个字符串(当你想指定原始 post 正文数据时),它不接受资源。
如果 php curl api 设计良好,在给 CURLOPT_POSTFIELDS 资源时,您会得到 InvalidArgumentException 或 TypeError。但它设计得不好。相反,发生的事情是 curl_setopt 将您的资源隐式转换为字符串,因此 resource id #X
与
相同
curl_setopt($request, CURLOPT_POSTFIELDS, (string) fopen(...));
我正在尝试将文件上传到 Google 已签名 URL,在 PHP 中使用 cURL。
我有从表单发布的文件,可以使用 $_FILES 变量访问它。
但是实际上传的文件不是正确的文件,我认为这与我处理 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 另一端的人试图打开文件时文件的样子。
这就是你想要的:完全删除 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']
));
This works when I had $file = fopen($temp_name, 'r');
永远不要使用r
模式,总是使用rb
模式(“二进制模式”的缩写),如果你在[=上使用r
模式会发生奇怪的事情40=], r
是“文本模式”的缩写 - 如果你真的想要文本模式,请使用 rt
(除非你真的知道你在做什么,否则你不需要文本模式, 不幸的是,它是默认模式),
but the file uploaded was a weird file. (...) This is what the file looks like when the person at the other end of this API tries to open it.
你给了 CURLOPT_POSTFIELDS 一个资源。 CURLOPT_POSTFIELDS 接受 2 种参数,#1:一个数组(用于 multipart/form-data
请求),#2:一个字符串(当你想指定原始 post 正文数据时),它不接受资源。
如果 php curl api 设计良好,在给 CURLOPT_POSTFIELDS 资源时,您会得到 InvalidArgumentException 或 TypeError。但它设计得不好。相反,发生的事情是 curl_setopt 将您的资源隐式转换为字符串,因此 resource id #X
与
curl_setopt($request, CURLOPT_POSTFIELDS, (string) fopen(...));