我有一个简单的文件上传服务,用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条件中,您需要检查最后一次时间戳更新的年龄,如果太老,则停止发送文件