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

时间:2011-10-23 04:47:41

标签: php mysql download

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

如果不是高级会员,我想实施一个系统,将并行/同步下载限制为每用户1个。在上面的下载脚本中,我可以使用MySQL数据库来存储具有以下内容的记录:(1)用户ID; (2)文件ID; (3)下载开始时; (4)当最后一个数据包被发送时,每次完成时更新(如果DL速度限制在150 kB / sec,那么在每150 kB之后,此记录将被更新,等等。)

但是,到目前为止,只有在下载成功完成后才会删除数据库记录 - 在脚本结束时,在完全下载完成后,记录将从表中删除:

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;

我如何能够检测下载何时被取消?如果现有的下载记录超过X分钟/小时,我是否只需要有一个Cron作业(或类似的东西)检测?或者我还有别的东西可以让我失踪吗?

我希望我已经解释得这么好了。我认为不需要发布特定代码;我对如何/是否可以这样做的后勤工作更感兴趣。如果需要具体,我很乐意提供。

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

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

3 个答案:

答案 0 :(得分:4)

<?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或任何时髦的自建连接观察。

答案 1 :(得分:1)

您需要查看以下函数:connection_status(),connection_aborted()和ignore_user_abort()(有关详细信息,请参阅PHP手册的connection handling部分)。

虽然我无法保证可靠性(自从我玩过它以来已经有一段时间了),但如果正确的组合,你应该能够完成你想要的。但是在处理这些问题时有一些注意事项,最重要的一点是,如果出现问题,您最终可能会在服务器上运行搁浅的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();

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

答案 2 :(得分:0)

默认情况下,没有HTTP“取消”信号。因此,看起来您需要决定超时,连接可以在不发送/接收另一个数据包的情况下持续的时间长度。如果您要发送相当小的数据包(我认为您是这样),请将超时保持为最佳效果。

在你的状态下你需要检查上次时间戳更新的年龄,如果它太旧,就停止发送文件。