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);
link|improve this question
feedback

3 Answers

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.

link|improve this answer
feedback

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');
link|improve this answer
feedback

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

link|improve this answer
feedback

Your Answer

 
or
required, but never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.