Is there a way to check the filetype of a file uploaded using PHP?
You want PHP's Fileinfo functions, which are the PHP moral equivalent of the Unix 'file' command.
Be aware that typing a file is a murky area at best. Aim for whitelist ("this small set of types is okay") instead of blacklist ("no exes, no dlls, no ..."). Do not depend on file typing as your sole defense against malicious files.
Files have signatures or "magic numbers" embedded in them, usually near the beginning of the file. libmagic is a library which extracts a files signature and looks it up in a signature database.
This is the way Unix type systems determine file types i.e. if you save a text file without an extension on Linux it will still automatically open with a text editor.
Systems like Windows on the other hand only look at file extension. Opening a text file with no extension on Windows will result in a WTf-is-this popup window.
So there are merits in checking both the extension and the magic number since your website will likely have visitors with different operation systems.
There is no conception of file type. In computer world everything is a bunch of 0/1 and whether it is and image or a lot of random characters depends on how do you interpret your zeros and ones. File type (as an extension like .docx, .png) are just for the convenience of the user to be able to do an educated guess of what can it be and to open it with a proper tool. As with any guess, it can be wrong.
So instead of trying to play around with techniques like suggested fileinfo, if I were you, I would rather figure out what do I allow people to upload.
So if you allow people to upload images, use getimagesize and may be even check that the width height is in appropriate range (who knows may be someone will upload an image like 500.000 pixels width/height and your server will die while resizing it. Its a valid image, but still not what you want). May it make sense to resize every image and only serve resized formats and store somewhere untouchable originals.
If you decide that users can upload .mp3 files, take a look at something that can deal with these sort of files. Who knows may be there are already tested methods to check whether this is really mp3 file.
Regarding of what you decide, use something to mitigate possible problems (assuming that the person upload a file $file = $_FILES['file'])
:
- check for errors during upload
if (!$file['name'] || $file['error']){ return false; }
- check that this file really has the size accepted by you
if ($file['size'] > MaxPossible || $file['size'] < MinPossible){ return false; }
- rename the file (if I submit something like
../../../t.py.png
, it will be renamed touniquefilename.png
) - it is saved with the least possible permissions. Surely without no permissions to be executed. ( may be 640 or 660 )
- to be sure that there is no way to perform XSS, save and serve them from a separate domain.