What is the best way to determine whether or not a file is an image in PHP?
I have a sever which people can upload files to. The problem is that some of the filenames are mangled (dont have any extension) and so I cannot immediately determine file type. This question is two part: for the files which do have filenames what is the best way to determine whether or not it is an image? (Just a big long if/else if list?) Secondly, for the files which dont have extensions, how can I determine if they are images?
12 Answers 12
- IMAGETYPE_GIF
- IMAGETYPE_JPEG
- IMAGETYPE_PNG
- IMAGETYPE_SWF
- IMAGETYPE_PSD
- IMAGETYPE_BMP
- IMAGETYPE_TIFF_II (intel byte order)
- IMAGETYPE_TIFF_MM (motorola byte order)
- IMAGETYPE_JPC
- IMAGETYPE_JP2
- IMAGETYPE_JPX
- IMAGETYPE_JB2
- IMAGETYPE_SWC
- IMAGETYPE_IFF
- IMAGETYPE_WBMP
- IMAGETYPE_XBM
- IMAGETYPE_ICO
When a correct signature is found, the appropriate constant value will be returned otherwise the return value is FALSE. The return value is the same value that getimagesize() returns in index 2 but exif_imagetype() is much faster.
You can use getimagesize It does not require the GD image library and it returns same information about image type. http://it2.php.net/manual/en/function.getimagesize.php
@chacham — It’s not an error, it’s only a warning. The function returns false if the file is invalid, one should check with getimagesize($filename) === false .
Which method requires GD? According to this link, exif_imagetype does not require GD, but it requires that PHP is compiled using —enable-exif.
If you have the GD2 extension enabled, you could just use that to load the file as an image, then if it returns invalid you can catch the error and return FALSE, otherwise return TRUE.
You have two options here, one’s simple and pre-built with some shortfalls, the other is complex and requires math.
PHP’s fileinfo can be used to detect file types based on the file’s actual header information. For instance, I just grabbed your gravitar:
But the actual code is this:
‰PNG IHDR szzô IDATX…—OL\UÆZÀhëT)¡ c•1T:1‘Š‘.Ú(]4†A“ÒEY˜à.
So, even without the file name I could detect it quite obviously. This is what the PHP Fileinfo extension will do. Most PNG and JPG files tend to have this header in them, but this is not so for every single file type.
That being said, fileinfo is dead simple to use, from the manual:
$fi = new finfo(FILEINFO_MIME,'/usr/share/file/magic'); $mime_type = $fi->buffer(file_get_contents($file));
Your other option is more complex and it depends on your own personal ambitions, you could generate a histogram and profile files based on their content.
Something like this looks like a GIF file:
And something like this looks like a TIFF file:
From there you’d need to generate a model over multiple types of files for what the histogram of each type should be, and then use that to guess. This is a good method to use for files that don’t really have those «magic headers» that can be read easily. Keep in mind, you’ll need to learn some math and how to model an average histogram function and match them against files.
Detecting image type from base64 string in PHP
Is it possible to find out the type of an image encoded as a base64 String in PHP? I have no method of accessing the original image file, just the encoded string. From what I’ve seen, imagecreatefromstring() can create an image resource from a string representation (after it’s been decoded from base64), but it automatically detects the image type and the image resource itself is a special PHP representation. In case I want to save the image as a file again, I would have no idea if the type I am saving it as corresponds to the original type from which the String representation was created.
8 Answers 8
$encoded_string = ". "; $imgdata = base64_decode($encoded_string); $f = finfo_open(); $mime_type = finfo_buffer($f, $imgdata, FILEINFO_MIME_TYPE);
Yeah, but I’m not sure what engine getimagesize uses to pick out the magic numbers. FileInfo depends on the external system mime database and can handle any file type. GIS could be using some hardcoded magic numbers and only look for those specifically.
@MarcB I’m fairly sure getimagesize is hard-coded. It gets a lot of additional information from the headers.
If you dont want to use these functions because of their dependencies you can use the first bytes of the data:
function getBytesFromHexString($hexdata) < for($count = 0; $count < strlen($hexdata); $count+=2) $bytes[] = chr(hexdec(substr($hexdata, $count, 2))); return implode($bytes); >function getImageMimeType($imagedata) < $imagemimetypes = array( "jpeg" =>"FFD8", "png" => "89504E470D0A1A0A", "gif" => "474946", "bmp" => "424D", "tiff" => "4949", "tiff" => "4D4D" ); foreach ($imagemimetypes as $mime => $hexbytes) < $bytes = getBytesFromHexString($hexbytes); if (substr($imagedata, 0, strlen($bytes)) == $bytes) return $mime; >return NULL; > $encoded_string = ". "; $imgdata = base64_decode($encoded_string); $mimetype = getImageMimeType($imgdata);
thankyou it works. For some who uses codeigniter don’t forget to add $this-> in every called functions.
The solution given by @Marc B is the best one for me (if our php version is > 5.3.0 otherwise we can use the solution given by @Aaron Murgatroyd).
I would like to give a little addition to this solution.
To get the image type you can do it like this :
$split = explode( '/', $mime_type ); $type = $split[1];
In fact, (if you don’t know it) the mime type for images is : image/type and type can be png or gif or jpeg or .
Hope that can help someone and thanks to @Marc B for his solution.
For an exhaustive list of mime type you can look here :
Code below will get the image type from its mime type.
The way shown by @Marc B is the nicest.
Should FInfo not be available, the only other way I know is to store the data into a file, and run a getimagesize() on it.
If you know a minimal amount about the file format structure, you could theoretically look at the top bytes of the file until you could work out what type of file it is.
For example, a GIF image always starts with the following bytes GIF89a . If you can find that string at the begining of the file, you can be reasonably sure that it is a GIF image and absolutely certain it isn’t any other image format. (it could still be a text file though, that just happens to start with ‘GIF89a’; you’d have to parse more of the file to be absolutely certain)
Likewise, PNG files have the string PNG fairly near the start (it’s not quite at the very begining; again, you’d need to research the file format specifics to help you determine how much you’d need to know to be certain).
JPEGs also contain recognisable strings in their headers, although these are more varied and complex. You might want to look out for the string Exif .
Getting the file format definitions would definitely give you more accuracy, but depending on how accurate you need to be, you might learn enough about the files formats just by opening some image files in a binary editor to see how they’re structured.
These resources may help you:
Validate that a file is a picture in PHP
If a file is uploaded to the server, is there a way using PHP, to make sure that it’s actually a picture and not just a file with a .jpg or .gif extension?
5 Answers 5
Using (part) of the GD library.
array getimagesize ( string $filename [, array &$imageinfo ] )
The first element of the array will be 0 if there is no image. PHP: getimagesize
If you don’t have GD installed (most of the time you will), you can read the file header as Shane mentioned.
EDIT: Actually, as Neal pointed out in the comments, the GD library is not even required to use this function. So use it.
@Neal — Actually, I didn’t! I had no idea. Thanks for pointing that out. Answer has been edited. Not the first time I’ve been RTFM’d
best way to check if file is an image
function is_image($path) < $a = getimagesize($path); $image_type = $a[2]; if(in_array($image_type , array(IMAGETYPE_GIF , IMAGETYPE_JPEG ,IMAGETYPE_PNG , IMAGETYPE_BMP))) < return true; >return false; >
The most efficient way would be to look at the beginning bytes of the file and test for ‘magic number’ file specifier. Here is a list of magic numbers.
That would be the more efficient than firing up GD, but I think with the binary opens, etc.. is a bit over the head of most people.
I don’t.. but I’ve been writing code since I was 7. Surprisingly, many people can get degrees without actually knowing what they’re supposed to. I speak from experience, because I do actually have a degree in civil engineering, and I knew a lot of «sliders» that just slid by. A degree doesn’t mean anything. Proof that you can do something does.
Oh and I believe that a large number of the users of this site do not have CS degrees. Most people end up here from Google who are trying to learn something about the language they are learning.
Agreed — I saw that for myself. However — it is still disappointing to think of people with programming jobs (as I assume many of these do) and that binary opens are over their head.
Header check is not enough for checking the validity of an image file. PHP Documentation clearly expresses that you shouldn’t use getimagesize to check that a given file is a valid image. See https://www.php.net/manual/en/function.getimagesize.php
I use the following function to validate a image file:
/** * Returns TRUE if $path is a valid Image File * * @param string $path * @return bool */ public static function isImage(string $path) < if (!is_readable($path)) < return false; >// see https://www.php.net/manual/en/function.exif-imagetype.php for Constants // adjust this array to your needs $supported = [IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG]; $type = exif_imagetype($path); // $type can be valid, but not "supported" if (!in_array($type, $supported)) < return false; >// check the image content, header check is not enough $image = false; switch ($type) < case IMAGETYPE_GIF: $image = @imagecreatefromgif($path); break; case IMAGETYPE_PNG: $image = @imagecreatefrompng($path); break; case IMAGETYPE_JPEG: $image = @imagecreatefromjpeg($path); break; >return (!!$image); >
How to check uploaded file type in PHP
but some users complain they get an error while uploading any type of images, while some others don’t get any errors! I was wondering if this fixes the problem: if (mime_content_type($_FILES[‘fupload’][‘type’]) == «image/gif»)<. Any comments?
9 Answers 9
Never use $_FILES..[‘type’] . The information contained in it is not verified at all, it’s a user-defined value. Test the type yourself. For images, exif_imagetype is usually a good choice:
$allowedTypes = array(IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF); $detectedType = exif_imagetype($_FILES['fupload']['tmp_name']); $error = !in_array($detectedType, $allowedTypes);
Alternatively, the finfo functions are great, if your server supports them.
I think this extensions are not enabled on my shared host : extension=php_mbstring.dll extension=php_exif.dll
@assensi You might want to read up on what the different fields in $_FILES mean: php.net/manual/en/features.file-upload.post-method.php. tmp_name is correct.
In addition to @deceze, you may also finfo() to check the MIME-type of non-image-files:
$finfo = new finfo(); $fileMimeType = $finfo->file($path . $filename, FILEINFO_MIME_TYPE);
Sure you could check if it’s an image with exif, but a better way I think is to do with finfo like this:
$allowed_types = array ( 'application/pdf', 'image/jpeg', 'image/png' ); $fileInfo = finfo_open(FILEINFO_MIME_TYPE); $detected_type = finfo_file( $fileInfo, $_FILES['datei']['tmp_name'] ); if ( !in_array($detected_type, $allowed_types) ) < die ( 'Please upload a pdf or an image ' ); >finfo_close( $fileInfo );
The best way in my opinion is first to use getimagesize() followed by imagecreatefromstring().
$size = getimagesize($filename); if ($size === false) < throw new Exception(": Invalid image."); > if ($size[0] > 2500 || $size[1] > 2500) < throw new Exception(": Image too large."); > if (!$img = @imagecreatefromstring(file_get_contents($filename))) < throw new Exception(": Invalid image content."); >
Checking by getimagesize() prevents some DoS attacks, because we don’t have to try to imagecreatefromstring() from every file provided by the user, either non-image file or file too big. Unfortunately, according to PHP docs cannot be relied on for checking image type content.
The imagecreatefromstring() finally tries to open the file as an image — if is succeeds — we have an image.