如何在不使用太多内存的情况下强制下载大文件?

我正在尝试向用户提供大型zip文件。 当有两个并发连接时,服务器耗尽内存(RAM)。 我增加了从300MB到4GB(Dreamhost的VPS)的内存量,然后它工作正常。

我需要允许多于2个并发连接。 实际的4GB将允许20个并发连接(太差)。

那么,我正在使用的当前代码需要内存的两倍,然后是实际的文件大小。 这太糟糕了。 我想像“stream”的文件给用户。 所以我会分配不超过被传送给用户的块。

以下代码是我在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函数如下(Codeingiter默认辅助函数):

 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中find的基于块的代码,但文件总是被损坏。 可能是因为代码不好。

任何人都可以帮我吗?

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

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

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

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

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

里面的文件数据不能使用$ data。 尝试传递给这个函数不是文件的内容而是它的路径。 接下来发送所有标题一次,然后使用fread()读取这个文件的一部分,回声该块,调用flush()并重复。 如果有其他的头文件将被发送,那么最后的传输将被破坏。

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

SESSION_START();之前添加你的ini_set SESSION_START();