PHP and MySQL Shopping Cart Tutorial Using COOKIES

php-shopping-cart-tutorial-using-cookies-1

php-shopping-cart-tutorial-using-cookies-1

Previously, we have learned how to code a shopping cart using PHP SESSIONS. Today, we will learn a second way to do it. We will have a PHP shopping cart tutorial using COOKIES!

Sounds delicious, isn’t it? But the cookie that we will use is not the cookie we eat. Let me explain. In this tutorial, we’ll use the HTTP cookie, also known as the web cookie or browser cookie.

It is usually a small piece of data stored in the user’s browser while the user is using the site. It is designed to be a reliable way for websites to remember useful information, such as shopping cart items, or to record any user activity on a website.

PHP SESSIONS code works and was used by many websites before but nowadays it is more advisable to use cookies for your shopping cart program.

By the way, we’ll also use my favorite front-end framework Bootstrap so that our sample shopping cart script will have a good-looking user interface.

If you’re not familiar with Bootstrap yet, please have a look at our step by step Bootstrap guide.

Contents

Why Use Cookies?

There are several reasons why you should use cookies when creating our shopping cart script. Here are some of the reasons I found useful for us to know.

  1. WooCommerce, a popular eCommerce plugin for WordPress, was previously using PHP sessions for storing cart data. But few years ago, they changed it and are now using cookies. One of the reasons they cited was “To reduce support regarding hosts and session configurations.” I think that’s also a big example and reason why we have to use cookies for storing cart data. See their version 2.0.0 change log her
  2. As explained earlier, cookies are designed to be a reliable mechanism for websites to remember information with certain state like the shopping cart items.
  3. Shopping cart items will stay even if the user closes the browser or shut down and restart his computer. It means the user can be reminded what he was going to buy from your website.

Prepare the database

Database Design

Our database name will be called “shop_cart_cookies_1”, and we will have two (2) tables.
php shopping cart tutorial database design

Create MySQL Tables

You may run the following SQL queries on our “shop_cart_cookies_1” database.

Create the products table. This table will hold products record.

