Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Validating the File Upload [duplicate]

I'm a PHP beginner and currently learning the "Validating the File Upload" part.

I made a test.php page containing following code:

var_dump(@$_FILES['file']['type']);

First, I uploaded an image "img.gif" and it returned:

string 'image/gif' (length=9)

Then, I changed the image's extension to ".jpg" and it returned:

string 'image/jpeg' (length=10)

So I realized $_FILES["file"]["type"] only return the uploaded file extension but didn't actually check what file is it.

In this page, http://www.w3schools.com/php/php_file_upload.asp, there is a code:

$allowedExts = array("gif", "jpeg", "jpg", "png");
$extension = end(explode(".", $_FILES["file"]["name"]));
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 20000)
&& in_array($extension, $allowedExts))

I'm wondering why above codes check file extension twice? I deleted some from above codes and this is my new code:

$allowedExts = array("gif", "jpeg", "jpg", "png");
$extension = end(explode(".", $_FILES["file"]["name"]));
if (($_FILES["file"]["size"] < 20000) && in_array($extension, $allowedExts))

Is my code correct? Or do you have any better ways to validate the upload file is a image?

Thanks!

like image 861
nut Avatar asked Mar 24 '13 05:03

nut


2 Answers

You should pass the tmp_name of the file* to getimagesize, it will give you the size and type of the image (if it is an image). If the passed argument is a file but not an image it returns false, that will allow you to validate.

Edit: The only reliable method of image validation is to make a copy of it using GD or Imagick - getimagesize can be easily hacked.

*: I mean, the temporal file created after upload.

For example:

if ($_SERVER['REQUEST_METHOD'] === 'POST')
{
    $file = $_FILES['file']['tmp_name'];
    if (file_exists($file))
    {
        $imagesizedata = getimagesize($file);
        if ($imagesizedata === FALSE)
        {
            //not image
        }
        else
        {
            //image
            //use $imagesizedata to get extra info
        }
    }
    else
    {
        //not file
    }
}

This code uses file_exists just to be general. In case no file were uploaded you would get $_FILES['file']['size'] = 0, $_FILES['file']['tmp_name'] = '' and $_FILES['file']['error'] = 4. See also is_readable. For the error values see file upload errors explained at php.net.

like image 99
Theraot Avatar answered Nov 17 '22 15:11

Theraot


$allowedExts = array("gif", "jpeg", "jpg", "png");
$extension = end(explode(".", $_FILES["file"]["name"]));
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 20000)
&& in_array($extension, $allowedExts))

This is checked twice because, the extension of the file and 'file type' can be differ, so someone can not upload executable file with .png extension.

In your modified code, it is possible to upload a different type of file with modified extension. like they can upload word document with '.png' extension.

Your new code is just checking extension and don't have double check.

like image 38
Maulik Vora Avatar answered Nov 17 '22 15:11

Maulik Vora