How to properly validate an uploaded image file using php

Updated: 21-Mar-2023 / Tags: PHP Tutorials / Views: 2614 - Author: George

Introduction

Hi guys.

In this post i m going to show you how to be sure, that the uploaded file is an image. We are going to properly validate an uploaded image using php. The code that we are going to write can easily used in a live project. So let's start.

Quick answer

To be sure that a user is uploading an image file and not a malicious script file that will mess with our server, or worse, follow these steps.

  1. Use the finfo php object. With the finfo object we can check the file type of a given file.
  2. Change the name of the image with a random alphanumeric string.
  3. Set a max-upload-size limit, and check the size of the image.
  4. Check if the new random image name exists in the folder, or in the database if you use one. It's high unlikely, but i feel more secure.

Now let's see how easy it is to do it.

Project's folder

Let's create the files that we need.

  • We need an index.php file to structure our form element.
  • And an functions.php file to write the image validation function.
  • Also we have an uploads/ folder in our project to save the files.

    Now that we have set-up the project's structure lets start coding.

The index file

In the index.php file we are going to have our form element. But we are going to start the file with a block of php code.

<?php require "functions.php" ?>
<?php 
	if(isset($_POST['image-upload'])){
		$response = image_validation($_FILES);
	}
?>	
  • In the first line we require the functions.php file, so we have access to the validation function that we are gonna write there.
  • Next in line 3 we are checking if the form is submitted. If this is true, we are going to call the image_validation() function and we are going to pass-in as an argument the superglobal $_FILES variable. We are going to store whatever message the function returns in the $response variable.
  • The image_validation() function doesn't exist. We are going to write the function after we complete the index.php file and the upload form.

The html page

Next and under the php code we are going to have a basic html page structure.

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	 <link rel="stylesheet" href="styles.css">
	<title>How to be sure that the uploaded file is an image</title>
</head>
<body>
	<!-- The upload form goes here -->
</body>
</html>	

The upload form

Next inside the body tags we are going to write our upload form.

	<form action="" method="post" enctype="multipart/form-data">
		<h2>Image upload</h2>
		<p class="info">
			Allowed image types are: [ <strong>jpg, png, gif</strong> ]
		</p>
		<p class="info">
			Allowed max-filesize is: [ <strong>2MB</strong> ] 
		</p>

		<label>Please select an image file</label>
		<input type="file" name="image">
		
		<button type="submit" name="image-upload">Upload</button>
	
		<?php 
			if(@$response == "success"){
				?>
					<p class="success">Your image file passed the validation test</p>
				<?php
			}else{
				?>
					<p class="error"><?php echo @$response ?></p>		
				<?php
			}
		?>
	</form>
  • In line 20 we have the input file button. The name attribute is set to "image". We are going to use the name attribute later on in the functions.php file to get the uploaded image. You will see when we get there.
  • In line 22 we have the submit button. The name attribute is set to "image-upload". If you go to the top of the page we check in the POST request if there is an "image-upload" key, ( $_POST['image-upload'] ). This is how we check if the form is submitted.
  • In line 24 we have a php block that checks the value that the $response variable holds. If the image_validation() function, ( that we are going to write ), returns the string success, we display a success message, else we display whatever message, (error), the function returns.
  • That is al the html code that we need. Now let's go to the functions.php file to write the image_validation() function.

The functions php file

In the functions.php file we are going to write the image_validation() function.

The image_validation function

<?php
function image_validation($image){
	$image_name = $image['image']['name'];
	$image_size = $image['image']['size'];
	$image_temp = $image['image']['tmp_name'];
	$image_type = $image['image']['type'];

	if(empty($image_name)){
		return "Please select a file";
	}

	$finfo = new finfo(FILEINFO_MIME_TYPE);
	$file_type = $finfo->file($image_temp);

	$allowed_image_types = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'];
	if(!in_array($file_type, $allowed_image_types) ){
		return "Your choosen file is not a valid image type";
	}

	$upload_max_size = 2 * 1024 * 1024; // 2MB
	if($image_size > $upload_max_size){
		return "Image must not be larger than 2MB";
	}

	$str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcefghijklmnopqrstuvwxyz";
	$length = 10;
	$shuffled_str = str_shuffle($str);
	$new_name = substr($shuffled_str, 0, $length);

	$extension = pathinfo($image_name, PATHINFO_EXTENSION);	
	$image_name = $new_name.".".$extension;
	
	$images = glob("uploads/*.*");
	if(in_array("uploads/".$image_name, $images)){
		return "Image already exists in the folder";
	}

	$move_file = move_uploaded_file($image_temp, "uploads/".$image_name);
	if($move_file == false){
		return "File not saved. Please try again";
	}
	return "success";
}

