English 中文(简体)
如何在不占用太多内存的情况下强制下载大文件?
原标题:How to force download of big files without using too much memory?

我正在尝试为用户提供大型zip文件。当有2个并发连接时,服务器的内存(RAM)将用完。我将内存量从300MB增加到4GB(Dreamhost VPS),然后它工作得很好。

我需要允许2个以上的并发连接。实际的4GB将允许大约20个并发连接(太糟糕了)。

嗯,我现在使用的代码,需要双倍的内存,然后是实际文件大小。那太糟糕了。我想要一些类似于将文件“流式传输”给用户的东西。因此,我只会将提供给用户的数据块分配给用户。

以下代码是我在CodeIgniter(PHP框架)中使用的代码:

ini_set( memory_limit ,  300M ); // it was the maximum amount of memory from my server
set_time_limit(0); // to avoid the connection being terminated by the server when serving bad connection downloads
force_download("download.zip", file_get_contents("../downloads/big_file_80M.zip"));exit;

force_download函数如下(CodeIgniter默认辅助函数):

function force_download($filename =   , $data =   )
{
    if ($filename ==    OR $data ==   )
    {
        return FALSE;
    }

    // Try to determine if the filename includes a file extension.
    // We need it in order to set the MIME type
    if (FALSE === strpos($filename,  . ))
    {
        return FALSE;
    }

    // Grab the file extension
    $x = explode( . , $filename);
    $extension = end($x);

    // Load the mime types
    @include(APPPATH. config/mimes .EXT);

    // Set a default mime if we can t find it
    if ( ! isset($mimes[$extension]))
    {
        $mime =  application/octet-stream ;
    }
    else
    {
        $mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
    }

    // Generate the server headers
    if (strpos($_SERVER[ HTTP_USER_AGENT ], "MSIE") !== FALSE)
    {
        header( Content-Type: " .$mime. " );
        header( Content-Disposition: attachment; filename=" .$filename. " );
        header( Expires: 0 );
        header( Cache-Control: must-revalidate, post-check=0, pre-check=0 );
        header("Content-Transfer-Encoding: binary");
        header( Pragma: public );
        header("Content-Length: ".strlen($data));
    }
    else
    {
        header( Content-Type: " .$mime. " );
        header( Content-Disposition: attachment; filename=" .$filename. " );
        header("Content-Transfer-Encoding: binary");
        header( Expires: 0 );
        header( Pragma: no-cache );
        header("Content-Length: ".strlen($data));
    }

    exit($data);
}

我尝试了一些在谷歌上找到的基于区块的代码,但文件总是被破坏了。可能是因为代码不正确。

有人能帮我吗?

最佳回答

这个线程。我不知道readfile()方法是否会节省内存,但听起来很有希望。

问题回答

你是通过PHP发送这个文件的内容($data)吗?

如果是这样的话,每个处理这个问题的Apache进程最终都会增长到这个文件的大小,因为这些数据将被缓存。

您唯一的解决方案是不通过PHP发送文件内容/数据,只需将用户重定向到文件系统上的下载URL。

使用生成的唯一符号链接或隐藏位置。

I searched too many scripts and advises and nothing worked for my 400MB PDF file. I ended up using mod_rewrite and here s the solution it works great https://unix.stackexchange.com/questions/88874/control-apache-referrer-to-restrict-downloads-in-htaccess-file The code only allows download from a referrer you specifies and forbids direct download

 RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://yourdomain.com/.* [NC]
RewriteRule .* - [F]

不能将$data与整个文件数据一起使用。请尝试传递给此函数,而不是仅传递文件的内容及其路径。接下来,使用fread()发送一次所有标头,然后读取该文件的一部分,回显该块,调用flush()并重复。如果在此期间将发送任何其他标头,则最终传输将被破坏。

将大文件符号链接到您的文档根(假设它不是唯一授权的文件),然后让Apache处理它。(这样您也可以接受字节范围)

SESSION_START()之前添加ini_set





相关问题
Using SimplePie with CodeIgniter and XAMPP

I am using CodeIgniter 1.7.2 with XAMPP 1.7.2 on a Windows computer. I am trying to make use of SimplePie. I followed all the instructions I could find: a copy of simplepie.inc is in my applications/...

Multiple Sites with common files

I have developed over 50 sites that all use the exact same files other than CSS and IMAGES, I currently duplicate the files each time I create a new site and upload different css and images. What ...

http server validation

I finish a litle http server, writing from scratch. I would like to be sure that my imlementation is conforme to the HTTP specifications. W3C give us tools for HTML/XML conformance, but i see nothing ...