Viewed   139 times

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.

 Answers

4

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(...));
Thursday, August 25, 2022
 
3

Like Comment under your original post say

Use PHPMailer

<?php
require_once('../class.phpmailer.php');

$mail             = new PHPMailer(); // defaults to using php "mail()"

$mail->AddReplyTo("[email protected]","First Last");

$mail->SetFrom('[email protected]', 'First Last');

$mail->AddReplyTo("[email protected]","First Last");

$address = "[email protected]";
$mail->AddAddress($address, "John Doe");

$mail->Subject    = "Php send pdf test";

$mail->AltBody    = "To view the message, please use an HTML compatible email viewer!"; // optional, comment out and test

$mail->MsgHTML($body);

$mail->AttachFromString (base64_encode(file_get_contents($urlToPdf)));      // attachment
// in your case it would be http://mydomian.com/pdf001.php


if(!$mail->Send()) {
  echo "Mailer Error: " . $mail->ErrorInfo;
} else {
  echo "Message sent!";
}
?>

I edited this code from online real quick and think that could work. with your tweaking for each variable.

Sunday, August 7, 2022
 
3

Test Below Example :

<form method="post" enctype="multipart/form-data" action="">
<input type="file" name="file" />
<div class="td" style="width: 100%; text-align: left;"><button type="submit">OK</button></div>
</form>
<?php
if( isset( $_FILES['file'] ) )
{
    $img = file_get_contents( $_FILES['file']['tmp_name'] );
    $image = imagecreatefromstring( $img );
    echo imagesx( $image );
}
?> 
Thursday, November 10, 2022
 
jdaval
 
3

It can be achieved using the Google Drive REST API for Android (it uses the Google Drive API directly), instead of using Google Drive SDK for Android.

First of all, you need to login in Google Drive by choosing a Google Account of the device. I guess you've done it because in Google Drive SDK also needs to login. To login I use this dependence.

compile 'com.google.android.gms:play-services-auth:10.2.0'

Then, to upload a file (by creating it in the REST API) do the following.

First, import the Google Drive REST API dependencies for Android:

compile('com.google.api-client:google-api-client-android:1.22.0') {
    exclude group: 'org.apache.httpcomponents'
}
compile('com.google.apis:google-api-services-drive:v3-rev75-1.22.0') {
    exclude group: 'org.apache.httpcomponents'
}

Second, create the service object in order to connect with the API:

private Drive createService(Context context) {
   GoogleAccountCredential mCredential = GoogleAccountCredential.usingOAuth2(context.getApplicationContext(), Arrays.asList(new String[]{DriveScopes.DRIVE})).setBackOff(new ExponentialBackOff());
   mCredential.setSelectedAccountName("your_logged_account_name");

   HttpTransport transport = AndroidHttp.newCompatibleTransport();
   JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
   mService = new com.google.api.services.drive.Drive.Builder(
        transport, jsonFactory, mCredential)
        .setApplicationName(context.getString(R.string.app_name))
        .build();

  return mService;
}

Afterwards, when you are logged in and you have the Drive instance (service), you can create a file:

public void uploadFile(java.io.File fileContent) {
   try {
     com.google.api.services.drive.model.File file = new com.google.api.services.drive.model.File();
     file.setName("filen_ame");

     List<String> parents = new ArrayList<>(1);
     parents.add("parent_folder_id"); // Here you need to get the parent folder id
     file.setParents(parents);

     FileContent mediaContent = new FileContent("your_file_mime_type", fileContent);
     mService.files().create(file, mediaContent).setFields("id").execute();
     Log.d(TAG, "File uploaded");
   } catch (IOException e) {
     Log.e(TAG, "Error uploading file: ", e);
     e.printStackTrace();
   }
}

Please note I used the full class name in order to differentiate the Java File to the Drive File.

Also note that this call is synchronous, so you must call it in a non-UiThread.

This method is able to create and upload a file to Google Drive without showing any chooser dialog and without user interaction.

Here you have some documentation.

Hope this helps.

Friday, December 23, 2022
 
3

you have an OAuth Token without the correct Scope!

Set you Scope to:

static string[] Scopes = { DriveService.Scope.Drive, DriveService.Scope.DriveFile };

In my first attempts, i used only Drive and not DriveFile

Monday, September 5, 2022
 
meet
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :