< Back to Posts

The correct way to handle file downloads in PHP


I've seen many download scripts written in PHP, from simple one-liners to dedicated classes. At least half of them share common issues; in many cases programmers simply copy the code from something that works, without even attempting to understand what it really does. With my experience in developing a successful online video platform and writing many variations of download scripts for clients, I thought it would be notable to mention one that I come across time and time again...

Never accept paths as input

It's very tempting to write something like

readfile($_GET['file']);
                

but before you do, think about it, anyone could request any file on the server, even if it's outside the public html area. Guessing is not too difficult and in a few tries, an attacker could obtain configuration or password files.

You might think you're being extra clever by doing something like

$mypath = '/path-to-my-files-folder/' . $_GET['file'];
                

but an attacker can use relative paths to evade that eg "../../../some-file.txt".

What you must do - always - is sanitise the input. Accept only file names, like this:

$path_parts = pathinfo($_GET['file']);
$file_name = $path_parts['basename'];
$file_path = '/path-to-my-files-folder/' . $file_name;
                

And work only with the file name and add the path to it yourself.

Even better would be to accept only numeric IDs and get the file path and name from a database (or even a text file or key => value array if it's something that doesn't change often). Anything is better than blindly accepting requests.

If you need to restrict access to a file, you should generate encrypted, one-time IDs, so you can be sure a generated path can be used only once.

Oh, don't forget to restrict direct access to your downloads folder.

Please share, have fun coding!

Let's make something great together!

If you'd like to discuss your next project with us, please feel free to give us a call on 01827 781 311 or press the "Start My Project" button to get in touch for a quick quote.

Start My Project