PHP

PHP & mysql shopping cart project (Live example + source code)

Share your learning

Today we are going to learn about php & mysql shopping cart project with Live example and source code. We will use HTML, Bootstrap, jQuery for front-end and PHP & MySQL for backend coding to build PHP shopping cart.

We will also provide you with the source code of PHP shopping cart for free of cost. You can learn and even can modify it as per your requirements too.

Features of php & mysql shopping cart project including source code

You will be able to use the following features of this project.

  1. Product listing from MySQL database
  2. Add to cart the product
  3. Login and registration
  4. Add and remove cart items
  5. Search product by name

It will iterate the products array on the product listing page. We have used a js library list.js to create a dynamic search for products.

We have used jQuery ajax to create add to cart, remove from cart etc. without any page refresh. If you try to add a product to a shopping cart without login, it will add cart items to a php session as an array and once user logged in, it will save all the items to the user’s cart. Then the user can see all those items in his/her cart. 

Local setup of php shopping cart project code

Go to your localhost directory like htdocs or www. Then open your command terminal and run the following command

git clone https://github.com/SATPAL-BHARDWAJ/php-ecommerce.git

It will clone the php-ecommerce project to your local server. Now, open your web browser and type localhost/path-to/php-ecommerce it will run our project.

Now, you need to change a few things, open your code editor and add this project there. Open the file app/Include.php and config/include.php and replace the BASE_PATH constant value with your project directory.

For example, my project is in the following directory

htdocs/projects/php-ecommerce

So,

define('BASE_PATH', '/projects/php-ecommerce');

Now, go to config/conn.php and replace the following dbname, username and password as per your local server credentials.

private $server = "mysql:host=localhost;dbname=QSale";
private $username = "root";
private $password = "";

File structure

The PHP shopping cart site has following files and directories.

Database Setup

We are using mysql PDO to connect with databases. You will find this file in the config/conn.php directory. You can update your database credentials here.

Navigate to http://localhost/phpmyadmin and create a database named qsale or anything else that you want. 

You will get the Sql file with the source code from my git-repo, you need to import that file to this created database.

Product listing page for php & mysql shopping cart example       

Let’s build the product listing page for our php shopping cart site. So, the product gallery page will be visible to all users, loggedIn and without login. 

Users can click on the add to cart button and it will directly add the product to the cart or cart session (if the user is not loggedIn).

How, technically, does it work?

Below is our product listing html with php loop for products. We are getting products array from mysql database.

<?php

    $conn = $pdo->open();

    try{
        $stmt = $conn->prepare("SELECT * FROM products");
        $stmt->execute();
        $products = $stmt->fetchAll();
        //dd($products);
    }
    catch(PDOException $e){
        echo "There is some problem in connection: " . $e->getMessage();
    }

    $pdo->close();

    $addedProducts = cartProducts();
?>

<div class='container py-5' id="qsale_products">
    <div class="pricing-header p-3 pb-md-4 mx-auto text-center">
        <!-- <h1 class="display-4 fw-normal">All Gadgets</h1> -->
        <img class="img-fluid w-25" src="./resources/assets/images/undraw_social_friends.svg"/>
    </div>


    <?php include "./resources/components/search.php"; ?>

    <div class="row row-cols-1 row-cols-lg-2 mb-3 list">
        <?php foreach($products as $product) { ?>
       
        <div class="col my-4">
            <div class="wrapper">
                <div class="product-img">
                    <img class="img-fluid" src="<?php echo './resources/assets/images/'.$product['photo'] ?>">
                </div>
                <div class="product-info">
                    <div class="product-text">
                        <h1 class="name"><?php echo substr($product['name'], 0, 20) ?></h1>
                        <h2>$<?php echo $product['price'] ?></h2>
                        <div><?php echo $product['description'] ?></div>
                    </div>
                    <div class="product-price-btn">
                        <button data-product-id="<?php echo $product['id']; ?>" type="button" class="add-to-cart-btn-js"><?php echo in_array($product['id'], $addedProducts) ? 'Added' : 'add to cart' ?> </button>
                    </div>
                </div>
            </div>
        </div>

        <?php } ?>
    </div>
</div>

Add product to the shopping cart with ajax    

