Ограничение параллельных / одновременных загрузок - Как узнать, была ли загрузка отменена? - PullRequest
2 голосов
/ 23 октября 2011

У меня есть простая служба загрузки файлов, написанная на PHP, которая также включает скрипт, который контролирует скорость загрузки, отправляя пакеты ограниченного размера, когда пользователь запрашивает загрузку с этого сайта.

Я хочу внедрить систему, ограничивающую количество одновременных / одновременных загрузок до 1 на пользователя, если они не являются премиум-членами. В приведенном выше сценарии загрузки я могу использовать базу данных MySQL для хранения записи, которая имеет: (1) идентификатор пользователя; (2) идентификатор файла; (3) когда загрузка была начата; и (4) когда был отправлен последний пакет, который обновляется каждый раз, когда это делается (если скорость DL ограничена 150 кБ / с, то после каждых 150 кБ эта запись обновляется и т. д.).

Однако пока запись в базе данных будет удалена только после успешного завершения загрузки - в конце сценария, после завершения загрузки, запись удаляется из таблицы:

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/ - он уже поддерживает загрузку нескольких частей и возобновление загрузки.

Ответы [ 3 ]

4 голосов
/ 23 октября 2011
<?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 голос
/ 23 октября 2011

Вы захотите проверить следующие функции: 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 файла.Так что, если вы хотите разрешить возобновляемую загрузку, вам тоже придется с этим справиться.

0 голосов
/ 23 октября 2011

Нет HTTP-сигнала «отмена», который отправляется по умолчанию. Итак, похоже, вам нужно будет выбрать тайм-аут, промежуток времени, в течение которого соединение может находиться без отправки / получения другого пакета. Если вы отправляете довольно маленькие пакеты (как я полагаю, вы делаете это), то для достижения наилучшего эффекта сократите время ожидания.

В вашем состоянии while вам нужно будет проверить возраст последнего обновления отметки времени, если оно устарело, прекратить отправку файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...