Artemis | Blog | About & Contact

2020 / 05 / 25 - PHP: Bad Idea / Good Idea (raw)

File-type verification

When allowing users to upload files, it's important to make sure that it's the expected format(s).

There are lots of solutions on Internet, but some are just plain awful, bad practices, and only still around due to misconceptions and bad habits.

Bad idea: Using the extension to check a file's format

For everyone used to knowing that a .jpeg file is an image, .pptx file is a presentation file, and .html is a HTML file, here's a huge news: your computer doesn't give a fuck about the thing at the end of the file.

You can call your image thisisnotanimage.mp4 and it won't change the fact that it is an image.

What does that mean?

Well, simply that if you validate file type by checking the extension, and if someone want to upload, for example, a malicious PHP file, they can simply add an "accepted" extension.

You'd then receive a file named virus.php.png, and you'd gladly accept it!

Solutions based on file extension should simply be dropped.

Good idea: Using the mime-type to check a file's format

The first question to ask is "what does format means?".

Basically, if the file respects a certain structure, which is tied to a certain format specification, it is recognized to be of said format.

The current "best-practice" solution to check this "structure" is the "Mime-type" mechanism.

Basically, a Mime is a set of expected indexes and values for a given format.

For example, a very naïve way to check if an image is a PNG file is to check if the file is at least 4 bytes long, and to check if the first 4 bytes are of value %PNG.

A PNG file being expected to have this format, that means that any file following this format would be considered as a valid PNG file.

Note that it's a dumbed-down rule, to keep the example simple.

So, for PHP, how do you actually check a file's format?

You have several ways, the simplest being mime_content_type($filename);.

As an example, if the file you want to test is available at a path stored in $path, the following code would return the mime-type.

$mimetype = mime_content_type($path);
// The file is a PNG file, the mimetype is image/png