Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
324 views
in Technique[技术] by (71.8m points)

Uploading a file to Google Signed URL with PHP cURL

I am trying to upload a file to a Google Signed URL with cURL in PHP.

I have the file being posted from a form and can access it with the $_FILES var.

However the file that actually gets uploaded is not the right file and I think it is to do with how I am handling the tmp file.

$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);

The following works as expected with content-type text instead of audio even though its a wav file.

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

Edit

I have tried this:

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

but this just crashes my page altogether.

I think it may be to do with how I am calling the request, so I wanted to create a cURL function that I can just pass the url and data to for all my requests like so:

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

Then my function is like this:

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;
    }
}

This works when I had $file = fopen($temp_name, 'r'); but the file uploaded was a weird file.

Edit 2

This is what the file looks like when the person at the other end of this API tries to open it.

enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

this is what you want: remove CURLOPT_POSTFIELDS altogether, and replace CURLOPT_CUSTOMREQUEST=>'PUT' with CURLOPT_UPLOAD=>1 and replace 'r' with 'rb', and use CURLOPT_INFILE (you're supposed to use INFILE instead of 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');

never use the r mode, always use the rb mode (short for "binary mode"), weird things happen if you ever use the r mode on Windows, r is short for "text mode" - if you actually want text mode, use rt (and unless you really know what you're doing, you don't want the text mode, ever, unfortunate that it's the default mode),

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.

well you gave CURLOPT_POSTFIELDS a resource. CURLOPT_POSTFIELDS accepts 2 kinds of arguments, #1: an array (for multipart/form-data requests), #2: a string (for when you want to specify the raw post body data), it does not accept resources.

if the php curl api was well designed, you would get an InvalidArgumentException, or a TypeError, when giving CURLOPT_POSTFIELDS a resource. but it's not well designed. instead, what happened is that curl_setopt implicitly casted your resource to a string, hence resource id #X , it's the same as doing

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...