问题
I have the following script to let a visitor download a file:
header( 'Content-Type: application/octet-stream' );
header( 'Content-Transfer-Encoding: binary' );
header( 'Content-Disposition: attachment; filename=' . $fileName );
header( 'Content-Length: ' . filesize( $filePath ) );
header( 'Content-Description: Download' );
header( 'Cache-Control: private' );
header( 'Pragma: no-cache' );
header( 'Expires: 0' );
readfile( $filePath );
exit();
It doesn't work very well. (I've also put the filename in quotes, same result).
It behaves very slow, and sometimes the downloads even halt. In Opera especially, it halts on 99% of the download. Sometimes it even immediately shows 99% completed, then it starts downloading and halts at around 34%.
The server is a shared host, Mac OS X server.
With using Firefox's Live HTTP headers add-on, I've noticed the server adds aditional headers to the response:
HTTP/1.1 200 OK
Date: Thu, 18 Feb 2010 09:27:25 GMT
Server: Apache
X-Powered-By: PHP/5.2.12
Content-Transfer-Encoding: binary
Content-Disposition: attachment; filename=test.psd
Content-Length: 398635
Content-Description: Download
Cache-Control: private
Pragma: no-cache
Expires: 0
Content-Encoding: gzip // <-- expecially this one,
Vary: Accept-Encoding // <-- this one,
MS-Author-Via: DAV // <-- and this one
Keep-Alive: timeout=10, max=100
Connection: Keep-Alive
Content-Type: application/octet-stream
Could these be the cause of the problem?
When I run the script on my localhost everything works fine. Also, when I directly download files from this host, the speed is also fine and fluent.
I'm really rather clueless on this one. Your help is appeciated. Thank you in advance.
UPDATE:
I think I have narrowed the problem down to the bottleneck. The webserver automatically gzip compresses the output. When I removed the Content-Length
header from my PHP script everything started downloading smooth. This makes sense: The value of the Content-Length
doesn't match the actual gzipped output anymore. In PHP I read the uncompressed filesize to set the Content-Length
header, but afterwards, Apache compresses it, and this is probably where the browsers choked.
I'll follow this question up with a question about how to set the correct Content-Length
header size when the webserver automatically gzip compresses output.
回答1:
Try unsetting the gzip-Content-Encoding.
Use ob_start()
at the very beginning of your script; before setting your headers, use @ob_end_clean();
and right after it, explicitely set header("Content-Encoding:");
to try to unset any gzip-Encoding that might come in.
At the end of your file place @ob_end_flush();
.
The output buffering functions are handy to make the header-setting more failsafe, but probably not related to your problem. I just remember to ran into problems in a setup where the enclosing PHP code used ob_gzhandler and I needed to unset it.
回答2:
I use the code below and it works. Telling you the truth I did not undersyand yet properly all the header that I send, I still did not have the time to investigate, I found explanations in:
Sources:
http://www.opendesigns.org/forum/discussion/1437/php-download-counter/#pgbottom http://www.webdeveloper.com/forum/showthread.php?t=115815&highlight=PHP+download+counter http://php.net/manual/en/function.header.php#83384
anyway it works:
/*
TODO: still to be read and better understood.
*/
//no caching (I don't uderstand what is this part useful for)
header("Pragma: public"); //?
header("Expires: 0"); //?
header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); //?
header("Cache-Control: private", false); //?
//sending download file
header("Content-Type: application/octet-stream"); //application/zip can use application/octet-stream that is more generic it works because in now days browsers are able to detect file anyway
header("Content-Disposition: attachment; filename=\"" . basename($file_serverfullpath) . "\""); //ok
header("Content-Transfer-Encoding: binary"); //?
header("Content-Length: " . filesize($file_serverfullpath)); //ok
readfile($file_serverfullpath);
回答3:
I have narrowed the problem down to the bottleneck. The webserver automatically gzip compresses the output. When I removed the Content-Length header from my PHP script everything started downloading smooth. This makes sense: The value of the Content-Length doesn't match the actual gzipped output anymore. In PHP I read the uncompressed filesize to set the Content-Length header, but afterwards, Apache compresses it, and this is probably where the browsers choked.
来源:https://stackoverflow.com/questions/2287576/problem-with-downloads-slow-and-or-fails