kreoton web development

More secure PHP image upload class tutorial

In the internet are many php image upload tutorials, but most of them are not so secure. In this tutorial i try to teach you how to write not very complex but secure image upload class. First of all we should define class ant it variables:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class image_upload
{
	var $tmp_image;
	var $max_file_size = 100000;
	var $max_width = 800;
	var $max_height = 600;
	var $allow_types = array(
'image/jpeg', 
'image/png', 
'image/gif'
);
var $errors;
}
?>

For variables $max_file_size, $max_width, $max_height and $allow_types I assigned default values. There are two more variables its $errors for error printing and $tmp_image for $_FILES[’xxxx’] global variable.

Now then we have defined class and variables we can make some standard functions for image upload class. First we need to know if given file is really image so we use function exif_imagetype() witch reads firs file bytes and returns true if file is image else it returns false. (Note: exif_imagetype() function will work only if module exif is installed in server.)

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
function is_image ()
{
	if (exif_imagetype($this->tmp_image['tmp_name']))
	{
		$this->errors[] = 'Uploaded file is not image';
		return true;
	}
	else
	{
		return false;
	}
}

To check uploaded image type (mime type) i use next function. It searches for uploaded image type in $allow_types types array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function is_type ()
{
	if (in_array($this->tmp_image['type'], 
$this->allow_types))
	{
		return true;
	}
	else
	{
		$this->errors[] = 'Image type is 
not acceptable';
		return false;
	}
}

Next I check if image is suitable size:

1
2
3
4
5
6
7
8
9
10
11
12
function is_size ()
{
	if ($this->tmp_image['type'] <= $this->max_file_size)
	{
		return true;
	}
	else
	{
		$this->errors[] = 'Image file size is too big';
		return false;
	}
}

To check image dimensions I call getimagesize() function it returns array with image parameters.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function is_dimensions ()
{
	$size = getimagesize($this->tmp_image['tmp_name']);
	$width = $size[0];
	$height = $size[1];
	if ($width <= $this->max_width && 
$height <= $this->max_height)
	{
		return true;
	}
	else
	{
		$this->errors[] = 'Image is too height 
or too width';
		return false;
	}
}

Finally I wrote image upload function it has two parameters $dest – upload destination and $safe for safe image upload witch by default is false.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function upload_image ($dest, $safe=false)
{
	if ($safe)
	{
		$status = true;
 
		$status = $this->is_image();
		$status = $this->is_type();
		$status = $this->is_size();
		$status = $this->is_dimensions();
 
		return ($status)?move_uploaded_file(
$this->tmp_image['tmp_name'], $dest)
:false;
	}
	else
	{
		return move_uploaded_file(
$this->tmp_image['tmp_name'], $dest);
	}
}

Now class is ready for use. For class test I wrote a simle script.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
 
include('upload.class.php');
 
$IM = new image_upload();
 
if ($_FILES['photo'])
{
	$IM->tmp_image = $_FILES['photo'];
 
	if ($IM->upload_image($_SERVER['DOCUMENT_ROOT'].
'/tnimg/'.$IM->tmp_image['name'], true))
	{
		echo 'Image uploaded';
	}
	else
	{
		foreach ($IM->errors as $error)
		{
			echo $error.'<br />';
		}
	}
}
 
?>
<form method="post" enctype="multipart/form-data" action="">
	<label for="photo">Photo file</label>
	<input type="file" name="photo" />
	<input type="submit" name="submit" value="Upload" />
</form>

