Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Stop Remote File Download if it Exceeds 5mb

Tags:

php

How do I stop a remote file from downloading a file if it exceeds 5mb? If I stop it while transferring, will the file be held somewhere in some other temp dir or memory? How would I know? Here is my current code:

$url = 'http://www.spacetelescope.org/static/archives/images/large/heic0601a.jpg';
$file = '../temp/test.jpg';
file_put_contents($file, file_get_contents($url));
like image 884
webdev Avatar asked Dec 19 '12 23:12

webdev


Video Answer


1 Answers

There are a number of ways in which you could do this, but because you are currently using file_get_contents(), here is what I would do:

  • Open the remote file using fopen()
  • Read the file and save it in increments using fread() - this allows you to track the current size and throw and error when you pass the threshold.

Something like this:

$url = 'http://www.spacetelescope.org/static/archives/images/large/heic0601a.jpg';
$file = '../temp/test.jpg';
$limit = 5 * 1024 * 1024; // 5MB

if (!$rfp = fopen($url, 'r')) {
  // error, could not open remote file
}
if (!$lfp = fopen($file, 'w')) {
  // error, could not open local file
}

// Check the content-length for exceeding the limit
foreach ($http_response_header as $header) {
  if (preg_match('/^\s*content-length\s*:\s*(\d+)\s*$/', $header, $matches)) {
    if ($matches[1] > $limit) {
      // error, file too large
    }
  }
}

$downloaded = 0;

while (!feof($rfp) && $downloaded < $limit) {
  $chunk = fread($rfp, 8192);
  fwrite($lfp, $chunk);
  $downloaded += strlen($chunk);
}

if ($downloaded > $limit) {
  // error, file too large
  unlink($file); // delete local data
} else {
  // success
}

NB: it is tempting to inspect the Content-Length: header before you receive any of the file to check whether the file is too large - you can still do this if you like, but do not trust the value! The header is essentially an arbitrary value, and while it would be a protocol violation to use a content length that does not match the size of the file, it could be used to fool the system into downloading a file that breaks the rules. You'd need count the bytes even if you do check this value.

You could also do this using curl via the data callback, but I would regard this as a less satisfactory solution, mostly because of fact that curl requires a string function name and not the standard generic callable type, which means you would either need to use a global variable or a static variable in order to keep track of the downloaded content length, neither of which are acceptable (IMHO) for this.

like image 82
DaveRandom Avatar answered Sep 17 '22 00:09

DaveRandom