Speed Limiting File Downloads

4.24 (83)

Creating a download script

It is common to have downloads on your website, and sometimes you want to moderate your downloads by speed, or possibly hide the directory that the download is coming from, protecting all your other files. This is very possible and very simple to solve in PHP. All you need is the header() function and some files function.

The header() function


The header() function is a predefined function in PHP which allows us to send raw HTTP headers to the browser. HTTP headers are what controls almost everything the browser will do when it receives information from your website. The general format of header() is:

void header ( string string [, bool replace [, int http_response_code]])


This indicates to us that the string called string is required and the other parameters are not. The string parameter is the actual raw header that you are going to send to the browser and this is the most important parameter. We won't deal with the other ones, however, replace will cause this new header to overwrite any similar headers, and http_response_code will force the response code to a certain value, i.e. 404 for error pages.

An important feature in the use of header() is that it must come before any text has been outputted to the screen. Hence, this is not valid:

Invalid Header
<html>
<body>
404  Not Found<br>
The page you requested, could not be found.
<?php
header
('HTTP/1.0 404 Not Found');
?>
</body>
</html>


This will definitely cause an error in your script if you tried to run it. Instead, we must do something like the following:

Valid Header
<?php
header
('HTTP/1.0 404 Not Found');
?>
<html>
<body>
404  Not Found<br>
The page you requested, could not be found.
</body>
</html>


This example script, would output the 404 error code to indicate a page not found.


The download script


What we are now going to do, is create a PHP file, which first will output the correct HTTP headers to indicate to the browser that we are doing a download. Then we are going to open the file that you want to be available to download, and we are going to send it to the output.

Whilst we are sending it to the output, we are going to moderate how much gets sent each time, therefore limiting the download speed. This is particularly useful if you have a high bandwidth site, and you must limit the speed of downloads to give a fair usage.

So, first we define our file location, name and speed parameters:

<?php

$fileName 
'myFiles.zip';
$fileLocation '/home/domain.com/httpdocs/hiddenDownloads/';

/* In kB/s */
$speed 10;
?>


Nothing too special about the above script, except that we are limiting our download speed to 10 kB/s. That is 10 * 1024 bytes or 10 * 1024 * 8 bits. We then send our special headers:

Download Headers
<?php
header
("Cache-control: private");
header('Content-Description: File Transfer'); 
header('Content-Type: application/force-download'); 
header('Content-Length: ' filesize($fileLocation $fileName)); 
header('Content-Disposition: attachment; filename=' $fileName);
?>


The header Cache-control tells the browser not to look for the file in cache that we are sending to be downloaded. Content-Description is just a text description of what we are doing. We could set this value to anything we wanted. Content-Type is set to application/force-download, this tells the browser that we are sending a file, which must be downloaded, it cannot be displayed in the browser. This prevents images such as .gif and .jpg from being displayed in the browser, but being forced to download them. Finally, the last two headers just specify the size of the download and the name of the download.

Next up, we read the file, and send it to the output:

Read the file
<?php
if (!$file fopen($fileLocation $fileName'r')) {
    exit;
}

while (!
feof($file)) {
    echo 
fread($file$speed 1024 8);
    
flush();
    
sleep(1);
}

@
fclose($file);
?>


That shouldn't be too complicated to understand. First the file is opened in read-only mode, and if that fails, we exit the script to try and prevent any download from beginning. We then run a while loop until the end of the file (eof) is found. Inside this while-loop, we read in a block of data using fread(). This takes the file handle we are accessing and the amount of data to read in bits. Hence, we must multiply our speed by 1024 * 8 to get it into bits.

Next comes the two important steps into speed limiting. First we use flush() which will send all the contents of the buffer to the webpage immediately. Usually, the whole page is parsed, and then the contents are sent, but using flush() we can send the contents as soon as they are ready. Next we use sleep(1) which completely pauses the execution of the script for 1 second each loop. This is what produces are download speed per second.

Finally, we just close the file and we're done. In a normal situation, we would gather the file name and location from a database so that this can become a generic file downloader, however, that is out of the scope of this article.

Full Code
<?php

$fileName 
'myFiles.zip';
$fileLocation '/home/domain.com/httpdocs/hiddenDownloads/';

/* In kB/s */
$speed 10;

header("Cache-control: private");
header('Content-Description: File Transfer'); 
header('Content-Type: application/force-download'); 
header('Content-Length: ' filesize($fileLocation $fileName)); 
header('Content-Disposition: attachment; filename=' $fileName);

if (!
$file fopen($fileLocation $fileName'r')) {
    exit;
}

while (!
feof($file)) {
    echo 
fread($file$speed 1024 8);
    
flush();
    
sleep(1);
}

@
fclose($file);
?>


NOTE: If you find your script is timing out, add set_time_limit(0); to the top of your code to let the script run indefinitely.
Rate this article: BAD 1 2 3 4 5   GOOD
Page 1 of 1

Build Your Own Database Driven Website Using PHP & MySQL

  • Installation instructions for Windows, Linux and Mac OS X
  • Instantly apply working code examples from the book to your Website
  • Build a working Content Management System from scratch
  • Master MySQL database administration
  • Fully updated for PHP 5

       Download FREESample Chapters Now!

Ads

PHPNerds Newsletter