1

I am trying to allow our users to be able to download a zip file using a php force download. I was having trouble getting the download to finish and it turned out the zip file was getting gzipped and sent to the browser, then the content-length header would stop the download before it was finished (because gzipping a zip file makes the file larger) so I added this to my code:

    if(ini_get('zlib.output_compression')) {
        ini_set('zlib.output_compression', 'Off');
    }

After adding this the downloaded zips were able to be opened but the Content-Length header was no longer being sent. I checked the headers that were sent using firebug and the downloads no longer had a progress bar. I'm not certain if the downloads are working because they are no longer being gzipped or because the content-length header is no longer being sent (and the larger gzip file is being downloaded fully). I'm also wondering why adding those three lines would cause the content-length header to disappear?

here is the section that is forcing the download:

    if(ini_get('zlib.output_compression')) {
        ini_set('zlib.output_compression', 'Off');
    }

    // Display the download
    ob_end_clean();
    header('Content-Description: File Transfer');
    header('Content-Type: application/zip');
    header('Content-Disposition: attachment; filename="'.$name.'.zip"');
    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($archive));
    flush();
    readfile($archive);
Brian
  • 73
  • 2
  • 8

3 Answers3

1

Do not pipe a file trough PHP application, it's very ineffective. You can easily use Nginx built-in functionality exactly for this. It's called X-Accel-Redirect and this is the header you need to return from PHP. Nginx will see it and send the file to a browser, while your PHP process is already free to serve other requests.

The documentation is here

Alexander Azarov
  • 3,550
  • 21
  • 19
0

Do one of the following:

  • change ob_end_clean to ob_clean
  • remove ob_end_clean altogether

I honestly don't know why it works that way. A trip to bugs.php.net would probably turn up something.

h0tw1r3
  • 2,776
  • 19
  • 17
0

I figured out that after turning off gzip in php my nginx settings were then using gzip to compress it since they both had gzip turned on. I had to add a new header that set the content encoding to application/zip so that nginx wouldn't try and compress it with gzip. I added this line of code:

    header('Content-Encoding: application/zip');
Brian
  • 73
  • 2
  • 8