We are using a css class selector for the add to cart button and we will use this selector in the app.js file.            

$(function () {

 $('.add-to-cart-btn-js').on('click', function () {
  var product_id = $(this).data('product-id');

  console.log({ product_id });

  var data = {
   id: product_id,
   quantity: 1
  }

  $.post("app/AddToCart.php", data, (response) => {
   console.log({ response });
   if (!response.error) {
    updateCartQty(1);
    $(this).text('Added');
   }

   showAlerts((!response.error ? 'success' : 'error'), response.message);
  }, "json");
 })

})



/* Cart page */
var total = 0;
$(function () {
 $(document).on('click', '.cart_delete', function (e) {
  e.preventDefault();
  var id = $(this).data('id');
  $.ajax({
   type: 'POST',
   url: 'app/CartDelete.php',
   data: { id: id },
   dataType: 'json',
   success: function (response) {
    if (!response.error) {
     getDetails();
     getCart();
     getTotal();

     updateCartQty(-1);
    }

    showAlerts((!response.error ? 'success' : 'error'), response.message);
   }
  });
 });

 $(document).on('click', '.minus', function (e) {
  e.preventDefault();
  var id = $(this).data('id');
  var qty = $('#qty_' + id).val();
  if (qty > 1) {
   qty--;
  }
  $('#qty_' + id).val(qty);
  $.ajax({
   type: 'POST',
   url: 'app/CartUpdate.php',
   data: {
    id: id,
    qty: qty,
   },
   dataType: 'json',
   success: function (response) {
    if (!response.error) {
     getDetails();
     getCart();
     getTotal();
    }
   }
  });
 });

 $(document).on('click', '.add', function (e) {
  e.preventDefault();
  var id = $(this).data('id');
  var qty = $('#qty_' + id).val();
  qty++;
  $('#qty_' + id).val(qty);
  $.ajax({
   type: 'POST',
   url: 'app/CartUpdate.php',
   data: {
    id: id,
    qty: qty,
   },
   dataType: 'json',
   success: function (response) {
    if (!response.error) {
     getDetails();
     getCart();
     getTotal();
    }
   }
  });
 });

 getDetails();
 getTotal();

});

function getDetails() {
 $.ajax({
  type: 'POST',
  url: "app/CartController.php",
  dataType: 'json',
  success: function (response) {
   console.log({ response });
   $('#tbody').html(response);
   getCart();
  },
 })
}

function getTotal() {
 $.ajax({
  type: 'POST',
  url: "app/CartTotal.php",
  dataType: 'json',
  success: function (response) {
   total = response;
  }
 });
}

function updateCartQty(cart_count) {
 var my_cart = $('.my-cart-btn-js');
 var notify_dot = my_cart.find('.notify-dot');

 if (notify_dot.length > 0) {
  var count = notify_dot.text();
  notify_dot.text((Number(count) + cart_count));
 } else {
  var cart_text = my_cart.text();
  my_cart.html(`<span class="notify-dot">1</span> ${cart_text}`);
 }
}

function showAlerts(type, message) {

 var errors = $('.errors-js');
 var alert = '.alert-success';
 errors.find('.alert').each((index, element) => {
  console.log(index, element);
  if (!$(element).hasClass('d-none')) {
   $(element).addClass('d-none');
  }
 });

 if (type === 'error') {
  alert = '.alert-danger';
 } else if (type === 'info') {
  alert = '.alert-info';
 }

 errors.find(alert).removeClass('d-none').text(message);
}

We are using ajax to save products to the cart table. It will add a smooth transition to add product to the cart. 

We are also adding a cart items count with the help of js function called updateCartQty(), So that when a user adds a product to the cart it will add a cart count over the “My Cart” menu in the navbar by using notify-dot selector.

It will tell the user how many products are in the cart.

PHP shopping cart items

Let’s build a cart items listing page. 

When the user clicks on the “my cart” menu from the navbar, it will load the cart page and we have called the ajax on load of the shopping cart page in app.js file. Something like below,

$(function(){
    getDetails();
})

function getDetails(){
        $.ajax({
            type: 'POST',
            url: "app/CartController.php",
            dataType: 'json',
            success: function(response){
                console.log({response});
                $('#tbody').html(response);
                getCart();
            },
        })
}

