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
How to Increment Count in the Replacement String When Using Preg_Replace
How to Run the Bind_Param() Statement in PHP
Is MySQLi_Multi_Query Asynchronous
PHP String Doesn't Allow < and > Characters
Replacing Invalid Utf-8 Characters by Question Marks, Mbstring.Substitute_Character Seems Ignored
Same Domain, Different Folder PHP Session
MySQL Group by and Fill Empty Rows
Group Duplicate Array Keys in a Multidimensional Array into Subarray
Remove First 4 Characters of a String with PHP
How to Check If a User Is Logged-In in PHP
Laravel Eloquent Orm Transactions
How to Execute PHP Code from the Command Line
Converting a Postman Request to Curl
How to Get the Function Name Inside a Function in PHP
Fatal Error: Call to Undefined Function Openssl_Random_Pseudo_Bytes()