Search code examples
phpcurlhttp-headersdropboxcontent-type

DropBox API application/octet-stream header


I'm attempting to make a cUrl request with PHP to the Dropbox API, in order to begin to upload a very large zip file. Here is the documentation I'm trying to implement, found at https://www.dropbox.com/developers/documentation/http/documentation#files-upload -

URL structure: https://content.dropboxapi.com/2/files/upload_session/start

Example cUrl Request:

curl -X POST https://content.dropboxapi.com/2/files/upload_session/start \
    --header "Authorization: Bearer <get access token>" \
    --header "Dropbox-API-Arg: {\"close\": false}" \
    --header "Content-Type: application/octet-stream" \
    --data-binary @local_file.txt

And here is my code:

$uploads = wp_upload_dir();
$file = $uploads['basedir']."/maintainme/backups/files/backup_".$filename.'/'.$filename.'.zip';
$ch = curl_init();
$url = 'https://content.dropboxapi.com/2/files/upload_session/start';
$headers = array(
    'Authorization: Bearer ' .$dropbox_token,
    'Dropbox-API-Arg: {\"close\": false}',
    'Content-Type: application/octet-stream',
);
$fields = array('file' => '@' . $file);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields ); 
curl_setopt($ch, CURLOPT_VERBOSE, 1);
$result = curl_exec($ch);
curl_close($ch);

The error message I get is:

Error in call to API function "files/upload_session/start": Bad HTTP "Content-Type" header: "application/octet-stream; boundary=------------------------1ee7d00b0e9b0c47". Expecting one of "application/octet-stream", "text/plain; charset=dropbox-cors-hack".

It seems that this 'Boundary=------------blahblahblah' gets appended to my content-type header each time I try to make this request. Anyone have any ideas??? Thanks!


Solution

  • Solved it! On a whim, I checked into the 'CURLOPT_POSTFIELDS' option found at http://php.net/manual/en/function.curl-setopt.php, and here's what it said:

    The full data to post in a HTTP "POST" operation. To post a file, prepend a filename with @ and use the full path. The filetype can be explicitly specified by following the filename with the type in the format ';type=mimetype'. This parameter can either be passed as a urlencoded string like 'para1=val1&para2=val2&...' or as an array with the field name as key and field data as value. If value is an array, the Content-Type header will be set to multipart/form-data. As of PHP 5.2.0, value must be an array if files are passed to this option with the @ prefix. As of PHP 5.5.0, the @ prefix is deprecated and files can be sent using CURLFile. The @ prefix can be disabled for safe passing of values beginning with @ by setting the CURLOPT_SAFE_UPLOAD option to TRUE.

    The relevant part is bolded in the paragraph above. Apparently passing an array to the CURLOPT_POSTFIELDS option is what was appending that 'Boundary=----blahblahblah' the Content-Type and causing the API call to fail. I changed

    curl_setopt($ch, CURLOPT_POSTFIELDS, $fields );
    

    to

    curl_setopt($ch, CURLOPT_POSTFIELDS, '@'.$file );
    

    and tried again. The initial issue was fixed, but I then encountered a new issue with the 'Dropbox-API-Arg' line in this section of code:

    $headers = array(
        'Authorization: Bearer ' .$dropbox_token,
        'Dropbox-API-Arg: {\"close\": false}',
        'Content-Type: application/octet-stream',
    );
    

    Turns out, these arguments need to be properly JSON-Encoded. I did this with the code below:

    $args = array('close'=>false);
    $args = json_encode($args);
    

    and then changed

    'Dropbox-API-Arg: {\"close\": false}' 
    

    to:

    'Dropbox-API-Arg:'.$args
    

    Here is the complete, final code:

        $uploads = wp_upload_dir();
        $file = $uploads['basedir']."/maintainme/backups/files/backup_".$filename.'/'.$filename.'.zip';
        error_log($file);
    
        $args = array('close'=>false);
        $args = json_encode($args);
    
        $ch = curl_init();
        $url = 'https://content.dropboxapi.com/2/files/upload_session/start';
        $headers = array(
            'Authorization: Bearer ' .$dropbox_token,
            'Dropbox-API-Arg:'.$args,
            'Content-Type: application/octet-stream',
        );
        $fields = array('file' => '@' . $file);
        error_log($fields);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POSTFIELDS, '@'.$file ); 
        curl_setopt($ch, CURLOPT_VERBOSE, 1);
        $result = curl_exec($ch);
        error_log($result);
        curl_close($ch);