Florian Müller
Florian Müller

Reputation: 7795

Upload large files to Dropbox via HTTP API

I am currently implementing an upload mechanism for files on my webserver into my Dropbox app directory.

As stated on the API docs, there is the /upload endpoint (https://www.dropbox.com/developers/documentation/http/documentation#files-upload) which accepts files up to 150MB in size. However I‘m dealing with images and videos with a potential size of up to 2GB.

Therefore I need to use the upload_session endpoints. There is an endpoint to start the session (https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-start), to append data and to finish the session.

What currently is unclear to me is how to exactly use these endpoints. Do I have to split my file on my server into 150MB chunks (how would I do that with a video file?) and then upload the first chunk with /start, the next chunks with /append and the last one with /finish? Or can I just specify the file and the API somehow (??) does the splitting for me? Obviously not, but I somehow can‘t get my head around on how I should calculate, split and store the chunks on my webserver and not lose the session inbetween...

Any advice or further leading links are greatly appreciated. Thank you!

Upvotes: 2

Views: 2737

Answers (2)

Artis Skuja
Artis Skuja

Reputation: 21

I know this is an old post, but here is a fully functional solution for your problem. Maybe anyone else finds it usefull. :)

<?php

$backup_folder = glob('/var/www/test_folder/*.{sql,gz,rar,zip}', GLOB_BRACE); // Accepted file types (sql,gz,rar,zip)
$token = '<ACCESS TOKEN>'; // Dropbox Access Token;
$append_url = 'https://content.dropboxapi.com/2/files/upload_session/append_v2';
$start_url = 'https://content.dropboxapi.com/2/files/upload_session/start';
$finish_url = 'https://content.dropboxapi.com/2/files/upload_session/finish';
if (!empty($backup_folder)) {
foreach ($backup_folder as $single_folder_file) {
    $file_name= basename($single_folder_file); // File name
    $destination_folder = 'destination_folder'; // Dropbox destination folder
    $info_array = array();
    $info_array["close"] = false;
    $headers = array(
        'Authorization: Bearer ' . $token,
        'Content-Type: application/octet-stream',
        'Dropbox-API-Arg: '.json_encode($info_array)
        );
    $chunk_size = 50000000; // 50mb

    $fp = fopen($single_folder_file, 'rb');
    $fileSize = filesize($single_folder_file); // File size
    $tosend = $fileSize;
    $first = $tosend > $chunk_size ? $chunk_size : $tosend;

    $ch = curl_init($start_url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, fread($fp, $first));
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
    $response = curl_exec($ch);
    $tosend -= $first;

    $resp = explode('"',$response);

    $sesion = $resp[3];
    $position = $first;

    $info_array["cursor"] = array();
    $info_array["cursor"]["session_id"] = $sesion;

    while ($tosend > $chunk_size)
    {
        $info_array["cursor"]["offset"] = $position;
        $headers[2] = 'Dropbox-API-Arg: '.json_encode($info_array);

        curl_setopt($ch, CURLOPT_URL, $append_url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POSTFIELDS, fread($fp, $chunk_size));
        curl_exec($ch);

        $tosend -= $chunk_size;
        $position += $chunk_size;
    }
    unset($info_array["close"]);
    $info_array["cursor"]["offset"] = $position;
    $info_array["commit"] = array();
    $info_array["commit"]["path"] = '/'. $destination_folder . '/' . $file_name;
    $info_array["commit"]["mode"] = array();
    $info_array["commit"]["mode"][".tag"] = "overwrite";
    $info_array["commit"]["autorename"] = true;
    $info_array["commit"]["mute"] = false;
    $info_array["commit"]["strict_conflict"] = false;
    $headers[2] = 'Dropbox-API-Arg: '. json_encode($info_array);

    curl_setopt($ch, CURLOPT_URL, $finish_url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $tosend > 0 ? fread($fp, $tosend) : null);
    curl_exec($ch);
    curl_close($ch);
    fclose($fp);
    unlink($single_folder_file); // Remove files from server folder
    }
}

Upvotes: 2

Taylor Krusen
Taylor Krusen

Reputation: 1053

As Greg mentioned in the comments, you decide how to manage the "chunks" of the files. In addition to his .NET example, Dropbox has a good upload session implementation in the JavaScript upload example of the Dropbox API v2 JavaScript SDK.

At a high-level, you're splitting up the file into smaller sizes (aka "chunks") and passing those to the upload_session mechanism in a specific order. The upload mechanism has a few parts that need to be used in the following order:

  1. Call /files/upload_session/start. Use the resulting session_id as a parameter in the following methods so Dropbox knows which session you're interacting with.
  2. Incrementally pass each "chunk" of the file to /files/upload_session/append_v2. A couple things to be aware of:

    • The first call will return a cursor, which is used to iterate over the file's chunks in a specific order. It gets passed as a parameter in each consecutive call to this method (with the cursor being updated on every response).
    • The final call must include the property "close": true, which closes the session so it can be uploaded.
  3. Pass the final cursor (and commit info) to /files/upload_session/finish. If you see the new file metadata in the response, then you did it!!

Upvotes: 4

Related Questions