问题描述
|
我正在尝试为用户提供大型zip文件。当有2个并发连接时,服务器内存不足(RAM)。我将内存量从300MB增加到4GB(Dreamhost VPS),然后工作正常。
我需要允许两个以上的并发连接。实际的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);
}
我尝试了一些在Google中找到的基于块的代码,但是该文件始终交付已损坏。可能是因为代码错误。
有人可以帮我吗?
解决方法
这个线程中有一些想法。我不知道readfile()方法是否可以节省内存,但这听起来很有希望。
, 您要通过PHP发送此文件的内容($ data)吗?
如果是这样,每个处理此问题的Apache进程最终将增长到该文件的大小,因为该数据将被缓存。
您唯一的解决方案是不通过PHP发送文件内容/数据,而只是将用户重定向到文件系统上的下载URL。
使用生成的唯一符号链接或隐藏位置。
, 我搜索了太多脚本和建议,但400MB PDF文件没有任何作用。我最终使用了mod_rewrite,这是它很好用的解决方案https://unix.stackexchange.com/questions/88874/control-apache-referrer-to-restrict-downloads-in-htaccess-file
该代码仅允许从您指定的引荐来源下载,并禁止直接下载
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://yourdomain.com/.* [NC]
RewriteRule .* - [F]
, 您不能将$ data与整个文件数据一起使用。尝试传递给此函数,而不是仅传递文件的路径。接下来发送一次所有标头,然后使用fread()读取该文件的一部分,回显该块,调用flush()并重复。如果在此期间发送其他任何报头,则最终传输将被破坏。
, 将大文件符号链接到您的文档根目录(假定其不是唯一的授权文件),然后让Apache处理它。 (这样,您也可以接受字节范围)
, 在SESSION_START();
之前加ini_set