2

I have written the below code in PHP with curl in an attempt to download a remote file (from Dropbox) that is provided by a user in a separate POST form. When I use any other server as the file's original home, like my own, the download works perfectly and the file is whole (learned this from a different SE thread). So I know that my code at least works for performing the task I've told it to.

There seems to be some issue with Dropbox, however, in that any files downloaded from their service cannot be opened.

You can't see it in the code but the Dropbox Share URL has the required "?dl=1" added to the end (forcing us to follow the redirect).

Could this be related to the SSL Cert or API that Dropbox has, and if so is there a way to bypass that check with curl?

The goal is to allow users to post their share URL using a private form and it download the file automatically, so I'm not sure that authenticating with Dropbox's API will help since that would require authenticating with each user (something too complex for them to handle).

<?php
var_dump($_POST);
$fileurl = $_POST['file'];
$path_parts = pathinfo($fileurl);
$filebase = $path_parts['basename'];
$filename = $path_parts['basename'];
$filepath = 'files/tmp/'.$filebase;

# start curl
$ch = curl_init();
# open file to write
$fp = fopen($filename, 'w+b');
curl_setopt( $ch, CURLOPT_URL, $fileurl );
# set return transfer to false
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_BINARYTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
# increase timeout to download big file
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 10 );
# write data to local file
curl_setopt( $ch, CURLOPT_FILE, $fp );
# execute curl
curl_exec( $ch );
# close local file
fclose( $fp );
# close curl
curl_close( $ch );

$curl = curl_init();
$postfields = "file=$filepath&sfname=$filename";
curl_setopt($curl, CURLOPT_URL,"url_goes_here");
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postfields);

curl_exec ($curl);
curl_close ($curl);

?>

Thanks in advance.

  • 3
    Please include your code in the question. Also, have you inspected the downloaded files? Maybe their content will give you a hint about the problem. Maybe they just have some extra bytes or bytes missing, or maybe you get a login page instead of the file, in which case the size should be very different, and you should see clear HTML code in the file. – GolezTrol Jan 28 '15 at 20:22
  • 1
    @GolezTrol - Added the code. Had a formatting issue, but it's fixed now. I'll inspect the files now. – Tim Stiffler-Dean Jan 28 '15 at 20:27
  • The files are full of Dropbox HTML messages saying that they found the file and will be redirecting me shortly. This is strange, because I have `CURLOPT_FOLLOWLOCATION` set to true, so it should be following those redirects automatically, yeah? – Tim Stiffler-Dean Jan 28 '15 at 20:42
  • No. Not per se. FollowLocation will follow redirects (Location headers). In this case there is not HTTP redirect, but just an HTML page that redirects after a while. This is not handled by cUrl, because it requires an actual interpretation of the redirect. With a bit of luck the redirect link is clearly visible in that page, and you can parse the page and download that link. With less luck this process is more obfuscated or the redirect link requires for instance a cookie to be set. I can't give you an exact answer now, but I hope you've got a new direction to explore. – GolezTrol Jan 29 '15 at 08:36

1 Answers1

1

It's a bit of hack, bit it works for me:

function getDropboxDownloadURL($url) {
  // create curl resource 
  $ch = curl_init(); 
  // set url 
  curl_setopt($ch, CURLOPT_URL, $url); 
  //return the transfer as a string 
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
  // $output contains the output string 
  $content = curl_exec($ch); 
  // close curl resource to free up system resources 
  curl_close($ch);      

  // http://stackoverflow.com/questions/3820666/grabbing-the-href-attribute-of-an-a-element
  $dom = new DOMDocument;
  $dom->loadHTML($content);

  foreach ($dom->getElementsByTagName('a') as $node) {
    $url = $node->getAttribute('href');
    // or you can check other conditions
    if (startsWith($url, "https://www.dropbox.com")) {
        return $url;
    }
  }
}

An input url would be "https://www.dropbox.com/s/m0cw695klan1dz1/running_men.jpg.zip?dl=0", and the out would be "https://www.dropbox.com/s/m0cw695klan1dz1/running_men.jpg.zip?dl=1"

Sung Kim
  • 8,417
  • 9
  • 34
  • 42