2010-04-11 101 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); 
} 

另外,尽量为经常可以刷新输出。