ANEXIA Development and Managed Hosting
SEP
21
2017

Limit Download-Speed with CodeIgniter and cURL

Written on September 21, 2017 by Manuel Wutte

Many websites, especially download portals, are known for limiting the speed with which files can be downloaded (sometimes to a very significant extent). The business model is generally based on the concept that you can only get the full download speed if you pay for it.
In this tutorial, I want to show you what’s behind this limitation, and the software tricks these providers are using. I’m also going to show you how to integrate an option to limit download speed into a CodeIgniter project here.

Download-Speed-Drosselung mit CodeIgniter

 

CURL AS THE CORE OF THE APPLICATION

When we talk about cURL, we are talking about a widely used command line application that is specifically designed to transfer data within computer networks. The advantage is in how easy it is to use, because the program library has been ported to essentially all operating systems. In addition, it also has a vast range of functions.

Unlike its older predecessor “wget”, cURL controls not only the downloading, but also the uploading of files. Numerous parameters provide a correspondingly large number of options, thereby covering nearly every scenario.

 

SETUP WITH CODEIGNITER

Now we’ve arrived at the essential part of this tutorial: the integration of speed limitation in a CodeIgniter project.

CodeIgniter Logo

 

STEP 1: BUILD THE BASIC SYSTEM

In order to start our project, we first have to establish a basis on which we can subsequently build. In order to do so, we need to download the latest version of the framework from the CodeIgniter homepage. In this case, this would be version 3.1.5.

Next copy all the files – ideally to the subfolder “ci-downloadspeed” – onto the webserver (e.g. XAMPP, LAMP, etc.), and open its root directory in your browser, e.g., http://localhost/ci-downloadspeed/. Once all of the requirements for the framework are met, you should then see the CodeIgniter welcome page.

In order to ensure that the speaking URLs can also be accessed correctly, create an .htaccess file with the following content:

All of the resources needed for the actual application (CSS and JS files) are created in the “assets” directory, and the sample download files will later be created in the “downloads” directory (information about this can be found in the “Conclusion” section).

Next, open /application/config/autoload.php (the autoloader configuration file) and then add the URL helper. This way, we will be able to use the base_url() function both in the frontend and this time, even within the application itself.

In /application/config/routes.php (the route configuration file), we then need to change the default controller from “welcome” to “home”, since we want our speed throttling application to be loaded by default later.

 

STEP 2: DEFINE THE BASIC LAYOUT

In order to do so, navigate to /application/controller and create a file named Home.php (case-sensitive!).
Next, we need to create the basic framework for our application in this file, which consists of two actions: one for the index page and one for the throttled file downloads. The latter will receive parameters for the type of download (in our example, the parameter will only distinguish between a small file and a large file), as well as parameters for the download speed itself (in KB/s).

In this case, the index action is very rudimentary, since it has no functionality on its own. It is only being used to display the main page of our application:

Now let’s look at the HTML layout in the linked view.

What we have created here is a basic layout with a navigation bar and a simple block of text with a heading.

Directly underneath it (where it currently still reads “Here will be…”) is the markup for our application: a speed meter, which we will configure based on the “HTML5 Canvas Speedometer”. In addition, there are two download buttons (one for a smaller file, and one for a larger file):

The linked bootstrap_flatly.min.css file is the free “Flatly” Bootstrap theme from Bootswatch.
This CSS theme is optional and can therefore be omitted if you prefer.

We will define a couple of basic styles in the style.css file:

The logic for the frontend of our application belongs in the linked app.js file.

This takes care of the graphical canvas rendering of the speed meter. We now expand this file to include our actual functions (important: it is essential that you write where “TODO: add listener…” is currently located within the “document.ready()” block!). There you will find, among other things, the central function used to set the selected download speed (“setSpeed()“) and a listener, which will react to the range input field. In due course, the listener will transfer the selected value into the speed meter, and will dynamically adjust our two download links.

Because the listener will dynamically adjust both download links, we didn’t set the link target for the two download buttons directly, but instead just set it via a data attribute using a placeholder for the actual speed. In this way, we can use the attribute as a template, and we can keep setting the link target dynamically. Initially, we set the download speed to 100 KB/s. This is the default setting that a user gets when they open our application.

 

STEP 3: INTEGRATING LIMITATION

To integrate speed limitation, we now need our download action, the structure of which we have already created.

In our example, we first check in this download action whether the large or the small sample file is being loaded. Once this check has been performed, we build the public URL (with domain or IP, depending on the configuration) and the internal URL (absolute path on the server). At the same time, we calculate our download speed by converting the KB/s into bytes/s (using a factor of 1000).

We subsequently define the PHP header for a file download. In order to do so, we simply use “application/octet-stream” as a “content type” so that the download is always forced and the browser doesn’t try to open or display the file itself. Moreover, information regarding the size of the file now (optionally) follows so that the browser is able to detect and display the progress of the download. The name of the file itself comes at the end.

The actual download then follows. We use cURL for this, and we set its parameters as follows:

These are essentially mostly standard parameters with two exceptions: CURLOPT_MAX_RECV_SPEED_LARGE and CURLOPT_WRITEFUNCTION.

The CURLOPT_MAX_RECV_SPEED_LARGE option allows us to determine the maximum download speed with which the cURL library reads the data. The task here is in bytes/s, which is the reason for our previous conversion. If the value “0” is specified, there is no throttling and the download is performed with no limits on the speed. The actual speed thus depends more on external factors such as the internet connection itself.

We indicate our own output handler using CURLOPT_WRITEFUNCTION so that the data being read by cURL can also be streamed directly to the user, and not loaded locally onto the server for minutes (or even hours, depending on the speed!) first, before it is delivered. This ensures that the content received is forwarded to the user 1:1 in real time.

To summarize, our download action now appears as follows:

 

CONCLUSION

Speed limitation for file downloads is quick and easy to implement using the cURL library. All that is necessary is to configure cURL correctly.

In our sample project, it is currently also possible to access downloads directly using their public URL. This is necessary for the internal download via cURL, since cURL is essentially functioning as a proxy here. In practice, however, the possibility of direct access should be prevented. Assuming that the server has a static IP address, it is possible to place an .htaccess in the “downloads” folder, for example, which would only allow the server to be accessed using the server IP address (alternatively, vHost-Config could also be used).

Here is an example of this kind of .htaccess file (in this case, 188.65.77.77 would be the IP of the server on which the application is running):

This would ensure that the application could access the public URL for the purposes of internal downloads, but that no other users would have access. It would also be possible to load the files from a remote server, and that the meta-information (such as file size) could be obtained from a database.

The two linked dummy download files could be obtained via the Anexia Network Map or alternatively, directly via these links, among other options: 100MB and 1GB (via the DATASIX datacenter).

We have been working with the CodeIgniter framework in this tutorial because it is very easy to understand and requires almost no training time. In principle, however, any framework could be used, for example Laravel or Zend.

 


facebooktwittergoogle_pluslinkedinmail