Nginx – PHP content-length header not specifying size for the forced download

gzipnginxPHP

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);

Best Answer

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

Related Topic