|
|
|
|
|
|
Всякое |
Ограничение скорости скачивания файла в PHPВ предыдущей заметке я рассмотрел способы отдачи файла через скрипт PHP. Приведенная там функция file_download() позволяет отдать произвольный файл, имя которого может быть параметром скрипта или быть заданным константой. Скорость закачки этого файла будет определятся только возможностями сервера и канала связи между ним и клиентом. В случае большого количества подключений к одному или нескольким файлам через скрипт, может наблюдаться перегрузка сервера. Один из методов борьбы с такой перегрузкой – это ограничение как скорости скачивания файла, так и числа подключений от одного клиента или IP-адреса. Поскольку файл у нас отдаётся клиенту программно, то и регулировать скорость отдачи файла и число подключений мы будем таким же образом. Последняя реинкарнация функции file_download() принимает два параметра $filename – имя файла и $mimetype – его MIME-тип. Для введения ограничения по скорости закачки нам понадобится еще один параметр – скорость скачивания. Поскольку, этот параметр не относятся к самому файлу его резонно задавать для всего сайта, а не в параметрах, которые передаются функции. Сделаем это в её заголовке. Ограничение скорости закачкиМодифицированный код будет выглядеть так: function file_download($filename, $mimetype='application/octet-stream') { // Задаем ограничение скорости закачки в байтах в секунду // или ноль, если ограничений не требуется. // Другим способом задания этого параметра может быть его определение // через константу, посредством функции define(), в этом случае значение // будет неизменным для любого запуска скрипта. // Можно его значение задавать и снаружи функции исходя из каких-либо соображений, // например, роли пользователя или загрузки сервера, и получать его // посредством директивы global. $download_speed = 25000; // Около 25 килобайт в секунду. // Задаём время дискретизации. С этой периодичностью клиенту будут отдаваться // блоки данных считываемые из файла. $time_discret = 1; if (file_exists($filename)) { header($_SERVER["SERVER_PROTOCOL"] . ' 200 OK'); header('Content-Type: ' . $mimetype); header('Last-Modified: ' . gmdate('r', filemtime($filename))); header('ETag: ' . sprintf('%x-%x-%x', fileinode($filename), filesize($filename), filemtime($filename))); header('Content-Length: ' . (filesize($filename))); header('Connection: close'); header('Content-Disposition: attachment; filename="' . basename($filename) . '";'); $f=fopen($filename, 'r'); // Проверяем задано ли ограничение скорости if((int) $download_speed > 0) { while(!feof($f)) { // Включаем таймер $time_start = microtime(true); // Читаем блок данных, которых мы должны отдать за время дискретизации echo fread($f, ceil($download_speed*$time_discret)); flush(); // Находим время за которое наши данные отправлены $time_end = microtime(true); $time = $time_end - $time_start; // Если время, оставшееся до конца времени дискретизации больше нуля, // то приостанавливаем выполнение скрипта на величину этого времени в микросекундах. if($time_discret-$time > 0) usleep(($time_discret-$time)*1000000); } } else { // Если у нас не задано ограничение скорости, то выполняем старый вариант кода while(!feof($f)) { echo fread($f, 1024); flush(); } } fclose($f); } else { header($_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found'); header('Status: 404 Not Found'); } exit; } Как видно из кода, файл будет отдаваться клиенту дискретными порциями один раз в секунду. Можно уменьшить это значение поставив время дискретизации менее, чем 1 сек. Собственно, в общем случае так и нужно сделать. Хотя время ожидания клиентских программ посылки данных сервером обычно довольно велико, стоит учитывать и разные отклонения от этого правила. На мой взгляд время дискретизации в этом скрипте должно быть не более 0,1 секунды. |
|
Direqtor Home Page by ASIADATA. |
|
Отправить комментарий