71

Is there a way to make sure a received file is an image in PHP?

Testing for the extension doesn't sound very secure to me as you could upload a script and change its extension to whatever you want.

I've tried to use getimagesize too, but there might be something more suited for that particular problem.

Vikalp Patel
  • 10,669
  • 6
  • 61
  • 96
sf89
  • 5,088
  • 7
  • 24
  • 27

3 Answers3

91

The getimagesize() should be the most definite way of working out whether the file is an image:

if(@is_array(getimagesize($mediapath))){
    $image = true;
} else {
    $image = false;
}

because this is a sample getimagesize() output:

Array (
[0] => 800
[1] => 450
[2] => 2
[3] => width="800" height="450"
[bits] => 8
[channels] => 3
[mime] => image/jpeg)
Tomas
  • 4,652
  • 6
  • 31
  • 37
George Mickleburgh
  • 1,181
  • 1
  • 6
  • 11
  • Yeah this was my gut feeling but I was looking for something that would be precisely suited to get the type of the file as you could trick this method. I've seen this done with Gifs (see here http://ha.ckers.org/blog/20070604/passing-malicious-php-through-getimagesize/). – sf89 Mar 14 '13 at 11:53
  • 23
    Since `getimagesize` returns false on failure, this can be pared down to `$image = getimagesize($mediapath) ? true : false;` – designosis Feb 24 '14 at 09:58
  • 1
    `if($array = getimagesize($mediapath)) { // true and use the $array if required }` – The Alpha Apr 01 '16 at 00:13
  • 1
    Thanks for solution. I think putting @ before is_array is not neccessary in this case. – Farid Movsumov Jul 15 '16 at 05:13
  • It will not work while uploading `swf` file instead of image. `swf` file will return `array`. – Kushal Suthar Sep 19 '16 at 08:48
  • 4
    `getimagesize()` is much slower. Better to use [exif_imagetype()](http://www.php.net/manual/en/function.exif-imagetype.php) – Elnoor Feb 13 '17 at 06:21
  • 36
    PHP official docs recommend against this https://secure.php.net/manual/en/function.getimagesize.php – Will Hua Jul 05 '17 at 00:46
  • @WilliamBingHua yeah, they do, but the warning was not there a few years back – rsz Jul 27 '17 at 09:07
  • 1
    `function fileIsImage($filepath){ return ( strpos(mime_content_type($filepath), 'image/') === 0 ); }` – jave.web Aug 08 '18 at 14:34
  • 1
    [Caution:](http://php.net/manual/function.getimagesize.php) **Do not use** `getimagesize()` to check that a given file is a valid image. –  Dec 02 '19 at 13:43
  • 1
    NOT WORK ON SVG! TESTED! – Pavel Kenarov Feb 05 '20 at 13:43
  • 1
    Do not use getimagesize() to check that a given file is a valid image. Use a purpose-built solution such as the Fileinfo extension instead. https://www.php.net/manual/en/function.finfo-file.php – 6opko Apr 04 '21 at 11:01
  • Whether using `getimagesize` or `finfo_file`, as @Sheen mentions, additional checks are necessary. See also: https://stackoverflow.com/questions/690108/how-to-prevent-every-malicious-file-upload-on-my-server-check-file-type, https://stackoverflow.com/questions/21525125/check-image-for-malicious-code-and-delete-it – ManInTheArena Feb 16 '22 at 20:21
35

Native way to get the mimetype:

For PHP < 5.3 use mime_content_type()
For PHP >= 5.3 use finfo_open() or mime_content_type()

Alternatives to get the MimeType are exif_imagetype and getimagesize, but these rely on having the appropriate libs installed. In addition, they will likely just return image mimetypes, instead of the whole list given in magic.mime.

While mime_content_type is available from PHP 4.3 and is part of the FileInfo extension (which is enabled by default since PHP 5.3, except for Windows platforms, where it must be enabled manually, for details see here).

If you don't want to bother about what is available on your system, just wrap all four functions into a proxy method that delegates the function call to whatever is available, e.g.

function getMimeType($filename)
{
    $mimetype = false;
    if(function_exists('finfo_open')) {
        // open with FileInfo
    } elseif(function_exists('getimagesize')) {
        // open with GD
    } elseif(function_exists('exif_imagetype')) {
       // open with EXIF
    } elseif(function_exists('mime_content_type')) {
       $mimetype = mime_content_type($filename);
    }
    return $mimetype;
}
clami219
  • 2,958
  • 1
  • 31
  • 45
Dead Man
  • 2,880
  • 23
  • 37
  • Unfortunately, this seems to have been deprecated. – sf89 Mar 14 '13 at 11:47
  • I just updated my answer. You can try this – Dead Man Mar 14 '13 at 11:54
  • Using exif_imagetype seems like what I was looking for. Thanks! – sf89 Mar 14 '13 at 12:03
  • 2
    `finfo_fopen`, `getimagesize`, `exif_imagetype`, `mime_content_type` are not fully secure.. i took an html code and save as png image.. after this i upload to server using filereader Api in client side and in server side using functions above write. – Phoenix Jun 06 '16 at 19:17
  • @Phoenix so there's is any better option to check whether the file is image file or not *before upload it* to server directory? thanks – Kamarul Anuar Jul 18 '17 at 16:50
  • 2
    `finfo_fopen()` should be `finfo_open()` - there is no `f` before `open`. "While `mime_content_type` is removed from PHP5.3" - I don't think it was ever "removed". It did appear to be (temporarily) deprecated, as many comments suggest, although there is no mention of this in the docs anymore. `mime_content_type()` is part of the [Fileinfo extension](http://php.net/manual/en/fileinfo.installation.php), which is enabled by default on PHP 5.3+ (except if you are on Windows, when you have to enable it) – MrWhite Jan 20 '18 at 01:46
  • 1
    Year 2018 PHP docs: `mime_content_type (PHP 4 >= 4.3.0, PHP 5, PHP 7)` , not any mark of "deprecated" or such... – jave.web Aug 08 '18 at 14:38
  • Year 2021 PHP docs `mime_content_type (PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)`, still no indication of "depreciated" notice. – Faizan Anwer Ali Rupani Aug 31 '21 at 11:01
13

Using file extension and getimagesize function to detect if uploaded file has right format is just the entry level check and it can simply bypass by uploading a file with true extension and some byte of an image header but wrong content.

for being secure and safe you may make thumbnail/resize (even with original image sizes) the uploaded picture and save this version instead the uploaded one. Also its possible to get uploaded file content and search it for special character like <?php to find the file is image or not.

Sheen
  • 155
  • 1
  • 3