One of the features of a dynamic website is being able to upload an image to the server. The most common and probably the best way is to upload the image to our server's directory and then insert the filename in our database.
In this tutorial, we will implement an image uploading feature using HTML, Bootstrap, PHP, and MySQL. For styling the HTML, you can use CSS instead of Bootstrap. The feature that we will create can detect if the image is a true image. Furthermore, the feature will create a unique filename but still keep the original filename.
-
Create the neccessary files
Before we proceed to our code, let's create the following files: index.php, upload_image.php, isImageValid.php, database.php, and a folder named images.
The index.php is the file that contains our upload form; the upload_image.php is where the upload form will be sent; the isImageValid.php contains functions that will determine if the image is valid or not; the database.php is where our database configurations are; and lastly, the images folder is where our uploaded images will be.
-
Create the upload form
Type the following code in index.php.
<?php require_once 'upload_image.php'; ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> <title>Upload Image file with PHP and MySQL</title> </head> <body class="bg-body-secondary"> <div class="container mt-3"> <?php echo $message; ?> <form class="card p-3" method="post" enctype="multipart/form-data"> <label for="image" class="fw-medium ps-1">Image</label> <input class="form-control" type="file" name="image" id="image" accept="image/jpeg, image/png, image/gif"> <input class="btn btn-primary mt-3" type="submit" name="upload" value="Upload"> </form> </div> </body> </html>
To have an upload file button that can access the files, we need an input element with the type attribute set to file inside our form. In addition, to limit the file format that users can upload, we need to set the accept attribute to image/jpeg, image/png, image/gif. However, this is just used to help users choose a file; we still need to validate on the server.
To be able to send the file to the server, we need two things in our form element. First, we need to set our method attribute to post. Then, we need to have the enctype attribute set to multipart/form-data.
In our above code, we echo the $message variable, which is supposedly created in our upload_image.php, so if you run the code, there might be a warning, but don't worry; it will go away once we get to the upload_image.php section.
-
Create Database image_upload and Table image
Run the following SQL code either on phpMyAdmin in SQL tab, or on the MySQL Command Line Client.
CREATE DATABASE image_upload; use image_upload; CREATE TABLE image ( image_id int(11) NOT NULL AUTO_INCREMENT, original_filename varchar(255) NOT NULL, current_filename varchar(30) NOT NULL, PRIMARY KEY (image_id), UNIQUE (current_filename) );
In our image table, we have image_id, original_filename, and current_filename fields. The original_filename is the filename the user uploaded, while the current_filename is the filename we will generate to create a unique filename.
-
Connect the Database
Type the following code in database.php.
<?php $host = 'localhost'; $dbname = 'image_upload'; $user = 'root'; $password = ''; $database = new PDO("mysql:host={$host};dbname={$dbname}", $user, $password);
-
Create isImageValid() function
Type the following code in isImageValid.php.
<?php function isImageValid($filename) { $type = exif_imagetype($filename); switch($type) { case 1: return imagecreatefromgif($filename) ? '.gif' : false; case 2: return imagecreatefromjpeg($filename) ? '.jpeg' : false; case 3: return imagecreatefrompng($filename) ? '.png' : false; default: return false; } }
TheĀ isImageValid() function verifies that the uploaded imageĀ is a legitimate image and not a malicious script. Additionally, it will confirm that the image's filetype is one of the three that we exclusively accept: .gif, .jpg/.jpeg, and .png. It returns the image extension on success; otherwise, it is false.
The function works by first finding out the filetype of an image using exif_imagetype(), then re-creating the image based on the filetype with specific functions such as imagecreatefromgif() for .gif, imagecreatefromjpeg() for .jpg/.jpeg, and imagecreatefrompng() for .png.
In order to support more image file types, first go to the exif_imagetype page to learn all of its return values and the image types they represent. Then, go to the GD Manual page to discover additional imagecreatefrom* functions.
-
Create the upload_image script
Type the following code in upload_image.php.
<?php require_once 'isImageValid.php'; require_once 'database.php'; $message = ''; if(!empty($_POST['upload'])) { uploadImage(); } function uploadImage() { global $message, $database; //validate the image $imageExtension = validateImage(); if(!$imageExtension) { return; } //create a unique filename. do { $filename = uniqid('',true) . $imageExtension; $filepath = "images/{$filename}"; clearstatcache(); } while(file_exists($filepath)); //upload the file. if(!move_uploaded_file($_FILES['image']['tmp_name'], $filepath)) { $message = "<div class='alert alert-danger'>Upload error. Please try again!</div>"; return; } //insert the filename in database. $statement = $database->prepare("INSERT INTO image (original_filename, current_filename) VALUES (:original_filename, :current_filename)"); $statement->bindParam(':original_filename', $_FILES['image']['name']); $statement->bindParam(':current_filename', $filename); if(!$statement->execute()) { $message = "<div class='alert alert-danger'>Upload error. Please try again!</div>"; } $message = "<div class='alert alert-success'>Image Successfully uploaded.</div>"; } function validateImage() { global $message; if(!is_uploaded_file($_FILES['image']['tmp_name'])) { $message = "<div class='alert alert-danger'>Please upload an image</div>"; return false; } $imageExtension = isImageValid($_FILES['image']['tmp_name']); if(!$imageExtension) { $message = "<div class='alert alert-danger'>Upload only a .jpeg, .png, or .gif file</div>"; return false; } if(filesize($_FILES['image']['tmp_name']) > 2097152) { $message = "<div class='alert alert-danger'>File size must not exceed 2MB.</div>"; return false; } return $imageExtension; }
In the code above, we created two functions: validateImage() and uploadImage().
The validateImage() function determines if the user uploaded a file via HTTP POST by using the is_uploaded_file() function, then checks if the user uploaded a valid image by using the function isImageValid() that we created earlier, and finally checks if the size of the image is no more than 2 MB by using the function filesize(). If the image is valid, it will return the image extension, otherwise; it will return false.
The uploadImage() function, on the other hand, validates the image using the function validateImage(), which we created in the same file, then creates a unique filename by using the function uniqid(). Since the uniqid() won't guarantee that it is really unique, we made a loop that will check if the filename already exists using the function file_exists(). In addition, I also called the function clearstatcache() because the file_exists() function cached the results. After that, we upload the file using the move_uploaded_file() function, and lastly, we insert the original filename and the current filename in the database.
Another thing about making the filename more unique using the uniqid() function is that we could replace the first parameter with something like a username or email. In that way, two users won't ever produce the same filename.
Summary
In our HTML part, we have learned how to create an upload button and how to make the form be able to send a file. In addition, we also learned how to filter the file types that users will upload.
In our PHP scripts, we have learned several functions that will determine if the user uploaded a file via HTTP POST, the image type of the file, and the size of the uploaded file. In addition, we have learned how to know if an image is a real image by recreating it. We also learned how to generate a unique filename and make sure that it doesn't exist in our image folder yet. Finally, we have learned how to upload the file and insert the filename in the database.