【问题标题】:Allowed memory size exhausted in fpasstrhufpasstrhu 中允许的内存大小已用尽
【发布时间】:2011-03-07 16:33:38
【问题描述】:

有没有办法在不超过 PHP 内存的情况下向浏览器发送一个大(大约 >700mb)文件?

我尝试使用fpassthrureadfile,但它超出了内存限制。

【问题讨论】:

  • @Abel 我不会认为它们是重复的 - 它们有不同的原因会耗尽所有内存。
  • 您使用的是什么版本的 PHP(以及在什么平台上)?另外,为什么您认为它的内存不足? (如果正在生成特定错误,请发布代码示例和确切的错误。)
  • @Dave Vogt:好的,感谢您指出这一点。我将保留它们,因为它们至少相似:文件通过 Internet 浏览器发送到服务器。

标签: php memory


【解决方案1】:

如果您的网络服务器支持,最有效的解决方案是使用 X-Sendfile 标头。

这意味着你根本不需要用 PHP 来提供文件,你只需发送 header 并让 web 服务器处理它。

示例(来自 Apache mod_xsendfile 页面:)

header("X-Sendfile: $path_to_somefile");
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$somefile\"");
exit;

【讨论】:

  • +1 很酷的解决方案。必须承认我以前从未遇到过这种情况,但这似乎是最有效的途径。
  • +1 - X-Sendfile 是解决这个问题的一个很好的解决方案,没有得到足够的新闻
  • 我会试一试的。让服务器完成这项工作听起来合乎逻辑,而不是两者兼而有之。
  • 不幸的是,在 Apache 上需要一个已弃用的非标准 mod_xsendfile
【解决方案2】:

好老的 fopen() + fread() + fclose():

<?php
$handle = fopen('/tmp/foo', 'rb');
while (!feof($handle)) {
    echo fread($handle, 8192);
}
fclose($handle);

8192 是 PHP 文档中显示的缓冲区大小,但根据我的经验,最好提高它,因为您可以以非常少的内存使用量增加为代价获得有趣的性能提升。

【讨论】:

    【解决方案3】:

    听起来你在使用fpassthru 时遇到的问题是由于整个文件被加载到内存中。你应该做的是使用传统的块读取文件数据fopen/fread/fclose循环,边走边输出数据。

    例如:

    <?php
        $fileRes = fopen('/path/to/your/file.data', 'rb');
        if(is_resource($fileRes) {
            while (!feof($fileRes)) {
                echo fread($fileRes);
            }
            fclose($fileRes);
        }
        else die("Couldn't open file...");
    ?>
    

    【讨论】:

    • fpassthrureadfile 将整个文件读入内存,除非有足够的空间。 Have a look at the source,这段代码几乎等同于 PHP 所做的,只是效率较低。
    • @Long 觉得这有点奇怪。也就是说,OP 可能正在使用一些旧版本的 PHP,尽管即使这样,如果存在这样的问题我也会感到惊讶。
    • 作为参考,我可以通过 readfile 提供 700MB 的文件,内存限制为 8MB。
    • 您链接到的 fpassthru 页面上的评论表明 PHP 4 中存在内存泄漏,因此很可能就是这样。
    • 确保你没有使用输出缓冲 - 通常,当我们看到 readfile() 消耗内存时,这是因为用户正在使用输出缓冲,导致 PHP 缓冲 readfile()。
    【解决方案4】:

    fpassthru (as readfile) 直接发送数据,没有太多的内存分配。 所以缓存问题和ob_end_flush 会有所帮助:

    <?php
    
    $fp = fopen($filename, 'rb');
    
    header('Content-Type: ' . mime_type($filename));
    header("Content-Length: " . filesize($filename));
    
    ob_end_flush()
    
    fpassthru($fp);
    exit;
    

    【讨论】:

      猜你喜欢
      • 2013-02-08
      • 2014-09-05
      • 2012-04-30
      • 1970-01-01
      • 2020-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      相关资源
      最近更新 更多