- PHP File Upload
- Configure The «php.ini» File
- Create The HTML Form
- Create The Upload File PHP Script
- Check if File Already Exists
- Limit File Size
- Limit File Type
- Complete Upload File PHP Script
- Complete PHP Filesystem Reference
- How To Upload An Image With PHP
- Setting Up An Image Upload Form
- Handling the PHP Image Upload
- Securing The Image Upload Process
- Making Sure The File Is An Image
- Limiting The File Size
- Guarding Against Malicious File Names
- Preventing Code Execution In The Images Directory
- Conclusion
PHP File Upload
However, with ease comes danger, so always be careful when allowing file uploads!
Configure The «php.ini» File
First, ensure that PHP is configured to allow file uploads.
In your «php.ini» file, search for the file_uploads directive, and set it to On:
Create The HTML Form
Next, create an HTML form that allow users to choose the image file they want to upload:
Some rules to follow for the HTML form above:
- Make sure that the form uses method=»post»
- The form also needs the following attribute: enctype=»multipart/form-data». It specifies which content-type to use when submitting the form
Without the requirements above, the file upload will not work.
- The type=»file» attribute of the tag shows the input field as a file-select control, with a «Browse» button next to the input control
The form above sends data to a file called «upload.php», which we will create next.
Create The Upload File PHP Script
The «upload.php» file contains the code for uploading a file:
$target_dir = «uploads/»;
$target_file = $target_dir . basename($_FILES[«fileToUpload»][«name»]);
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
// Check if image file is a actual image or fake image
if(isset($_POST[«submit»])) $check = getimagesize($_FILES[«fileToUpload»][«tmp_name»]);
if($check !== false) echo «File is an image — » . $check[«mime»] . «.»;
$uploadOk = 1;
> else echo «File is not an image.»;
$uploadOk = 0;
>
>
?>?php
- $target_dir = «uploads/» — specifies the directory where the file is going to be placed
- $target_file specifies the path of the file to be uploaded
- $uploadOk=1 is not used yet (will be used later)
- $imageFileType holds the file extension of the file (in lower case)
- Next, check if the image file is an actual image or a fake image
Note: You will need to create a new directory called «uploads» in the directory where «upload.php» file resides. The uploaded files will be saved there.
Check if File Already Exists
Now we can add some restrictions.
First, we will check if the file already exists in the «uploads» folder. If it does, an error message is displayed, and $uploadOk is set to 0:
// Check if file already exists
if (file_exists($target_file)) echo «Sorry, file already exists.»;
$uploadOk = 0;
>
Limit File Size
The file input field in our HTML form above is named «fileToUpload».
Now, we want to check the size of the file. If the file is larger than 500KB, an error message is displayed, and $uploadOk is set to 0:
// Check file size
if ($_FILES[«fileToUpload»][«size»] > 500000) echo «Sorry, your file is too large.»;
$uploadOk = 0;
>
Limit File Type
The code below only allows users to upload JPG, JPEG, PNG, and GIF files. All other file types gives an error message before setting $uploadOk to 0:
Complete Upload File PHP Script
The complete «upload.php» file now looks like this:
$target_dir = «uploads/»;
$target_file = $target_dir . basename($_FILES[«fileToUpload»][«name»]);
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
?php
// Check if image file is a actual image or fake image
if(isset($_POST[«submit»])) $check = getimagesize($_FILES[«fileToUpload»][«tmp_name»]);
if($check !== false) echo «File is an image — » . $check[«mime»] . «.»;
$uploadOk = 1;
> else echo «File is not an image.»;
$uploadOk = 0;
>
>
// Check if file already exists
if (file_exists($target_file)) echo «Sorry, file already exists.»;
$uploadOk = 0;
>
// Check file size
if ($_FILES[«fileToUpload»][«size»] > 500000) echo «Sorry, your file is too large.»;
$uploadOk = 0;
>
// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) echo «Sorry, your file was not uploaded.»;
// if everything is ok, try to upload file
> else if (move_uploaded_file($_FILES[«fileToUpload»][«tmp_name»], $target_file)) echo «The file «. htmlspecialchars( basename( $_FILES[«fileToUpload»][«name»])). » has been uploaded.»;
> else echo «Sorry, there was an error uploading your file.»;
>
>
?>
Complete PHP Filesystem Reference
For a complete reference of filesystem functions, go to our complete PHP Filesystem Reference.
How To Upload An Image With PHP
In this quick tutorial we set up a basic HTML form to upload images with PHP, we also explore how to secure our PHP script so it can’t be abused by malicious users.
Setting Up An Image Upload Form
We start with a basic form.
The form contains a submit button and has an action attribute. The action attribute points to the page the form will post all its contents to when the submit button is clicked.
form action="upload.php" method="POST"> button type="submit">Uploadbutton> form>
The form posts to a PHP file called upload.php . This file will handle the image upload. We’ll get to that in a minute.
To allow users to select a file we add a file input field.
form action="upload.php" method="POST" enctype="multipart/form-data"> input type="file" name="image" accept="image/*" /> button type="submit">Uploadbutton> form>
At the same time we’ve also added the enctype form attribute and set it to «multipart/form-data» . This is needed if we have a file input field in our form.
Because we’re only uploading images we add the accept attribute to the file input element and set it to image/* telling it to only accept files that have a mimetype that starts with image , like image/jpeg or image/png .
Let’s write the PHP image upload handler next.
Handling the PHP Image Upload
We’ll create a new file called upload.php in the same directory as the page that contains our form.
Next we create a directory called «images» , also in the same directory. This is where our script will store uploaded image files using the move_uploaded_file function.
// Get reference to uploaded image $image_file = $_FILES["image"]; // Image not defined, let's exit if (!isset($image_file)) die('No file uploaded.'); > // Move the temp image file to the images/ directory move_uploaded_file( // Temp image location $image_file["tmp_name"], // New image location, __DIR__ is the location of the current PHP file __DIR__ . "/images/" . $image_file["name"] );
We’re done. This is all that’s needed to make it work.
Unfortunately not everyone on the internet is a saint. Our script currently allows anyone to upload anything, this is a security risk. We need to make sure people upload valid images and are not trying to harm our server.
Securing The Image Upload Process
We’re going to make extra sure these three things are in order.
- The file needs to be an image.
- The file must be smaller than 5MB.
- The file must have a valid name.
Making Sure The File Is An Image
Let’s start by making sure the uploaded file is indeed an image.
Using exif_imagetype we can get the image mimetype, the function returns false when the file is not an image.
// Get reference to uploaded image $image_file = $_FILES["image"]; // Exit if no file uploaded if (!isset($image_file)) die('No file uploaded.'); > // Exit if is not a valid image file $image_type = exif_imagetype($image_file["tmp_name"]); if (!$image_type) die('Uploaded file is not an image.'); > // Move the temp image file to the images/ directory move_uploaded_file( // Temp image location $image_file["tmp_name"], // New image location __DIR__ . "/images/" . $image_file["name"] );
Next we need to stop users from uploading very large files.
Limiting The File Size
In the example below we limit the image file size to 5MB, of course you can choose your own limit, but it’s a good idea to at least cap it at a certain point to prevent users from uploading gigabytes of data in an attempt to DoS attack your server.
In the directory of our upload.php script we create a .htaccess file and set its contents to the following.
The LimitRequestBody prevents a request from exceeding 5MB, note that this includes other fields in the form.
Now let’s make sure users can’t uploading 0 byte files. We use filesize to read out the actual file size instead of rely on the [«size»] reported by $_FILES as that can be modified by the user.
// Get reference to uploaded image $image_file = $_FILES["image"]; // Exit if no file uploaded if (!isset($image_file)) die('No file uploaded.'); > // Exit if image file is zero bytes if (filesize($image_file["tmp_name"]) 0) die('Uploaded file has no contents.'); > // Exit if is not a valid image file $image_type = exif_imagetype($image_file["tmp_name"]); if (!$image_type) die('Uploaded file is not an image.'); > // Move the temp image file to the images/ directory move_uploaded_file( // Temp image location $image_file["tmp_name"], // New image location __DIR__ . "/images/" . $image_file["name"] );
Let’s now make sure the file name of the image is valid.
Guarding Against Malicious File Names
Malicious actors can try to upload an image with named ‘../index.php’ , our PHP script would now store this “image” in ‘images/../index.php’ possibly overwriting our own index.php file.
We can try to sanitize the image file name, but a safer approach is to generate our own file name.
We’ll generate some random_bytes and use those as the name for our image.
// Get reference to uploaded image $image_file = $_FILES["image"]; // Exit if no file uploaded if (!isset($image_file)) die('No file uploaded.'); > // Exit if image file is zero bytes if (filesize($image_file["tmp_name"]) 0) die('Uploaded file has no contents.'); > // Exit if is not a valid image file $image_type = exif_imagetype($image_file["tmp_name"]); if (!$image_type) die('Uploaded file is not an image.'); > // Get file extension based on file type, to prepend a dot we pass true as the second parameter $image_extension = image_type_to_extension($image_type, true); // Create a unique image name $image_name = bin2hex(random_bytes(16)) . $image_extension; // Move the temp image file to the images directory move_uploaded_file( // Temp image location $image_file["tmp_name"], // New image location __DIR__ . "/images/" . $image_name );
Our last step is to prevent code from being executed in our images directory.
Preventing Code Execution In The Images Directory
In our images directory we create a .htaccess file and set its contents to the following to prevent any uploaded PHP files from being run.
This make sure that PHP code in this folder won’t execute. So if someone still manages to upload a PHP file, for example a PHP file disguised as an image, it still won’t run.
Our file upload process is now secure. 🎉
Conclusion
We’ve written a basic form with file input element, to handle the upload we created a PHP file that moves the uploaded image to a directory on the server. To secure the upload process, we made sure the filename is valid, the file size is not too high, and the uploaded file is actually an image.
If you’re also looking to add image editing functionality to the file upload field you can use the element. This Pintura powered web component automatically opens a powerful image editor when an image is added to the field and enables your users to edit images before upload.
I share web dev tips on Twitter, if you found this interesting and want to learn more, follow me there
At PQINA I design and build highly polished web components.
Make sure to check out FilePond a free file upload component, and Pintura an image editor that works on every device.