We are adding ajax response as html to the table body in the cart.php.

<table class="table table-bordered">
<thead>
           <th></th>
           <th>Photo</th>
           <th>Name</th>
           <th>Price</th>
           <th width="20%">Quantity</th>
           <th>Subtotal</th>
        </thead>
        <tbody id="tbody">
      </tbody>
 </table>

We have prepared the products html data in the CartController.php and then have returned it as ajax response.

try {
            $total = 0;
            $stmt = $conn->prepare("SELECT *, cart.id AS cartid FROM cart LEFT JOIN products ON products.id=cart.product_id WHERE user_id=:user");
            $stmt->execute(['user'=>$user['id']]);
            foreach($stmt as $row){
                $image = (!empty($row['photo'])) ? 'resources/assets/images/'.$row['photo'] : 'images/noimage.jpg';
                $subtotal = $row['price']*$row['quantity'];
                $total += $subtotal;
                $output .= "
                    <tr>
                        <td><i data-id='".$row['cartid']."' class='fa fa-close cart_delete cursor-pointer'></i> </td>
                        <td><img src='".$image."' width='30px' height='30px'></td>
                        <td>".$row['name']."</td>
                        <td>&#36; ".number_format($row['price'], 2)."</td>
                        <td class='input-group'>
                            <span class='input-group-btn'>
                                <button type='button' id='minus' class='btn btn-default btn-flat minus' data-id='".$row['cartid']."'><i class='fa fa-arrow-down'></i></button>
                            </span>
                            <input type='text' class='form-control' value='".$row['quantity']."' id='qty_".$row['cartid']."'>
                            <span class='input-group-btn'>
                                <button type='button' id='add' class='btn btn-default btn-flat add' data-id='".$row['cartid']."'><i class='fa fa-arrow-up'></i>
                                </button>
                            </span>
                        </td>
                        <td>&#36; ".number_format($subtotal, 2)."</td>
                    </tr>
                ";
            }
            $output .= "
                <tr>
                    <td colspan='5' align='right'><b>Total</b></td>
                    <td><b>&#36; ".number_format($total, 2)."</b></td>
                <tr>
            ";

        }
        catch(PDOException $e){
            $output .= $e->getMessage();
        }

$pdo->close();
echo json_encode($output);

Update cart quantity or remove cart items

In the cart page, we can remove cart items and can also increase/decrease the quantity. We are doing all these things with the help of below js.

$(function(){
        $(document).on('click', '.cart_delete', function(e){
            e.preventDefault();
            var id = $(this).data('id');
            $.ajax({
                type: 'POST',
                url: 'app/CartDelete.php',
                data: {id:id},
                dataType: 'json',
                success: function(response){
                    if(!response.error){
                        getDetails();
                        getCart();
                        getTotal();

                        updateCartQty(-1);    
                    }

                    showAlerts( (!response.error ? 'success' : 'error'), response.message );
                }
            });
        });

        $(document).on('click', '.minus', function(e){
            e.preventDefault();
            var id = $(this).data('id');
            var qty = $('#qty_'+id).val();
            if(qty>1){
                qty--;
            }
            $('#qty_'+id).val(qty);
            $.ajax({
                type: 'POST',
                url: 'app/CartUpdate.php',
                data: {
                    id: id,
                    qty: qty,
                },
                dataType: 'json',
                success: function(response){
                    if(!response.error){
                        getDetails();
                        getCart();
                        getTotal();
                    }
                }
            });
        });

        $(document).on('click', '.add', function(e){
            e.preventDefault();
            var id = $(this).data('id');
            var qty = $('#qty_'+id).val();
            qty++;
            $('#qty_'+id).val(qty);
            $.ajax({
                type: 'POST',
                url: 'app/CartUpdate.php',
                data: {
                    id: id,
                    qty: qty,
                },
                dataType: 'json',
                success: function(response){
                    if(!response.error){
                        getDetails();
                        getCart();
                        getTotal();
                    }
                }
            });
        });

        getDetails();
        getTotal();

    });

