HTTP文件下载:监控下载进度

5
我现在需要从一个Web服务器(Apache 2.4.4)通过HTTP协议下载大文件(高达4GB),我尝试了几种方法,但最好的解决方案似乎是使用X-SendFile模块。由于我为文件上传提供进度条,所以我需要为文件下载提供相同的功能。以下是我的问题:
1. 是否有任何方法(包括解决方法)可以实现文件下载进度监控? 2. 是否有任何方法(包括解决方法)可以计算文件下载传输速度? 3. 是否有比使用X-Sendfile模块更有效的方式来提供来自Web服务器的文件下载?
总的来说,是否有更好的文件下载选项,可以让我监控文件下载进度?它可以是客户端(JavaScript)或服务器解决方案(PHP)。是否有一种特定的Web服务器允许这样做?
目前我使用的是: - Apache 2.4.4 - Ubuntu
非常感谢。

1
你可以在php中使用cURL。https://dev59.com/lmYr5IYBdhLWcg3wGmeq - posit labs
@Web_bod,将从服务器下载许多文件。换句话说,文件下载和上传将是服务器的主要功能。由于我控制着服务器,我可以决定任何形式的文件下载。我尝试通过PHP下载,但这会对文件大小和下载的文件数量带来限制。因此,我尝试了看起来不错的X-SendFile。然而,如果流式传输是正确的方法,我很乐意放弃X-SendFile。 - Bunkai.Satori
@positlabs,cURL看起来也很有趣。感谢您的提示。由于我不太了解cURL,所以我打算去学习一下。我希望cURL不会在下载文件大小或同时下载数量方面设置障碍。 - Bunkai.Satori
我会在周末为您草拟一些东西 - PHP是您首选的语言吗? - web_bod
@positlabs,我已经测试了cURL。它甚至有进度条信息。cURL的问题在于,当需要下载大文件时,在文件下载之前会有很长的延迟。我不知道是什么原因导致的。但是想象一下,你点击一个链接来获取一个文件,现在你必须等待几分钟才能开始下载。但这是个好建议+1。 - Bunkai.Satori
显示剩余3条评论
3个回答

4
两个想法(未经验证):
第一个:
在您的页面上,不要放置常规文件链接(您想要下载的文件),而是放置像.../dowanload.php这样的链接,它可能看起来像这样:
<?php

    // download.php file
    session_start(); // if needed

    $filename = $_GET['filename']);

    header( 'Content-type: text/plain' ); // use any MIME you want here
    header( 'Content-Disposition: attachment; filename="' . htmlspecialchars($filename) . '"' );
    header( 'Pragma: no-cache' );

    // of course add some error handling

    $filename = 'c:/php/php.ini';

    $handle = fopen($filename, 'rb');

    // do not use file_get_contents as you've said files are up to 4GB - so read in chunks
    while($chunk = fread($handle, 1000)) // chunk size may depend on your filesize
    {
        echo $chunk;
        flush();
        // write progress info to the DB, or session variable in order to update progress bar
    }

    fclose($handle);
?>

这样,您可以监控下载过程。同时,您可以将进度信息写入到数据库/会话变量中,并使用Ajax更新进度条读取状态,当然是轮询读取进度信息的脚本。
这很简单,但我认为它可能按照您的要求工作。
第二:
Apache 2.4内置了Lua语言:
- mod_lua - 用mod_lua创建钩子和脚本 我敢打赌,您可以尝试编写LUA Apache处理程序来监视您的下载 - 发送进度到数据库并使用PHP/AJAX更新进度条,从数据库获取进度信息。
同样地,还有Perl和Python模块(但不适用于Windows)。

可以使用mod_rewrite隐藏奇怪的URL。外部世界不需要知道download.php脚本的存在。 - Palec
你可以使用mod_perl代替mod_lua,后者不处于实验状态。 - Palec
使用数据库来存储进度更新?我现在明白为什么Node.js变得流行了...至少建议使用APC... - dandavis
@dandavis:当然,APC也可以,但最新的PHP已经没有了(Opcache应该允许类似的事情)。Node.js - 这是我需要更多了解的东西 - 只是听说过它 - 没有更多了。谢谢。 - Artur
@Artur,你好,感谢你的反馈。老实说,对我来说看起来有点复杂,可能超出了我所需的范围。对我有用的是fopen()fread()print()的组合,同时通过AJAX请求监控下载进度。 - Bunkai.Satori
@Artur,你好,我想就你的回答向你请教一下。看起来在下载时无法运行下载监控PHP脚本。请参考我的帖子:http://stackoverflow.com/questions/21506560/monitoring-php-script-wont-start-during-file-download。你有什么解决方案吗?提前感谢。 - Bunkai.Satori

2
我看到的主要问题是: 在php+apache解决方案中,输出缓冲可以放置在多个位置:
浏览器 <= 1 => Apache <= 2 => PHP处理程序 <= 3 => PHP解释器进程
你需要控制第一个缓冲区。但是从PHP直接控制它是不可能的。
可能的解决方案:
1)你可以编写自己的小型守护进程,其主要功能仅为发送文件并在另一个端口(例如8880而非80)上运行它。从那里处理下载文件并监视输出缓冲区。 你的输出缓冲区将只有一个,并且您可以对其进行控制:
浏览器 <= 1 => PHP解释器进程
2)还可以使用mod_lua直接从Apache控制输出缓冲区。
3)还可以使用nginx,并使用内置perl控制nginx输出缓冲区(它很稳定)。
4) 尝试使用 PHP内置Web服务器 并直接控制PHP输出缓冲区。对于它的稳定性,我无法做出任何评论,抱歉。但你可以尝试一下。 ;)

我认为nginx+php+内置perl是更稳定和强大的解决方案。但你可以选择并可能使用列表中没有的其他解决方案。我会关注这个话题,并对你的最终解决方案感到兴趣。


2

频繁读写数据库会影响性能。

建议使用会话(session)(在循环中递增发送数据的值),通过该方法可以安全地关闭另一个php文件,您可以返回JSON格式的数据,这些数据可以被javascript函数/插件使用。


好主意。我也有同样的想法。然而,我遇到了一个意外的问题:当主PHP下载脚本正在运行时,监视PHP脚本不会被AJAX调用执行。我已经陷入了这个问题很长时间并一直在测试它。但是,显然只有在没有其他PHP脚本正在运行时,AJAX监视脚本才会被运行。请参见我的另一篇帖子 - Bunkai.Satori
我尝试了许多方法,但它们都存在某种问题。使用 fopen() fread() print() 的方法对我来说最好,并且在文件大小方面没有限制。因此,我将这个答案标记为有用的答案,接受它,并授予我的赏金。 - Bunkai.Satori

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接