Simple PHP Shopping Cart using Sessions


A shopping cart is an important part of every eCommerce project. It helps the user to select multiple items for purchase and view total price before submitting the order. If you want to build a simple PHP shopping cart from scratch, this step-by-step tutorial will help you a lot. In this tutorial, we’ll provide the complete guide and script to creating a simple shopping cart in PHP using sessions and MySQL.

This tutorial is designed in a way that can be implemented easily in PHP project and made easy to understand the shopping cart concept. In our example script, we’ll use PHP session to store the products information in the cart. Once the order is submitted by the user, the products information would be inserted into the database using PHP and MySQL.

Before you begin, take a look at the files structure of PHP shopping cart script.

php-shopping-cart-tutorial-files-structure-codexworld

Create Database Tables

Minimum four database tables (customers, products, orders, and order_items) are needed to create a simple session-based shopping cart in PHP with MySQL.

customers table contains all the customer information. customers tables SQL will like the below.

CREATE TABLE `customers` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
 `email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
 `phone` varchar(15) COLLATE utf8_unicode_ci NOT NULL,
 `address` text COLLATE utf8_unicode_ci NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime NOT NULL,
 `status` enum('1','0') COLLATE utf8_unicode_ci NOT NULL DEFAULT '1',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

products table contains all the product details. products tables SQL will like the below.

CREATE TABLE `products` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
 `description` text COLLATE utf8_unicode_ci NOT NULL,
 `price` float(10,2) NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime NOT NULL,
 `status` enum('1','0') COLLATE utf8_unicode_ci NOT NULL DEFAULT '1',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

orders table contains the orders submitted by the customer. customer_id would be a FOREIGN KEY which is associated with customers table. orders tables SQL will like the below.

CREATE TABLE `orders` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `customer_id` int(11) NOT NULL,
 `total_price` float(10,2) NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime NOT NULL,
 `status` enum('1','0') COLLATE utf8_unicode_ci NOT NULL DEFAULT '1',
 PRIMARY KEY (`id`),
 KEY `customer_id` (`customer_id`),
 CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`customer_id`) REFERENCES `customers` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

order_items table contains the order items of each order, so, multiple rows will insert for the same order. order_id would be a FOREIGN KEY which is associated with orders table. order_items tables SQL will like the below.

CREATE TABLE `order_items` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `order_id` int(11) NOT NULL,
 `product_id` int(11) NOT NULL,
 `quantity` int(5) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `order_id` (`order_id`),
 CONSTRAINT `order_items_ibfk_1` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Cart Class (Cart.php)

Cart class helps to do all shopping cart related operations easily. The methods of Cart class and their uses are mentioned below.
contents() Returns the entire cart content as an array.
get_item() Returns a specific cart item details.
total_items() Returns the total item count in cart.
total() Returns the total price of the cart.
insert() Insert items into the cart and save it in the session.
update() Update the cart.
remove() Removes an item from the cart.
destroy() Empties the cart and destroy the session.

<?php session_start();
class 
Cart {
    protected 
$cart_contents = array();
    
    public function 
__construct(){
        
// get the shopping cart array from the session
        
$this->cart_contents = !empty($_SESSION['cart_contents'])?$_SESSION['cart_contents']:NULL;
        if ($this->cart_contents === NULL){
            
// set some base values
            
$this->cart_contents = array('cart_total' => 0'total_items' => 0);
        }
    }
    
    
/**
     * Cart Contents: Returns the entire cart array
     * @param    bool
     * @return    array
     */
    
public function contents(){
        
// rearrange the newest first
        
$cart array_reverse($this->cart_contents);

        
// remove these so they don't create a problem when showing the cart table
        
unset($cart['total_items']);
        unset(
$cart['cart_total']);

        return 
$cart;
    }
    
    
/**
     * Get cart item: Returns a specific cart item details
     * @param    string    $row_id
     * @return    array
     */
    
public function get_item($row_id){
        return (
in_array($row_id, array('total_items''cart_total'), TRUE) OR ! isset($this->cart_contents[$row_id]))
            ? 
FALSE
            
$this->cart_contents[$row_id];
    }
    
    
/**
     * Total Items: Returns the total item count
     * @return    int
     */
    
public function total_items(){
        return 
$this->cart_contents['total_items'];
    }
    
    
/**
     * Cart Total: Returns the total price
     * @return    int
     */
    
public function total(){
        return 
$this->cart_contents['cart_total'];
    }
    
    
/**
     * Insert items into the cart and save it to the session
     * @param    array
     * @return    bool
     */
    
public function insert($item = array()){
        if(!
is_array($item) OR count($item) === 0){
            return 
FALSE;
        }else{
            if(!isset(
$item['id'], $item['name'], $item['price'], $item['qty'])){
                return 
FALSE;
            }else{
                
/*
                 * Insert Item
                 */
                // prep the quantity
                
$item['qty'] = (float) $item['qty'];
                if(
$item['qty'] == 0){
                    return 
FALSE;
                }
                
// prep the price
                
$item['price'] = (float) $item['price'];
                
// create a unique identifier for the item being inserted into the cart
                
$rowid md5($item['id']);
                
// get quantity if it's already there and add it on
                
$old_qty = isset($this->cart_contents[$rowid]['qty']) ? (int) $this->cart_contents[$rowid]['qty'] : 0;
                
// re-create the entry with unique identifier and updated quantity
                
$item['rowid'] = $rowid;
                
$item['qty'] += $old_qty;
                
$this->cart_contents[$rowid] = $item;
                
                
// save Cart Item
                
if($this->save_cart()){
                    return isset(
$rowid) ? $rowid TRUE;
                }else{
                    return 
FALSE;
                }
            }
        }
    }
    
    
/**
     * Update the cart
     * @param    array
     * @return    bool
     */
    
public function update($item = array()){
        if (!
is_array($item) OR count($item) === 0){
            return 
FALSE;
        }else{
            if (!isset(
$item['rowid'], $this->cart_contents[$item['rowid']])){
                return 
FALSE;
            }else{
                
// prep the quantity
                
if(isset($item['qty'])){
                    
$item['qty'] = (float) $item['qty'];
                    
// remove the item from the cart, if quantity is zero
                    
if ($item['qty'] == 0){
                        unset(
$this->cart_contents[$item['rowid']]);
                        return 
TRUE;
                    }
                }
                
                
// find updatable keys
                
$keys array_intersect(array_keys($this->cart_contents[$item['rowid']]), array_keys($item));
                
// prep the price
                
if(isset($item['price'])){
                    
$item['price'] = (float) $item['price'];
                }
                
// product id & name shouldn't be changed
                
foreach(array_diff($keys, array('id''name')) as $key){
                    
$this->cart_contents[$item['rowid']][$key] = $item[$key];
                }
                
// save cart data
                
$this->save_cart();
                return 
TRUE;
            }
        }
    }
    
    
/**
     * Save the cart array to the session
     * @return    bool
     */
    
protected function save_cart(){
        
$this->cart_contents['total_items'] = $this->cart_contents['cart_total'] = 0;
        foreach (
$this->cart_contents as $key => $val){
            
// make sure the array contains the proper indexes
            
if(!is_array($val) OR !isset($val['price'], $val['qty'])){
                continue;
            }
     
            
$this->cart_contents['cart_total'] += ($val['price'] * $val['qty']);
            
$this->cart_contents['total_items'] += $val['qty'];
            
$this->cart_contents[$key]['subtotal'] = ($this->cart_contents[$key]['price'] * $this->cart_contents[$key]['qty']);
        }
        
        
// if cart empty, delete it from the session
        
if(count($this->cart_contents) <= 2){
            unset(
$_SESSION['cart_contents']);
            return 
FALSE;
        }else{
            
$_SESSION['cart_contents'] = $this->cart_contents;
            return 
TRUE;
        }
    }
    
    
/**
     * Remove Item: Removes an item from the cart
     * @param    int
     * @return    bool
     */
     
public function remove($row_id){
        
// unset & save
        
unset($this->cart_contents[$row_id]);
        
$this->save_cart();
        return 
TRUE;
     }
     
    
/**
     * Destroy the cart: Empties the cart and destroy the session
     * @return    void
     */
    
public function destroy(){
        
$this->cart_contents = array('cart_total' => 0'total_items' => 0);
        unset(
$_SESSION['cart_contents']);
    }
}

Database Configuration (dbConfig.php)

This file is used to connect and select the database.

<?php
//DB details
$dbHost 'localhost';
$dbUsername 'root';
$dbPassword '';
$dbName 'codexworld';

//Create connection and select DB
$db = new mysqli($dbHost$dbUsername$dbPassword$dbName);

if (
$db->connect_error) {
    die(
"Unable to connect database: " $db->connect_error);
}

cartAction.php

This file handles all the action requested by the user from view page. The code blocks would be executed based on the requested action. The following operations can happen based on the action.
addToCart Fetches the product details from the products table by the specified product ID and insert the item into the cart using Cart class. After successful operation, the user is redirected to the viewCart.php page.
updateCartItem Updates the cart by specific rowid using Cart class and returns the status message.
removeCartItem Removes the item from the cart by the specific item id using Cart class. After successful operation, the user is redirected to the viewCart.php page.
placeOrder Inserts the cart items data to the orders and order_items table and destroy the cart data from the session. using Cart class. After successful operation, the user is redirected to the orderSuccess.php page.

<?php
// initialize shopping cart class
include 'Cart.php';
$cart = new Cart;

// include database configuration file
include 'dbConfig.php';
if(isset(
$_REQUEST['action']) && !empty($_REQUEST['action'])){
    if(
$_REQUEST['action'] == 'addToCart' && !empty($_REQUEST['id'])){
        
$productID $_REQUEST['id'];
        
// get product details
        
$query $db->query("SELECT * FROM products WHERE id = ".$productID);
        
$row $query->fetch_assoc();
        
$itemData = array(
            
'id' => $row['id'],
            
'name' => $row['name'],
            
'price' => $row['price'],
            
'qty' => 1
        
);
        
        
$insertItem $cart->insert($itemData);
        
$redirectLoc $insertItem?'viewCart.php':'index.php';
        
header("Location: ".$redirectLoc);
    }elseif(
$_REQUEST['action'] == 'updateCartItem' && !empty($_REQUEST['id'])){
        
$itemData = array(
            
'rowid' => $_REQUEST['id'],
            
'qty' => $_REQUEST['qty']
        );
        
$updateItem $cart->update($itemData);
        echo 
$updateItem?'ok':'err';die;
    }elseif(
$_REQUEST['action'] == 'removeCartItem' && !empty($_REQUEST['id'])){
        
$deleteItem $cart->remove($_REQUEST['id']);
        
header("Location: viewCart.php");
    }elseif(
$_REQUEST['action'] == 'placeOrder' && $cart->total_items() > && !empty($_SESSION['sessCustomerID'])){
        
// insert order details into database
        
$insertOrder $db->query("INSERT INTO orders (customer_id, total_price, created, modified) VALUES ('".$_SESSION['sessCustomerID']."', '".$cart->total()."', '".date("Y-m-d H:i:s")."', '".date("Y-m-d H:i:s")."')");
        
        if(
$insertOrder){
            
$orderID $db->insert_id;
            
$sql '';
            
// get cart items
            
$cartItems $cart->contents();
            foreach(
$cartItems as $item){
                
$sql .= "INSERT INTO order_items (order_id, product_id, quantity) VALUES ('".$orderID."', '".$item['id']."', '".$item['qty']."');";
            }
            
// insert order items into database
            
$insertOrderItems $db->multi_query($sql);
            
            if(
$insertOrderItems){
                
$cart->destroy();
                
header("Location: orderSuccess.php?id=$orderID");
            }else{
                
header("Location: checkout.php");
            }
        }else{
            
header("Location: checkout.php");
        }
    }else{
        
header("Location: index.php");
    }
}else{
    
header("Location: index.php");
}

Products list (index.php)

In this page, we’ve used bootstrap to design the products list, you can omit bootstrap and use your web page design. All the products will be fetched from the products table and listed with the “Add to cart” button. Add to cart button redirects the user to the cartAction.php page with addToCart request and respective product ID.

<?php
// include database configuration file
include 'dbConfig.php';
?> <!DOCTYPE html> <html lang="en"> <head> <title>PHP Shopping Cart Tutorial</title> <meta charset="utf-8"> <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <style> .container{padding: 50px;} .cart-link{width: 100%;text-align: right;display: block;font-size: 22px;} </style> </head> </head> <body> <div class="container"> <h1>Products</h1> <a href="viewCart.php" class="cart-link" title="View Cart"><i class="glyphicon glyphicon-shopping-cart"></i></a> <div id="products" class="row list-group">         <?php
        
//get rows query
        
$query $db->query("SELECT * FROM products ORDER BY id DESC LIMIT 10");
        if(
$query->num_rows 0){ 
            while(
$row $query->fetch_assoc()){
        
?> <div class="item col-lg-4"> <div class="thumbnail"> <div class="caption"> <h4 class="list-group-item-heading"><?php echo $row["name"]; ?></h4> <p class="list-group-item-text"><?php echo $row["description"]; ?></p> <div class="row"> <div class="col-md-6"> <p class="lead"><?php echo '$'.$row["price"].' USD'?></p> </div> <div class="col-md-6"> <a class="btn btn-success" href="cartAction.php?action=addToCart&id=<?php echo $row["id"]; ?>">Add to cart</a> </div> </div> </div> </div> </div>         <?php } }else{ ?> <p>Product(s) not found.....</p>         <?php ?> </div> </div> </body> </html>

Shopping Cart (viewCart.php)

This page gets the cart contents from the Cart class and displays the cart items with the total price. Also, the user would be able to add more item to the cart by Continue Shopping button or Checkout from cart. Checkout button redirects the user to the checkout.php page to preview the order before submit.

<?php
// initializ shopping cart class
include 'Cart.php';
$cart = new Cart;
?> <!DOCTYPE html> <html lang="en"> <head> <title>View Cart - PHP Shopping Cart Tutorial</title> <meta charset="utf-8"> <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <style> .container{padding: 50px;} input[type="number"]{width: 20%;} </style> <script> function updateCartItem(obj,id){ $.get("cartAction.php", {action:"updateCartItem", id:id, qty:obj.value}, function(data){ if(data == 'ok'){ location.reload(); }else{ alert('Cart update failed, please try again.'); } }); } </script> </head> </head> <body> <div class="container"> <h1>Shopping Cart</h1> <table class="table"> <thead> <tr> <th>Product</th> <th>Price</th> <th>Quantity</th> <th>Subtotal</th> <th>&nbsp;</th> </tr> </thead> <tbody>         <?php
        
if($cart->total_items() > 0){
            
//get cart items from session
            
$cartItems $cart->contents();
            foreach(
$cartItems as $item){
        
?> <tr> <td><?php echo $item["name"]; ?></td> <td><?php echo '$'.$item["price"].' USD'?></td> <td><input type="number" class="form-control text-center" value="<?php echo $item["qty"]; ?>" onchange="updateCartItem(this, '<?php echo $item["rowid"]; ?>')"></td> <td><?php echo '$'.$item["subtotal"].' USD'?></td> <td> <a href="cartAction.php?action=removeCartItem&id=<?php echo $item["rowid"]; ?>" class="btn btn-danger" onclick="return confirm('Are you sure?')"><i class="glyphicon glyphicon-trash"></i></a> </td> </tr>         <?php } }else{ ?> <tr><td colspan="5"><p>Your cart is empty.....</p></td>         <?php ?> </tbody> <tfoot> <tr> <td><a href="index.php" class="btn btn-warning"><i class="glyphicon glyphicon-menu-left"></i> Continue Shopping</a></td> <td colspan="2"></td>             <?php if($cart->total_items() > 0){ ?> <td class="text-center"><strong>Total <?php echo '$'.$cart->total().' USD'?></strong></td> <td><a href="checkout.php" class="btn btn-success btn-block">Checkout <i class="glyphicon glyphicon-menu-right"></i></a></td>             <?php ?> </tr> </tfoot> </table> </div> </body> </html>

Order Preview (checkout.php)

In this page, logged in customer ID is collected from the session and respective customer details are fetched from the customers table. Cart items details and customer details are displayed for preview the order before submit. Once the customer chooses to place the order, cartAction.php file is called with “placeOrder” request.

<?php
// include database configuration file
include 'dbConfig.php';

// initializ shopping cart class
include 'Cart.php';
$cart = new Cart;

// redirect to home if cart is empty
if($cart->total_items() <= 0){
    
header("Location: index.php");
}

// set customer ID in session
$_SESSION['sessCustomerID'] = 1;

// get customer details by session customer ID
$query $db->query("SELECT * FROM customers WHERE id = ".$_SESSION['sessCustomerID']);
$custRow $query->fetch_assoc();
?> <!DOCTYPE html> <html lang="en"> <head> <title>Checkout - PHP Shopping Cart Tutorial</title> <meta charset="utf-8"> <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <style> .container{width: 100%;padding: 50px;} .table{width: 65%;float: left;} .shipAddr{width: 30%;float: left;margin-left: 30px;} .footBtn{width: 95%;float: left;} .orderBtn {float: right;} </style> </head> <body> <div class="container"> <h1>Order Preview</h1> <table class="table"> <thead> <tr> <th>Product</th> <th>Price</th> <th>Quantity</th> <th>Subtotal</th> </tr> </thead> <tbody>         <?php
        
if($cart->total_items() > 0){
            
//get cart items from session
            
$cartItems $cart->contents();
            foreach(
$cartItems as $item){
        
?> <tr> <td><?php echo $item["name"]; ?></td> <td><?php echo '$'.$item["price"].' USD'; ?></td> <td><?php echo $item["qty"]; ?></td> <td><?php echo '$'.$item["subtotal"].' USD'?></td> </tr>         <?php } }else{ ?> <tr><td colspan="4"><p>No items in your cart......</p></td>         <?php ?> </tbody> <tfoot> <tr> <td colspan="3"></td>             <?php if($cart->total_items() > 0){ ?> <td class="text-center"><strong>Total <?php echo '$'.$cart->total().' USD'?></strong></td>             <?php ?> </tr> </tfoot> </table> <div class="shipAddr"> <h4>Shipping Details</h4> <p><?php echo $custRow['name']; ?></p> <p><?php echo $custRow['email']; ?></p> <p><?php echo $custRow['phone']; ?></p> <p><?php echo $custRow['address']; ?></p> </div> <div class="footBtn"> <a href="index.php" class="btn btn-warning"><i class="glyphicon glyphicon-menu-left"></i> Continue Shopping</a> <a href="cartAction.php?action=placeOrder" class="btn btn-success orderBtn">Place Order <i class="glyphicon glyphicon-menu-right"></i></a> </div> </div> </body> </html>

Order Success (orderSuccess.php)

The customer is redirected to this page if their order is submitted successfully.

<?php
if(!isset(
$_REQUEST['id'])){
    
header("Location: index.php");
}
?> <!DOCTYPE html> <html lang="en"> <head> <title>Order Success - PHP Shopping Cart Tutorial</title> <meta charset="utf-8"> <style> .container{width: 100%;padding: 50px;} p{color: #34a853;font-size: 18px;} </style> </head> </head> <body> <div class="container"> <h1>Order Status</h1> <p>Your order has submitted successfully. Order ID is #<?php echo $_GET['id']; ?></p> </div> </body> </html>

Conclusion

We hope this guide will help you to understand the basic shopping cart functionality in PHP with session and MySQL. Using this process and script you’ll be able to implement a shopping cart in your web application instantly. Also, you can upgrade it with advanced functionality based on your shopping cart requirement.

1 Comment

  1. Sami Said...

Leave a reply

Connect With CodexWorld