function getDetails(){
        $.ajax({
            type: 'POST',
            url: "app/CartController.php",
            dataType: 'json',
            success: function(response){
                console.log({response});
                $('#tbody').html(response);
                getCart();
            },
        })
    }

    function getTotal(){
        $.ajax({
            type: 'POST',
            url: "app/CartTotal.php",
            dataType: 'json',
            success:function(response){
                total = response;
            }
        });
    }

    function updateCartQty( cart_count ) {
        var my_cart = $('.my-cart-btn-js');
        var notify_dot = my_cart.find('.notify-dot');

        if ( notify_dot.length > 0 ) {
            var count = notify_dot.text();
            notify_dot.text( (Number(count) + cart_count) );
        } else {
            var cart_text = my_cart.text();
            my_cart.html(`<span class="notify-dot">1</span> ${cart_text}`);
        }
    }

    function showAlerts( type, message ) {

        var errors = $('.errors-js');
        var alert = '.alert-success';
        errors.find('.alert').each((index, element) => {
            console.log(index, element);
            if ( !$(element).hasClass('d-none') ) {
                $(element).addClass('d-none');
            }
        });
    
        if ( type === 'error' ) {
            alert = '.alert-danger';
        } else if ( type === 'info' ) {
            alert = '.alert-info';
        }
    
        errors.find(alert).removeClass('d-none').text(message);
    }

Routing System

Routing System Instead of file names with php extension in the url like https://example.com/cart.php can be https://example.com/cart

Sounds amazing!

We have created a helper file where we have defined an array of routes. Now we can use this route array to get the actual file path. You can see this thing in the resources/index.php file.

Oh I forgot! 

We have created the htaccess file to redirect all http calls to a single index.php file. So that we could use our routing system instead of the default php file calls.

<?php

$Routes = [
    '/' => './resources/home.php',
    '/login' => './resources/auth/auth.php',
    '/signup' => './resources/auth/auth.php',

    '/app/login' => './app/auth/LoginController.php',
    '/app/signup' => './app/auth/RegisterController.php',
    '/logout' => './app/auth/LogoutController.php',

    '/cart' => './resources/cart.php',
    '/app/cart' => './app/CartController.php',
    '/app/cart-total' => './app/CartTotal.php',
];

Common helper functions

We have one more interesting feature that is helper functions. We have created a helper file which helps us to use common functions in the whole site. 

It simplifies our code and our code will look short, easy to understand and maintainable. We have created the following common functions which are very useful in our site.

  1. url() : To get the url with the base path.
  2. layout() : To get the layout from resources directory
  3. redirect() : To redirect to a particular path

There are other functions too. You will get to know when you go through the code.

<?php

if( !function_exists('url') ) {
    function url( $url = null, $parameter = [] ) {
        echo BASE_PATH."{$url}";
    }
}

if( !function_exists('layout') ) {
    function layout( $file ) {
        include_once "./resources/layouts/{$file}.php";
    }
}

if( !function_exists('redirect') ) {
    function redirect( $path ) {
        header('location: '.BASE_PATH.$path);
    
        exit();
    }
}

if( !function_exists('session') ) {
    function session( $key ) {
        return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
    }
}

if( !function_exists('setSession') ) {
    function setSession( $key, $value ) {
        $_SESSION[$key] = $value;
    }
}

if( !function_exists('hasSession') ) {
    function hasSession( $key ) {
        $keys = is_array($key) ? $key : array($key);

        $exist = false;
        foreach($keys as $k) {
            if(isset($_SESSION[$k])) {
                $exist = true;
            }
        }

        return $exist;
    }
}


if( !function_exists('removeSession') ) {
    function removeSession( $key ) {
        $keys = is_array($key) ? $key : array($key);
        
        foreach($keys as $k) {
            if(isset($_SESSION[$k])) {
                unset($_SESSION[$key]);
            }
        }
    }
}

if( !function_exists('dd') ) { 
    function dd( ...$data ) {

        if ( is_array($data) ) {
            echo '<pre>';
            print_r($data);
            echo '</pre>';
        } else {
            var_dump($data);
        }
        
        die;
    }
}

