Подтвердить что ты не робот

PHP/Javascript: Как я могу ограничить скорость загрузки?

У меня есть следующий сценарий: Вы можете загрузить с нашего сервера некоторые файлы. Если вы "обычный" пользователь, у вас ограниченная пропускная способность, например, 500 кбит. Если вы премиум-пользователь, у вас нет предела вашей пропускной способности и вы можете скачать как можно быстрее. Но как я могу это понять? Как это загружено и co?

4b9b3361

Ответ 1

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

Существует расширение PECL, которое делает это довольно тривиальной задачей, называемой pecl_http, которая содержит функцию http_throttle. Документы содержат простой пример того, как это сделать. Это расширение также содержит a HttpResponse класс, который плохо документирован ATM, но я подозреваю, что играю с его setThrottleDelay и setBufferSize должны давать желаемый результат (задержка дросселя = > 0,001, размер буфера 20 == ~ 20 Кбит/с). С точки зрения вещей, это должно работать:

$download = new HttpResponse();
$download->setFile('yourFile.ext');
$download->setBufferSize(20);
$download->setThrottleDelay(.001);
//set headers using either the corresponding methods:
$download->setContentType('application/octet-stream');
//or the setHeader method
$download->setHeader('Content-Length', filesize('yourFile.ext'));
$download->send();

Если вы не можете/не хотите его устанавливать, вы можете написать простой цикл:

$file = array(
    'fname' => 'yourFile.ext',
    'size'  => filesize('yourFile.ext')
);
header('Content-Type: application/octet-stream');
header('Content-Description: file transfer');
header(
    sprintf(
        'Content-Disposition: attachment; filename="%s"',
        $file['fname']
    )
);
header('Content-Length: '. $file['size']);
$open = fopen($file['fname'], "rb");
//handle error if (!$fh)
while($chunk = fread($fh, 2048))//read 2Kb
{
    echo $chunk;
    usleep(100);//wait 1/10th of a second
}

Конечно, не буферизуйте вывод, если вы это сделаете:), и было бы лучше добавить оператор set_time_limit(0);. Если файл большой, вполне вероятно, что ваш script будет убит в середине загрузки, так как он достиг максимального времени выполнения.

Другим (и, вероятно, предпочтительным) подходом было бы ограничение скорости загрузки через конфигурацию сервера:

Я никогда не ограничивал скорость загрузки самостоятельно, но, глядя на ссылки, я считаю справедливым сказать, что nginx является самым простым:

location ^~ /downloadable/ {
    limit_rate_after 0m;
    limit_rate 20k;
}

Это приводит к немедленному удару скорости и устанавливает значение 20k. Подробности можно найти на вики nginx.

Что касается apache, это не намного сложнее, но вам потребуется включить модуль ratelimit

LoadModule ratelimit_module modules/mod_ratelimit.so

Тогда просто сказать apache, какие файлы должны быть дросселированы:

<IfModule mod_ratelimit.c>
    <Location /downloadable>
        SetOutputFilter RATE_LIMIT
        SetEnv rate-limit 20
    </Location>
</IfModule>

Ответ 2

Вы можете использовать http_throttle из расширения pecl_http PHP:

<?php
// ~ 20 kbyte/s
# http_throttle(1, 20000);
# http_throttle(0.5, 10000);
if (!$premium_user) {
    http_throttle(0.1, 2000);
}
http_send_file('document.pdf');
?>

(Выше приведен пример из http://php.net/manual/en/function.http-throttle.php.)

Если ваш API-интерфейс сервера не позволяет http_throttle создавать два разных, неописуемых URL-адреса для ваших премиальных и непрофессиональных пользователей и ссылаться на вашу документацию по серверу HTTP для того, как дросселировать один из них. См. https://serverfault.com/questions/179646/nginx-throttle-requests-to-prevent-abuse для примера для Nginx. Последнее имеет преимущество, позволяющее обойти проблемы, связанные с тем, что загрузка заканчивается раньше из-за того, что PHP убил ваш script.

Ответ 3

Вот эта земельная библиотека пользователя PHP bandwidth-throttle/bandwidth-throttle

use bandwidthThrottle\BandwidthThrottle;

$in  = fopen(__DIR__ . "/resources/video.mpg", "r");
$out = fopen("php://output", "w");

$throttle = new BandwidthThrottle();
$throttle->setRate(500, BandwidthThrottle::KIBIBYTES); // Set limit to 500KiB/s
$throttle->throttle($out);

stream_copy_to_stream($in, $out);