限制并行/同时下载-如何知道下载是否被取消


Limiting Parallel/Simultaneous Downloads - How to know if download was cancelled?

我有一个简单的文件上传服务,用PHP编写,其中还包括一个脚本,当用户请求从这个站点下载时,通过发送有限大小的数据包来控制下载速度。

我想实现一个系统,以限制并行/同时下载1每个用户,如果他们不是高级会员。在上面的下载脚本中,我可以使用MySQL数据库来存储一条记录,它具有:(1)用户ID;(2)文件ID;(3)何时开始下载;(4)最后一个数据包发送的时间,每次发送时都会更新(如果DL速度限制为150kb/秒,则在每150kb之后更新此记录,等等)。

然而,到目前为止,数据库记录只会在下载成功完成后才会被删除——在脚本的末尾,在下载完全完成后,记录将从表中删除:

insert DB record;
while (download is being served) {
    serve packet of data;
    update DB record with current date/time;
}
// Download is now complete
delete DB record;

我如何能够检测何时下载已被取消?我只需要有一个Cron作业(或类似的东西)检测现有的下载记录是否超过X分钟/小时?还是我还能做些什么,但我却错过了?

我希望我已经解释得够清楚了。我不认为张贴特定的代码是必需的;我更感兴趣的是如何/是否能做到这一点。如果具体需要,我将乐意提供。

注意:我知道如何检测文件是否成功下载;我需要知道如何检测它是否被取消、中止或以其他方式停止(而不仅仅是暂停)。这将有助于停止并行下载,以及防止用户取消下载#1并试图启动下载#2,却发现网站声称他仍在下载文件#1。

编辑:你可以在这里找到我的下载脚本:http://codetidy.com/1319/-它已经支持多部分下载和下载恢复。

<?php
class DownloadObserver
{
  protected $file;
  public function __construct($file) {
    $this->file = $file;
  }
  public function send() {
    // -> note in DB you've started
    readfile($this->file);
  }
  public function __destruct() {
    // download is done, either completed or aborted
    $aborted = connection_aborted();
    // -> note in DB
  }
}
$dl = new DownloadObserver("/tmp/whatever");
$dl->send();

应该可以正常工作。不需要shutdown_function或任何时髦的自建连接观察

您将需要查看以下函数:connection_status(), connection_aborted()和ignore_user_abort()(更多信息请参阅PHP手册中的连接处理部分)。

虽然我不能保证它的可靠性(我已经有一段时间没有使用它了),但是通过正确的组合,你应该能够完成你想要的。在使用这些工具时,有一些注意事项,其中最大的一个是,如果出现问题,您可能会在服务器上运行搁浅的PHP脚本,要求您杀死Apache以阻止它们。

下面的代码应该会给你一个很好的想法,如何做到这一点(改编自PHP代码示例和一些注释):

<?php
//Set PHP not to cancel execution if the connection is aborted
//and drop the time limit to allow for big file downloads
ignore_user_abort(true);
set_time_limit(0);
while(true){
    //See the ignore_user_abort() docs re having to send data
    echo chr(0);
    //Make sure the data gets flushed properly or the connection check won't work
    flush();
    ob_flush();
    //Check then connection status and exit loop if aborted
    if(connection_status() != CONNECTION_NORMAL || connection_aborted()) break;
    //Just to provide some spacing in this example
    sleep(1);
}
file_put_contents("abort.txt", "aborted'n", FILE_APPEND);
//Never hurts to ensure that the script halts execution
die();

显然,对于你如何使用它,被发送的数据将只是下载数据块(只是确保你正确刷新缓冲区,以确保数据被实际发送)。据我所知,没有办法区分暂停和中止/停止。暂停/恢复功能(以及多部分下载-即下载管理器如何加速下载)依赖于"Range"头,基本上是请求文件的字节x到字节y。所以如果你想允许可恢复下载你也需要处理这个

默认情况下不发送HTTP "cancel"信号。因此,看起来您需要决定超时,即连接在不发送/接收另一个数据包的情况下可以停留的时间长度。如果您正在发送相当小的数据包(我认为您是),请保持超时时间短以获得最佳效果。

在while条件中,您需要检查最后一次时间戳更新的年龄,如果太老,则停止发送文件