【问题标题】:php, file downloadphp,文件下载
【发布时间】:2011-08-01 12:23:01
【问题描述】:

我正在使用简单的文件下载脚本:

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;
}

它在我的本地服务器上运行,最大 200mb。

当我在我的网站上尝试此代码时,它会下载 173KB 而不是 200MB 的文件。

我检查了所有内容,编写了一些自定义代码(使用 ob 函数和 fread 而不是 readfile),但无法下载大文件。

感谢您的回答。

  • 我使用的是 Apache 2.2、PHP 5.3
  • 处理大文件的所有 PHP 设置都可以。 (执行时间、内存限制……

【问题讨论】:

  • 我的主机,dreamhost 有时会杀死消耗大量 CPU 或资源的脚本。这可能是你的情况。

标签: php file header download


【解决方案1】:

针对某些场景的一种解决方案是,您可以使用 PHP 脚本智能地决定从何处下载文件,但不是直接从 PHP 发送文件,您可以将重定向返回到客户端,然后包含直接链接由网络服务器单独处理。

这至少可以通过两种方式完成:要么 PHP 脚本将文件复制到“下载区域”,例如可能由其他后台/服务脚本定期从“旧”文件中清除,或者您公开真实的客户的永久位置。

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

【讨论】:

    【解决方案2】:

    我对以下代码的一个问题是你无法控制输出流,你让 PHP 处理它而不知道后台发生了什么:

    您应该做的是设置一个输出系统,您可以控制和复制整个服务器。

    例如:

    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

    【讨论】:

    • 谢谢。分块发送在所有服务器上都没有问题。另外我正在发送文件大小,实际上发送完整的文件大小并逐块发送文件可能微不足道,但现在效果很好。否则对于大下载用户将看不到完整的文件大小,这可能不利于可用性。
    • 这完全取决于数据的传输方式,例如流式传输和下载需要两种不同的内容交付方式。乐于助人
    • 不应该对base name($file) 进行编码吗?如果它包含与 http 混淆的字符怎么办?
    【解决方案3】:

    真正的解决方案是避免使用 PHP 脚本来仅向客户端发送文件,这太过分了,您的网络服务器更适合该任务。

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

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

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

    【讨论】:

    • 谢谢Zofrex,是的,在发送文件之前必须进行一些身份验证和一些其他操作。 mod_xsendfile 看起来不错,我会试试的。这可能是更清晰的解决方案。
    【解决方案4】:

    似乎 readfile 可能对长文件有问题。正如@Khez 所问,可能是脚本运行时间过长。快速谷歌搜索导致了几个分块文件的示例。

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

    【讨论】:

    • 所有设置都适用于大文件、执行时间、内存限制……
    • 第一个链接的 read_chunked() 函数解决了这个问题。
    【解决方案5】:

    您是否确保您的脚本can run long 足够并且有足够的内存?

    你真的需要输出缓冲吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      • 1970-01-01
      • 2014-04-05
      • 2020-01-13
      • 2016-11-20
      • 2023-04-04
      • 2013-03-31
      相关资源
      最近更新 更多