DEV Community

Cover image for PHP crash course: Simple Image Gallery
MD ARIFUL HAQUE
MD ARIFUL HAQUE

Posted on

PHP crash course: Simple Image Gallery

A fully functional image gallery with upload capabilities using PHP, HTML, jQuery, AJAX, JSON, Bootstrap, CSS, and MySQL. This project includes a detailed step-by-step solution with code explanations and documentation, making it a comprehensive tutorial for learning.

Topics: php, mysql, blog, ajax, bootstrap, jquery, css, image gallery, file upload

Step-by-Step Solution

1. Directory Structure

simple-image-gallery/
│
├── index.html
├── db/
│   └── database.sql
├── src/
│   ├── fetch-image.php
│   └── upload.php
├── include/
│   ├── config.sample.php
│   └── db.php
├── assets/
│   ├── css/
│   │   └── style.css
│   ├── js/
│   │   └── script.js
│   └── uploads/
│   │   └── (uploaded images will be stored here)
├── README.md
└── .gitignore
Enter fullscreen mode Exit fullscreen mode

2. Database Schema

db/database.sql:

CREATE TABLE IF NOT EXISTS `images` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `file_name` varchar(255) NOT NULL,
    `uploaded_on` datetime NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Enter fullscreen mode Exit fullscreen mode

3. Configuration File

Configuration settings (include/config.sample.php)

<?php
define('DB_HOST', 'localhost'); // Database host
define('DB_NAME', 'image_gallery'); // Database name
define('DB_USER', 'root'); // Change if necessary
define('DB_PASS', ''); // Change if necessary
define('UPLOAD_DIRECTORY', '/assets/uploads/'); // Change if necessary
?>
Enter fullscreen mode Exit fullscreen mode

4. Configure the Database Connection

Establishing database connection (include/db.php)

<?php
include 'config.php';

// Database configuration
$dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME;
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];

// Create a new PDO instance
try {
    $pdo = new PDO($dsn, DB_USER, DB_PASS, $options);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Set error mode to exception
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage(); // Display error message if connection fails
}
?>
Enter fullscreen mode Exit fullscreen mode

5. HTML and PHP Structure

