Отправить заявку

PHP - как ограничить скорости скачивания файла

Иногда нужно ограничить скорость загрузки файла. Хорошо - если есть возможность настроить это на веб-сервере - тогда все просто и ресурсов сервера будет потребляться меньше. Но, что делать если доступа к настройкам веб-сервера нет? Правильно - нужно писать свой костыль. И php нам поможет в этом.

Есть сайт, который предоставляет файлы для загрузки. И мы хотим сделать ограничение скорости загрузки только для незарегистрированных пользователей, а для зарегистрированных пользователей нет никаких ограничений. Причина для ограничения скорости скачивания может быть и иной: пользователь, оплативший скачивание без ограничений - получает файл на максимальной скорости, а тот, кто пожадничал - будет скачивать очень медленно.

<?php
// скорость скачивания - 128КБ в сек.
$speed = 1024*128;
// имя файла
$filename = 'music.mp3';
// размер файла
$filesize = filesize($filename);
// смещение от начала файла
$range = 0;

while( is_already_download() ) {
  // спим пока у пользователя есть активные потоки
  sleep(1);
}

// открываем файл на чтение
$f = fopen($filename, 'rb');

if (isset($_SERVER['HTTP_RANGE'])) { // поддерживается ли докачка 
  $range = $_SERVER['HTTP_RANGE'];
  $range = str_replace('bytes=', '', $range);
  $range = str_replace('-', '', $range);
  if ($range) fseek($f, $range);
}
 
// если есть смещение
if ($range) {
  header($_SERVER['SERVER_PROTOCOL'].' 206 Partial Content');
} else {
  header($_SERVER['SERVER_PROTOCOL'].' 200 OK');
}

header( 'Last-Modified: '.date('D, d M Y H:i:s T', filemtime($filename)) );
header('Content-Length: '.($filesize-$range));
header('Accept-Ranges: bytes');
header('Content-Range: bytes '.$range.'-'.($filesize - 1).'/'.$filesize);
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="'.$filename.'"');

while( !feof($f) ) {
  echo fread($f, $speed);
  flush();
  sleep(1); // засыпаем
}

// закрываем файл
fclose($f);

// удаляем информацию о соединении из БД
mysql_query("DELETE FROM `sessions` WHERE `session_ip`='".$_SERVER['REMOTE_ADDR']."' LIMIT 1");

function is_already_download() {
  // проверяем на наличие соединений от пользователя
  $res = mysql_query("SELECT `session_ip` FROM `sessions` WHERE `session_ip`='".$_SERVER['REMOTE_ADDR']."' LIMIT 1");
  if (mysql_num_rows($res)) {
    return true;
  } else { // если запись отсутствует, то добавляем
    mysql_query ("INSERT INTO `sessions` VALUES ('".$_SERVER['REMOTE_ADDR']."')");
    return false;
  }
}
?>

В данном случае мы используем таблицу MySQL sessions, в которй всего одно поле - IP-адрес скачивающего. При наличии IP-адреса скачивающего в таблице отдаем true, в противном случае записываем его и отдаем false.

Другие публикации