11

I created a file download script in PHP, it works, but web browsers report the file as "Unknown Length". My code is as follows:

function downloadFile($file){
  // Set up the download system...
  header('Content-Description: File Transfer');
  header('Content-Type: '.mime_content_type($file));
  header('Content-Disposition: attachment; filename="'.basename($file).'"');
  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($file));

  // Flush the cache
  ob_clean();
  flush();

  // Send file to browser
  readfile($file);

  // DO NOT DO ANYTHING AFTER FILE DOWNLOAD
  exit;
}
gen_Eric
  • 223,194
  • 41
  • 299
  • 337

3 Answers3

19

Originally from http://paul.luminos.nl/update/471:

The CrimsonBase website verifies downloads by passing them through a robust PHP script similar to the one published by Andrew Johnson in his article about PHP-controlled file downloads.

Andrew makes a very important comment at the end of the article:

"If you compress files with Zlib, mod_deflate and so on the Content-Length header won't be accurate so you'll end up seeing "Unknown size" and "Unknown time remaining" when downloading files."

I would like to stress this: if your browser doesn't appear to be obeying the headers generated by your PHP script—especially Content-Length—it is fairly likely that Apache's mod_deflate extension is enabled.

You can easily disable it for a single script using the following line in an applicable .htaccess file:

SetEnvIfNoCase Request_URI ^/download\.php no-gzip dont-vary

where download.php is here assumed to be in the download script located in the server's root directory path (e.g. www.crimsonbase.com/download.php). (That's because the regular expression is ^/download\.php.)

Community
  • 1
  • 1
Honso
  • 206
  • 2
  • 3
  • Interesting. I'll need to look into that. – gen_Eric Mar 12 '10 at 17:13
  • Thank you, I was getting "gzip" content type in my download and was able to get rid of it with your htaccess line, now I can see the download progress again because total file size is read correctly by the browser. – adrianTNT Oct 23 '14 at 19:36
15

I had this same problem, and I fixed it by sending the Content-Length header before the Content-Disposition.

header('Content-Type: video/mp4');
header("Content-Transfer-Encoding: Binary"); 
header("Content-Length: ".filesize($file_url));
header("Content-disposition: attachment; filename=\"" . basename($file_url) . "\""); 
readfile($file_url);
Skylar Ittner
  • 802
  • 11
  • 26
0

Try not flushing the cache before readfile() function. My code is almost identical to yours otherwise, and works fine.

  • Tried that, nothing. The download still works fine, it's just that web browsers will say "unknown file size" even though I gave it a "Content-length". Thing is, if I use wget, it reports the correct file size. – gen_Eric Dec 30 '09 at 21:17