mrpatg
mrpatg

Reputation: 10117

Check picture file type and size before file upload in php

I have the following code:

$filecheck = basename($_FILES['imagefile']['name']);
  $ext = substr($filecheck, strrpos($filecheck, '.') + 1);
  if (($ext == "jpg" || $ext == "gif" || $ext == "png") && ($_FILES["imagefile"]["type"] == "image/jpeg" || $_FILES["imagefile"]["type"] == "image/gif" || $_FILES["imagefile"]["type"] == "image/png") && 
    ($_FILES["imagefile"]["size"] < 2120000)){
} else {
echo "F2";
die();
}

What i need to do is check if the uploaded file is a jpg/gif/png and that its less than 2 megs in size.

If its larger than 2 megs, or not the right file type, i need to return/echo F2 (error code for api).

When i use the code above to process a 70k jpg file, it returns F2.

SUBNOTE the picture im uploading has an extension of .JPG. Could case be a factor? If so, how do i accommodate for that?

Upvotes: 5

Views: 37840

Answers (7)

mauris
mauris

Reputation: 43619

take note that for Internet Explorer, they submit JPEG file's mime type as image/pjpeg - which is different from other browsers.

Here's a simple function to get your mime type against the file extension:

function mime2ext($mime){ // mime is like image/jpeg
    $m = explode('/',$mime);
    $mime = $m[count($m)-1]; // get the second part of the mime type
    switch($mime){
        case 'jpg':
        case 'jpeg':
        case 'pjpeg':
            return 'jpg';
            break;
        case 'png':
            return 'png';
            break;
        case 'gif':
            return 'gif';
            break;
    }
    return '';
}

Upvotes: 3

grimman
grimman

Reputation: 170

File size is fairly obvious, but what people are doing above to check that it's the right format is somewhat inefficient, and "unsafe".

Here's what I do:

if($_FILES["userPicture"]["error"] == 0) {
// File was uploaded ok, so it's ok to proceed with the filetype check.
    $uploaded_type = exif_imagetype($_FILES["userPicture"]["tmp_name"]);
    // What we have now is a number representing our file type.

    switch($uploaded_type) {
        case "1":
            $uploaded_type = "gif";
        break;
        case "2":
            $uploaded_type = "jpg";
        break;
        case "3":
            $uploaded_type = "png";
        break;
    }
}

More info at;
http://www.php.net/manual/en/function.exif-imagetype.php

Edit: This has the advantage of working "in every browser" because it doesn't rely on the filename, or anything user supplied, except the files array value "error" which tells us there wasn't really an error.

Upvotes: 3

Andrew Moore
Andrew Moore

Reputation: 95474

Note that you might not want to rely on file extensions to determine file type. It would be rather easy for someone to upload an executable file with a .png extension for example. A mime-type can also easily be forged by a malicious client to pass as an image. Relying on that information is a security risk.

PHP Documentation:
The mime type of the file, if the browser provided this information. An example would be "image/gif". This mime type is however not checked on the PHP side and therefore don't take its value for granted.

Try loading the images with gd (getimagesize()) to make sure they are actually valid images (and not just random files pretended with the header of an image file... finfo_file relies on those headers).

if($_FILES["imagefile"]["size"] >= 2120000) {
  echo "F2";
  die();
} else {
    $imageData = @getimagesize($_FILES["imagefile"]["tmp_name"]);

    if($imageData === FALSE || !($imageData[2] == IMAGETYPE_GIF || $imageData[2] == IMAGETYPE_JPEG || $imageData[2] == IMAGETYPE_PNG)) {
      echo "F2";
      die();
    }
}

If you really must use the extension to verify if the file is an image, use strtolower() to put the extension into lowercase.

$filecheck = basename($_FILES['imagefile']['name']);
$ext = strtolower(substr($filecheck, strrpos($filecheck, '.') + 1));

if (!(($ext == "jpg" || $ext == "gif" || $ext == "png") && ($_FILES["imagefile"]["type"] == "image/jpeg" || $_FILES["imagefile"]["type"] == "image/gif" || $_FILES["imagefile"]["type"] == "image/png") && 
    ($_FILES["imagefile"]["size"] < 2120000))){
    echo "F2";
    die();
}

Upvotes: 23

Pascal MARTIN
Pascal MARTIN

Reputation: 401182

The comparisons like $ext == "jpg" only check that the $ext is exactly "jpg".

You might want to use strtolower on $ext before doing those comparisons, to deal with the ".JPG" situation.


If you are using PHP <= 5.2, you might want to use mime_content_type to check the content-type of the files, instead of relying on $_FILES['imagefile']['name'] and/or $_FILES["imagefile"]["type"], which are both sent by the client -- and can, as such, be faked.

If you are using PHP >= 5.3, you might want to consider the new extension fileinfo, and it's finfo_file function


For the size of the file, you are already using $_FILES["imagefile"]["size"] ; that's OK, I guess, but you will only know it when the file has been uploaded -- still, there is no real way of checking that kind of thing before upload, I'm afraid...


you might be able to find some JS code to do a first pre-check of extension before the file is uploaded -- but you'll still have to check on the server side, as anything done client-side is inherently not secure.

Not sure you could do the same about the file's size, though...

Some browsers might support a hidden field called MAX_FILE_SIZE (see the documentation about file upload) ; but not sure it is really supported (never seen it used, actually ; so probably isn't :-( )


As a sidenote, you will probably want to configure upload_max_filesize, so it allows upload at least as big as what you want (by default, it is generally set to 2MB ; so should already be OK for you)

Upvotes: 5

Scharrels
Scharrels

Reputation: 3065

You need two things:

Make your extension check case insensitive:

if($strtolower($ext == "jpg")){
  // do your stuff
}

Check if the file actually contains an image. An easy way to do this is fileinfo:

$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo, $filename);
$finfo_close($finfo);

An alternative way of checking if a file is really an image is loading in an image library like gd. If your file can successfully be loaded, it is an image.

Keep in mind that jpeg images can have either the .jpg or the .jpeg extension.

Upvotes: 2

Ahmet Kakıcı
Ahmet Kakıcı

Reputation: 6404

Php is a server side scripting language and if the pictures are at client side, you can't check their size via php before upload.

Upvotes: 2

Mark
Mark

Reputation: 6228

SUBNOTE the picture im uploading has an extension of .JPG. Could case be a factor? If so, how do i accommodate for that?

Yes, that is the problem. You should be add strtolower() to this line:

$ext = substr($filecheck, strrpos($filecheck, '.') + 1);

like:

$ext = strtolower(substr($filecheck, strrpos($filecheck, '.') + 1));

That will fix your currently issue. But technically, you shouldn't worry about file extensions, you should really only need to check the MIME type

Upvotes: 5

Related Questions