23 Responses to “More secure PHP image upload class tutorial”


  1. […] More secure php image upload class This tutorial shows how to make secure image upload class. Class is very flexible and easy to use. […]


  2. It’s a very good explained code about uploading pictures and useful.

    Congritulations


  3. Hey.

    First off, thanks for this tutorial.

    Im having a problem though, Im getting a fatal error of the below sort:

    Fatal error: Call to undefined method image_upload::upload_image()

    at this line of code:
    if ($IM->upload_image($_SERVER[’DOCUMENT_ROOT’].
    ‘/tnimg/’.$IM->tmp_image[’name’], true))\

    Any ideas?

    Thanks


  4. It looks like you forgot to add function to class. Please check you class file.


  5. This is great! thanks!
    I had the same problem above (Call to undefined method). The } in the first code chunk with ‘class image_uplo….’ should come after the list of functions.

    Also, don’t forget to set the permissions of the upload directory to ‘write’.


  6. This is exactly what I expected to find out after reading the title More secure PHP image upload class tutorial. Thanks for informative article


  7. It’s really simple and useful, with a clear explanation, congratulations for that. I tried this code but i had some problems (i had to put vars after the functions code and it worked) and i’d only add 2 opinions:

    in the code where you test the $status, it would be this way..?:


    $status = $this->is_image();
    $status = $status && $this->is_type();
    $status = $status && $this->is_size();
    $status = $status && $this->is_dimensions();

    $status then would give us the information about if the image has passed ok all tests, not only the last one.

    And another question.. if you try to put an image with embedded code (like php) it would pass the tests or not? i don’t know if the image_type test would be enough, or we’d need another test for avoiding php, jsp and these type of extensions..?

    thanks for all, and good job!


  8. Great tutorial, however I have found an error in the image file size check.

    Line 3 of this function reads:

    if ($this->tmp_image[’type’] max_file_size)

    This line should read:

    if ($this->tmp_image[’size’] max_file_size)


  9. Kaffeemaschine kaufen…

    I think this is pretty interesting idea but i have to wait for the results…


  10. I have to say, that I could not agree with you in 100% regarding More secure PHP image upload class tutorial, but it’s just my opinion, which could be wrong :)


  11. Thank you for this grate tutorial. I am at the begining with PHP and Web Programing and this helped me a lot. However, I get one ore.

    “Fatal error: Call to undefined function exif_imagetype() in C:\wamp\www\Image Upload Class\imageUploadClass.php on line 23″

    I toke a look in the PHP documentation and exif_imagetype() is there, no instalation required (right?). I am useing PHP 5.. Any suggestions ?


  12. Yes exif module does not need any specific installiation, however it should be enabled.

    i see that you are using wamp server on Windows platform, so try open php.ini in notepad and enable both php_mbstring.dll and php_exif.dll. Note that php_mbstring.dll should be loaded before php_exif.dll


  13. I tryed to enable it but I am not realy keen on changeing the php.ini. However I found another solution. I used the value from position 2 from getimagesize() instead of exif_imagetype. It works! (I think..).
    Anyway, I wanted to mention this just in case some1 else has the same problem as me.
    Keep up the good work.


  14. This is the most appropriate solution so far i have found. Most helpful. Thanks for the help :).


  15. Affiliate Marketing Tips…

    I couldn’t understand some parts of this article, but it sounds interesting…


  16. $status = $this->is_image();
    if($status)
    $status = $this->is_type();
    if($status)
    $status = $this->is_size();
    if($status)
    $status = $this->is_dimensions();


  17. Hi,
    I haven’t tested the code yet, but after running through it I believe the following code in the is_image() function to be incorrect…

    if (exif_imagetype($this->tmp_image[’tmp_name’])){
    $this->errors[] = ‘Uploaded file is not image’;
    return true;

    Surely the error text should be in the ‘false’ part of the IF statement?

    I guess the author left these mistakes in to make sure we are paying attention!

    David Kirkbride


  18. I just did some severe scouring of the internet in search of solid image uploader, and it seems as though I have hit the holy grail. Thanks so much for the tutorial!!!

    A quick note to people implementing it. I didn’t know what the exif_imagetype function was, so I looked it up at php.net, and lo and behold, I saw this comment posted THIS VERY morning (God’s timing is impeccable) regarding some quirkiness in the exif_imagetype function. Thought it might help some other people that want ROCK SOLID code:

    By trial and error, it seems that a file has to be 12 bytes or larger in order to avoid a “Read error!”. Here’s a work-around to avoid an error being thrown:

    // exif_imagetype throws “Read error!” if file is too small
    if (filesize($uploadfile) > 11)
    $mimetype = exif_imagetype($uploadfile);
    else
    $mimetype = false;

    PS: I haven’t tested this yet, but wanted to post the comment anyway in likes that it is probably true.


  19. The PHP Image Upload Script you have available to download appears to have a major bug within it, if possible email me and I will discuss it further.


  20. $_SERVER[’DOCUMENT_ROOT’].’/tnimg/’.$IM->tmp_image[’name’]

    flaw: ‘name’ is user input
    example: tmp_image[’name’] = ‘../../../../etc/file’
    solution: use basename()

    Suggestions:
    - finfo_file for file type validation (fileinfo extension)
    - just getimagesize (reads header) for “all” images types
    - pay attention to damn magic quotes in file names


  21. i have a problem with exif in function exif…exif is enable.
    more example to use exif?

    thx


  22. I have a doubt in the above code.

    What if the names are same? I mean say we upload a file named \


  23. To treat user uploaded image files (gif/jpg/png only) I do as below:

    - get basename.
    - determine type using exif_imagetype().
    - if result is neither IMAGETYPE_GIF nor IMAGETYPE_JPEG nor IMAGETYPE_PNG, discard file.
    - give my own name to file with correct extension (see above).
    - it\’s now safe to store within a public folder where browsers can access them as images.

    I have also read suggestions to chmod the stored files to prevent execution, but I\’m not sure how it improves security as properly named gif/jpg/png files won\’t get executed. Also I believe the files are 644 by default.

Leave a Reply

This is a captcha-picture. It is used to prevent mass-access by robots. (see: www.captcha.net)

You must read and type the 5 chars within 0..9 and A..F, and submit the form.

  

Oh no, I cannot read this. Please, generate a