Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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

3 Answers 3

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

share|improve this answer

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.

share|improve this answer

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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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