Let's break down the above code.

In line 3 we define our function.

<?php
function image_validation($image){
  • We use the variable $image as a parameter. The $image variable is holding the $_FILES superglobal variable.
    Remember that the function runs in the index file, and we pass-in, as an argument the $_FILES variable.

Next we are going to store in variables the uploaded image's properties.

	$image_name = $image['image']['name'];
	$image_size = $image['image']['size'];
	$image_temp = $image['image']['tmp_name'];
	$image_type = $image['image']['type'];
  • You see that we use the $image variable to access the file's properties ( $image['image']['name'] ), and not the superglobal $_FILES['image']['name'].

Next we are going to check the $image_name variable. If it is empty we return a message that says "Please select a file". We are going to see this error if someone presses the submit button without selecting a file first.

	if(empty($image_name)){
		return "Please select a file";
	}

Next we are going to check if the file is a real image, and not something else like a pdf, or text file, or some malicious script file that someone has changed the file-extension to look like an image.

	$finfo = new finfo(FILEINFO_MIME_TYPE);
	$file_type = $finfo->file($image_temp);

	$allowed_image_types = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'];
	if(!in_array($file_type, $allowed_image_types) ){
		return "Your chosen file is not a valid image type";
	}
  • To check if a file is an image we are going to use the finfo php object.
    With the finfo object we can check the file type of a given file. So in line 13 we create a new finfo object and we use the FILEINFO_MIME_TYPE flag. This tells the object to return the mime type of the file.
  • The finfo object has a method called file(), which takes the path to the file as a parameter, and returns the file's mime type like image/gif or image/png etc.
  • So in line 13 we call the file() method, and we pass in as an argument the filepath to the temporary location of the uploaded file and we store the mime type to the $file_tpe variable.

    Every time we upload a file, php stores the file in a temporary location, and we move the file from there to a folder that we specify.

  • Next in line 15 we create an array that contains the mime types that we allow to upload.
  • And in line 16 we check if the uploaded file type is NOT included in the $allowed_image_types array.
    If this is the case we return the message "Your chosen file is not a valid image type".

Next we check the file's size.
If it is greater than 2MB we return that message "Image must not be larger than 2MB".

	$upload_max_size = 2 * 1024 * 1024; // 2MB
	if($image_size > $upload_max_size){
		return "Image must not be larger than 2MB";
	}	

Next we will rename the image's name. This way we will be sure that no malicious code is hidden in the image's name.

	$str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcefghijklmnopqrstuvwxyz";
	$length = 10;
	$shuffled_str = str_shuffle($str);
	$new_name = substr($shuffled_str, 0, $length);	
  • In line 25 we have a string that contains the digits from 0 to 9, and the English alphabet in lower and upper case.
  • In line 26 we set the length of the new name.
  • In line 27 we shuffle the string so we get a new string in a random order.
  • And in line 28 we take the first 10 characters out of the randomized string.
  • Now the $new_name variable holds a 10 character long random string.

Next we are going to take the extension of the uploaded file, and add it to the new name.

	$extension = pathinfo($image_name, PATHINFO_EXTENSION);	
	$image_name = $new_name.".".$extension;	
  • Now the image name is complete, and looks something like this, "1hyug3vt4D.png".

Next, and as rare as it is to get the same random string twice, just to be sure we will check in the uploads/ folder if the image name exists.

	$images = glob("uploads/*.*");
	if(in_array("uploads/".$image_name, $images)){
		return "An error occurred. Please try again";
	}
  • In this rare occasion that the image name already exists in the folder, we display an error that says, "An error occurred. Please try again", so the user will upload the same image and assign a new random name.

And last we move the uploaded file from its temporary location to the uploads/ folder.

	$move_file = move_uploaded_file($image_temp, "uploads/".$image_name);
	if($move_file == false){
		return "File not saved. Please try again";
	}
	return "success";
  • If something goes wrong, we display an error that says, "File not saved. Please try again".
    Else we return the string "success".
  • And that's it, we completed the image validation function.

Summary

That is how we validate an uploaded image file. I hope you liked it, and everything was understandable.

Last Words

Thanks for reading, i hope you find the article helpful.
Please leave a comment if you find any errors, so i can update the page with the correct code.

Source code

You can download the source code and use it in any way you like.

Times downloaded: 133

Buy me a coffee

If you like to say thanks, you can buy me a coffee.

Buy me a coffee with paypal

Comment section

You can leave a comment, it will help me a lot.

Or you can just say hi. 😉