bruno
bruno

Reputation: 85

"Allowed memory .. exhausted" when using readfile

I made a download script in PHP that was working until yesterday. Today I tried to download one of the files only to discover that suddenly it stopped working:

PHP Fatal error: Allowed memory size of 67108864 bytes exhausted (tried to allocate 119767041 bytes) in E:\home\tecnoponta\web\aluno\download.php on line 52

For some reason PHP is trying to allocate the size of the file in the memory, and I have no idea why. If the file size is smaller than the memory limit, I can download it without a problem, the problem is with bigger files.

I do know that it can be corrected by increasing the memory limit in php.ini or even use ini_set on the code but I would like a more accurate way to fix this and an answer to why it stopped working.

Here's my code:

$file = utf8_decode($_GET['d']);

header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename='.$file);
header('Content-Type: application/octet-stream');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');

$file = "uploads/$curso/$file";

ob_clean();
flush();
readfile($file);

echo "<script>window.history.back();</script>";
exit;

Upvotes: 5

Views: 7054

Answers (4)

GSite
GSite

Reputation: 954

I solved like this:

if(file_exists($filepath)){

  header('Content-Description: File Transfer');
  header('Content-Type: application/octet-stream');
  header('Content-Disposition: attachment; filename='.basename($filepath));
  header('Content-Transfer-Encoding: binary');
  header('Expires: 0');
  header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
  header('Pragma: public');
  header('Content-Length: ' . filesize($filepath));

  if(ob_get_level()){
     ob_end_clean();
  }

  readfile($filepath);
}

Upvotes: 0

Clickbeetle
Clickbeetle

Reputation: 639

From php.net for readfile:

readfile() will not present any memory issues, even when sending large files, on its own. If you encounter an out of memory error ensure that output buffering is off with ob_get_level().

From php.net for ob_clean:

This function does not destroy the output buffer like ob_end_clean() does.

What you need is this:

if (ob_get_level()) {
      ob_end_clean();
    }

Also consider adding this:

header('Content-Length: ' . filesize($file));

Upvotes: 22

Al-Noor Ladhani
Al-Noor Ladhani

Reputation: 2433

The ob-level solution resulted in always an empty output.

This solution works for me:

<?php


$myFile = $myPath.$myFileName;

if (file_exists($myFile)) {


header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$myFileName.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($myFile));

//alternative for readfile($myFile);

$myInputStream = fopen($myFile, 'rb');
$myOutputStream = fopen('php://output', 'wb');

stream_copy_to_stream($myInputStream, $myOutputStream);

fclose($myOutputStream);
fclose($myInputStream);

exit;

} else {

echo "*** ERROR: File does not exist: ".$myFile;

}

?>

So using stream_copy_to_stream() instead of fileread()

Hope this can help you.

Upvotes: 9

Jaime
Jaime

Reputation: 1410

The size of the file is greater than the php memory limit.

Do

ini_set('memory_limit','16M');

And set the '16M' part to at least the filesize.

Upvotes: -4

Related Questions