Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/magento/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 限制并行/同时下载-如何知道下载是否被取消?_Php_Mysql_Download - Fatal编程技术网

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

Php 限制并行/同时下载-如何知道下载是否被取消?,php,mysql,download,Php,Mysql,Download,我有一个简单的文件上传服务,用PHP编写,它还包括一个脚本,当用户请求从这个站点下载时,通过发送有限大小的数据包来控制下载速度 我想实现一个系统,将并行/同时下载限制为每个用户1次,如果他们不是高级成员。在上面的下载脚本中,我可以使用MySQL数据库存储一条记录,该记录具有:(1)用户ID;(2) 文件ID;(3) 下载启动时;和(4)当发送最后一个数据包时,每次发送时都会更新该数据包(如果DL速度限制为150 kB/秒,则每发送150 kB后,会更新该记录,以此类推) 但是,到目前为止,只有在

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

我想实现一个系统,将并行/同时下载限制为每个用户1次,如果他们不是高级成员。在上面的下载脚本中,我可以使用MySQL数据库存储一条记录,该记录具有:(1)用户ID;(2) 文件ID;(3) 下载启动时;和(4)当发送最后一个数据包时,每次发送时都会更新该数据包(如果DL速度限制为150 kB/秒,则每发送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;
我将如何检测下载何时被取消?我是否需要一个Cron作业(或类似的东西)来检测现有的下载记录是否超过X分钟/小时?或者我还能做些什么,但我错过了

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

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

编辑:您可以在此处找到我的下载脚本:-它已经支持多部分下载和下载恢复。

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


在while状态下,您需要检查上次时间戳更新的时间,如果时间戳太长,请停止发送文件。

您需要检查以下函数:connection_status()、connection_aborted()和ignore_user_abort()(有关详细信息,请参阅PHP手册的一节)

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

以下内容将为您提供一个很好的方法(改编自PHP代码示例和一些注释):


Hmm,我还必须检查该记录是否仍然存在(即,检查过期下载记录的cron作业尚未删除该记录)。如果没有,请停止下载(和脚本),因为它被认为已过期。这听起来对吗?
register\u shutdown\u功能在这方面有用吗?在我当前的代码中,我有一个注释掉的部分,我一定是从我获取代码的站点复制的,它说在中止/完成下载时使用它来运行特定的函数。您可以在这里找到我的下载脚本:(它被传递了一个“ID”GET参数)我想我能做的是在这个脚本中有两个全局PHP变量,它们存储(1)到目前为止已经提供了多少字节,以及(2)文件总共有多少字节。在shutdown函数中,如果所服务的字节数小于总字节数,则文件被中止。否则,它将成功完成。问题是,当页面本身关闭时,或者当下载本身停止时,会调用关闭函数吗?从技术上讲,
dl.php
在向用户提供下载时仍在运行,即使页面本身没有在选项卡中打开。die()和exit可能会造成伤害。例如,当PHP在fcgid中运行时,每个出口都会终止本来可以缓存的进程。浪费性能和填充日志。在我的
download\u file
函数的末尾有一个
die()
函数。我假设这将调用
register\u shutdown\u函数()。我已经支持恢复下载,其中发送的字节数和总字节数都被跟踪。我假设我可以简单地注册一个shutdown函数来检查这两个值,对吗?这样做可以更好地控制何时中断连接以及何时可以停止提供文件。此外,您还可以在那里处理中止的进程,而不必尝试使用uu析构函数或关闭函数捕获它。您发布的脚本是否会与您简单添加的while循环后的脚本工作不完全一样?
if(connection_aborted()){//do cleanup}
?我假设
公共函数send()
也会包含脚本以限制下载大小、处理恢复的下载等。?在
\u destruct()
函数中,我可以比较
$bytes\u sent
$bytes\u total
以查看它是否被中止/取消和成功完成,对吗?这看起来干净多了,你是对的。由于您已经解决了其他问题,我只指出了面向对象方法(特别是u destruct())来解决您的“抓住事情的结尾”问题。我相信这是我应该采取的最佳方向。它是面向对象的,包含整洁,易于阅读。这些天我一直在尝试使用尽可能多的OO代码,所以
<?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();
<?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();