How do you check the file type in PHP and secure file uploads? It is important to validate MIME types in PHP, especially of files uploaded through an upload form on your website. Using PHP, the best way to validate MIME types is with the PHP extension Fileinfo. Any other method might not be as good or secure as you might think...
Never trust a file extension to tell you what an uploaded file is. getimagesize() only works for images, so use the Fileinfo functions (finfo_open() and finfo_file() with FILEINFO_MIME_TYPE) to check the real MIME type of the uploaded temporary file against a list of types you allow.
I originally wrote this post in 2014, in the PHP 5 era. The ereg() and eregi() functions in the first example were removed in PHP 7.0. The Fileinfo approach at the end of this post is still the way to go.
PHP file input validation, the old^Wwrong way
It is quite common to only look at the file extension to determine what type of file it is (I was hoping to say "years and years ago", but unfortunately I still see this on a regular basis...). An image always has an extension like .jpg, .jpeg, .png or .gif, right? And a Portable Document Format is the only file type to use .pdf as extension. Oh, we were wrong!
To validate a file's extension, we used something along the lines of:
if(eregi("\.jpg|\.jpeg|\.gif|\.png|\.bmp", $_FILES['userfile']['name']) != FALSE) {
// do stuff
// some more ...
}
Whether this example uses ereg, eregi or preg_match doesn't matter. Seeing an extension like jpg, jpeg, gif, png or bmp made sure these are only images, right? Not!
Some of us might have expanded the validation of PHP uploaded files with an extra check.
PHP file validation, a better way to validate MIME types, but only for images
A better way to validate MIME types in PHP is:
$imageInfo = getimagesize( $_FILES['userfile']['tmp_name'] );
if ($imageInfo['mime'] == ("image/png") ||
$imageInfo['mime'] == ("image/jpeg") ||
$imageInfo['mime'] == ("image/gif") ||
$imageInfo['mime'] == ("image/psd") ||
$imageInfo['mime'] == ("image/bmp")) {
// an image type we accept
}
This check uses a PHP image function called getimagesize(). It determines the size of an image file and returns its dimensions together with the file type, including the corresponding MIME type. So this only works on images, and fails on other file types. PHP's own documentation even warns not to use getimagesize() to check that a given file is a valid image.
Therefore a lot of developers use (hopefully used to use?) mime_content_type(). Well, that function got deprecated in favor of the PECL extension Fileinfo. And in its turn, the PECL extension Fileinfo was deprecated in favor of the PHP extension Fileinfo. Can you still follow?
So it is best to use the PHP extension Fileinfo, because it works for file types other than images too.
PHP Fileinfo extension: validate MIME types and secure file uploads in PHP
To properly validate MIME types in PHP, in order to provide some sort of file upload security, you need to use the PHP Fileinfo functions. These can validate Office MIME types and others.
An example PHP function to validate Office and PDF MIME types is:
<?php
function check_doc_mime( $tmpname ) {
// MIME types: https://filext.com/faq/office_mime_types.html
$finfo = finfo_open( FILEINFO_MIME_TYPE );
$mtype = finfo_file( $finfo, $tmpname );
finfo_close( $finfo );
if( $mtype == ( "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ) ||
$mtype == ( "application/vnd.ms-excel" ) ||
$mtype == ( "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) ||
$mtype == ( "application/vnd.ms-powerpoint" ) ||
$mtype == ( "application/vnd.openxmlformats-officedocument.presentationml.presentation" ) ||
$mtype == ( "application/pdf" ) ) {
return TRUE;
}
else {
return FALSE;
}
}
if( function_exists( "check_doc_mime" ) ) {
if ( !check_doc_mime( $_FILES['userfile']['tmp_name'] ) ) {
/*
* Not a MIME type we want uploaded to our site, stop here
* and return an error message, or just die();
*/
} else {
/*
* a MIME type we support is uploaded. Continue with our
* upload script
*/
}
}
?>
This function can be used to verify the MIME type of files uploaded through HTTP $_POST. Proper user input validation is important for your website security!
Validating uploads is one layer. Also make sure uploaded scripts can't be executed: disallow direct access to PHP files in wp-content/uploads/, and use .htaccess as a Web Application Firewall.