-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

halfer
  • 19,824
  • 17
  • 99
  • 186
Paddy Hallihan
  • 1,624
  • 3
  • 27
  • 76
  • 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? – Chris Haas Jul 13 '20 at 13:05
  • Hi @ChrisHaas see my new edit to the question for a screenshot – Paddy Hallihan Jul 13 '20 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`](https://www.php.net/manual/en/function.fread.php). Instead, however, you might want to look into the `@` syntax for `POSTFIELDS` https://stackoverflow.com/a/3433581/231316 – Chris Haas Jul 13 '20 at 13:34
  • Note that we prefer a technical style of writing here. We gently discourage greetings, hope-you-can-helps, thanks, advance thanks, notes of appreciation, regards, kind regards, signatures, please-can-you-helps, chatty material and abbreviated txtspk, pleading, how long you've been stuck, voting advice, meta commentary, etc. Just explain your problem, and show what you've tried, what you expected, and what actually happened. – halfer Jul 13 '20 at 14:13
  • 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? – ficuscr Jul 16 '20 at 21:00
  • btw don't use `CURLOPT_CUSTOMREQUEST=>'PUT'`, instead use `CURLOPT_UPLOAD=>1` – hanshenrik Jul 17 '20 at 10:44

1 Answers1

0

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(...));
hanshenrik
  • 19,904
  • 4
  • 43
  • 89