if( !function_exists('formError') ) {
    function formError( $key ) {
        if ( isset($_SESSION['errorsBag']) && isset($_SESSION['errorsBag'][$key]) ) {
            $error = $_SESSION['errorsBag'][$key];
            unset($_SESSION['errorsBag'][$key]);
            return $error;
        }
    }
}

if( !function_exists('HasFormError') ) {
    function HasFormError( $key ) {
        if ( isset($_SESSION['errorsBag']) && isset($_SESSION['errorsBag'][$key]) ) {
            return true;
        }

        return false;
    }
}

if( !function_exists('setErrorsBag') ) {
    function setErrorsBag( $key, $value ) {
        $_SESSION['errorsBag'][$key] = $value;
    }
}

if( !function_exists('hasErrorBag') ) {
    function hasErrorBag() {
        return isset($_SESSION['errorsBag']) && count($_SESSION['errorsBag']) > 0;
    }
}

if( !function_exists('showFormError') ) {
    function showFormError($key) {
        if (HasFormError( $key )) {
            $error = formError( $key );
            echo "<span class='text-white'>*{$error}</span>";
        };
    }
}

if( !function_exists('resetErrorBag') ) {
    function resetErrorBag() {
        if( isset($_SESSION['errorsBag']) ) {
            unset($_SESSION['errorsBag']);
        }
    }
}

if ( !function_exists('setUser') ) {
    function setUser($id) {
        $pdo = new Database();
        $conn = $pdo->open();

        $stmt = $conn->prepare("SELECT * FROM users WHERE id=:id");
        $stmt->execute(['id'=>$id]);
        $user = $stmt->fetch();
        return $user;
    }
}

if ( !function_exists('countCartProducts') ) {
    function countCartProducts( $user_id ) {
        $pdo = new Database();
        $conn = $pdo->open();

        $stmt = $conn->prepare("SELECT 'id', COUNT('id') as numrows FROM cart WHERE user_id=:user_id");
  $stmt->execute(['user_id'=>$user_id]);
  $row = $stmt->fetch();

        return $row['numrows'];
    }
}

if ( !function_exists('countCart') ) { 
    function countCart( ) {
        $cart_count = 0;
        if( isset($_SESSION['user']) ) {
            $cart_count = countCartProducts($_SESSION['user']);
        } elseif (isset($_SESSION['cart'])) {
            $cart_count = count($_SESSION['cart']);
        }

        return $cart_count;
    }
}

if ( !function_exists('cartProducts') ) { 
    
    function cartProducts( ) {
        $products = [];

        if ( isset($_SESSION['user']) ) {
            $pdo = new Database();
            $conn = $pdo->open();

            $stmt = $conn->prepare("SELECT products.id, cart.id AS cartid FROM cart LEFT JOIN products ON products.id=cart.product_id WHERE user_id=:user");
   $stmt->execute(['user'=>$_SESSION['user']]);

            $rows = $stmt->fetchAll();
            $products = array_column($rows, 'id');

        } else if ( isset($_SESSION['cart']) ) {
            $products = array_column($_SESSION['cart'], 'productid');
        }

        return $products;
    }

}

You will find a lot in the source code of this php & mysql shopping cart project with live example and source code.

Hope it will help you.

Satpal

Recent Posts

How to Switch PHP Versions in XAMPP Easily: Managing Multiple PHP Versions on Ubuntu

Today we are going to learn about managing multiple PHP versions on ubuntu with xampp.…

1 year ago

How to Use Coding to Improve Your Website’s SEO Ranking?

Let's understand about how to use coding to improve your website's SEO. In today’s computerized…

1 year ago

Most Important Linux Commands for Web Developers

Let's understand the most important linux commands for web developers. Linux, as an open-source and…

1 year ago

Top 75+ Laravel Interview Questions Asked by Top MNCs

Today we are going to discuss top 75+ Laravel interview questions asked by top MNCs.Laravel,…

1 year ago

Mailtrap Integration for Email Testing with Laravel 10

Today we will discuss about the Mailtrap integration with laravel 10 .Sending and receiving emails…

1 year ago

Firebase Cloud Messaging (FCM) with Ionic 6: Push Notifications

Today we are going to integrate FCM (Firebase Cloud Messaging) push notifications with ionic application.Firebase…

1 year ago