2011-04-08 95 views
16

我使用的是简单的文件下载脚本:PHP,文件下载

if (file_exists($file)) { 
    header('Content-Description: File Transfer'); 
    header('Content-Type: application/octet-stream'); 
    header('Content-Disposition: attachment; filename='.basename($file)); 
    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($file)); 
    ob_clean(); 
    flush(); 
    readfile($file); 
    exit; 
} 

它工作在我的LocalServer高达200MB。

当我在我的网站上试用这段代码时,它下载了173KB而不是200MB的文件。

我检查了一切,写了一些自定义代码(使用ob函数和fread代替readfile)但无法下载大文件。

谢谢你的回答。

  • 我使用的Apache 2.2,PHP 5.3
  • 所有PHP的设置来处理大文件都OK。 (执行时间,内存限制,...
+0

我的主机,dreamhost有时会杀死消耗太多cpu或资源的脚本。这可能是你的情况。 – nerkn 2011-04-08 13:18:34

回答

19

一个问题我有下面的代码是你必须在输出流的控制权,你让PHP处理它不知道究竟是什么背景里的情形:

你应该做的是建立一个输出系统,您可以控制和复制accros服务器。

例如:

if (file_exists($file)) 
{ 
    if (FALSE!== ($handler = fopen($file, 'r'))) 
    { 
     header('Content-Description: File Transfer'); 
     header('Content-Type: application/octet-stream'); 
     header('Content-Disposition: attachment; filename='.basename($file)); 
     header('Content-Transfer-Encoding: chunked'); //changed to chunked 
     header('Expires: 0'); 
     header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
     header('Pragma: public'); 
     //header('Content-Length: ' . filesize($file)); //Remove 

     //Send the content in chunks 
     while(false !== ($chunk = fread($handler,4096))) 
     { 
      echo $chunk; 
     } 
    } 
    exit; 
} 
echo "<h1>Content error</h1><p>The file does not exist!</p>"; 

这仅仅是基本的,但给它一个去!

又看了我的答复这里:file_get_contents => PHP Fatal error: Allowed memory exhausted

+0

谢谢。分块发送正在所有服务器上正常工作。另外我发送的文件大小,实际上发送完整的文件大小,并发送大块文件块可能微不足道,但它现在很好。否则,对于大量下载,用户将看不到完整的文件大小,这可能不利于可用性。 – jsonx 2011-04-10 13:52:40

+0

这完全取决于数据如何传输,例如流式传输和下载需要2种独立的内容传输方法。高兴地帮助 – RobertPitt 2011-04-10 21:23:25

+0

不应该'基地名称($文件)'被编码?如果它包含用http拧紧的字符呢? – 735Tesla 2014-01-02 00:07:39

0

你是否确信你的脚本can run long够了,有足够的内存?

你真的需要输出缓冲?

3

看来ReadFile的可以有问题长文件。作为@Khez问,它可能是在脚本运行时间过长。快速谷歌搜索导致分块文件的几个例子。

http://teddy.fr/blog/how-serve-big-files-through-php http://www.php.net/manual/en/function.readfile.php#99406

+0

所有设置都适用于大文件,执行时间,内存限制...... – jsonx 2011-04-08 13:46:19

+0

在第一个链接的read_chunked()函数中解决了这个问题。 – jsonx 2011-04-08 13:53:28

+0

read_chunked()在某些服务器上表现不一致 – jsonx 2011-04-10 13:46:34

0

真正的解决办法是避免使用PHP脚本只是将文件发送到客户端,这是矫枉过正,你的网络服务器是更适合的任务。

大概你有通过PHP发送文件的原因,也许用户必须先验证身份?如果是这种情况,那么您应该在lighttpd上使用X-Accel-Redirect(如果您使用的是nginx)或X-Sendfile(以前是X-LIGHTTPD-send-file)。

如果您使用的是Apache,我发现了一些mod_xsendfile的引用,但我从未亲自使用它,如果您管理主机,我怀疑它是否已安装。

如果这些解决方案是站不住脚的,我很抱歉,但我真的需要关于实际问题的更多信息:为什么您首先通过PHP发送这些文件?

+0

谢谢Zofrex,是的,在发送文件之前必须做一些验证和其他一些操作。 mod_xsendfile看起来不错,我会试试看。这可能是更清晰的解决方案。 – jsonx 2011-04-08 14:05:30

3

某些方案的一个解决方案是,您可以使用PHP脚本智能地决定从哪里下载文件,但不是直接从PHP发送文件,而是可以将重定向返回给客户端,然后包含直接链接由Web服务器单独处理。

这可以通过两种方式来完成:或者PHP脚本将文件复制到“下载区”,例如可能会通过其他背景/服务脚本定期从“旧”文件中清除该文件,或者暴露真正的永久性位置给客户。

每种解决方案的情况当然都有缺点。在这个文件中,取决于请求文件的客户端(curl,wget,GUI浏览器),他们可能不支持重定向,而在另一个文件中,这些文件非常暴露于外部世界,可以随时读取PHP脚本的(访问)控制。