Limit Download Speed Using PHP

Limit download speed using PHP

The reason your download stops after 5MB is because it takes over 60 seconds to download 5MB at 80KB/s. Most of those "speed limiter" scripts use sleep() to pause for a while after sending a chunk, resume, send another chunk, and pause again. But PHP will automatically terminate a script if it's been running for a minute or more. When that happens, your download stops.

You can use set_time_limit() to prevent your script from being terminated, but some web hosts will not allow you to do this. In that case you're out of luck.

PHP/Javascript: How I can limit the download speed?

Note: you can do this with PHP, but I would recommend you let the server itself handle throttling. The first part of this answer deals with what your options are if you want to cap the download speed with PHP alone, but below you'll find a couple of links where you'll find how to manage download limits using the server.

There is a PECL extension that makes this a rather trivial task, called pecl_http, which contains the function http_throttle. The docs contain a simple example of how to do this already. This extension also contains a HttpResponse class, which isn't well documented ATM, but I suspect playing around with its setThrottleDelay and setBufferSize methods should produce the desired result (throttle delay => 0.001, buffer size 20 == ~20Kb/sec). From the looks of things, this ought to work:

$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();

If you can't/don't want to install that, you can write a simple loop, though:

$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
}

Of course, don't buffer the output if you do this :), and it might be best to add a set_time_limit(0); statement, too. If the file is big, it's quite likely your script will get killed mid-way through the download, because it hits the max execution time.

Another (and probably preferable) approach would be to limit the download speed through the server configuration:

  • using NGINX
  • using Apache2
  • using MS IIS (either install the bitrate throttling module, or set the max bandwith)

I've never limited the download rates myself, but looking at the links, I think it's fair to say that nginx is the easiest by far:

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

This makes the rate limit kick in immediately, and sets it to 20k. Details can be found on the nginx wiki.

As far as apache is concerned, it's not that much harder, but it'll require you to enable the ratelimit module

LoadModule ratelimit_module modules/mod_ratelimit.so

Then, it's a simple matter of telling apache which files should be throttled:

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

Limiting download speed in PHP web frameworks

Your server should deal with this issue, not PHP.

In case you have Apache see here:

  • Apache Module mod_ratelimit
  • Webserver Bandwidth Limiting in Apache

For Lighttpd see here:

  • http://www.debianhelp.co.uk/ssllighttpd.htm
  • TrafficShaping

PHP Download file, limit max speed and calculate downloading speed

Limiting download speed is up to your webserver. PHP is too high level. It knows nothing of the outgoing data.

  • Apache: https://stackoverflow.com/a/13355834/247372
  • Nginx: http://www.nginxtips.com/how-to-limit-nginx-download-speed/

The same goes for measuring: the webserver will know and might tell you somehow. Logs, unix socket, after-the-fact, I don't know. Those links will know.

Throttling download speed in PHP

@set_time_limit(0); // don't abort if it takes to long
header("Content-type: application/force-download");
header("Content-Transfer-Encoding: Binary");
header("Content-length: ".filesize("uploads/".$filename));
header('Content-disposition: attachment; filename="'.$origname.'"');
$perSecond = 5; // 5 bytes per second

$file = fopen("uploads/".$filename, 'r');
while(!feof($file)) {
echo fread($file, $perSecond);
flush();
sleep(1);
}

This will send a file with throttled download speed to the user. It works basically like this:

  • Open a file
  • loop until we are at the end
  • echo X bytes
  • flush the output to the User
  • sleep for one second.

Make Speed Limit In download file by Xsendfile

X-Sendfile offloads the data transmission to the Linux kernel, which sends data from the file directly to the network. This avoids having to copy the data of the file into userspace memory, and therefore uses less CPU. As the data does not pass through any user space process, there's no way to throttle it manually.

You can limit the bandwidth with traffic shaping, but that's a system configuration question and therefore off-topic here. There are many questions on serverfault on this, e.g. https://serverfault.com/questions/174010/limit-network-bandwith-for-an-ip https://serverfault.com/questions/191560/how-can-i-do-traffic-shaping-in-linux-by-ip

As for file ranges, mod_xsendfile supposedly already takes care of that (see under "Benefits").



Related Topics



Leave a reply



Submit