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