CREATE TABLE IF NOT EXISTS `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(512) NOT NULL,
  `description` text NOT NULL,
  `price` decimal(10,2) NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COMMENT='products that can be added to cart' AUTO_INCREMENT=41 ;

Create product_images table. This table will hold images related to product.

CREATE TABLE IF NOT EXISTS `product_images` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `product_id` int(11) NOT NULL,
  `name` varchar(512) NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='image files related to a product' AUTO_INCREMENT=105 ;

Download sample data

The products and product_images table will not fully work without the sample data and images in the “/uploads/images/” directory.

You’ll have to download the SQL and image files. Use the download button below. What will you get?

Once downloaded, you may import the SQL file using PhpMyAdmin. Put the image files in “/uploads/images/” directory. You are now one step closer to the output shown in section 2.1 above.

Database connection file

Create “config” folder and inside it, create “database.php” file with the following code.

<?php
// used to get mysql database connection
class Database{
 
    // specify your own database credentials
    private $host = "localhost";
    private $db_name = "shop_cart_cookies_1";
    private $username = "root";
    private $password = "";
    public $conn;
 
    // get the database connection
    public function getConnection(){
 
        $this->conn = null;
 
        try{
            $this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
        }catch(PDOException $exception){
            echo "Connection error: " . $exception->getMessage();
        }
 
        return $this->conn;
    }
 
}
?>

Prepare the user interface

Download jQuery and Bootstrap

Download jQuery library here. Create “libs” folder. Inside it, create “js” folder. Put jQuery library inside “js” folder.

Download Bootstrap framework here. Inside “libs” folder, create “css” folder. Put bootstrap library inside “css” folder.

Create layout files

Layout files are needed so we can use the same header and footer code.

Create “layout_head.php” with the following code.

<!DOCTYPE html>
<html lang="en">
<head>
 
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
 
    <title><?php echo isset($page_title) ? $page_title : "The Code of a Ninja"; ?></title>
 
    <!-- Bootstrap CSS -->
    <link href="libs/css/bootstrap/dist/css/bootstrap.css" rel="stylesheet" media="screen">
 
    <!-- HTML5 Shiv and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
    <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
 
    <!-- custom css for users -->
    <link href="libs/css/user.css" rel="stylesheet" media="screen">
 
</head>
<body>
 
    <?php include 'navigation.php'; ?>
 
    <!-- container -->
    <div class="container">
        <div class="row">
 
        <div class="col-md-12">
            <div class="page-header">
                <h1><?php echo isset($page_title) ? $page_title : "The Code of a Ninja"; ?></h1>
            </div>
        </div>

Create “layout_foot.php” with the following code.

        </div>
        <!-- /row -->
 
    </div>
    <!-- /container -->
 
<!-- jQuery library -->
<script src="libs/js/jquery.js"></script>
 
<!-- bootstrap JavaScript -->
<script src="libs/css/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="libs/css/bootstrap/docs-assets/js/holder.js"></script>
 
</body>
</html>

Create navigation.php file and place the following code.

<!-- navbar -->
<div class="navbar navbar-default navbar-static-top" role="navigation">
    <div class="container">
 
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="products.php">XYZ Webstore</a>
        </div>
 
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
 
                <!-- highlight if $page_title has 'Products' word. -->
                <li <?php echo strpos($page_title, "Product")!==false ? "class='active dropdown'" : "class='dropdown'"; ?>>
                    <a href="products.php">Products</a>
                </li>
 
                <li <?php echo $page_title=="Cart" ? "class='active'" : ""; ?> >
                    <a href="cart.php">
                        <?php
                        // count items in the cart
                        $cookie = isset($_COOKIE['cart_items_cookie']) ? $_COOKIE['cart_items_cookie'] : "";
                        $cookie = stripslashes($cookie);
                        $saved_cart_items = json_decode($cookie, true);
                        $cart_count=count($saved_cart_items);
                        ?>
                        Cart <span class="badge" id="comparison-count"><?php echo $cart_count; ?></span>
                    </a>
                </li>
            </ul>
 
        </div><!--/.nav-collapse -->
 
    </div>
</div>
<!-- /navbar -->

Add Custom CSS

Inside “libs/css” directory, create user.css with the following code inside it.

.text-align-center{ text-align:center; }
.f-w-b{ font-weight:bold; }
.display-none{ display:none; }

.w-5-pct{ width:5%; }
.w-10-pct{ width:10%; }
.w-15-pct{ width:15%; }
.w-20-pct{ width:20%; }
.w-25-pct{ width:25%; }
.w-30-pct{ width:30%; }
.w-35-pct{ width:35%; }
.w-40-pct{ width:40%; }
.w-45-pct{ width:45%; }
.w-50-pct{ width:50%; }
.w-55-pct{ width:55%; }
.w-60-pct{ width:60%; }
.w-65-pct{ width:65%; }
.w-70-pct{ width:70%; }
.w-75-pct{ width:75%; }
.w-80-pct{ width:80%; }
.w-85-pct{ width:85%; }
.w-90-pct{ width:90%; }
.w-95-pct{ width:95%; }
.w-100-pct{ width:100%; }

.m-t-0px{ margin-top:0px; }
.m-b-10px{ margin-bottom:10px; }
.m-b-20px{ margin-bottom:20px; }
.m-b-30px{ margin-bottom:30px; }
.m-b-40px{ margin-bottom:40px; }

.stock-text {
    font-weight: bold;
    color: #008a00;
}

.stock-text-red{
    font-weight:bold;
    color:#b12704;
}

.product-detail {
    font-weight: bold;
    margin: 0 0 5px 0;
}

.blueimp-gallery>.prev, .blueimp-gallery>.next{ border:none; }

.update-quantity-form {
    width: 150px;
    float: left;
    margin: 0 10px 0 0;
}

.cart-row {
    border-bottom: thin solid #f1f1f1;
    overflow: hidden;
    width: 100%;
    padding: 20px 0 20px 0;
}

.product-link{
    color:#000000;
}

.product-link:hover{
    color:#000000;
    text-decoration:none;
}

.product-img-thumb {
    margin: 0 0 10px 0;
    width: 100%;
    cursor: pointer;
}

Display Products

Create products.php

Now we are going to start displaying products from the database. Create products.php with the following basic code.

<?php
// read items in the cart
$cookie = isset($_COOKIE['cart_items_cookie']) ? $_COOKIE['cart_items_cookie'] : "";
$cookie = stripslashes($cookie);
$saved_cart_items = json_decode($cookie, true);
 
// to prevent null value
$saved_cart_items=$saved_cart_items==null ? array() : $saved_cart_items;
 
// set page title
$page_title="Products";
 
// page header html
include 'layout_head.php';
 
// contents will be here 
 
// layout footer code
include 'layout_foot.php';
?>

Important Note: PHP cookies must be used before any HTML output. This will prevent failure of cookies to be read or write.

Include PHP Classes

Put the following code before the “$page_title” code of the previous section.

// connect to database
include 'config/database.php';

// include objects
include_once "objects/product.php";
include_once "objects/product_image.php";

Create “product” object file

Create “objects” folder. Inside it, create product.php file with the following code.

<?php
// 'product' object
class Product{
 
    // database connection and table name
    private $conn;
    private $table_name="products";
 
    // object properties
    public $id;
    public $name;
    public $price;
    public $description;
    public $category_id;
    public $category_name;
    public $timestamp;
 
    // constructor
    public function __construct($db){
        $this->conn = $db;
    }
}

Create “product image” object file

Create product_image.php file inside “objects” folder.

<?php
// 'product image' object
class ProductImage{
 
    // database connection and table name
    private $conn;
    private $table_name = "product_images";
 
    // object properties
    public $id;
    public $product_id;
    public $name;
    public $timestamp;
 
    // constructor
    public function __construct($db){
        $this->conn = $db;
  

Connect to the database

Put the following code after the code on the previous section.

// get database connection
$database = new Database();
$db = $database->getConnection();
 
// initialize objects
$product = new Product($db);
$product_image = new ProductImage($db);

Initialize action and pagination

Put the following code after the code on the previous section.

// to prevent undefined index notice
$action = isset($_GET['action']) ? $_GET['action'] : "";

// for pagination purposes
$page = isset($_GET['page']) ? $_GET['page'] : 1; // page is the current page, if there's nothing set, default is page 1
$records_per_page = 6; // set records or rows of data per page
$from_record_num = ($records_per_page * $page) - $records_per_page; // calculate for the query LIMIT clause

Display messages based on action

We’ll display messages basedon given action. Put the following code after “include ‘layout_head.php’;” code.

]
echo "<div class='col-md-12'>";
    if($action=='added'){
        echo "<div class='alert alert-info'>";
            echo "Product was added to your cart!";
        echo "</div>";
    }
 
    if($action=='exists'){
        echo "<div class='alert alert-info'>";
            echo "Product already exists in your cart!";
        echo "</div>";
    }
echo "</div>";

Request data from the database

Request data from the database. Put the following code after the code on the previous section.

// read all products in the database
$stmt=$product->read($from_record_num, $records_per_page);
 
// count number of retrieved products
$num = $stmt->rowCount();
 
// if products retrieved were more than zero
if($num>0){
    // needed for paging
    $page_url="products.php?";
    $total_rows=$product->count();
 
    // show products
    include_once "read_products_template.php";
}
 
// tell the user if there's no products in the database
else{
    echo "<div class='col-md-12'>";
        echo "<div class='alert alert-danger'>No products found.</div>";
    echo "</div>";
}

Add “read” and “count” methods

The previous section will not work without the following code inside “objects/product.php” object file.

// read all products
function read($from_record_num, $records_per_page){
 
    // select all products query
    $query = "SELECT
                id, name, description, price
            FROM
                " . $this->table_name . "
            ORDER BY
                created DESC
            LIMIT
                ?, ?";
 
    // prepare query statement
    $stmt = $this->conn->prepare( $query );
 
    // bind limit clause variables
    $stmt->bindParam(1, $from_record_num, PDO::PARAM_INT);
    $stmt->bindParam(2, $records_per_page, PDO::PARAM_INT);
 
    // execute query
    $stmt->execute();
 
    // return values
    return $stmt;
}
 
// used for paging products
public function count(){
 
    // query to count all product records
    $query = "SELECT count(*) FROM " . $this->table_name;
 
    // prepare query statement
    $stmt = $this->conn->prepare( $query );
 
    // execute query
    $stmt->execute();
 
    // get row value
    $rows = $stmt->fetch(PDO::FETCH_NUM);
 
    // return count
    return $rows[0];
}

Template to display products

The previous section won’t work without “read_products_template.php“, so create that file and put the following code.

<?php
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
    extract($row);
 
    // creating box
    echo "<div class='col-md-4 m-b-20px'>";
 
        // product id for javascript access
        echo "<div class='product-id display-none'>{$id}</div>";
 
        echo "<a href='product.php?id={$id}' class='product-link'>";
            // select and show first product image
            $product_image->product_id=$id;
            $stmt_product_image=$product_image->readFirst();
 
            while ($row_product_image = $stmt_product_image->fetch(PDO::FETCH_ASSOC)){
                echo "<div class='m-b-10px'>";
                    echo "<img src='uploads/images/{$row_product_image['name']}' class='w-100-pct' />";
                echo "</div>";
            }
 
            // product name
            echo "<div class='product-name m-b-10px'>{$name}</div>";
        echo "</a>";
 
        // add to cart button
        echo "<div class='m-b-10px'>";
            if(array_key_exists($id, $saved_cart_items)){
                echo "<a href='cart.php' class='btn btn-success w-100-pct'>";
                    echo "Update Cart";
                echo "</a>";
            }else{
                echo "<a href='add_to_cart.php?id={$id}&page={$page}' class='btn btn-primary w-100-pct'>Add to Cart</a>";
            }
        echo "</div>";
 
    echo "</div>";
}
 
include_once "paging.php";
?>

Add “readFirst()” method

Add “readFirst()” method in “objects/product_image.php” file. The previous section will not work without it.

// read the first product image related to a product
function readFirst(){
 
    // select query
    $query = "SELECT id, product_id, name
            FROM " . $this->table_name . "
            WHERE product_id = ?
            ORDER BY name DESC
            LIMIT 0, 1";
 
    // prepare query statement
    $stmt = $this->conn->prepare( $query );
 
    // sanitize
    $this->id=htmlspecialchars(strip_tags($this->id));
 
    // bind prodcut id variable
    $stmt->bindParam(1, $this->product_id);
 
    // execute query
    $stmt->execute();
 
    // return values
    return $stmt;
}

Make “add to cart” button work

<script>
$(document).ready(function(){
    // add to cart button listener
    $('.add-to-cart-form').on('submit', function(){
 
        // info is in the table / single product layout
        var id = $(this).find('.product-id').text();
        var quantity = $(this).find('.cart-quantity').val();
 
        // redirect to add_to_cart.php, with parameter values to process the request
        window.location.href = "add_to_cart.php?id=" + id + "&quantity=" + quantity;
        return false;
    });
});
</script>

Create pagination file

The previous section won’t work without the paging.php file. Create paging.php with the following code.

<?php
echo "<div class='col-md-12'>";
 
    echo "<ul class='pagination m-b-20px m-t-0px'>";
 
    // button for first page
    if($page>1){
        echo "<li><a href='{$page_url}' title='Go to the first page.'>";
            echo "First Page";
        echo "</a></li>";
    }
 
    $total_pages = ceil($total_rows / $records_per_page);
 
    // range of links to show
    $range = 2;
 
    // display links to 'range of pages' around 'current page'
    $initial_num = $page - $range;
    $condition_limit_num = ($page + $range)  + 1;
 
    for ($x=$initial_num; $x<$condition_limit_num; $x++) {
 
        // be sure '$x is greater than 0' AND 'less than or equal to the $total_pages'
        if (($x > 0) && ($x <= $total_pages)) {
 
            // current page
            if ($x == $page) {
                echo "<li class='active'><a href=\"#\">$x <span class=\"sr-only\">(current)</span></a></li>";
            }
 
            // not current page
            else {
                echo "<li><a href='{$page_url}page=$x'>$x</a></li>";
            }
        }
    }
 
    // button for last page
    if($page<$total_pages){
        echo "<li>";
            echo "<a href='" . $page_url . "page={$total_pages}' title='Last page is {$total_pages}.'>";
                echo "Last Page";
            echo "</a>";
        echo "</li>";
    }
 
    echo "</ul>";
echo "</div>";
?>

How to add to cart?

Create add_to_cart.php

Create add_to_cart.php file because when the “Add to cart” button was clicked, that file with the following code inside will be executed.

<?php
 
// get the product id
$id = isset($_GET['id']) ? $_GET['id'] : "";
$quantity = isset($_GET['quantity']) ? $_GET['quantity'] : 1;
$page = isset($_GET['page']) ? $_GET['page'] : 1;
 
// make quantity a minimum of 1
$quantity=$quantity<=0 ? 1 : $quantity;
 
// add new item on array
$cart_items[$id]=array(
    'quantity'=>$quantity
);
 
// read
$cookie = isset($_COOKIE['cart_items_cookie']) ? $_COOKIE['cart_items_cookie'] : "";
$cookie = stripslashes($cookie);
$saved_cart_items = json_decode($cookie, true);
 
// if $saved_cart_items is null, prevent null error
if(!$saved_cart_items){
    $saved_cart_items=array();
}
 
// check if the item is in the array, if it is, do not add
if(array_key_exists($id, $saved_cart_items)){
    // redirect to product list and tell the user it was added to cart
    header('Location: product.php?id=' . $id . '&action=exists');
}
 
// else, add the item to the array
else{
    // if cart has contents
    if(count($saved_cart_items)>0){
        foreach($saved_cart_items as $key=>$value){
            // add old item to array, it will prevent duplicate keys
            $cart_items[$key]=array(
                'quantity'=>$value['quantity']
            );
        }
    }
 
    // put item to cookie
    $json = json_encode($cart_items, true);
    setcookie("cart_items_cookie", $json, time() + (86400 * 30), '/'); // 86400 = 1 day
    $_COOKIE['cart_items_cookie']=$json;
 
    // redirect to product list and tell the user it was added to cart
    header('Location: product.php?id=' . $id . '&action=added');
}
die();
?>

Create cart.php

Create cart.php with the following basic code.

<?php
// read cookie contents
$cookie = isset($_COOKIE['cart_items_cookie']) ? $_COOKIE['cart_items_cookie'] : "";
$cookie = stripslashes($cookie);
$saved_cart_items = json_decode($cookie, true);
 
// connect to database
include 'config/database.php';
 
// include objects
include_once "objects/product.php";
include_once "objects/product_image.php";
 
// get database connection
$database = new Database();
$db = $database->getConnection();
 
// initialize objects
$product = new Product($db);
$product_image = new ProductImage($db);
 
// set page title
$page_title="Cart";
 
// include page header html
include 'layout_head.php';
 
// contents will be here 
 
// layout footer
include 'layout_foot.php';
?>

Display message based on action

We’ll display message on cart.php based on given action. Put the following code after “include ‘layout_head.php’;” of the previous section.

$action = isset($_GET['action']) ? $_GET['action'] : "";
 
echo "<div class='col-md-12'>";
    if($action=='removed'){
        echo "<div class='alert alert-info'>";
            echo "Product was removed from your cart!";
        echo "</div>";
    }
 
    else if($action=='quantity_updated'){
        echo "<div class='alert alert-info'>";
            echo "Product quantity was updated!";
        echo "</div>";
    }
 
    else if($action=='empty_cart'){
        echo "<div class='alert alert-danger'>";
            echo "Cart was emptied!";
        echo "</div>";
    }
 
    else if($action=='exists'){
        echo "<div class='alert alert-info'>";
            echo "Product already exists in your cart!";
        echo "</div>";
    }
echo "</div>";

Display cart items

Put the following code based on the code of the previous section.

if(count($saved_cart_items)>0){
 
    echo "<div class='col-md-12'>";
        // remove all cart contents
        echo "<div class='right-button-margin' style='overflow:hidden;'>";
            echo "<button class='btn btn-default pull-right' id='empty-cart'>Empty Cart</button>";
        echo "</div>";
    echo "</div>";
 
    // get the product ids
    $ids = array();
    foreach($saved_cart_items as $id=>$name){
        array_push($ids, $id);
    }
 
    $stmt=$product->readByIds($ids);
 
    $total=0;
    $item_count=0;
 
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
        extract($row);
 
        $quantity=$saved_cart_items[$id]['quantity'];
        $sub_total=$price*$quantity;
 
        // =================
        echo "<div class='cart-row'>";
            echo "<div class='col-md-8'>";
 
                echo "<div class='product-name m-b-10px'>";
                    echo "<h4>{$name}</h4>";
                echo "</div>";
 
                // update quantity
                echo "<form class='update-quantity-form w-200-px'>";
                    echo "<div class='product-id' style='display:none;'>{$id}</div>";
                    echo "<input type='number' value='{$quantity}' name='quantity' class='form-control cart-quantity m-b-10px cart-quantity-dropdown' min='1' />";
                    echo "<button class='btn btn-default update-quantity' type='submit'>Update</button>";
                echo "</form>";
 
                // delete from cart
                echo "<a href='remove_from_cart.php?id={$id}' class='btn btn-default'>";
                    echo "Delete";
                echo "</a>";
            echo "</div>";
 
            echo "<div class='col-md-4'>";
                echo "<h4>$" . number_format($price, 2, '.', ',') . "</h4>";
            echo "</div>";
        echo "</div>";
        // =================
 
        $item_count += $quantity;
        $total+=$sub_total;
    }
 
    echo "<div class='col-md-8'></div>";
    echo "<div class='col-md-4'>";
        echo "<div class='cart-row'>";
            echo "<h4 class='m-b-10px'>Total ({$item_count} items)</h4>";
            echo "<h4>$" . number_format($total, 2, '.', ',') . "</h4>";
            echo "<a href='checkout.php' class='btn btn-success m-b-10px'>";
                echo "<span class='glyphicon glyphicon-shopping-cart'></span> Proceed to Checkout";
            echo "</a>";
        echo "</div>";
    echo "</div>";
 
}
 
else{
    echo "<div class='col-md-12'>";
        echo "<div class='alert alert-danger'>";
            echo "No products found in your cart!";
        echo "</div>";
    echo "</div>";
}

Read products by IDs

The previous section will not work without the following “readByIds()” method inside “objects/product.php” file.

// read all product based on product ids included in the $ids variable
// reference http://stackoverflow.com/a/10722827/827418
public function readByIds($ids){
 
    $ids_arr = str_repeat('?,', count($ids) - 1) . '?';
 
    // query to select products
    $query = "SELECT id, name, price FROM " . $this->table_name . " WHERE id IN ({$ids_arr}) ORDER BY name";
 
    // prepare query statement
    $stmt = $this->conn->prepare($query);
 
    // execute query
    $stmt->execute($ids);
 
    // return values from database
    return $stmt;
}

How to update cart?

Update cart quantity with JavaScript

We have the ‘update’ button on cart.php file. When that button was clicked, a javascript code is triggered. Put the following code inside “$(document).ready(function(){” of layout_foot.php file.

// update quantity button listener
$('.update-quantity-form').on('submit', function(){
 
    // get basic information for updating the cart
    var id = $(this).find('.product-id').text();
    var quantity = $(this).find('.cart-quantity').val();
 
    // redirect to update_quantity.php, with parameter values to process the request
    window.location.href = "update_quantity.php?id=" + id + "&quantity=" + quantity;
    return false;
});

PHP script to update cart

The previous section will not work without the update_quantity.php file with the following code inside it.

<?php
// get the product id
$id = isset($_GET['id']) ? $_GET['id'] : 1;
$quantity = isset($_GET['quantity']) ? $_GET['quantity'] : "";
 
// make quantity a minimum of 1
$quantity=$quantity<=0 ? 1 : $quantity;
 
// read cookie
$cookie = $_COOKIE['cart_items_cookie'];
$cookie = stripslashes($cookie);
$saved_cart_items = json_decode($cookie, true);
 
// remove the item from the array
unset($saved_cart_items[$id]);
 
// delete cookie value
setcookie("cart_items_cookie", "", time()-3600);
 
// add the item with updated quantity
$saved_cart_items[$id]=array(
    'quantity'=>$quantity
);
 
// enter new value
$json = json_encode($saved_cart_items, true);
setcookie("cart_items_cookie", $json, time() + (86400 * 30), '/'); // 86400 = 1 day
$_COOKIE['cart_items_cookie']=$json;
 
// redirect to product list and tell the user it was added to cart
header('Location: cart.php?action=quantity_updated&id=' . $id);
die();
?>

How to remove product on cart?

We have the ‘remove’ button on cart.php file. When that button was clicked, the remove_from_cart.php file with the following code will be executed.

<?php
// get the product id
$id = isset($_GET['id']) ? $_GET['id'] : "";
 
// read
$cookie = $_COOKIE['cart_items_cookie'];
$cookie = stripslashes($cookie);
$saved_cart_items = json_decode($cookie, true);
 
// remove the item from the array
unset($saved_cart_items[$id]);
 
// delete cookie value
unset($_COOKIE["cart_items_cookie"]);
 
// empty value and expiration one hour before
setcookie("cart_items_cookie", "", time() - 3600);
 
// enter new value
$json = json_encode($saved_cart_items, true);
setcookie("cart_items_cookie", $json, time() + (86400 * 30), '/'); // 86400 = 1 day
$_COOKIE['cart_items_cookie']=$json;
 
// redirect to product list and tell the user it was added to cart
header('Location: cart.php?action=removed&id=' . $id);
die();
?>

Create the checkout page

The checkout page looks like the cart page but the items cannot be updated or removed. It just like the summary of orders. Create checkout.php with the following code.

<?php
// read cookie contents
$cookie = isset($_COOKIE['cart_items_cookie']) ? $_COOKIE['cart_items_cookie'] : "";
$cookie = stripslashes($cookie);
$saved_cart_items = json_decode($cookie, true);
 
// connect to database
include 'config/database.php';
 
// include objects
include_once "objects/product.php";
include_once "objects/product_image.php";
 
// get database connection
$database = new Database();
$db = $database->getConnection();
 
// initialize objects
$product = new Product($db);
$product_image = new ProductImage($db);
 
// set page title
$page_title="Checkout";
 
// include page header html
include 'layout_head.php';
 
if(count($saved_cart_items)>0){
 
    // get the product ids
    $ids = array();
    foreach($saved_cart_items as $id=>$name){
        array_push($ids, $id);
    }
 
    $stmt=$product->readByIds($ids);
 
    $total=0;
    $item_count=0;
 
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
        extract($row);
 
        $quantity=$saved_cart_items[$id]['quantity'];
        $sub_total=$price*$quantity;
 
        //echo "<div class='product-id' style='display:none;'>{$id}</div>";
        //echo "<div class='product-name'>{$name}</div>";
 
        // =================
        echo "<div class='cart-row'>";
            echo "<div class='col-md-8'>";
 
                echo "<div class='product-name m-b-10px'><h4>{$name}</h4></div>";
                echo $quantity>1 ? "<div>{$quantity} items</div>" : "<div>{$quantity} item</div>";
 
            echo "</div>";
 
            echo "<div class='col-md-4'>";
                echo "<h4>$" . number_format($price, 2, '.', ',') . "</h4>";
            echo "</div>";
        echo "</div>";
        // =================
 
        $item_count += $quantity;
        $total+=$sub_total;
    }
 
    // echo "<div class='col-md-8'></div>";
    echo "<div class='col-md-12 text-align-center'>";
        echo "<div class='cart-row'>";
            if($item_count>1){
                echo "<h4 class='m-b-10px'>Total ({$item_count} items)</h4>";
            }else{
                echo "<h4 class='m-b-10px'>Total ({$item_count} item)</h4>";
            }
            echo "<h4>$" . number_format($total, 2, '.', ',') . "</h4>";
            echo "<a href='place_order.php' class='btn btn-lg btn-success m-b-10px'>";
                echo "<span class='glyphicon glyphicon-shopping-cart'></span> Place Order";
            echo "</a>";
        echo "</div>";
    echo "</div>";
 
}
 
else{
    echo "<div class='col-md-12'>";
        echo "<div class='alert alert-danger'>";
            echo "No products found in your cart!";
        echo "</div>";
    echo "</div>";
}
 
include 'layout_foot.php';
?>

Create place_order.php

We’ll use this file to show a “thank you” message and remove all items in the cart.

<?php
// you can do a lot more processing here but for now,
// we'll just empty the cart contents and redirect to a 'thank you' page
header('Location: empty_cart.php?redirect_to=thank_you');
die();
?>

Create empty_cart.php

This file will remove the contents of our cart once the order has been placed. Create empty_cart.php file. Place the following code.

<?php
header('Expires: Sun, 01 Jan 2014 00:00:00 GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', FALSE);
header('Pragma: no-cache');
 
// read
$cookie = $_COOKIE['cart_items_cookie'];
$cookie = stripslashes($cookie);
$saved_cart_items = json_decode($cookie, true);
 
// remove values
unset($saved_cart_items);
 
// delete cookie value
unset($_COOKIE["cart_items_cookie"]);
 
// empty value and expiration one hour before
setcookie("cart_items_cookie", "", time() - 3600);
 
// enter empty value
$json = json_encode($saved_cart_items, true);
setcookie("cart_items_cookie", $json, time() + (86400 * 30), '/'); // 86400 = 1 day
$_COOKIE['cart_items_cookie']=$json;
 
// redirect
$redirect_to=isset($_GET['redirect_to']) ? $_GET['redirect_to'] : "";
 
// redirect to thank you page
if($redirect_to=="thank_you"){
    header('Location: thank_you.php');
}
 
// redirect to cart
else{
    header('Location: cart.php?action=empty_cart');
}
die();
?>

Create Thank You Page

Once cart was emptied with parameter “redirect_to=thank_you” (like the one on the previous section), it will be redirected to this page.

<?php
// set page title
$page_title="Thank You!";
 
// include page header html
include 'layout_head.php';
 
echo "<div class='col-md-12'>";
    echo "<div class='alert alert-success'>";
        echo "Order has been placed, thank you!";
    echo "</div>";
echo "</div>";
 
include 'layout_foot.php';
?>

How to make the product page?

Create product.php

Create product.php with the following basic code.

<?php
// read items in the cart
$cookie = isset($_COOKIE['cart_items_cookie']) ? $_COOKIE['cart_items_cookie'] : "";
$cookie = stripslashes($cookie);
$saved_cart_items = json_decode($cookie, true);
 
// include classes
include_once "config/database.php";
include_once "objects/product.php";
include_once "objects/product_image.php";
 
// get database connection
$database = new Database();
$db = $database->getConnection();
 
// initialize objects
$product = new Product($db);
$product_image = new ProductImage($db);
 
// include page header HTML
include_once 'layout_head.php';
 
// content will be here
 
// include page footer HTML
include_once 'layout_foot.php';
?>

Read product details

Put the following code after “$product_image = new ProductImage($db);” code of the previous section.

// get ID of the product to be edited
$id = isset($_GET['id']) ? $_GET['id'] : die('ERROR: missing ID.');
 
// set the id as product id property
$product->id = $id;
 
// to read single record product
$product->readOne();
 
// set page title
$page_title = $product->name;

Read one product method

The previous section will not work without the “readOne()” method. Add the following method inside “objects/product.php” file.

// used when filling up the update product form
function readOne(){
 
    // query to select single record
    $query = "SELECT
                name, description, price
            FROM
                " . $this->table_name . "
            WHERE
                id = ?
            LIMIT
                0,1";
 
    // prepare query statement
    $stmt = $this->conn->prepare( $query );
 
    // sanitize
    $this->id=htmlspecialchars(strip_tags($this->id));
 
    // bind product id value
    $stmt->bindParam(1, $this->id);
 
    // execute query
    $stmt->execute();
 
    // get row values
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 
    // assign retrieved row value to object properties
    $this->name = $row['name'];
    $this->description = $row['description'];
    $this->price = $row['price'];
}

Display product thumbnails

When these product thumbnails hovered, it displays a larger version of the image. It is Amazon-style. Put the following code after the previous section’s code.

// set product id
$product_image->product_id=$id;
 
// read all related product image
$stmt_product_image = $product_image->readByProductId();
 
// count all relatd product image
$num_product_image = $stmt_product_image->rowCount();
 
echo "<div class='col-md-1'>";
    // if count is more than zero
    if($num_product_image>0){
        // loop through all product images
        while ($row = $stmt_product_image->fetch(PDO::FETCH_ASSOC)){
            // image name and source url
            $product_image_name = $row['name'];
            $source="uploads/images/{$product_image_name}";
            echo "<img src='{$source}' class='product-img-thumb' data-img-id='{$row['id']}' />";
        }
    }else{ echo "No images."; }
echo "</div>";

Read images related to product

The previous section section will not work without the “readByProductId()” method inside “objects/product_image.php” file.

// read all product image related to a product
function readByProductId(){
 
    // select query
    $query = "SELECT id, product_id, name
            FROM " . $this->table_name . "
            WHERE product_id = ?
            ORDER BY name ASC";
 
    // prepare query statement
    $stmt = $this->conn->prepare( $query );
 
    // sanitize
    $this->product_id=htmlspecialchars(strip_tags($this->product_id));
 
    // bind prodcut id variable
    $stmt->bindParam(1, $this->product_id);
 
    // execute query
    $stmt->execute();
 
    // return values
    return $stmt;
}

Display product image

Only one product image are displayed at a time. This part displays the larger product image based on the hovered product thumbnail. Put the following code after the previous section’s code.

echo "<div class='col-md-4' id='product-img'>";
 
    // read all related product image
    $stmt_product_image = $product_image->readByProductId();
    $num_product_image = $stmt_product_image->rowCount();
 
    // if count is more than zero
    if($num_product_image>0){
        // loop through all product images
        $x=0;
        while ($row = $stmt_product_image->fetch(PDO::FETCH_ASSOC)){
            // image name and source url
            $product_image_name = $row['name'];
            $source="uploads/images/{$product_image_name}";
            $show_product_img=$x==0 ? "display-block" : "display-none";
            echo "<a href='{$source}' target='_blank' id='product-img-{$row['id']}' class='product-img {$show_product_img}'>";
                echo "<img src='{$source}' style='width:100%;' />";
            echo "</a>";
            $x++;
        }
    }else{ echo "No images."; }
echo "</div>";

Make image hover work

Put the following jQuery code inside “$(document).ready(function(){” of layout_foot.php file.

// change product image on hover
$(document).on('mouseenter', '.product-img-thumb', function(){
    var data_img_id = $(this).attr('data-img-id');
    $('.product-img').hide();
    $('#product-img-'+data_img_id).show();
});

Display product details

This part display product price, description and category. Put the following code after the previous section’s code.

echo "<div class='col-md-5'>";
 
    echo "<div class='product-detail'>Price:</div>";
    echo "<h4 class='m-b-10px price-description'>$" . number_format($product->price, 2, '.', ',') . "</h4>";
 
    echo "<div class='product-detail'>Product description:</div>";
    echo "<div class='m-b-10px'>";
        // make html
        $page_description = htmlspecialchars_decode(htmlspecialchars_decode($product->description));
 
        // show to user
        echo $page_description;
    echo "</div>";
 
    echo "<div class='product-detail'>Product category:</div>";
    echo "<div class='m-b-10px'>{$product->category_name}</div>";
 
echo "</div>";

Render ‘Cart’ button

Now we will display ‘Add to cart’ button if the product is not yet added to cart. Else, we will display ‘update cart’ button.

echo "<div class='col-md-2'>";
 
    // to prevent null value
    $saved_cart_items=$saved_cart_items==null ? array() : $saved_cart_items;
 
    // if product was already added in the cart
    if(array_key_exists($id, $saved_cart_items)){
        echo "<div class='m-b-10px'>This product is already in your cart.</div>";
        echo "<a href='cart.php' class='btn btn-success w-100-pct'>";
            echo "Update Cart";
        echo "</a>";
 
    }
 
    // if product was not added to the cart yet
    else{
 
        echo "<form class='add-to-cart-form'>";
            // product id
            echo "<div class='product-id display-none'>{$id}</div>";
 
            echo "<div class='m-b-10px f-w-b'>Quantity:</div>";
            echo "<input type='number' value='1' class='form-control m-b-10px cart-quantity' min='1' />";
 
            // enable add to cart button
            echo "<button style='width:100%;' type='submit' class='btn btn-primary add-to-cart m-b-10px'>";
                echo "<span class='glyphicon glyphicon-shopping-cart'></span> Add to cart";
            echo "</button>";
 
        echo "</form>";
    }
echo "</div>";

Download source code

You can get the source code by following the whole, well-detailed tutorial above. But isn’t it more convenient if you can just download the complete source code we used, and play around with it?

List of features

There’s a small fee in getting the complete source code, it is small compared to the value or skill upgrade it can bring you, income you can get from your website project or business, and precious time you save.

FEATURESLEVEL 1 Source codeLEVEL 2 Source code
List all products from the MySQL databaseYESYES
Pagination of productsYESYES
Add to cart action buttonYESYES
Remove from the cart action buttonYESYES
Update cart quantityYESYES
Checkout PageYESYES
Place order / Thank you pageYESYES
Amazon-style product details pageYESYES
Change image on hover of thumbnailYESYES
Show message about a product added to cartYESYES
Show message about a product removed from cartYESYES
Navigation bar highlights which page is selectedYESYES
Cart link shows the count of products added to the cartYESYES
Show message if no products found in databaseYESYES
Show message if no product found in the cartYESYES
Cart page that lists all products added to cartYESYES
Auto compute the total cost of all products added to the cartYESYES
The navigation bar has a drop down of product categoriesNOYES
Highlight selected category in the dropdownNOYES
Categories are retrieved from the databaseNOYES
Show products by categoryNOYES
List products under a category with paginationNOYES
Search productNOYES
Search results with paginationNOYES
Search box located on the upper right corner of the navigation barNOYES
Search box requires search term before clicking the search buttonNOYES
Quantity text box beside the add to cart buttonNOYES
Quantity text box required to have a minimum value of 1NOYES
Quantity text box required to be a number, negative value not allowedNOYES
Remember the page number where the user clicked the “Add to cart” buttonNOYES
Quantity drop-down options based on available stockNOYES
Well formatted money valueNOYES
Product image viewable in a lightbox popupNOYES
Shows number of stock leftNOYES
Stock decreases once checked outNOYES
Empty cart button with confirmation popupNOYES
Show price, category, and stocks left on the product list pageNOYES
Bootstrap enabled UIYESYES
Used PDO bindParam() to prevent SQL injection in MySQL queriesYESYES
Used PHP htmlspecialchars() to prevent XSS attacksYESYES
Free support and source code updates1 year1 year

What people say?

I’m so glad that this code delights other people. The following are some of them from the comments section!

★★★★★ “Hey Mike, my name is Leonardo from Argentina. I’ve been reading your blog since like 4 months from now, and I really must say: your tutorials are very good, they has helped me in many of my works… Well, thank you very much man. I really admire your work.” ~ Leonardo

★★★★★ “Man, your tut’s are awesome. Im so glad ive found your blog. Big respect!” ~ Milos

★★★★★ “I bought your level-2 source code and it was so good, very big help for me. It was worth it. Thank you very much!” ~ Ashley Deanna Plata

★★★★★ “Hello, This is a great script and I have paid 6.99 for your work (it Worth it).” ~ Louis Blais

★★★★★ “Words can’t express how grateful I am for the work and the articles you post, had some troubles with doing somethings but your articles as per usual hit the hammer right on the head. They are a great way for expanding upon later too!” ~ Jeremy Smith

Need more features?

We have two more source codes related to our tutorial above.

PHP Shopping Cart Module. It has several features you will enjoy learning. Some examples: how to handle the users, shopping cart, and ordering using the PHP & MySQL technology. Click here to learn more.

PHP Shopping Cart SYSTEM. Many of you requested this source code. You needed a shopping cart system with user management (admin/merchant and customer), product management, category management, order management, and more features. Click here to learn more.

What’s Next?

We just learned how to code an online shopping cart from scratch using PHP and COOKIES. But did you know that we can create almost the same functions using plain PHP and MySQL?

If you’re excited to learn this new concept, let us go to the next tutorial: PHP Shopping Cart Tutorial using MySQL Database

Related Tutorials

We listed all our high quality full-stack web development tutorials here: Click here.

Some Notes

Found An Issue?


If you found a problem with this code, please send us an email. Before you send an email, please read our our code of conduct. Our team's email address is [email protected]


Please be descriptive about your issue. Please provide the error messages, screenshots (or screen recording) and your test URL. Thanks!


Subscribe to CodeOfaNinja


Receive valuable web development tutorials to your email. Subscribe now for FREE!



Thank You!

Thanks for reading this PHP shopping cart tutorial using cookies!

By Mike Dalisay

I'm Mike Dalisay, a pro web developer since 2010. I love web development. Improving our tutorials and source codes makes me happy. Do you want to suggest an edit to our tutorial? Got something to ask about our source codes? You may use our comments section below or email our team at [email protected]

35 comments

  1. Hi Mike,

    Great tutorial. But I dunno if it’s an issue on my end or in the code. I was checking out your Level 1 Demo (on this site) and even tho I added 4 or so items, the cart only showed one item (the first one I added). How to solve this?

    Many thanks!

    1. Hi @disqus_1JzSfjR2zY , I checked our demo and it is working fine. I tried to add 4 items in the cart and it counts to 4.

      Would you show us your code and test URL? You can send it to my email as well so we can examine. My email address is [email protected]

  2. Hi Mike, I am having an issue…products get added to the cart but on cart.php it only shows one product? Thanks

      1. Hi Mike,

        http://localtarian.nyc/app/cart/cart.php is exactly as yours (what’s happening here is nothing is being added to the cart —or at least its not showing up)

        And my integration is at http://localtarian.nyc/app/cook.php?id=2 (once you’re on the page, click menu to add to the cart, and cart is at cart.php).

        My assumption with both is there’s something incorrect here:

        if(count($saved_cart_items)>0){

        // get the product ids

        $ids = “”;

        foreach($saved_cart_items as $id=>$dish_name){

        $ids = $ids . $id . “,”;

        }

        And thus, WHERE id in (`ids})”

        // remove the last comma

        $ids = rtrim($ids, ‘,’);

        Thanks

  3. Hi Mike! I just bought the source code, thanks for making this tutorial, it helped me a lot.
    I’m having some troubles and I was hoping that you could help me.
    Notice: Undefinex index: cart_items_cookie in navigation.php on line 28
    Notice: Undefinex index: cart_items_cookie in products.php on line 34

    (Lines may vary.) Thanks.

    1. Hello Carlos, did you try to use the PHP isset() function for that? You can try to use it like this:

      $cookie = $_COOKIE[‘cart_items_cookie’];

      to this one:

      $cookie = isset($_COOKIE[‘cart_items_cookie’]) ? $_COOKIE[‘cart_items_cookie’] : “”;

  4. Hello @disqus_Lt5W37fqkt, thanks for downloading the script! Regarding your issue, how about change this line:

    $cookie = $_COOKIE[‘cart_items_cookie’];

    to this one:

    $cookie = isset($_COOKIE[‘cart_items_cookie’]) ? $_COOKIE[‘cart_items_cookie’] : “”;

  5. Thank you very much for this great tutorial. I am new to web development so this code has been a huge help. I have downloaded the source code and have it up and running. I have also made a few minor modifications so that I can have multiple product pages and dictate which product id’s are listed on each page. However, this has caused two problems:

    The first is that add-to-cart.php redirects to the general products page. I have tried a few things to make it redirect to the last individual product page but nothing is working. Is there a method that you could recommend to make this work?

    Second, it seems like the cookie does not read if I am in a different directory than where add-to-cart.php is located. Does this makes sense or is this just a coincidence? At any rate, when I am on a page that is in a different directory than add-to-cart.php the cart quantity in the header no longer works and reads zero. Is there anything I can do to fix this?

    Thank you!

    1. Hello @disqus_Wf9lcYoGH7, thanks for downloading the code! Would you give us your test URL so we can examine more of the issues?

      1. Alright, so I just put it up here: http://www.oldmissionboat.com. It is still a WIP, but I’m sure you will be able to tell what I am going for. I have put your code in a directory at oldmissionboat.com/cart/. The products page from your source code is located at http://www.oldmissionboat.com/cart/products.php. As you will see, when you are on this page the cart quantity in the header works and items that are in the cart show as “added.” I have also created a separate test page where I can select the products to be shown. This is located at http://www.oldmissionboat.com/testProduct.php. On this page the quantity header always reads zero and “add to cart” does not change to “added” when the item already exists in the cart. You will also see that you get redirected to …products.php when you click add to cart.

        To be completely honest, I can live with cart quantity and “added” issues if there isn’t a simple way to fix it. However, having “add-to-cart.php” redirect to the general products page is something that I would really like to be able to change. It would be really great if it could redirect back to the product page the user was previously on.

        Thank you very much for your help. I really appreciate it!

      2. Hello @disqus_Wf9lcYoGH7, nice site! Regarding the redirection you want to accomplish, you can save the product ID in a session variable, that way, you can always go back to the product page the user was previously on.

      3. Hi @ninjazhai, thank you! Unfortunately, due to my directory structure I am unable to have the url based solely on product ID. Instead I have tried setting the product page url to a session variable and then redirecting to that url, but I end up with a redirect loop. I also tried adding an additional field to my products table which contained the url of the product page, but this too caused a redirect loop.

        Regarding the cookie problem, I was able to solve it by modifying the setcookie() command in add_to_cart.php, remove_from_cart.php, and update_quantity.php. I changed this line on all three pages to: setcookie(‘cart_items_cookie’, $json, time()+31536000, ‘/’). It seems that setting the cookie path to ‘/’ solves it. The header now displays the cart quantity and the “add to cart” buttons change to “added” on every page.

      4. So I just realized I forgot to start the session in add_to_cart.php. That explains why the redirect wasn’t working. Oops! Everything is up and running now. Thank you for the help!

  6. I would LOVE to see a tutorial for adding product attributes to this shopping cart system. There is NO tutorials out there.

      1. great to hear. To ellaborate more. For example, I want to have a product of “T-Shirt” and be able to add “Color” and size dropdowns. Or Checkboxes, or etc…. Is the OOP tutorial gonna put me in the right direction for this? So if I do this, does your new tutorial you are working on build on it?

  7. I am having an issue with an infinite redirect loop when going to ‘add_to_cart.php’. I’m studying the code and am failing at finding the reason.

  8. hi ninjazhai can you post on this website on how to solve my question because i am a beginner in php so that i can fully understand my error.. thanks…

  9. hi i have a problem your first tutorial it says undefined: index: cart_items../navigation.php on line 24 please help me

      1. I am also having the same problem a @reil john except I downloaded this tutorial and get the same error as @reil john. I also get it with ‘cart_count’. Can you please help? I tried the isset approach mentioned and I think I merely bypassed the first error. I wrote the following:

        if (isset($cookie)) {

        $cookie = $_COOKIE[‘cart_items_cookie’];

        $cookie = stripslashes($cookie);

        $saved_cart_items = json_decode($cookie, true);

        $cart_count=count($saved_cart_items);

        what am I doing wrong?

      2. ninjazhai here is what I did to get passed this error:

        Not sure if this will work but am still working on it.

        I will let you know

      1. I’m fine @disqus_Tkg3Hukomt, thanks for asking! How about you? Yeah I saw it, thanks for sharing that technique!

      2. please can you help me out with the codes, even if i enter everytin correctly as shown. i still get errors please help me out,thank you

Leave a comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back to top