HTML Structure (index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Gallery Upload</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <link rel="stylesheet" href="assets/css/styles.css">
</head>
<body>
<div class="container">
    <h1 class="text-center mt-5">Image Gallery</h1>
    <div class="row">
        <div class="col-md-6 offset-md-3">
            <form id="uploadImage" enctype="multipart/form-data">
                <div class="form-group">
                    <label for="image">Choose Image</label>
                    <input type="file" name="image" id="image" class="form-control" required>
                </div>
                <button type="submit" class="btn btn-primary">Upload</button>
            </form>
            <div id="upload-status"></div>
        </div>
    </div>
    <hr>
    <div class="row" id="gallery">
        <!-- Images will be loaded here -->
    </div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="assets/js/script.js"></script> <!-- Custom JS -->
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

6. JavaScript and AJAX

AJAX Handling (assets/js/script.js)

$(document).ready(function(){
    // load gallery on page load
    loadGallery();

    // Form submission for image upload
    $('#uploadImage').on('submit', function(e){
        e.preventDefault(); // Prevent default form submission
        var file_data = $('#image').prop('files')[0];
        var form_data = new FormData();
        form_data.append('file', file_data);
        //hide upload section
        $('#uploadImage').hide();
        $.ajax({
            url: 'src/upload.php', // PHP script to process upload
            type: 'POST',
            dataType: 'text', // what to expect back from the server
            cache: false,
            data: new FormData(this), // Form data for upload
            processData: false,
            contentType: false,
            success: function(response){
                let jsonData = JSON.parse(response);
                if(jsonData.status == 1){
                    $('#image').val(''); // Clear the file input
                    loadGallery(); // Fetch and display updated images
                    $('#upload-status').html('<div class="alert alert-success">'+jsonData.message+'</div>');
                } else {
                    $('#upload-status').html('<div class="alert alert-success">'+jsonData.message+'</div>'); // Display error message
                }
                // hide message box
                autoHide('#upload-status');
                //show upload section
                autoShow('#uploadImage');
            }
        });
    });
});

// Function to load the gallery from server
function loadGallery() {
    $.ajax({
        url: 'src/fetch-images.php', // PHP script to fetch images
        type: 'GET',
        success: function(response){
            let jsonData = JSON.parse(response);
            $('#gallery').html(''); // Clear previous images
            if(jsonData.status == 1){
                $.each(jsonData.data, function(index, image){
                    $('#gallery').append('<div class="col-md-3"><img src="assets/uploads/'+image.file_name+'" class="img-responsive img-thumbnail"></div>'); // Display each image
                });
            } else {
                $('#gallery').html('<p>No images found...</p>'); // No images found message
            }
        }
    });
}

//Auto Hide Div
function autoHide(idORClass) {
    setTimeout(function () {
        $(idORClass).fadeOut('fast');
    }, 1000);
}

//Auto Show Element
function autoShow(idORClass) {
    setTimeout(function () {
        $(idORClass).fadeIn('fast');
    }, 1000);
}
Enter fullscreen mode Exit fullscreen mode

7. Backend PHP Scripts

Fetching Images (src/fetch-images.php)

<?php
include '../include/db.php'; // Include database configuration

$response = array('status' => 0, 'message' => 'No images found.');

// Fetching images from the database
$query = $pdo->prepare("SELECT * FROM images ORDER BY uploaded_on DESC");
$query->execute();
$images = $query->fetchAll(PDO::FETCH_ASSOC);

if(count($images) > 0){
    $response['status'] = 1;
    $response['data'] = $images; // Returning images data
}

// Return response
echo json_encode($response);
?>
?>
Enter fullscreen mode Exit fullscreen mode

Image Upload (src/upload.php)

<?php
include '../include/db.php'; // Include database configuration
$response = array('status' => 0, 'message' => 'Form submission failed, please try again.');

if(isset($_FILES['image']['name'])){
    // Directory where files will be uploaded
    $targetDir = UPLOAD_DIRECTORY;
    $fileName = date('Ymd').'-'.str_replace(' ', '-', basename($_FILES['image']['name']));
    $targetFilePath = $targetDir . $fileName;
    $fileType = pathinfo($targetFilePath, PATHINFO_EXTENSION);

    // Allowed file types
    $allowTypes = array('jpg','png','jpeg','gif');
    if(in_array($fileType, $allowTypes)){
        // Upload file to server
        if(move_uploaded_file($_FILES['image']['tmp_name'], $targetFilePath)){
            // Insert file name into database
            $insert = $pdo->prepare("INSERT INTO images (file_name, uploaded_on) VALUES (:file_name, NOW())");
            $insert->bindParam(':file_name', $fileName);
            $insert->execute();
            if($insert){
                $response['status'] = 1;
                $response['message'] = 'Image uploaded successfully!';
            }else{
                $response['message'] = 'Image upload failed, please try again.';
            }
        }else{
            $response['message'] = 'Sorry, there was an error uploading your file.';
        }
    }else{
        $response['message'] = 'Sorry, only JPG, JPEG, PNG, & GIF files are allowed to upload.';
    }
}

// Return response
echo json_encode($response);
?>
Enter fullscreen mode Exit fullscreen mode

6. CSS Styling

CSS Styling (assets/css/style.css)

body {
    background-color: #f8f9fa;
}

#gallery .col-md-4 {
    margin-bottom: 20px;
}

#gallery img {
    display: block;
    width: 200px;
    height: auto;
    margin: 10px;
}
Enter fullscreen mode Exit fullscreen mode

Documentation and Comments

  • config.php: Contains database configuration and connects to MySQL using PDO.
  • index.php: Main page with HTML structure, includes Bootstrap for styling, and a modal for adding/editing posts.
  • assets/js/script.js: Handles AJAX requests for loading and saving posts. Uses jQuery for DOM manipulation and AJAX.
  • src/fetch-images.php: Fetches posts from the database and returns them as JSON.
  • src/upload.php: Handles post creation and updating based on the presence of an ID.

This solution includes setting up the project, database configuration, HTML structure, styling with CSS, handling image upload with AJAX, and storing image data in the database using PHP PDO. Each line of code is commented to explain its purpose and functionality, making it a comprehensive tutorial for building an image gallery with upload functionality.

Connecting Links

If you found this series helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!

If you want more helpful content like this, feel free to follow me:

Source Code

ACI image

ACI.dev: Best Open-Source Composio Alternative (AI Agent Tooling)

100% open-source tool-use platform (backend, dev portal, integration library, SDK/MCP) that connects your AI agents to 600+ tools with multi-tenant auth, granular permissions, and access through direct function calling or a unified MCP server.

Star our GitHub!

Top comments (0)

DevCycle image

Ship Faster, Stay Flexible.

DevCycle is the first feature flag platform with OpenFeature built-in to every open source SDK, designed to help developers ship faster while avoiding vendor-lock in.

Start shipping

Join the Runner H "AI Agent Prompting" Challenge: $10,000 in Prizes for 20 Winners!

Runner H is the AI agent you can delegate all your boring and repetitive tasks to - an autonomous agent that can use any tools you give it and complete full tasks from a single prompt.

Check out the challenge

DEV is bringing live events to the community. Dismiss if you're not interested. ❤️