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.
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.
Our database name will be called “shop_cart_cookies_1”, and we will have two (2) 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 ;
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.
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; } } ?>
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.
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 -->
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; }
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.
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 “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.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;
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);
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
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. 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>"; }
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]; }
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 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; }
<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>
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>"; ?>
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
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'; ?>
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>";
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>"; }
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; }
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; });
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(); ?>
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(); ?>
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'; ?>
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(); ?>
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(); ?>
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'; ?>
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'; ?>
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;
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']; }
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>";
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; }
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>";
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(); });
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>";
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>";
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?
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.
FEATURES | LEVEL 1 Source code | LEVEL 2 Source code |
---|---|---|
List all products from the MySQL database | YES | YES |
Pagination of products | YES | YES |
Add to cart action button | YES | YES |
Remove from the cart action button | YES | YES |
Update cart quantity | YES | YES |
Checkout Page | YES | YES |
Place order / Thank you page | YES | YES |
Amazon-style product details page | YES | YES |
Change image on hover of thumbnail | YES | YES |
Show message about a product added to cart | YES | YES |
Show message about a product removed from cart | YES | YES |
Navigation bar highlights which page is selected | YES | YES |
Cart link shows the count of products added to the cart | YES | YES |
Show message if no products found in database | YES | YES |
Show message if no product found in the cart | YES | YES |
Cart page that lists all products added to cart | YES | YES |
Auto compute the total cost of all products added to the cart | YES | YES |
The navigation bar has a drop down of product categories | NO | YES |
Highlight selected category in the dropdown | NO | YES |
Categories are retrieved from the database | NO | YES |
Show products by category | NO | YES |
List products under a category with pagination | NO | YES |
Search product | NO | YES |
Search results with pagination | NO | YES |
Search box located on the upper right corner of the navigation bar | NO | YES |
Search box requires search term before clicking the search button | NO | YES |
Quantity text box beside the add to cart button | NO | YES |
Quantity text box required to have a minimum value of 1 | NO | YES |
Quantity text box required to be a number, negative value not allowed | NO | YES |
Remember the page number where the user clicked the “Add to cart” button | NO | YES |
Quantity drop-down options based on available stock | NO | YES |
Well formatted money value | NO | YES |
Product image viewable in a lightbox popup | NO | YES |
Shows number of stock left | NO | YES |
Stock decreases once checked out | NO | YES |
Empty cart button with confirmation popup | NO | YES |
Show price, category, and stocks left on the product list page | NO | YES |
Bootstrap enabled UI | YES | YES |
Used PDO bindParam() to prevent SQL injection in MySQL queries | YES | YES |
Used PHP htmlspecialchars() to prevent XSS attacks | YES | YES |
Free support and source code updates | 1 year | 1 year |
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
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.
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
[adinserter block=”1″]
[adinserter block=”3″]
Thanks for reading this PHP shopping cart tutorial using cookies!