如何直接开始下载远程大文件?

时间:2013-05-21 14:34:41

标签: php stream download fopen

我正在尝试将外部API中的大文件传递给用户(想想100MB或更多)

目前,我正在使用一些偏执的脚本(由于过去的失败)来尽快下载脚本。

通过'下载',我只是指浏览器上的下载触发器,而不是文件的实际下载。只是用户可以选择他想要保存文件的位置。

set_time_limit(0);

apache_setenv('no-gzip', 1);
ini_set('zlib.output_compression', 0);
ini_set('output_buffering', 0);
ini_set('implicit_flush', 1);
for($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
ob_implicit_flush(1);

header('Content-Description: File Transfer');
header('Content-type: application/octet-stream');
header('Content-Transfer-Encoding: Binary');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Cache-Control: private');

ob_flush();
flush();

$fh = fopen($external_api_url, 'rb');
while(!feof($fh))
{
    echo fread($fh, 512);
    ob_flush();
    flush();
}
fclose($fh);

使用此脚本,在下载弹出窗口显示之前,50mb文件仍然需要20秒,而对于更大的文件,则需要更长时间。

有没有办法更快地启动流?

编辑: 我也尝试了fpassthru()和readfile(),但这些相同的50mb文件需要40秒,这让我觉得这样更好。我也玩了不同的读取大小(512,256,64,其他几个),但我没有注意到差异)

1 个答案:

答案 0 :(得分:0)

浏览器花费这么长时间来触发下载对话框的原因是由于API需要很长时间才能返回其第一块数据,例如他们可能在开始发送之前将整个文件读取到内存中给你的数据,这可以解释为什么更长的文件需要更长的时间才能启动,即使你总是尝试尽可能快地写入前512个字节。

我试图通过从本地文件中读取来本地模拟它,但在sleep(5);循环之前发出while语句。

我可以让谷歌浏览器开始下载任何数据,省略 header('Content-type: application/octet-stream');行,同时在尝试阅读之前仍然发出flush();来电文件。 (你已经在做第二部分了)

然而,这似乎不适用于Firefox 3.6,因此您可能需要针对不同浏览器使用不同的噱头,除非您可以预测文件的第一个字符(请查看BOM)并在之前回复任何事情,随后从您第一次fread()电话的开头删除它。

我希望它有所帮助!但基本上外部API会让你失望。