-3

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

5
  • Can you explain what a "weird file" is? For instance, is it a completely wrong file or does it appear to be corrupted in some way. Are you able to perform a binary comparison of the two files? Commented Jul 13, 2020 at 13:05
  • Hi @ChrisHaas see my new edit to the question for a screenshot Commented Jul 13, 2020 at 13:14
  • 1
    Okay. fopen opens a file for reading and returns a resource, not the file's contents. To do that you'd use functions such as fread. Instead, however, you might want to look into the @ syntax for POSTFIELDS stackoverflow.com/a/3433581/231316 Commented Jul 13, 2020 at 13:34
  • Well curl_setopt($request, CURLOPT_POSTFIELDS, $file); looks wrong. The $file should be an array no? Are you not getting errors? Have you even isolated the issue? Is it on upload? Commented Jul 16, 2020 at 21:00
  • btw don't use CURLOPT_CUSTOMREQUEST=>'PUT', instead use CURLOPT_UPLOAD=>1 Commented Jul 17, 2020 at 10:44

1 Answer 1

0
+50

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(...));
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.