HTML CSS JavaScript jQuery PHP Python MySQL

Gallery System with PHP, MySQL and JS

Updated on by David Adams

Gallery System with PHP, MySQL and JS

In this tutorial we'll be creating a gallery system with PHP, MySQL, and JavaScript. We'll be able to upload, view, and delete images, information for our images will be stored in our MySQL database (description, title, etc).

1. Getting Started

There are a few steps we need to take before we create our gallery system with PHP, we need to set up our web server environment (if you haven't already) and make sure we have the required extensions enabled.

1.1. Requirements

  • If you haven't got a local web server setup you should download and install XAMPP.
  • The PDO extension needs to be enabled, it should be already if you have the latest PHP installed.

1.2. What You Will Learn in this Tutorial

  • Template System — Create a basic template system with PHP.
  • Upload Images — Upload images to the server using an HTML form and PHP.
  • MySQL Interaction — Insert image information into a MySQL database and retrieve results.
  • Delete Images — Delete image files from the server (PHP) and delete records from a MySQL database.
  • Image Popup with JS — Create a popup with JavaScript that will show an image with its title and description.
  • Gallery System Design — Design a gallery system with HTML5 and CSS3.

1.3. File Structure & Setup

We can now start our web server and create the files and folders we're going to use for our gallery system.

  • Open XAMPP Control Panel
  • Next to the Apache module click Start
  • Next to the MySQL module click Start
  • Navigate to XAMPPs installation folder (C:\xampp)
  • Open the htdocs folder
  • Create the following folders and files:

File Structure

\-- phpgallery
  |-- functions.php
  |-- index.php
  |-- upload.php
  |-- delete.php
  |-- style.css
  \-- images
   |-- abandoned-building.jpg
   |-- beach.jpg
   |-- city.jpg
   |-- mountain.jpg
   |-- road.jpg
   |-- stars.jpg

Each file/folder will contain the following:

  • functions.php — This file will contain all the functions we need for our app (template header, template footer, and database connection function).
  • index.php — We will be able to view all the images that we have uploaded, this is basically our home page.
  • upload.php — This file will be used to upload images and insert the image information into our MySQL database.
  • delete.php — This file will be used to delete an image from our server and image information from our MySQL database.
  • style.php — The stylesheet (CSS3) for our gallery system.
  • images — This directory will contain all our images that we upload, click the example images in the file structure box above to download them.

2. Creating the Database and setting-up Tables

For this part, you will need to access your MySQL database, either using phpMyAdmin (included with XAMPP) or your preferred MySQL database management application.

If you're using phpMyAdmin follow these instructions:

  • Navigate to http://localhost/phpmyadmin/
  • Click the Databases tab at the top
  • Under Create database, type in phpgallery in the text box
  • Select utf8_general_ci as the collation (UTF-8 is the default encoding in HTML5)
  • Click Create

This will create the database we're going to use, now we need to create the table and insert example images, instead of manually doing this we can simply execute the below SQL, just remember to select the phpgallery database first and click the SQL tab located at the top.

SQL Copy
CREATE TABLE IF NOT EXISTS `images` (
	`id` int(11) NOT NULL AUTO_INCREMENT,
	`title` text NOT NULL,
  	`description` text NOT NULL,
  	`path` text NOT NULL,
  	`uploaded_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
	PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

INSERT INTO `images` (`id`, `title`, `description`, `path`, `uploaded_date`) VALUES
(1, 'Abandoned Building', '', 'images/abandoned-building.jpg', '2019-07-16 20:09:26'),
(2, 'Beach', 'Hot summer day at the beach.', 'images/beach.jpg', '2019-07-16 20:10:05'),
(3, 'City', 'A view down at the city.', 'images/city.jpg', '2019-07-16 20:10:45'),
(4, 'Mountain', '', 'images/mountain.jpg', '2019-07-16 20:11:27'),
(5, 'Road', 'Going down the only road I''ve even known.', 'images/road.jpg', '2019-07-16 20:12:00'),
(6, 'Stars', 'A wonderful view of the night sky.', 'images/stars.jpg', '2019-07-16 20:12:39');

This will create the images table with the following columns:

  • id — The unique identitifier of the record.
  • title — The title of the image.
  • description — The description of the image.
  • path — The file path of the image.
  • uploaded_date — The date the image was uploaded.

Take note we have also inserted example images into the images table, to make sure they show on your gallery system correctly you need to download the images from the File Structure section and put them in the images directory.

The images table should look like the following on phpMyAdmin:

http://localhost/phpmyadmin/
MySQL Images Table

That's all we need to do for our MySQL database, feel free to close phpMyAdmin as we no longer need to use it.

3. Designing the Gallery System with CSS

If we want our web app to look more appealing we need to add some CSS, add the following CSS to style.css:

CSS Copy
* {
    box-sizing: border-box;
    font-family: -apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, ubuntu, cantarell, "fira sans", "droid sans", "helvetica neue", Arial, sans-serif;
    font-size: 16px;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
body {
    background-color: #FFFFFF;
    margin: 0;
}
.navtop {
    background-color: #3f69a8;
    height: 60px;
    width: 100%;
    border: 0;
}
.navtop div {
    display: flex;
    margin: 0 auto;
    width: 1000px;
    height: 100%;
}
.navtop div h1, .navtop div a {
    display: inline-flex;
    align-items: center;
}
.navtop div h1 {
    flex: 1;
    font-size: 24px;
    padding: 0;
    margin: 0;
    color: #ecf0f6;
    font-weight: normal;
}
.navtop div a {
    padding: 0 20px;
    text-decoration: none;
    color: #c5d2e5;
    font-weight: bold;
}
.navtop div a i {
    padding: 2px 8px 0 0;
}
.navtop div a:hover {
    color: #ecf0f6;
}
.content {
    width: 1000px;
    margin: 0 auto;
}
.content h2 {
    margin: 0;
    padding: 25px 0;
    font-size: 22px;
    border-bottom: 1px solid #ebebeb;
    color: #666666;
}
.image-popup {
    display: none;
    flex-flow: column;
    justify-content: center;
    align-items: center;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.8);
    z-index: 99999;
}
.image-popup .con {
    display: flex;
    flex-flow: column;
    background-color: #ffffff;
    padding: 25px;
    border-radius: 5px;
}
.image-popup .con h3 {
    margin: 0;
    font-size: 18px;
}
.image-popup .con .edit, .image-popup .con .trash {
    display: inline-flex;
    justify-content: center;
    align-self: flex-end;
    width: 40px;
    text-decoration: none;
    color: #FFFFFF;
    padding: 10px 12px;
    border-radius: 5px;
    margin-top: 10px;
}
.image-popup .con .trash {
    background-color: #b73737;
}
.image-popup .con .trash:hover {
    background-color: #a33131;
}
.image-popup .con .edit {
    background-color: #37afb7;
}
.image-popup .con .edit:hover {
    background-color: #319ca3;
}
.home .upload-image {
    display: inline-block;
    text-decoration: none;
    background-color: #38b673;
    font-weight: bold;
    font-size: 14px;
    border-radius: 5px;
    color: #FFFFFF;
    padding: 10px 15px;
    margin: 15px 0;
}
.home .upload-image:hover {
    background-color: #32a367;
}
.home .images {
    display: flex;
    flex-flow: wrap;
}
.home .images a {
    display: block;
    text-decoration: none;
    position: relative;
    overflow: hidden;
    width: 300px;
    height: 200px;
    margin: 0 20px 20px 0;
}
.home .images a:hover span {
    opacity: 1;
    transition: opacity 1s;
}
.home .images span {
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    position: absolute;
    opacity: 0;
    top: 0;
    left: 0;
    color: #fff;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.2);
    padding: 15px;
    transition: opacity 1s;
}
.upload form {
    padding: 15px 0;
    display: flex;
    flex-flow: column;
    width: 400px;
}
.upload form label {
    display: inline-flex;
    width: 100%;
    padding: 10px 0;
    margin-right: 25px;
}
.upload form input, .upload form textarea {
    padding: 10px;
    width: 100%;
    margin-right: 25px;
    margin-bottom: 15px;
    border: 1px solid #cccccc;
}
.upload form textarea {
    height: 200px;
}
.upload form input[type="submit"] {
    display: block;
    background-color: #38b673;
    border: 0;
    font-weight: bold;
    font-size: 14px;
    color: #FFFFFF;
    cursor: pointer;
    width: 200px;
    margin-top: 15px;
    border-radius: 5px;
}
.upload form input[type="submit"]:hover {
    background-color: #32a367;
}
.delete .yesno {
    display: flex;
}
.delete .yesno a {
    display: inline-block;
    text-decoration: none;
    background-color: #38b673;
    font-weight: bold;
    color: #FFFFFF;
    padding: 10px 15px;
    margin: 15px 10px 15px 0;
    border-radius: 5px;
}
.delete .yesno a:hover {
    background-color: #32a367;
}

This is the stylesheet we'll use for the gallery system, simple and clean design, feel free to customize it.

4. Creating the Functions File

The functions file will contain the template header and footer functions and the database connection function.

Edit functions.php and add:

PHP Copy
<?php
function pdo_connect_mysql() {
    // Update the details below with your MySQL details
    $DATABASE_HOST = 'localhost';
    $DATABASE_USER = 'root';
    $DATABASE_PASS = '';
    $DATABASE_NAME = 'phpgallery';
    try {
    	return new PDO('mysql:host=' . $DATABASE_HOST . ';dbname=' . $DATABASE_NAME . ';charset=utf8', $DATABASE_USER, $DATABASE_PASS);
    } catch (PDOException $exception) {
    	// If there is an error with the connection, stop the script and display the error.
    	die ('Failed to connect to database!');
    }
}

The above function will be used to connect to our MySQL database, just remember to update the database variables to your MySQL database details, if you don't it could result in a MySQL error.

Add after:

PHP Copy
// Template header, feel free to customize this
function template_header($title) {
echo <<<EOT
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>$title</title>
		<link href="style.css" rel="stylesheet" type="text/css">
		<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
	</head>
	<body>
    <nav class="navtop">
    	<div>
    		<h1>Gallery System</h1>
            <a href="index.php"><i class="fas fa-image"></i>Gallery</a>
    	</div>
    </nav>
EOT;
}

This is the header function we'll use for all the pages that we create, instead of writing the same code we can just call the above function, feel free to customize the header, we're using Font Awesome to display icons on our pages.

Add after:

PHP Copy
// Template footer
function template_footer() {
echo <<<EOT
    </body>
</html>
EOT;
}
?>

Just like the header function but instead this will be the footer function, this will just close the tags that are created in the header function.

5. Creating the Home Page

This page is our home page and will be the first page we see when we visit our gallery system, it will contain all the photos we have uploaded.

Edit index.php and add:

PHP Copy
<?php
include 'functions.php';
// Connect to MySQL
$pdo = pdo_connect_mysql();
// MySQL query that selects all the images
$stmt = $pdo->query('SELECT * FROM images ORDER BY uploaded_date DESC');
$images = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

First we include the functions.php file, remember this file contains the functions that we're going to use, after, we connect to our MySQL database by calling the pdo_connect_mysql() function and then we retrieve all the images information that we have uploaded from our database table images, this will be ordered by the uploaded date column (descending).

Add after:

PHP Copy
<?=template_header('Gallery')?>

<div class="content home">
	<h2>Gallery</h2>
	<p>Welcome to the gallery page, you can view the list of images below.</p>
	<a href="upload.php" class="upload-image">Upload Image</a>
	<div class="images">
		<?php foreach ($images as $image): ?>
		<a href="#">
			<img src="<?=$image['path']?>" alt="<?=$image['description']?>" data-id="<?=$image['id']?>" data-title="<?=$image['title']?>" width="300" height="200">
			<span><?=$image['description']?></span>
		</a>
		<?php endforeach; ?>
	</div>
</div>
<div class="image-popup"></div>

Now we have started creating the template for our home page, as you can see we include the template header function with the title Gallery, this will include the code from the template header function.

The upload button is created and points to the upload.php file, all our images will be in the images container, we use a foreach loop to iterate the images and create the HTML code that will display each one.

The data-* attributes will be used to store information about the image, this is so we can get the information with JavaScript.

Add after:

JavaScript Copy
<script>
// Container we'll use to show an image
let image_popup = document.querySelector('.image-popup');
// Loop each image so we can add the on click event
document.querySelectorAll('.images a').forEach(img_link => {
	img_link.onclick = e => {
		e.preventDefault();
		let img_meta = img_link.querySelector('img');
		let img = new Image();
		img.onload = () => {
			// Create the pop out image
			image_popup.innerHTML = `
				<div class="con">
					<h3>${img_meta.dataset.title}</h3>
					<p>${img_meta.alt}</p>
					<img src="${img.src}" width="${img.width}" height="${img.height}">
					<a href="delete.php?id=${img_meta.dataset.id}" class="trash" title="Delete Image"><i class="fas fa-trash fa-xs"></i></a>
				</div>
			`;
			image_popup.style.display = 'flex';
		};
		img.src = img_meta.src;
	};
});
// Hide the image popup container if user clicks outside the image
image_popup.onclick = e => {
	if (e.target.className == 'image-popup') {
		image_popup.style.display = "none";
	}
};
</script>

This is the JavaScript code that will display the pop up of the image when it has been clicked. If you prefer to put your JavaScript code in a separate JS file you can do that too.

Add after:

PHP Copy
<?=template_footer()?>

And now we end the template for the home page by calling the template footer function.

That's all we need to do for the home page. If we navigate to http://localhost/phpgallery/index.php we'll see the following:

http://localhost/phpgallery/index.php
PHP MySQL Gallery Home Page

And if we click one of the images we'll see the following:

http://localhost/phpgallery/index.php
PHP MySQL Gallery Popup

Remember the popup image effect is created with JavaScript, the page doesn't need to reload every time we click a different one, you can close the popup by clicking outside of the image container.

6. Creating the Upload Page

The upload page is the page we'll use to upload new images and store information about those images in our MySQL database images table.

Edit upload.php and add:

PHP Copy
<?php
include 'functions.php';
// The output message
$msg = '';
// Check if user has uploaded new image
if (isset($_FILES['image'], $_POST['title'], $_POST['description'])) {
	// The folder where the images will be stored
	$target_dir = 'images/';
	// The path of the new uploaded image
	$image_path = $target_dir . basename($_FILES['image']['name']);
	// Check to make sure the image is valid
	if (!empty($_FILES['image']['tmp_name']) && getimagesize($_FILES['image']['tmp_name'])) {
		if (file_exists($image_path)) {
			$msg = 'Image already exists, please choose another or rename that image.';
		} else if ($_FILES['image']['size'] > 500000) {
			$msg = 'Image file size too large, please choose an image less than 500kb.';
		} else {
			// Everything checks out now we can move the uploaded image
			move_uploaded_file($_FILES['image']['tmp_name'], $image_path);
			// Connect to MySQL
			$pdo = pdo_connect_mysql();
			// Insert image info into the database (title, description, image path, and date added)
			$stmt = $pdo->prepare('INSERT INTO images VALUES (NULL, ?, ?, ?, CURRENT_TIMESTAMP)');
	        $stmt->execute([$_POST['title'], $_POST['description'], $image_path]);
			$msg = 'Image uploaded successfully!';
		}
	} else {
		$msg = 'Please upload an image!';
	}
}
?>

This is the code that will upload a new image into the images directory, but before the image is uploaded we first check if the image file already exists and make sure it's actually an image, we can check if it's an image with the getimagesize() function.

If the uploaded image already exists the code will output a message to the user, the maximum image size is set to 500kb, you can change this value if you want to upload images with larger file size.

And finally if everything was successful the image information will be inserted into our MySQL images table.

Add after:

PHP Copy
<?=template_header('Upload Image')?>

<div class="content upload">
	<h2>Upload Image</h2>
	<form action="upload.php" method="post" enctype="multipart/form-data">
		<label for="image">Choose Image</label>
		<input type="file" name="image" accept="image/*" id="image">
		<label for="title">Title</label>
		<input type="text" name="title" id="title">
		<label for="description">Description</label>
		<textarea name="description" id="description"></textarea>
	    <input type="submit" value="Upload Image" name="submit">
	</form>
	<p><?=$msg?></p>
</div>

<?=template_footer()?>

This is the template for the upload page, it's an HTML form that we'll use to fill out the information about an image and select an image.

If the user clicks the submit button the upload file will check and validate the sent data, the request method will be POST, this will submit data to upload.php.

If we navigate to the upload page we'll see the following:

http://localhost/phpgallery/upload.php
PHP MySQL Upload Image Form

To test that it is working correctly select an image and fill out the form, remember the image needs to be less than 500kb, click the Upload Image button after you've finished.

7. Creating the Delete Page

This page will be used to delete images that we have uploaded, images will be deleted from the images directory and information about the image will be deleted from the MySQL images table.

Edit delete.php and add:

PHP Copy
<?php
include 'functions.php';
$pdo = pdo_connect_mysql();
$msg = '';
// Check that the poll ID exists
if (isset($_GET['id'])) {
    // Select the record that is going to be deleted
    $stmt = $pdo->prepare('SELECT * FROM images WHERE id = ?');
    $stmt->execute([$_GET['id']]);
    $image = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$image) {
        die ('Image doesn\'t exist with that ID!');
    }
    // Make sure the user confirms beore deletion
    if (isset($_GET['confirm'])) {
        if ($_GET['confirm'] == 'yes') {
            // User clicked the "Yes" button, delete file & delete record
            unlink($image['path']);
            $stmt = $pdo->prepare('DELETE FROM images WHERE id = ?');
            $stmt->execute([$_GET['id']]);
            // Output msg
            $msg = 'You have deleted the image!';
        } else {
            // User clicked the "No" button, redirect them back to the home/index page
            header('Location: index.php');
            exit;
        }
    }
} else {
    die ('No ID specified!');
}
?>

Before we delete an image the code requires the ID of the image from the GET request, this will determine which image we're going to delete.

We also check if the image is in the database and check if the user has clicked the Yes confirmation button, if the user clicked Yes the code will delete the file from the server using the unlink() function and then execute a MySQL DELETE FROM statement that will delete the image record from the database.

Add after:

PHP Copy
<?=template_header('Delete')?>

<div class="content delete">
	<h2>Delete Image #<?=$image['id']?></h2>
    <?php if ($msg): ?>
    <p><?=$msg?></p>
    <?php else: ?>
	<p>Are you sure you want to delete <?=$image['title']?>?</p>
    <div class="yesno">
        <a href="delete.php?id=<?=$image['id']?>&confirm=yes">Yes</a>
        <a href="delete.php?id=<?=$image['id']?>&confirm=no">No</a>
    </div>
    <?php endif; ?>
</div>

<?=template_footer()?>

This is the template for our delete page, this will confirm to the user with a Yes and No button if they want to delete the image.

If we navigate to the home page and click on one of the images we will see the delete icon and if we click on that we'll see something like the following:

http://localhost/tutorial/delete.php?id=6
PHP MySQL Gallery Delete

If we click Yes the image will be deleted from our images directory and from our MySQL database.

Conclusion

You have now created a working gallery system with PHP, MySQL, and JavaScript. Feel free to do as you want with the code, consider adding your own features.

You should now have a basic understanding of how to display images and upload images with PHP.

Consider sharing this article on social websites if you've found it helpful and drop a comment below.

Enjoy coding!