DEV Community

Cover image for Building a simple shop using HTML SQL and PHP
Arya Ishaan Patrjbauli
Arya Ishaan Patrjbauli

Posted on • Updated on

Building a simple shop using HTML SQL and PHP

Introduction:

In this blog, I will guide you step by step through the process of building a complete online shop using PHP and MySQL. From setting up the database to developing essential features like user registration, login, product management, and handling orders, we will cover everything. Whether you're a beginner or an advanced developer, this guide will help you build your own online shop from scratch.

Important note: This is just for beginner practicing the code, i do not recommend turning this into a real E-Commerce store!

Let's start!

*Creating the Database and Inserting Products
*

CREATE DATABASE IF NOT EXISTS your_database;
USE your_database;
Enter fullscreen mode Exit fullscreen mode

This SQL command creates a new database if it doesn't already exist, and then selects it for use. The** IF NOT EXISTS** clause prevents errors if the database already exists.

Create Tables:

Users Table: Store user data (including admin roles).
Products Table: Hold product details (with active/inactive status).
Addresses Table: Store user addresses (both billing and shipping).
Orders Table: Store order details with payment information.
Order Details Table: Track each product and quantity for orders.

Image description

Create table users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    fname VARCHAR(100) NOT NULL,
    lname VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    is_admin TINYINT(1) NOT NULL
);

Create table products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    sku VARCHAR(100) NOT NULL UNIQUE,
    name VARCHAR(100) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL,
    image_url VARCHAR(255),
    stock INT,
    is_active TINYINT(1) NOT NULL
);


CREATE TABLE addresses (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    address_type ENUM('billing', 'shipping') NOT NULL,
    street VARCHAR(255) NOT NULL,
    house_number VARCHAR(10) NOT NULL,
    zip VARCHAR(20) NOT NULL,
    city VARCHAR(100) NOT NULL,
    country VARCHAR(100) NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    billing_address_id INT NOT NULL,
    shipping_address_id INT NOT NULL,
    pay_method VARCHAR(100) NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (billing_address_id) REFERENCES addresses(id),
    FOREIGN KEY (shipping_address_id) REFERENCES addresses(id)
);


Create table order_details(
    id INT AUTO_INCREMENT PRIMARY KEY,
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT NOT NULL,
    price_at_time DECIMAL(10, 2) NOT NULL,
    FOREIGN KEY (product_id) REFERENCES products(id),
    FOREIGN KEY (order_id) REFERENCES orders(id)
);
Enter fullscreen mode Exit fullscreen mode

Now we add some products to display them later in the shop!

INSERT INTO products (sku, name, description, price, image_url, stock, is_active) 
VALUES 
('FR001', 'Apple', 'A fresh and juicy apple', 0.99, 'images/apple.jpg', 50, 1),
('FR002', 'Banana', 'A ripe and delicious banana', 0.69, 'images/banana.jpg', 100, 1),
('FR003', 'Orange', 'A sweet and tangy orange', 1.29, 'images/orange.jpg', 75, 1);

Enter fullscreen mode Exit fullscreen mode

Image description


Creating a PDO Connection in PHP

You're creating a database connection using **PDO **with proper exception handling.

create a db_connection.php

<?php 
// SET DB Variables
$host = '127.0.0.1';
$dbn = 'database name';
$user = 'root';
$pw = '';
// Set DATA SOURCE NAME for Connection
$dsn = "mysql:host=$host;dbname=$dbn";
// CREATE NEW PDO CONNECTION
try {
    $conn = new PDO ($dsn, $user, $pw);
    // SET EXCEPTION HANDLING
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    // echo 'Connected!';
} catch (PDOException $e) {
    // RETURN ERROR MESSAGES 
    echo 'Connection Failed:' . $e->getMessage();
}
?>
Enter fullscreen mode Exit fullscreen mode

This script uses PHP Data Objects (PDO) to create a database connection:

It constructs a Data Source Name (DSN) string with the host and database name.
It attempts to create a new PDO object using the DSN, username, and password.
It sets the error mode to throw exceptions, allowing for better error handling.
If the connection fails, it catches the exception and displays an error message.


Now we want to CREATE Files that will help us organizing everything. They are called Header, Footer, Functions, Session_Messages and one File that puts them all together.

In the header we have to start the SESSION and use "require" function to include important files like the database connection file we created.

For now just write checkRole($conn), we will come back to this after a few steps!

We are also using **"classless CSS" **for the design of the page, since we just want to learn the code of PHP.

We will also add a Navigation Bar with HTML with added PHP so we can check if the user is logged in or with the user is an admin.

header.php

<?php
session_start();
require_once 'functions.php';
require_once 'db/dbconnect.php';
checkRole($conn);
?>

<!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="https://cdn.jsdelivr.net/npm/holiday.css@0.11.2">
    <title>Document</title>
</head>
<main>
<nav>
    <ul>
        <li><a href="index.php">Home</a></li>
        <li><a href="products.php">Products</a></li>
        <?php if(!$isLoggedIn): ?>
        <li><a href="register.php">Register</a></li>
        <li><a href="login.php">Login</a></li>
        <?php endif; ?>
        <li><a href="logout.php">Logout</a></li>
        <?php if($isAdmin): ?>
        <li><a href="admin.php">Admin</a></li>
        <?php endif; ?>
        <li><a href="cart.php">Cart<a/></li>
    </ul>
</nav>
Enter fullscreen mode Exit fullscreen mode

This PHP code at the top of the header file:

Starts a new session or resumes an existing one.
Includes the functions and database connection files.
Calls the checkRole() function to determine the user's login status and role.


In this example we will save some messages in the SESSION Variable, for example if you update a product it will save the message in the variable and you can see it afterwards. THats why we need the "session_message.php" File now.

It looks like this.

<?php

if (isset($_SESSION['successmsg'])) {
    echo $_SESSION['successmsg'];
    unset($_SESSION['successmsg']);
}

if (isset($_SESSION['errormsg'])) {
    echo $_SESSION['errormsg']; // Display the message
    unset($_SESSION['errormsg']);
}

?>
Enter fullscreen mode Exit fullscreen mode

After that you create another file called "include_all.php" where you input the header, database_connection, footer and session_message files.

<?php 

require_once 'inc/header.php';
require_once 'db/dbconn.php';
require_once 'functions.php';
require_once 'sesssion_message.php';

?>

Enter fullscreen mode Exit fullscreen mode

Now lets move on to the FUNCTIONS

Creating a checkRole Function for User Authentication and Admin Role in PHP
When building an online shop with PHP, managing user roles is crucial, especially for differentiating between regular users and administrators. In this post, we will create a function called checkRole that checks if a user is logged in and whether they have administrative privileges. This function will be stored in a separate functions.php file, allowing you to include it wherever needed in your application.

functions.php

function checkRole($conn)
{
    global $isLoggedIn, $isAdmin;

    $isLoggedIn = $isAdmin = false;

    // Check if user is logged in by verifying the user_id in the session
    if (!empty($_SESSION['user_id'])) {
        // Query the database to get the user's admin status
        $stmt = $conn->prepare("SELECT is_admin FROM users WHERE id = ?");
        $stmt->execute([$_SESSION['user_id']]);
        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        // If the user exists in the database, update the global variables
        if ($user) {
            $isLoggedIn = true;
            $isAdmin = (bool)$user['is_admin'];
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

This checkRole() function:

Declares global variables to store the user's login and admin status.
Checks if a user ID exists in the session.
If it does, it queries the database to fetch the user's admin status.
It then sets the global variables based on the query results.

This function allows you to easily check a user's status throughout your application, which is crucial for implementing proper access control and displaying appropriate content.

You can create a INDEX.PHP File, that is gonna be the homepage for the WEBSITE


Now lets start with one of the most important: REGISTER.PHP

Image description

Building a User Registration Page for Your PHP Online Shop
When setting up an online shop, having a registration page is essential. It allows users to create accounts, enabling you to track their orders, save preferences, and provide a personalized shopping experience. In this post, we’ll walk through how to create a registration page in PHP that connects to a MySQL database using PDO. We’ll also ensure the form is secure by validating user inputs and storing passwords safely.

Over the HTML we have to add some PHP code too!

Once the form is submitted, we need to process the input data. We’ll write a PHP function that validates the input, checks if the email is already registered, and stores the new user in the database.

Here’s the PHP code that handles the form submission:

register.php

<?php
require_once 'incall.php';

$registerError = registerUser($conn);

if ($registerError) {
    echo $registerError;
}

?>
Enter fullscreen mode Exit fullscreen mode

Includes all necessary files using 'incall.php'.
Calls the registerUser() function, passing the database connection as an argument.
If an error occurs during registration, it's stored in the session and displayed to the user.

Create the HTML Structure first.

Key points:

HTML Escaping: We use htmlspecialchars() to ensure any data returned to the form doesn’t introduce potential XSS vulnerabilities.
Validation: First name and last name fields are restricted to letters only (pattern="[A-Za-z]+"). The email field automatically checks for valid email format, and we make sure the password field is required.
Required Attributes: All fields are marked as required so that the user cannot submit the form without providing all necessary information.

HTML:

<form action="register.php" method="post">

    <input type="text" name="fname" placeholder="First Name:" value="<?= htmlspecialchars($_POST['fname'] ?? ''); ?>"
        pattern="[A-Za-z]+" title="Only Letters allowed!" required> <br>

    <input type="text" name="lname" placeholder="Last Name:" value="<?= htmlspecialchars($_POST['lname'] ?? '') ?>"
        pattern="[A-Za-z]+" title="Only Letters allowed!" required> <br>

    <input type="email" name="email" placeholder="Email:" value="<?= htmlspecialchars($_POST['email'] ?? '') ?>"> <br>

    <input type="password" name="password" placeholder="Password:" required> <br>

    <button type="submit" name="btregister">Register</button>

</form>
Enter fullscreen mode Exit fullscreen mode

This HTML form:

Uses the POST method to submit data to 'register.php'.
Includes input fields for first name, last name, email, and password.
Uses htmlspecialchars() to prevent XSS attacks when redisplaying submitted data.
Implements client-side validation using the pattern attribute for names and the type="email" for email validation.


Now, let’s look at the registerUser function that performs the actual registration process.

This function:

Checks if the registration form was submitted.
Validates the email format and password length.
Hashes the password for secure storage.
Checks if the email is already registered.
If not, it inserts the new user into the database.
Uses prepared statements to prevent SQL injection.
Redirects to the index page on successful registration.
Handles database errors and stores them in the session.

functions.php

// Register a new user
function registerUser($conn)
{
    if (isset($_POST['btregister'])) {
        // Collect user input from the registration form
        $fname = $_POST['fname'];
        $lname = $_POST['lname'];
        $email = $_POST['email'];
        $password = $_POST['password'];

        // Validate email format using PHP's filter_var function
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return 'Email is not Valid!';
        }

        // Check password length for basic security
        if (strlen($password) < 8) {
            return 'Password must be at least 8 characters';
        }

        // Hash the password for secure storage
        $hashedPassword = password_hash($password, PASSWORD_DEFAULT);

        try {
            // Check if the email is already registered
            $stmt = $conn->prepare("SELECT id from `users` WHERE email = :email");
            $stmt->bindParam(':email', $email);
            $stmt->execute();

            if ($stmt->rowCount() > 0) {
                return 'Email already registered';
            }

            // Insert the new user into the database
            $stmt = $conn->prepare("INSERT INTO users (fname, lname, email, password) VALUES (:fname, :lname, :email, :password)");
            $stmt->bindParam(':fname', $fname);
            $stmt->bindParam(':lname', $lname);
            $stmt->bindParam(':email', $email);
            $stmt->bindParam(':password', $hashedPassword);
            $stmt->execute();

            // Set a success message and redirect to the index page
            $_SESSION['successmsg'] = "Thanks for the registration, NOW GO AND BUY IT ALL!!";
            header("Location: index.php");
            exit();
        } catch (PDOException $e) {
            // Catch and store any database errors
            $_SESSION['errormsg'] = "Registration failed: " . $e->getMessage();
        }
    }
    return null;
}
Enter fullscreen mode Exit fullscreen mode

AWESOME! You can test it now by registering and checking in your Database if there is a user in the users Table!


Now Lets move on to the LOGIN

A login page is a crucial part of any online shop. It allows users to access their accounts and provides personalized shopping experiences, order tracking, and other benefits. In this blog post, we’ll walk through creating a secure login system for your PHP online shop, ensuring proper input validation and session management.

login.php

<?php

require_once 'incall.php';

if(isset($_POST['btlogin'])) {
    loginUser($conn);
}

?>
Enter fullscreen mode Exit fullscreen mode

For the LOGIN FORM we add this:

<form action="login.php" method="post">
    <input type="email" name="email" placeholder="Email:" required value="<?= isset($_POST['email']) ? htmlspecialchars($_POST['email']) : '' ?>"><br>
    <input type="password" name="password" placeholder="Password:" required> <br>
    <button type="submit" name="btlogin">Login</button>
    <p>Don't have an account? <a href="register.php">Register here</a></p>
</form>
Enter fullscreen mode Exit fullscreen mode

Email Validation:
The type="email" ensures that the email format is checked on the client side. If the user tries to submit an invalid email, they’ll get an immediate browser warning.
HTML Escaping: The htmlspecialchars() function escapes any special characters in the email field to prevent potential XSS (Cross-Site Scripting) attacks.
Password Field: The required attribute ensures that the user must enter a password before submitting the form.

This function:

Starts a session if one isn't already active.
Validates the email format.
Queries the database for the user with the provided email.
Verifies the password using password_verify().
If login is successful, it stores user information in the session and redirects to the index page.
If login fails, it stores an error message in the session.

function loginUser($conn)
{
    // Collect user input from the login form
    $email = $_POST['email'];
    $password = $_POST['password'];

    // Validate email format
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $_SESSION['errormsg'] = "Invalid email format";
    } else {
        // Query the database for the user
        $stmt = $conn->prepare("SELECT * FROM users WHERE email = :email");
        $stmt->execute([':email' => $email]);
        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        // Verify the password and set session variables if correct
        if ($user && password_verify($password, $user['password'])) {
            $_SESSION['user_id'] = $user['id'];
            $_SESSION['is_admin'] = $user['is_admin'];
            $_SESSION['user_name'] = $user['name'];
            $_SESSION['successmsg'] = "Login successful!";
            header("Location: index.php");
            exit;
        } else {
            // Set error message if login fails
            $_SESSION['errormsg'] = "Invalid email or password";
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

What’s happening in the code:

Session Management: The session_start() function initializes a session, which allows you to store user-specific data (like their user ID and admin status) that persists across different pages.

Email Validation: We use PHP’s filter_var() to ensure that the email entered is valid.

**Password Verification: **The password_verify() function compares the entered password with the hashed password stored in the database. This ensures that even if the database is compromised, the passwords remain secure.

**User Data Storage: **Upon successful login, the user’s ID, admin status, and name are stored in the session, making it easy to personalize the experience on other pages.

Logging out is a crucial functionality in any web application, ensuring that a user’s session is properly terminated. We will walk through a script that:

logout.php

<?php
session_start(); 

$_SESSION = [];

session_destroy();

header("Location: index.php");

exit();

?>
Enter fullscreen mode Exit fullscreen mode

Starts the session to gain access to session data.
Clears all session variables to remove any stored data.
Destroys the session to fully log out the user.
Redirects the user back to the homepage (index page).

That’s it! Your logout functionality is now complete. When a user clicks the logout button, they’ll be logged out and redirected to the homepage.


Displaying Products on the Products Page
Next, we’ll set up the Products Page where users can browse through the available products. As an admin, you might have products that are not active and should only be visible to other admins. In this tutorial, we'll show how to display only the active products to regular users.

We’ll add a function called showActiveProducts() to handle fetching only active products from the database. Admin users can see all products, but regular users should only see products marked as "active." This function will query the database to retrieve only products where the is_active field is set to 1 (active).

products.php

<?php

require_once 'incall.php';

$products = showActiveProducts($conn);

?>
Enter fullscreen mode Exit fullscreen mode

Here is the Container to show all the Products using an foreach.

<main>
    <h2>Products</h2>

    <?php if (!empty($products)): ?>
        <div class="product-list">
            <?php foreach ($products as $product): ?>
                <div class="product">
                    <?php if (!empty($product['image_url'])): ?>
                        <img src="<?= htmlspecialchars($product['image_url']); ?>" 
                        alt="<?= htmlspecialchars($product['name']); ?>" style="max-width: 200px;">
                    <?php endif; ?>
                    <h3><a href="product.php?id=<?= $product['id']; ?>"><?= htmlspecialchars($product['name']); ?></a></h3>
                    <p>Price: <?= htmlspecialchars($product['price']); ?> €</p>
                    <a href="add_to_cart.php?id=<?= $product['id']; ?>">Add it to the cart</a><br><br>
                </div>
            <?php endforeach; ?>
        </div>
    <?php else: ?>
        <p>No products yet</p>
    <?php endif; ?>
</main>
Enter fullscreen mode Exit fullscreen mode

To retrieve only the active products, we’ll write a PHP function that queries the database for products where is_active = 1. This function uses a prepared statement to ensure security, particularly against SQL injection, and returns an array of active products.

This function:

Prepares a SQL statement to select all active products.
Executes the statement and fetches all results as an associative array.
Returns the array of active products.
Catches and handles any database errors, storing them in the session.

function showActiveProducts($conn)
{
    try {
        // Prepare the SQL statement to Fetch all active products
        $stmt = $conn->prepare("SELECT * FROM products WHERE is_active = 1");
        $stmt->execute(); // Execute the query
        $products = $stmt->fetchAll(PDO::FETCH_ASSOC); // Fetch all active products
        return $products; // Return the result as an associative array
    } catch (PDOException $e) {
        // Handle any errors and log them or show a message
        $_SESSION['errormsg'] = "Error fetching products: " . $e->getMessage();
    }
}

Enter fullscreen mode Exit fullscreen mode

Now you can open the Products page in your browser and check if you see any Products displayed!


In an online shop, it's common to display detailed information about a specific product on a dedicated product page. To do this, you need to retrieve a product from the database using its unique identifier (ID). In this blog post, we’ll explain how to create a PHP function that retrieves a product by its ID from the database and handles potential errors efficiently.

Create PRODUCT.PHP

This code:

Includes necessary files.
Checks if a product ID is provided in the URL.
Calls getProductById() to retrieve the product details.
Displays an error message if the product is not found or no ID is provided.

product.php

<?php

require_once 'incall.php';

if (isset($_GET['id'])) {
    $productId = (int)$_GET['id'];

$product = getProductById($conn, $productId);

    if (!$product) {
        echo "<p>Product not found</p>";
    }
 } else {
    echo "<p>No product-id!</p>";
}

?>
Enter fullscreen mode Exit fullscreen mode

we will come back to the function after the CONTAINER with HTML that looks like this!

<main>
    <?php if (isset($product)): ?>
        <h2><?= htmlspecialchars($product['name']); ?></h2>
        <?php if (!empty($product['image_url'])): ?>
            <img src="<?= htmlspecialchars($product['image_url']); ?>" style="max-width: 300px;">
        <?php endif; ?>
        <p>SKU: <?= htmlspecialchars($product['sku']); ?></p>
        <p><?= htmlspecialchars($product['description']); ?></p>
        <p>Price: <?= htmlspecialchars($product['price']); ?> €</p>
        <p>Stock: <?= htmlspecialchars($product['stock']); ?> On stock</p>
        <a href="add_to_cart.php?id=<?= $product['id']; ?>">Add to cart</a>
    <?php endif; ?>
</main>
Enter fullscreen mode Exit fullscreen mode

Now lets add the function to make sure we get a product id when clicking on an product!

What this function does:

Prepared Statement: **This ensures that the product ID is securely passed to the SQL query, preventing SQL injection attacks.
**Fetching Product:
The fetch() method retrieves the product details as an associative array (PDO::FETCH_ASSOC).
Error Handling: If the product is not found, the function returns null. Any database errors are caught and stored in the session, making it easier to debug or display error messages on the frontend.

function getProductById($conn, $productId) {
    try {
        // Prepare the SQL statement to select the product by ID
        $stmt = $conn->prepare("SELECT * FROM products WHERE id = :id");
        $stmt->bindParam(':id', $productId); // Bind the product ID to the SQL statement
        $stmt->execute(); // Execute the query
        $product = $stmt->fetch(PDO::FETCH_ASSOC); // Fetch the product as an associative array

        // Check if the product exists
        if (!$product) {
            return null; // Return null if no product is found
        }

        return $product; // Return the product details
    } catch (PDOException $e) {
        // Handle any errors by storing the error message in the session
        $_SESSION['errormsg'] = "Error fetching product: " . $e->getMessage();
        return null; // Return null if an error occurs
    }
}

Enter fullscreen mode Exit fullscreen mode

Make sure to test this aswell!


Now its time that we move to the admin terrain.

as always we include all the files we need

<?php

require_once 'incall.php';

checkAdmin();

$products = showAllProducts($conn);

?>
Enter fullscreen mode Exit fullscreen mode

We are using 2 new Functions here!

We will create them after we made the HTML AND PHP CODE BELOW

You can copy the code from the other Products page so you dont have to write it again!. Here is it anyways!

admin.php

<p>Use the buttons to edit and delete products</p>
<a href="add_product.php">add products</a>

<main>
    <h2>Products</h2>

    <?php if (!empty($products)): ?>
        <div class="product-list">
            <?php foreach ($products as $product): ?>
                <div class="product">
                    <?php if (!empty($product['image_url'])): ?>
                        <img src="<?= htmlspecialchars($product['image_url']); ?>"
                            alt="<?= htmlspecialchars($product['name']); ?>" style="max-width: 200px;">
                    <?php endif; ?>
                    <h3><a href="product.php?id=<?= $product['id']; ?>"><?= htmlspecialchars($product['name']); ?></a></h3>
                    <p>Price: <?= htmlspecialchars($product['price']); ?> €</p>


                    <form action="edit_product.php" method="get">
                        <input type="hidden" name="product_id" value="<?= $product['id']; ?>">
                        <button type="submit">edit</button>
                    </form>
                    <br>
                </div>


            <?php endforeach; ?>
        </div>
    <?php else: ?>
        <p>no products yet.</p>
    <?php endif; ?>
</main>
Enter fullscreen mode Exit fullscreen mode

So now lets move on the functions!

first we do the checkAdmin function!

A very easy but efficient way to check if someone is an admin is this

This function:

Checks if the global isAdmin variable is set to true.
If not, it sets an error message and redirects to the homepage.

function checkAdmin()
{
    if (!$GLOBALS['isAdmin']) {
        $_SESSION['errormsg'] = "SORRY! U have no rights to access this PAGE!";
        header("Location: index.php");
        exit;
    }
}
Enter fullscreen mode Exit fullscreen mode

Thats it!

Now we want the showAllProducts Function because we are logged in as an admin and want to make sure to see all the products!

This function:

Retrieves all products from the database, including inactive ones.
Returns the products as an associative array.
Catches and handles any database errors.

function showAllProducts($conn)
{
    try {
        $stmt = $conn->prepare("SELECT * FROM products");
        $stmt->execute();
        $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
        return $products;
    } catch (PDOException $e) {
        $_SESSION['errormsg']  . $e->getMessage();
    }
}
Enter fullscreen mode Exit fullscreen mode

How about we make the ADDPRODUCTS Page ?

This page includes a form for adding new products and handles form submission. It uses the addProduct() function to insert the new product into the database.

add_product.php

<?php
require_once 'incall.php';

$productSku = "";
$productName = "";
$productDescription = "";
$productPrice = "";
$productStock = "";
$isActive = 1; // Standardwert ist aktiv (1)
$errorMessage = "";
$successMessage = "";

if (isset($_POST['add_product'])) {
    $productSku = $_POST['product_sku'];
    $productName = $_POST['product_name'];
    $productDescription = $_POST['product_description'];
    $productPrice = $_POST['product_price'];
    $productStock = $_POST['product_stock'];

    // Check if checkbox is set and give Status back
    $isActive = isset($_POST['is_active']) ? 1 : 0;

    if (empty($productName) || empty($productPrice) || empty($productSku)) {
        $errorMessage = "Pls use all the fields";
    } else {
        try {
            addProduct($conn, $productSku, $productName, $productDescription, $productPrice, $productStock, $isActive, $_FILES["product_image"]);
            $successMessage = "product added!";
            // Clear form fields after successful addition
            $productSku = $productName = $productDescription = $productPrice = $productStock = "";
            $isActive = 1;
        } catch (Exception $e) {
            $errorMessage = $e->getMessage();
        }
    }
}
?>
Enter fullscreen mode Exit fullscreen mode

It initializes variables to hold product details ($productSku, $productName, $productDescription, $productPrice, $productStock, and $isActive, which defaults to 1 for active status). Two other variables, $errorMessage and $successMessage, are used to store feedback messages for the user.

When the form is submitted, indicated by isset($_POST['add_product']), the script captures input from the form using the $_POST array. The values of $_POST['product_sku'], $_POST['product_name'], $_POST['product_description'], $_POST['product_price'], and $_POST['product_stock'] are assigned to corresponding variables. The script also checks if the "is active" checkbox is checked by using isset($_POST['is_active']), setting $isActive to 1 if checked, or 0 if not.

The script then validates the form, checking if essential fields like the product name, price, and SKU are not empty. If any are missing, an error message is saved in $errorMessage.

If the form passes validation, the script calls the addProduct() function, passing the database connection $conn, product details like SKU, name, description, price, stock, active status, and the uploaded image file $_FILES["product_image"]. If successful, a success message is saved in $successMessage.

After adding the product, the form fields are cleared by resetting the variables to empty strings, and $isActive is set back to 1. If an error occurs during the product addition, an exception is caught, and the error message is saved in $errorMessage.

This script ensures required fields are filled out, handles the product's active status through a checkbox, and supports image uploads. Error and success messages are provided to the user based on the outcome.

Security-wise, it's important to validate and sanitize inputs to prevent SQL injection and XSS. Additionally, file upload handling should validate the file type and size to avoid security risks.

Here is the HTML Form!

<main>
    <h1>add product</h1>

    <?php if (!empty($errorMessage)): ?>
        <div style="color: red;"><?= htmlspecialchars($errorMessage); ?></div>
    <?php endif; ?>

    <?php if (!empty($successMessage)): ?>
        <div style="color: green;"><?= htmlspecialchars($successMessage); ?></div>
    <?php endif; ?>

    <form action="add_product.php" method="post" enctype="multipart/form-data">
        <input type="text" name="product_sku" value="<?= htmlspecialchars($productSku); ?>" placeholder="Artikelnummer" required><br>

        <input type="text" name="product_name" value="<?= htmlspecialchars($productName); ?>" placeholder="Produktname" required><br>

        <textarea name="product_description" placeholder="Produktbeschreibung"><?= htmlspecialchars($productDescription); ?></textarea><br>

        <input type="number" name="product_price" value="<?= htmlspecialchars($productPrice); ?>" pattern="[0-9]+" placeholder="Preis" required step="0.01"><br>

        <input type="number" name="product_stock" value="<?= htmlspecialchars($productStock); ?>" placeholder="Lagerbestand"><br>

        <input type="file" name="product_image" required><br>

        <label>
            <input type="checkbox" name="is_active" <?= $isActive ? 'checked' : '' ?>> Produkt aktiv
        </label><br>

        <input type="submit" name="add_product" value="Produkt hinzufügen"><br>
    </form>

    <a href="admin.php">Zurück zum Dashboard</a>
</main>

<?php require_once 'inc/footer.php'; ?>
Enter fullscreen mode Exit fullscreen mode

The form sends the product data to add_product.php using the POST method and supports file uploads through enctype="multipart/form-data".

Number input for product_price with step "0.01" to allow decimal pricing.

And here is the function

function addProduct($conn, $sku, $name, $description, $price, $stock, $isActive, $file)
{
    try {
        $targetDir = "img/";
        $targetFile = $targetDir . basename($file["name"]);

        if (move_uploaded_file($file["tmp_name"], $targetFile)) {
            $stmt = $conn->prepare("INSERT INTO products (sku, name, description, price, stock, image_url, is_active) VALUES (:sku, :name, :description, :price, :stock, :image_url, :is_active)");

            $stmt->bindParam(':sku', $sku);
            $stmt->bindParam(':name', $name);
            $stmt->bindParam(':description', $description);
            $stmt->bindParam(':price', $price);
            $stmt->bindParam(':stock', $stock);
            $stmt->bindParam(':image_url', $targetFile);
            $stmt->bindParam(':is_active', $isActive);

            $stmt->execute();
            return true;
        } else {
            throw new Exception("error while uploading file");
        }
    } catch (PDOException $e) {
        throw new Exception("error at adding product: " . $e->getMessage());
    }
}
Enter fullscreen mode Exit fullscreen mode

Receiving Parameters: The function accepts several parameters:

$conn: This is the database connection object (typically a PDO instance).
$sku, $name, $description, $price, $stock, $isActive: These hold the product details, such as SKU (Stock Keeping Unit), product name, description, price, stock quantity, and whether the product is active or not.

**$file: **This is an array containing file upload details (such as the product image).

Image Upload: The first task inside the function is to handle the image file upload:

It sets the target directory for image uploads to "img/" and constructs the full path of the target file using basename($file["name"]). This extracts the filename of the uploaded file and appends it to the target directory.
The move_uploaded_file() function attempts to move the uploaded file from the temporary location (where it's stored when uploaded) to the desired directory. If successful, it proceeds to the next step. If the file cannot be moved (e.g., due to permission issues or incorrect file paths), it throws an exception with the error message.

Preparing the SQL Statement: If the file upload is successful, the function prepares an SQL INSERT statement:

The query inserts the product details into the products table, specifically into the columns sku, name, description, price, stock, image_url, and is_active.
The image URL is stored in the image_url column, referencing the uploaded file's path.

Binding Parameters:

The bindParam() method binds the values from the function parameters (such as $sku, $name, etc.) to the corresponding placeholders in the SQL query (such as :sku, :name, etc.).
This is done to safely insert data into the database, helping prevent SQL injection attacks by separating the query structure from the actual values.
Executing the SQL Query:

The execute() method runs the prepared SQL statement, inserting the product data into the database.

Return Value:

If everything is successful (file upload and database insertion), the function returns true.
If something goes wrong, such as an error with the database connection or an issue with the SQL query, it catches a PDOException and throws a new exception with the message "Error at adding product, along with the specific error message from the database.

Perfect make sure to add some Products now!!


In an online shop, administrators often need to update or delete product information to ensure that customers see accurate details. This blog post will guide you through creating a PHP script that allows an admin to edit product details and delete products from the database securely. We will cover error handling, form processing, and the overall flow of managing products effectively.

edit_product.php

<?php
require_once 'incall.php';
checkAdmin();

// Check if ID has been gaven
if (isset($_GET['product_id'])) {
    $productId = $_GET['product_id'];

    // return productinfos
    try {
        $stmt = $conn->prepare("SELECT * FROM products WHERE id = :id");
        $stmt->bindParam(':id', $productId);
        $stmt->execute();
        $product = $stmt->fetch(PDO::FETCH_ASSOC);
        // if product not found exit the page
        if (!$product) {
            echo "product not found";
            exit;
        }
    } catch (PDOException $e) {
        echo "error when calling product " . $e->getMessage();
    }

    // check if form has been submitted
    if (isset($_POST['btupdate'])) {
        $name = $_POST['name'];
        $description = $_POST['description'];
        $price = $_POST['price'];
        $stock = $_POST['stock'];
        $isActive = isset($_POST['is_active']) ? 1 : 0;
        $image_url = $product['image_url']; // Keep the old image URL by default

        try {
            editProduct($conn, $productId, $name, $description, $price, $stock, $isActive, $image_url, $_FILES['product_image']);
            header("Location: admin.php");
            exit;
        } catch (Exception $e) {
            echo $e->getMessage();
        }
    }

    // check if delete submitted
    if (isset($_POST['btdelete'])) {
        try {
            deleteProduct($conn, $productId);
            header("Location: admin.php");
            exit;
        } catch (Exception $e) {
            echo $e->getMessage();
        }
    }
}
?>
Enter fullscreen mode Exit fullscreen mode

*Including Required Files and Checking Admin Status:
*

The script starts by including incall.php, which likely contains common functionality (like database connections or helper functions). It then calls checkAdmin() to ensure that the user is an admin before proceeding with product management.

*Checking if a Product ID is Provided:
*

The script checks if a product_id is passed via the URL ($_GET['product_id']). This ID corresponds to the product that will be edited or deleted.

Fetching Product Information:

If a product ID is available, the script prepares an SQL query to fetch the product details from the database.
It binds the product_id to the :id placeholder using bindParam(), which ensures secure parameter binding, and then executes the query.
If the product is found, its details are stored in the $product variable. If the product does not exist, an error message ("product not found") is displayed, and the script terminates with exit; to prevent further actions.
If a database error occurs, it catches the PDOException and displays an error message.

Handling Product Update:

The script checks if the "Update" button (btupdate) was clicked by checking if the form was submitted via POST.
It retrieves the updated product information from the form fields, including name, description, price, stock, and is_active (the checkbox that determines whether the product is active or not).
The product’s existing image URL is initially kept unchanged ($image_url = $product['image_url']) in case the image is not updated.
It then calls the editProduct() function, passing the product's new details and any uploaded image (if provided via $_FILES['product_image']).
If the update is successful, the user is redirected to the admin page (admin.php). If there's an error, the exception is caught and the error message is displayed.

Handling Product Deletion:

The script checks if the "Delete" button (btdelete) was clicked.
If so, it calls the deleteProduct() function, passing the product ID to delete the product from the database.
If the deletion is successful, the user is redirected to the admin page. If an error occurs, it catches the exception and displays the error message.

This PHP script provides a straightforward way for administrators to manage product updates and deletions in an online shop. By following this guide, you can ensure that product information is current, which enhances user experience and trust in your e-commerce platform.

Additionally, by implementing proper error handling, you maintain a professional approach, allowing for debugging and user notifications without exposing sensitive information. The methods used here (prepared statements, session checks, and redirections) contribute to a secure and efficient product management system.

Now create a Form for editing in HTML

edit_product.php

<main>
    <h1>Edit products</h1>

    <form action="edit_product.php?product_id=<?= htmlspecialchars($productId); ?>" method="post" enctype="multipart/form-data">

        <?php if (!empty($product['image_url'])): ?>
            <img src="<?= htmlspecialchars($product['image_url']); ?>" alt="<?= htmlspecialchars($product['name']); ?>" style="max-width: 200px;">
        <?php endif; ?>

        <label for="name">product name:</label>
        <input type="text" name="name" id="name" value="<?= htmlspecialchars($product['name']); ?>" required><br>

        <label for="description">description:</label>
        <textarea name="description" id="description" required><?= htmlspecialchars($product['description']); ?></textarea><br>

        <label for="price">price:</label>
        <input type="number" pattern="[0-9]+" step="0.01" name="price" id="price" value="<?= htmlspecialchars($product['price']); ?>" required><br>

        <label for="stock">stock:</label>
        <input type="number" pattern="[0-9]+" name="stock" id="stock" value="<?= htmlspecialchars($product['stock']); ?>" required><br>

        <label for="is_active">active:</label>
        <input type="checkbox" name="is_active" id="is_active" <?= $product['is_active'] ? 'checked' : ''; ?>><br>

        <label for="product_image">image:</label>
        <input type="file" name="product_image" id="product_image"><br>

        <input type="submit" name="btupdate" value="Aktualisieren">
    </form>

    <!-- Delete Button -->
    <form action="edit_product.php?product_id=<?= htmlspecialchars($productId); ?>" method="post" onsubmit="return confirm('Are you sure you want to delete this?');">
        <input type="submit" name="btdelete" value="DELETE PRODUCT" style="color: red;">
    </form>
</main>
Enter fullscreen mode Exit fullscreen mode

Now lets not forget our Edit and delete functions!

The editProduct function is responsible for updating the details of a specific product in the database. This includes updating the product's name, description, price, stock, active status, and image URL. If a new image is uploaded, the function also handles the file upload process.

The deleteProduct function is designed to remove a product from the database based on its ID.

This PHP code consists of four functions that manage a shopping cart system for an online shop.

functions.php

function editProduct($conn, $productId, $name, $description, $price, $stock, $isActive, $image_url, $file = null)
{
    try {
        // Handle file upload if a new file is provided
        if ($file && $file['size'] > 0) {
            $targetDir = "img/";
            $targetFile = $targetDir . basename($file["name"]);

            if (move_uploaded_file($file["tmp_name"], $targetFile)) {
                $image_url = $targetFile;
            } else {
                throw new Exception("Error while uploading.");
            }
        }

        // Prepare the SQL statement
        $stmt = $conn->prepare("
            UPDATE products SET 
            name = :name, 
            description = :description, 
            price = :price, 
            stock = :stock, 
            is_active = :is_active,
            image_url = :image_url 
            WHERE id = :id
        ");

        // Bind parameters
        $stmt->bindParam(':name', $name);
        $stmt->bindParam(':description', $description);
        $stmt->bindParam(':price', $price);
        $stmt->bindParam(':stock', $stock);
        $stmt->bindParam(':is_active', $isActive);
        $stmt->bindParam(':image_url', $image_url);
        $stmt->bindParam(':id', $productId);

        // Execute the statement
        $stmt->execute();

        return true;
    } catch (PDOException $e) {
        throw new Exception("Error when updating product " . $e->getMessage());
    }
}
Enter fullscreen mode Exit fullscreen mode

This function, editProduct(), is used to update a product's information in a database, including handling image uploads if a new file is provided. It interacts with the database to modify the product's name, description, price, stock, availability status, and image URL. Let’s break it down step by step:

  1. File Upload Handling:
    The function checks if a new image file ($file) has been provided and if its size is greater than 0.
    Target Directory: The image is uploaded to the img/ directory on the server.
    Move Uploaded File: The function attempts to move the uploaded file from its temporary location to the target directory.
    If the file upload is successful, the $image_url is updated with the file path of the new image.
    If the upload fails, an exception is thrown with the message.

  2. SQL Query Preparation:
    After handling the image upload (if any), the function prepares a SQL UPDATE query to modify the product's details in the products table.
    The query updates the following columns:
    name: Product's name.
    description: Product's description.
    price: Product's price.
    stock: Available stock quantity.
    is_active: Whether the product is active.
    image_url: The image file path or URL.

  3. Binding Parameters:
    The function uses bindParam() to safely bind the parameters (such as name, description, etc.) to the SQL query, protecting against SQL injection attacks.
    The :id parameter identifies the product that should be updated, based on its productId.

  4. Executing the SQL Statement:
    The prepared statement is executed, updating the product details in the database.

  5. Exception Handling:
    If any error occurs during the SQL execution (e.g., invalid query or connection issue), a PDOException is caught, and an exception is thrown with a detailed error message indicating the problem
    Return Value:
    The function returns true if the product is successfully updated. If an error occurs (such as a failed file upload or SQL query), an exception is thrown with a relevant error message.

functions.php

function deleteProduct($conn, $productId)
{
    try {
        $stmt = $conn->prepare("DELETE FROM products WHERE id = :id");
        $stmt->bindParam(':id', $productId);
        $stmt->execute();
        return true;
    } catch (PDOException $e) {
        throw new Exception("error when deleting: " . $e->getMessage());
    }
}
Enter fullscreen mode Exit fullscreen mode

SQL Deletion: Prepares a DELETE SQL query to remove a product from the database based on its productId.
Parameter Binding: Safely binds the productId to the query, preventing SQL injection.
Error Handling: Uses a try-catch block to catch database errors and throws an exception with a custom message if something goes wrong.
This function is essential in managing an online store, allowing administrators to remove products from the store's inventory or product listings efficiently and securely.

Its time to make a cart but thats what we're gonna do next time! STAY TUNED

Top comments (0)