2010-04-11 84 views
2

這篇文章是作爲ServerFault(https://serverfault.com/questions/131156/user-receiving-partial-downloads)的一個問題開始的,但我確定我們的php腳本是罪魁禍首。所以我在這裏發佈一個更新的問題,關於我認爲的實際問題。PHP文件服務腳本:不可靠的下載?

我正在使用php腳本來驗證權限,然後爲我的網站的用戶提供文件下載。大多數情況下,這是有效的,但最近有一位用戶發現下載量更大的問題。對於大於100MB的文件,他只獲得〜80%的下載量。此外,此腳本的所有下載都無法報告文件大小。此外,測試表明,如果給定直接鏈接(報告文件大小),相同的用戶可以可靠地下載每個失敗的文件。

這裏的代碼中的相關片段,我們使用的服務文件:

header("Content-type:$contenttype"); 
$len = filesize($filename); 
header("Content-Length: $len"); 
header("Content-Disposition: attachment; filename=".$title.".".$ext); 
readfile($filename); 

注意$的contentType,$文件名,$ title和$ EXT都設置正確,纔來到這裏。這些已經過三重檢查。他們都不是問題。另外,$ len確實提供了正確的文件大小。

雖然研究這個問題,我遇到了這個帖子:Content-Length header always zero

看來,我遇到了同樣的問題。當我使用腳本時,我在文件上獲得了分塊編碼,並且沒有爲內容長度設置大小。我假設在大量下載中出現問題,導致他在文件結束之前得到一個零長度的塊。

這裏頭是什麼樣子的直接請求:

http://www.grinderschool.com/videos/zfff5061b65ae00e8b21/KillsAids021.wmv 

GET /videos/zfff5061b65ae00e8b21/KillsAids021.wmv HTTP/1.1 
Host: www.grinderschool.com 
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-us,en;q=0.5 
Accept-Encoding: gzip,deflate 
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 
Keep-Alive: 115 
Connection: keep-alive 
Referer: http://www.grinderschool.com/phpBB3/viewtopic.php?f=14&p=29468 
Cookie: style_cookie=printonly; phpbb3_7c544_u=2; phpbb3_7c544_k=44b832912e5f887d; phpbb3_7c544_sid=e8852df42e08cc1b2250300c2897f78f; __utma=174624884.2719561324781918700.1251850714.1270986325.1270989003.575; __utmz=174624884.1264524375.411.12.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=low%20stakes%20poker%20videos; phpbb3_cmviy_k=; phpbb3_cmviy_u=2; phpbb3_cmviy_sid=d8df5c0943863004ca40ef9c392d371d; __utmb=174624884.4.10.1270989003; __utmc=174624884 
Pragma: no-cache 
Cache-Control: no-cache 

HTTP/1.1 200 OK 
Date: Sun, 11 Apr 2010 12:57:41 GMT 
Server: Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8l DAV/2 mod_auth_passthrough/2.1 FrontPage/5.0.2.2635 
Last-Modified: Sun, 04 Apr 2010 12:51:06 GMT 
Etag: "eb42d6-7d9b843-48368aa6dc280" 
Accept-Ranges: bytes 
Content-Length: 131708995 
Keep-Alive: timeout=10, max=30 
Connection: Keep-Alive 
Content-Type: video/x-ms-wmv 

而這裏就是他們的樣子供我的腳本回答請求:

http://www.grinderschool.com/download_video_test.php?t=KillsAids021&format=wmv 

GET /download_video_test.php?t=KillsAids021&format=wmv HTTP/1.1 
Host: www.grinderschool.com 
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-us,en;q=0.5 
Accept-Encoding: gzip,deflate 
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 
Keep-Alive: 115 
Connection: keep-alive 
Cookie: style_cookie=printonly; phpbb3_7c544_u=2; phpbb3_7c544_k=44b832912e5f887d; phpbb3_7c544_sid=e8852df42e08cc1b2250300c2897f78f; __utma=174624884.2719561324781918700.1251850714.1270986325.1270989003.575; __utmz=174624884.1264524375.411.12.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=low%20stakes%20poker%20videos; phpbb3_cmviy_k=; phpbb3_cmviy_u=2; phpbb3_cmviy_sid=d8df5c0943863004ca40ef9c392d371d; __utmb=174624884.4.10.1270989003; __utmc=174624884 

HTTP/1.1 200 OK 
Date: Sun, 11 Apr 2010 12:58:02 GMT 
Server: Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8l DAV/2 mod_auth_passthrough/2.1 FrontPage/5.0.2.2635 
X-Powered-By: PHP/5.2.11 
Content-Disposition: attachment; filename=KillsAids021.wmv 
Vary: Accept-Encoding 
Content-Encoding: gzip 
Keep-Alive: timeout=10, max=30 
Connection: Keep-Alive 
Transfer-Encoding: chunked 
Content-Type: video/x-ms-wmv 

所以,問題是...我能做些什麼來使腳本下載正常工作?同樣,對於99%的用戶來說,它的工作原理是這樣的(儘管現在我覺得它沒有報告文件大小,因此沒有時間估計可以計算下載)。

回答

2

這是您的GZIP壓縮。當您指定內容長度但打開壓縮時,它會將所有內容都粘在一起。這發生在我身上幾次:嘗試在腳本中關閉它。

通常你會用其打開:

ob_start("ob_gzhandler"); 

...所以只是評論說,線路輸出。如果這不在你的代碼中,可能是你的php.ini文件或apache.conf/conf.d中的設置。

希望這會有所幫助!

+0

該行不在代碼中,因此我正在通過php.ini進行挖掘。如果你碰巧知道我應該尋找什麼,那會非常有幫助! – 2010-04-11 16:17:22

+0

試試看:'zlib_output_compression'。它應該設置爲關。 – mattbasta 2010-04-11 16:41:34

+0

我的不好:'zlib.output_compression = Off'和'zlib.output_handler = Off' – mattbasta 2010-04-11 16:42:24

2
Content-Encoding: gzip 

嗯。據推測,PHP的zlib.output_compression正在這樣做。 (看起來不像Apache的mod_deflate。)

嘗試關閉它,看看它是否是強制分塊編碼。您不想壓縮已經高度壓縮的WMV文件類型的下載。

但是,分塊編碼只能解釋缺少大小報告。下載應該仍然有效。是否有可能遭到暫停(例如,PHP的set_time_limit或Apache Timeout)?

+0

我同意這兩個可能是相關的。我試圖理清原因。 zlib.output_compression已在php.ini中設置爲關閉 – 2010-04-11 16:30:33

0

如果是腳本,那麼您是否嘗試使用readfile()函數的替代函數來讀取和輸出一次?這背後的原因可能是內存限制達到某個地方,並且失敗。

http://php.net/manual/en/function.readfile.php

function readfile_chunked ($filename) { 
    $chunksize = 1*(1024*1024); // how many bytes per chunk 
    $buffer = ''; 
    $handle = fopen($filename, 'rb'); 
    if ($handle === false) { 
    return false; 
    } 
    while (!feof($handle)) { 
    $buffer = fread($handle, $chunksize); 
    print $buffer; 
    } 
    return fclose($handle); 
} 

另外,儘量爲經常可以刷新輸出。