HTML CSS JavaScript jQuery PHP Python MySQL

Shopping Cart System with PHP and MySQL

Updated on by David Adams

Shopping Cart System with PHP and MySQL

In this tutorial we'll be creating a shopping cart system with PHP and MySQL, the shopping cart system will allow users to browse for products, add to cart products, and place orders.

We'll be using the PDO extension to access our MySQL database in our PHP scripts.

The shopping cart system we'll be creating will contain 4 products, these products are basically just gadgets/accessories, they are just examples for this tutorial.

The Basic and Advanced packages include additional features and a download link to the source code.

1. Getting Started

There are a few steps we need to take before we create our shopping cart system, we need to set up our web server environment (if you haven't already) and make sure we have the required extensions enabled.

1.1. Demos

The tutorial demo is what we'll be creating, the Basic and Advanced demos are packages you can purchase at the end of the post, these include more features and a download link to the source code, click a link below to view a demo.

1.2. Requirements

  • If you haven't got a local web server setup you should download and install XAMPP.
  • Make sure the PDO extension is enabled (it should already be).

1.3. What You Will Learn in this Tutorial

  • Template Design — Design a home page, products page, product page, shopping cart page, and place order page with HTML5 and CSS3, and learn how to use the PHP templating system with HTML.
  • GET and POST Requests — Create HTML forms and data request handling with PHP.
  • Prepared SQL Queries — How to prepare SQL queries to prevent SQL injection.
  • Basic Validation — Validating form data that is sent to the server.
  • Session Management — Initialize sessions and store shopping cart products.

1.4. File Structure & Setup

We can now start our web server and create the files and folders we're going to use for our shopping cart system.

  • Open XAMPP Control Panel
  • Next to the Apache module click Start
  • Next to the MySQL module click Start
  • Navigate to XAMPPs installation folder (C:\xampp)
  • Open the htdocs folder
  • Create the following folders and files:

File Structure

\-- shoppingcart
  |-- index.php
  |-- home.php
  |-- products.php
  |-- product.php
  |-- cart.php
  |-- placeorder.php
  |-- style.css
  \-- imgs
   |-- featured-image.jpg
   |-- camera.jpg
   |-- headphones.jpg
   |-- wallet.jpg
   |-- watch.jpg

Each file/folder will contain the following:

  • index.php — This file will contain the master template (header, footer, etc) and basic routing so we can include the pages below.
  • home.php — This file will be the home page, this will contain a featured image and 4 recently added products.
  • products.php — This file will be for displaying all products with basic pagination.
  • product.php — This file will display a product (depends on the GET request) and will contain a form that will allow the user to change the quantity and add to cart.
  • cart.php — The shopping cart page, this will list all the products that have been added to cart, with the quantities, total prices, and subtotal price.
  • placeorder.php — A basic message that will be displayed to the user when they place an order on the shopping cart page.
  • style.css — The stylesheet we'll use for our shopping cart website.
  • imgs — This folder will contain all the images for our shopping cart system, this includes featured images and product images, to download the example images just click the file name in the file structure box.

2. Creating the Database and setting-up Tables

For this part, you will need to access your MySQL database, either using phpMyAdmin or your preferred MySQL database management application.

If you're using phpMyAdmin follow these instructions:

  • Navigate to http://localhost/phpmyadmin/
  • Click the Databases tab at the top
  • Under Create database, type in shoppingcart in the text box
  • Select utf8_general_ci as the collation
  • Click Create

You can use your own database name, but for this tutorial, I'll use shoppingcart.

What we need now is a products table, this table will store all the products and will contain the product name, description, image, price, RRP price, quantity, and the date added.

Click the database on the left side panel (shoppingcart) and execute the following SQL statement:

CREATE TABLE IF NOT EXISTS `products` (
	`id` int(11) NOT NULL AUTO_INCREMENT,
	`name` varchar(200) NOT NULL,
	`desc` text NOT NULL,
	`price` decimal(7,2) NOT NULL,—
	`rrp` decimal(7,2) NOT NULL DEFAULT '0.00',
	`quantity` int(11) NOT NULL,
	`img` text NOT NULL,
	`date_added` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
	PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

INSERT INTO `products` (`id`, `name`, `desc`, `price`, `rrp`, `quantity`, `img`, `date_added`) VALUES
(1, 'Smart Watch', '<p>Unique watch made with stainless steel, ideal for those that prefer interative watches.</p>\r\n<h3>Features</h3>\r\n<ul>\r\n<li>Powered by Android with built-in apps.</li>\r\n<li>Adjustable to fit most.</li>\r\n<li>Long battery life, continuous wear for up to 2 days.</li>\r\n<li>Lightweight design, comfort on your wrist.</li>\r\n</ul>', '29.99', '0.00', 10, 'watch.jpg', '2019-03-13 17:55:22'),
(2, 'Wallet', '', '14.99', '19.99', 34, 'wallet.jpg', '2019-03-13 18:52:49'),
(3, 'Headphones', '', '19.99', '0.00', 23, 'headphones.jpg', '2019-03-13 18:47:56'),
(4, 'Digital Camera', '', '69.99', '0.00', 7, 'camera.jpg', '2019-03-13 17:42:04');

On phpMyAdmin this should look like:

http://localhost/phpmyadmin/
MySQL Products Table

The above SQL statement code will create the products table with the following columns:

  • id — Unique ID for the product.
  • name — The name of the product.
  • desc — The description of the product.
  • price — The price of the product.
  • rrp — The retail pricing, if you want a product on sale you put the value higher than the price.
  • date_added — The date the product was added, we'll use this for sorting products.

The SQL statement will also insert 4 example products, these are just examples for the tutorial, you can change/remove them later on.

3. Designing the Shopping Cart System with CSS

Instead of using a library such as Bootstrap, I've decided to create a clean, crisp, and modern design with pure CSS3.

The Basic and Advanced packages include the SCSS file and the responsive design CSS code, you can easily change the color scheme, fonts, content size, etc, with SCSS.

Edit style.css and insert the following code:

* {
	box-sizing: border-box;
	font-family: -apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, ubuntu, cantarell, "fira sans", "droid sans", "helvetica neue", Arial, sans-serif;
	font-size: 16px;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}
html {
	height: 100%;
}
body {
	position: relative;
	min-height: 100%;
	color: #555555;
	background-color: #FFFFFF;
	margin: 0;
	padding-bottom: 100px; /* Same height as footer */
}
h1, h2, h3, h4, h5 {
	color: #394352;
}
.content-wrapper {
	width: 1050px;
	margin: 0 auto;
}
header {
	border-bottom: 1px solid #EEEEEE;
}
header .content-wrapper {
	display: flex;
}
header h1 {
	display: flex;
	flex-grow: 1;
	flex-basis: 0;
	font-size: 20px;
	margin: 0;
	padding: 24px 0;
}
header nav {
	display: flex;
	flex-grow: 1;
	flex-basis: 0;
	justify-content: center;
	align-items: center;
}
header nav a {
	text-decoration: none;
	color: #555555;
	padding: 10px 10px;
	margin: 0 10px;
}
header nav a:hover {
	border-bottom: 1px solid #aaa;
}
header .link-icons {
	display: flex;
	flex-grow: 1;
	flex-basis: 0;
	justify-content: flex-end;
	align-items: center;
	position: relative;
}
header .link-icons a {
	text-decoration: none;
	color: #394352;
	padding: 0 10px;
}
header .link-icons a:hover {
	color: #4e5c70;
}
header .link-icons a i {
	font-size: 18px;
}
header .link-icons a span {
	display: inline-block;
	text-align: center;
	background-color: #63748e;
	border-radius: 50%;
	color: #FFFFFF;
	font-size: 12px;
	line-height: 16px;
	width: 16px;
	height: 16px;
	font-weight: bold;
	position: absolute;
	top: 22px;
	right: 0;
}
main .featured {
	display: flex;
	flex-direction: column;
	background-image: url(imgs/featured-image.jpg);
	background-repeat: no-repeat;
	background-size: cover;
	height: 500px;
	align-items: center;
	justify-content: center;
	text-align: center;
}
main .featured h2 {
	display: inline-block;
	margin: 0;
	width: 1050px;
	font-family: Rockwell, Courier Bold, Courier, Georgia, Times, Times New Roman, serif;
	font-size: 68px;
	color: #FFFFFF;
	padding-bottom: 10px;
}
main .featured p {
	display: inline-block;
	margin: 0;
	width: 1050px;
	font-size: 24px;
	color: #FFFFFF;
}
main .recentlyadded h2 {
	display: block;
	font-weight: normal;
	margin: 0;
	padding: 40px 0;
	font-size: 24px;
	text-align: center;
	width: 100%;
	border-bottom: 1px solid #EEEEEE;
}
main .recentlyadded .products, main .products .products-wrapper {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	padding: 40px 0 0 0;
}
main .recentlyadded .products .product, main .products .products-wrapper .product {
	display: block;
	overflow: hidden;
	text-decoration: none;
	width: 25%;
	padding-bottom: 60px;
}
main .recentlyadded .products .product img, main .products .products-wrapper .product img {
	transform: scale(1);
	transition: transform 1s;
}
main .recentlyadded .products .product .name, main .products .products-wrapper .product .name {
	display: block;
	color: #555555;
	padding: 20px 0 2px 0;
}
main .recentlyadded .products .product .price, main .products .products-wrapper .product .price {
	display: block;
	color: #999999;
}
main .recentlyadded .products .product .rrp, main .products .products-wrapper .product .rrp {
	color: #BBBBBB;
	text-decoration: line-through;
}
main .recentlyadded .products .product:hover img, main .products .products-wrapper .product:hover img {
	transform: scale(1.05);
	transition: transform 1s;
}
main .recentlyadded .products .product:hover .name, main .products .products-wrapper .product:hover .name {
	text-decoration: underline;
}
main > .product {
	display: flex;
	padding: 40px 0;
}
main > .product > div {
	padding-left: 15px;
}
main > .product h1 {
	font-size: 34px;
	font-weight: normal;
	margin: 0;
	padding: 20px 0 10px 0;
}
main > .product .price {
	display: block;
	font-size: 22px;
	color: #999999;
}
main > .product .rrp {
	color: #BBBBBB;
	text-decoration: line-through;
	font-size: 22px;
	padding-left: 5px;
}
main > .product form {
	display: flex;
	flex-flow: column;
	margin: 40px 0;
}
main > .product form input[type="number"] {
	width: 400px;
	padding: 10px;
	margin-bottom: 15px;
	border: 1px solid #ccc;
	color: #555555;
	border-radius: 5px;
}
main > .product form input[type="submit"] {
	background: #4e5c70;
	border: 0;
	color: #FFFFFF;
	width: 400px;
	padding: 12px 0;
	text-transform: uppercase;
	font-size: 14px;
	font-weight: bold;
	border-radius: 5px;
	cursor: pointer;
}
main > .product form input[type="submit"]:hover {
	background: #434f61;
}
main > .products h1 {
	display: block;
	font-weight: normal;
	margin: 0;
	padding: 40px 0;
	font-size: 24px;
	text-align: center;
	width: 100%;
}
main > .products .buttons {
	text-align: right;
	padding-bottom: 40px;
}
main > .products .buttons a {
	display: inline-block;
	text-decoration: none;
	margin-left: 5px;
	padding: 12px 20px;
	border: 0;
	background: #4e5c70;
	color: #FFFFFF;
	font-size: 14px;
	font-weight: bold;
	border-radius: 5px;
}
main > .products .buttons a:hover {
	background: #434f61;
}
main .cart h1 {
	display: block;
	font-weight: normal;
	margin: 0;
	padding: 40px 0;
	font-size: 24px;
	text-align: center;
	width: 100%;
}
main .cart table {
	width: 100%;
}
main .cart table thead td {
	padding: 30px 0;
	border-bottom: 1px solid #EEEEEE;
}
main .cart table thead td:last-child {
	text-align: right;
}
main .cart table tbody td {
	padding: 20px 0;
	border-bottom: 1px solid #EEEEEE;
}
main .cart table tbody td:last-child {
	text-align: right;
}
main .cart table .img {
	width: 80px;
}
main .cart table .remove {
	color: #777777;
	font-size: 12px;
	padding-top: 3px;
}
main .cart table .remove:hover {
	text-decoration: underline;
}
main .cart table .price {
	color: #999999;
}
main .cart table a {
	text-decoration: none;
	color: #555555;
}
main .cart table input[type="number"] {
	width: 68px;
	padding: 10px;
	border: 1px solid #ccc;
	color: #555555;
	border-radius: 5px;
}
main .cart .subtotal {
	text-align: right;
	padding: 40px 0;
}
main .cart .subtotal .text {
	padding-right: 40px;
	font-size: 18px;
}
main .cart .subtotal .price {
	font-size: 18px;
	color: #999999;
}
main .cart .buttons {
	text-align: right;
	padding-bottom: 40px;
}
main .cart .buttons input[type="submit"] {
	margin-left: 5px;
	padding: 12px 20px;
	border: 0;
	background: #4e5c70;
	color: #FFFFFF;
	font-size: 14px;
	font-weight: bold;
	cursor: pointer;
	border-radius: 5px;
}
main .cart .buttons input[type="submit"]:hover {
	background: #434f61;
}
main .placeorder h1 {
	display: block;
	font-weight: normal;
	margin: 0;
	padding: 40px 0;
	font-size: 24px;
	text-align: center;
	width: 100%;
}
main .placeorder p {
	text-align: center;
}
footer {
	position: absolute;
	bottom: 0;
	border-top: 1px solid #EEEEEE;
	padding: 20px 0;
	width: 100%;
}

This will be the stylesheet we'll use for the shopping cart system.

4. Creating the Index File

The index.php file will basically be our main file for accessing pages, we'll setup basic routing and use GET request to determine which page is which.

4.1. Connect to MySQL Database

Edit index.php and insert the following:

<?php
session_start();
// Change the variables below to your connection info.
$DATABASE_HOST = 'localhost';
$DATABASE_USER = 'root';
$DATABASE_PASS = '';
$DATABASE_NAME = 'shoppingcart';
// Try and connect using the info above.
try {
	$pdo = new PDO('mysql:host=' . $DATABASE_HOST . ';dbname=' . $DATABASE_NAME . ';charset=utf8', $DATABASE_USER, $DATABASE_PASS);
} catch (PDOException $exception) {
	// If there is an error with the connection, stop the script and display the error.
	die ('Failed to connect to database!');
}

The first thing we do is start the sessions, we'll be using sessions to store the cart data, after, we connect to MySQL using PDO and select the shoppingcart database that we created earlier.

4.2. Basic Routing

Add after the above code:

// Add pages we only need for our shopping cart system, for example addtocart will include the addtocart.php file.
$pages = array('cart', 'home', 'product', 'products', 'placeorder');
// Page is set to home (home.php) by default, so when the visitor visits that will be the page they see.
$page = isset($_GET['page']) && in_array($_GET['page'], $pages) ? $_GET['page'] : 'home';
?>

The basic routing method used above checks if the GET request variable ($_GET['page']) exists, if not, the default page will be set to the home page, the $pages array is all the pages that exist in our shopping cart system, we don't want users to try and access none page files.

If we want to access the products page, for example, we can navigate to http://localhost/shoppingcart/index.php?page=products.

4.3. Create Master Template

Add after the PHP closing tag:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Shopping Cart System</title>
		<link href="style.css" rel="stylesheet" type="text/css">
		<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
	</head>
	<body>
        <header>
            <div class="content-wrapper">
                <h1>Shopping Cart System</h1>
                <nav>
                    <a href="index.php">Home</a>
                    <a href="index.php?page=products">Products</a>
                </nav>
                <div class="link-icons">
                    <a href="index.php?page=cart">
						<i class="fas fa-shopping-cart"></i>
					</a>
                </div>
            </div>
        </header>
        <main>
        <?php include $page . '.php'; ?>
        </main>
        <footer>
			<div class="content-wrapper">
            	<p>© <?=date('Y')?>, Shopping Cart System</p>
			</div>
        </footer>
    </body>
</html>

This is our master template file, as you can see we include the PHP page file between the main tags, this is a basic templating system, it's useful because we don't have to include the above code in every single file, and we also don't need to connect to the database.

If you access the index.php in your browser you will see the header and footer but nothing in between, that's because we haven't edited the home.php file yet.

For the icons (shopping cart icon) we're using Font Awesome, the stylesheet CDN is included in the head section.

5. Creating the Home Page

The home page will be the first page our visitors will see, so for this page, we can add a featured image and text, and also a list of 4 recently added products.

5.1. Get 4 Products from Database

Edit home.php and insert the following:

<?php
// Get the 4 most recently added products
$stmt = $pdo->prepare('SELECT * FROM products ORDER BY date_added DESC LIMIT 4');
$stmt->execute();
$recently_added_products = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

The above code will get the 4 most recently added products, all we do is order by the date_added column and limit the amount by 4, pretty simple right? And then store the result in the $recently_added_products variable (as an array).

5.2. Create Home Template

Add after the PHP closing tag:

<div class="featured">
    <h2>Gadgets</h2>
    <p>Essential gadgets for everyday use</p>
</div>
<div class="recentlyadded content-wrapper">
    <h2>Recently Added Products</h2>
    <div class="products">
        <?php foreach ($recently_added_products as $product): ?>
        <a href="index.php?page=product&id=<?=$product['id']?>" class="product">
            <img src="imgs/<?=$product['img']?>" width="200" height="200" alt="<?=$product['name']?>">
            <span class="name"><?=$product['name']?></span>
            <span class="price">
                &dollar;<?=$product['price']?>
                <?php if ($product['rrp'] > 0): ?>
                <span class="rrp">&dollar;<?=$product['rrp']?></span>
                <?php endif; ?>
            </span>
        </a>
        <?php endforeach; ?>
    </div>
</div>

This will create us a basic home page, we loop each product in the $recently_added_products variable and display them accordingly if there's an RRP price we include it.

If you prefer to use your own currency you can change the $ entity code, you can find the list here.

Also, take note all the product images are in the img folder if you're using the example products you can download them in the File Structure section.

if we navigate to http://localhost/shoppingcart/index.php, it should look like the following:

http://localhost/shoppingcart/index.php
Shopping Cart Home Page

You can also access the home page by going to http://localhost/shoppingcart/index.php?page=home because of the routing we setup earlier.

6. Creating the Products Page

The products page will be where users will go to browse all products, we can set a maximum number of products to show on each page and add pagination with a next and previous button to navigate.

6.1. Get Products from Database with Pagination

Edit products.php and insert the following:

<?php
// The amounts of products to show on each page
$num_products_on_each_page = 4;
// The current page, in the URL this will appear as index.php?page=products&p=1, index.php?page=products&p=2, etc...
$current_page = isset($_GET['p']) && is_numeric($_GET['p']) ? (int)$_GET['p'] : 1;
// Select products ordered by the date added
$stmt = $pdo->prepare('SELECT * FROM products ORDER BY date_added DESC LIMIT ?,?');
// bindValue will allow us to use integer in the SQL statement, we need to use for LIMIT
$stmt->bindValue(1, ($current_page - 1) * $num_products_on_each_page, PDO::PARAM_INT);
$stmt->bindValue(2, $num_products_on_each_page, PDO::PARAM_INT);
$stmt->execute();
// Fetch the products from the database and return the result as an Array
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);

You can change the $num_products_on_each_page variable to how many products you want to show on each page.

To determine what page a user is on we can use a GET request, in the URL this will appear as index.php?page=products&p=1 etc, and in our PHP script the parameter p we can get with the $_GET['p'] variable, and then select products from our database with a limit clause.

Take note that we are using prepared statements, prepared statements will prevent SQL injection, you should always use them with GET and POST requests.

6.2. Get the Total amount of Products

Add after the above code:

// Get the total number of products
$total_products = $pdo->query('SELECT * FROM products')->rowCount();
?>

This will get the total amount of products in our database table products, the user will be able to see the total products at the top of the products page.

6.3. Create Products Template

Add after the PHP closing tag:

<div class="products content-wrapper">
    <h1>Products</h1>
    <p><?=$total_products?> Products</p>
    <div class="products-wrapper">
        <?php foreach ($products as $product): ?>
        <a href="index.php?page=product&id=<?=$product['id']?>" class="product">
            <img src="imgs/<?=$product['img']?>" width="200" height="200" alt="<?=$product['name']?>">
            <span class="name"><?=$product['name']?></span>
            <span class="price">
                &dollar;<?=$product['price']?>
                <?php if ($product['rrp'] > 0): ?>
                <span class="rrp">&dollar;<?=$product['rrp']?></span>
                <?php endif; ?>
            </span>
        </a>
        <?php endforeach; ?>
    </div>
    <div class="buttons">
        <?php if ($current_page > 1): ?>
        <a href="index.php?page=products&p=<?=$current_page-1?>">Prev</a>
        <?php endif; ?>
        <?php if ($total_products > ($current_page * $num_products_on_each_page) - $num_products_on_each_page + count($products)): ?>
        <a href="index.php?page=products&p=<?=$current_page+1?>">Next</a>
        <?php endif; ?>
    </div>
</div>

Remember the recently added products we created for the home page? We basically use the same code but instead, it's determined by the products page and the $num_products_on_each_page variable.

Next and Prev buttons will only be visible to the user if there are more products to show.

If we navigate to http://localhost/shoppingcart/index.php?page=products it should look like the following:

http://localhost/shoppingcart/index.php?page=products
Shopping Cart Products Page

That's basically all we need for a products page, additional features such as product sorting are available in the Basic and Advanced packages.

7. Creating the Product Page

The product page is where users will get to view a product, view it's price, image, and description. The user will be able to change the quantity and add to cart with a click of a button.

7.1. Get Product from Database with GET Request

Edit product.php and insert the following:

<?php
// Check to make sure the id parameter is specified in the URL
if (isset($_GET['id'])) {
    // Prepare statement and execute, prevents SQL injection
    $stmt = $pdo->prepare('SELECT * FROM products WHERE id = ?');
    $stmt->execute([$_GET['id']]);
    // Fetch the product from the database and return the result as an Array
    $product = $stmt->fetch(PDO::FETCH_ASSOC);
    // Check if the product exists (array is not empty)
    if (!$product) {
        // Simple error to display if the id for the product doesn't exists (array is empty)
        die ('Product does not exist!');
    }
} else {
    // Simple error to display if the id wasn't specified
    die ('Product does not exist!');
}
?>

The code above will check if the id GET request exists, this is how we get a product from the products table in our database, the prepared statement will get a product by the id column (if exists).

If the product doesn't exist in the database we can throw a simple error, the die() function will prevent further script execution.

7.2. Create Product Template

Add after the PHP closing tag:

<div class="product content-wrapper">
    <img src="imgs/<?=$product['img']?>" width="500" height="500" alt="<?=$product['name']?>">
    <div>
        <h1 class="name"><?=$product['name']?></h1>
        <span class="price">
            &dollar;<?=$product['price']?>
            <?php if ($product['rrp'] > 0): ?>
            <span class="rrp">&dollar;<?=$product['rrp']?></span>
            <?php endif; ?>
        </span>
        <form action="index.php?page=cart" method="post">
            <input type="number" name="quantity" value="1" min="1" max="<?=$product['quantity']?>" placeholder="Quantity" required>
            <input type="hidden" name="product_id" value="<?=$product['id']?>">
            <input type="submit" value="Add To Cart">
        </form>
        <div class="description">
            <?=$product['desc']?>
        </div>
    </div>
</div>

This will create the template for the product page, notice here we use a form and the method set to the shopping cart page, the shopping cart page will add the product to cart.

With the quantity form field, we can set maximum value, this value is set to the product's quantity (not the users). The product ID is also added to the form, this is so we know which product the user has added.

We don't need to include the product's name, description, etc, because we can get that data from the products table in our database.

If we navigate to http://localhost/shoppingcart/index.php?page=product&id=1 it should look like the following:

http://localhost/shoppingcart/index.php?page=product&id=1
Shopping Cart Product Page

If you change the id parameter in the URL to let's say 2, it will show us a different product.

8. Creating the Shopping Cart Page

The shopping cart page is where the user will be able to see their products added to the shopping cart, they will be able to remove products and update the quantities.

8.1. Adding a Product to Cart

Edit cart.php and insert the following:

// If the user clicked the add to cart button on the product page we can check for the form data
if (isset($_POST['product_id'], $_POST['quantity']) && is_numeric($_POST['product_id']) && is_numeric($_POST['quantity'])) {
    // Set the post variables so we easily identify them, also make sure they are integer
    $product_id = (int)$_POST['product_id'];
    $quantity = (int)$_POST['quantity'];
    // Prepare the SQL statement, we basically are checking if the product exists in our databaser
    $stmt = $pdo->prepare('SELECT * FROM products WHERE id = ?');
    $stmt->execute([$_POST['product_id']]);
    // Fetch the product from the database and return the result as an Array
    $product = $stmt->fetch(PDO::FETCH_ASSOC);
    // Check if the product exists (array is not empty)
    if ($product && $quantity > 0) {
        // Product exists in database, now we can create/update the session variable for the cart
        if (isset($_SESSION['cart']) && is_array($_SESSION['cart'])) {
            if (array_key_exists($product_id, $_SESSION['cart'])) {
                // Product exists in cart so just update the quanity
                $_SESSION['cart'][$product_id] += $quantity;
            } else {
                // Product is not in cart so add it
                $_SESSION['cart'][$product_id] = $quantity;
            }
        } else {
            // There are no products in cart, this will add the first product to cart
            $_SESSION['cart'] = array($product_id => $quantity);
        }
    }
}

This is where we make use of PHP sessions, we can use PHP sessions to remember the shopping cart products, so when a user navigates to another page etc, the shopping cart will still contain the products added until the session expires.

The code above will check if a product was added to cart, if you go back to the product.php file you can see we created a form, we are checking for those form values, if the product exists, we verify the product by selecting it from our products table in our database.

The session variable cart will be an array of products, this is so we can add multiple products to the cart, the array key will be the product ID and the value will be the quantity if a product already exists in the cart we just update the quantity.

8.2. Removing a Product from Cart

Add after the above code:

// Remove product from cart, check for the URL param "remove", this is the product id, make sure it's a number and check if it's in the cart
if (isset($_GET['remove']) && is_numeric($_GET['remove']) && isset($_SESSION['cart']) && isset($_SESSION['cart'][$_GET['remove']])) {
    // Remove the product from the shopping cart
    unset($_SESSION['cart'][$_GET['remove']]);
}

On the shopping cart page the user can remove a product, when the link is clicked we can use a GET request to determine what product to remove, for example, if we have a product with the ID 1, the following URL will remove it from the shopping cart: http://localhost/shoppingcart/index.php?page=cart&remove=1.

8.3. Updating Product Quantities

Add after the above code:

// Update product quantities in cart if the user clicks the "Update" button on the shopping cart page
if (isset($_POST['update']) && isset($_SESSION['cart'])) {
    // Loop through the post data so we can update the quantities for every product in cart
    foreach ($_POST as $k => $v) {
        if (strpos($k, 'quantity') !== false && is_numeric($v)) {
            $id = str_replace('quantity-', '', $k);
            $quantity = (int)$v;
            // Always do checks and validation
            if (is_numeric($id) && isset($_SESSION['cart'][$id]) && $quantity > 0) {
                // Update new quantity
                $_SESSION['cart'][$id] = $quantity;
            }
        }
    }
}

The code above will loop through every product in the shopping cart and update the quantities, the user can change the quantities on the shopping cart page. The Update button has a name of update, this is how we'll know when to update the quantities using a POST request.

8.4. Handling the Place Order

Add after the above code:

// Send the user to the place order page if they click the Place Order button, also the cart should not be empty
if (isset($_POST['placeorder']) && isset($_SESSION['cart']) && !empty($_SESSION['cart'])) {
    header('Location: index.php?page=placeorder');
    exit;
}

Redirect the user to the place order page if they click the Place Order button.

8.5. Get Products in Cart and Select from Database

Add after the above code:

// Check the session variable for products in cart
$products_in_cart = isset($_SESSION['cart']) ? $_SESSION['cart'] : array();
$products = array();
$subtotal = 0.00;
// If there are products in cart
if ($products_in_cart) {
    // There are products in the cart so we need to select those products from the database
    // Products in cart array to question mark string array, we need the SQL statement to include IN (?,?,?,...etc)
    $array_to_question_marks = implode(',', array_fill(0, count($products_in_cart), '?'));
    $stmt = $pdo->prepare('SELECT * FROM products WHERE id IN (' . $array_to_question_marks . ')');
    // We only need the array keys, not the values, the keys are the id's of the products
    $stmt->execute(array_keys($products_in_cart));
    // Fetch the products from the database and return the result as an Array
    $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
    // Calculate the subtotal
    foreach ($products as $product) {
        $subtotal += $product['price'] * $products_in_cart[$product['id']];
    }
}
?>

If there are products in the cart we need to select those products from our database table products, we need the product name, description, image, and price, as before we didn't store this information in our session variable.

We also calculate the subtotal by iterating the products and multiplying the price by the quantity.

8.6. Create Shopping Cart Template

Add below the PHP closing tag:

<div class="cart content-wrapper">
    <h1>Shopping Cart</h1>
    <form action="index.php?page=cart" method="post">
        <table>
            <thead>
                <tr>
                    <td colspan="2">Product</td>
                    <td>Price</td>
                    <td>Quantity</td>
                    <td>Total</td>
                </tr>
            </thead>
            <tbody>
                <?php if (empty($products)): ?>
                <tr>
                    <td colspan="5" style="text-align:center;">You have no products added in your Shopping Cart</td>
                </tr>
                <?php else: ?>
                <?php foreach ($products as $product): ?>
                <tr>
                    <td class="img">
                        <a href="index.php?page=product&id=<?=$product['id']?>">
                            <img src="imgs/<?=$product['img']?>" width="50" height="50" alt="<?=$product['name']?>">
                        </a>
                    </td>
                    <td>
                        <a href="index.php?page=product&id=<?=$product['id']?>"><?=$product['name']?></a>
                        <br>
                        <a href="index.php?page=cart&remove=<?=$product['id']?>" class="remove">Remove</a>
                    </td>
                    <td class="price">&dollar;<?=$product['price']?></td>
                    <td class="quantity">
                        <input type="number" name="quantity-<?=$product['id']?>" value="<?=$products_in_cart[$product['id']]?>" min="1" max="<?=$product['quantity']?>" placeholder="Quantity" required>
                    </td>
                    <td class="price">&dollar;<?=$product['price'] * $products_in_cart[$product['id']]?></td>
                </tr>
                <?php endforeach; ?>
                <?php endif; ?>
            </tbody>
        </table>
        <div class="subtotal">
            <span class="text">Subtotal</span>
            <span class="price">&dollar;<?=$subtotal?></span>
        </div>
        <div class="buttons">
            <input type="submit" value="Update" name="update">
            <input type="submit" value="Place Order" name="placeorder">
        </div>
    </form>
</div>

That's all we need to do for the shopping cart page, the user can remove products and update quantities.

If you add a few products to the shopping cart and navigate to http://localhost/shoppingcart/index.php?page=cart, it will look something like the following:

http://localhost/shoppingcart/index.php?page=cart
Shopping Cart

To get the quantity to display in the header you'll need to edit index.php and add the following:

// Get the amount of items in the shopping cart, this will be displayed in the header.
$num_items_in_cart = isset($_SESSION['cart']) ? count($_SESSION['cart']) : 0;

Find:

<i class="fas fa-shopping-cart"></i>

Add after:

<span><?=$num_items_in_cart?></span>

And now the user will know how many products they have in their shopping cart despite the page they're on.

Product in Shopping Cart

9. Creating the Place Order Page

This page will let the user know that they have placed an order, to place an order they must have products in their shopping cart and have clicked the Place Order button on the shopping cart page.

9.1. Creating the Place Order Template

Edit placeorder.php and add the following:

<div class="placeorder content-wrapper">
    <h1>Your Order Has Been Placed</h1>
    <p>Thank you for ordering with us, we'll contact you by email with your order details.</p>
</div>

And now if we add a product to our shopping cart and click the Place Order button, we'll see the following:

http://localhost/index.php?page=placeorder
Shopping Cart Place Order

You can change the place order message etc, that's just there for an example of what you could put.

Conclusion

Congratulations, you've created a shopping cart system with PHP and MySQL, what next? Consider adding a checkout page and integrate a payment method, such as PayPal, they provide their own API for developers.

Remember that this is just a base shopping cart system for you to work from, I don't recommend going production until you have made a reasonable amount of changes and additions, for example, you would need to add your own error handling, payment method, and validation.

If you enjoyed this tutorial don't forget to hit the share button and drop a comment, this will help us create more tutorials.

If you would like to support us consider purchasing a package below, this will greatly help us create more tutorials and keep our server up and running.

Basic

Advanced

Source code
Database SQL file
Home page
Shopping cart page
Products page
Product page
Place order page
Checkout page
My account page
Account creation feature
Transactions feature
Product images feature
Search products feature
Sort products feature
Empty cart feature
Responsive design
SCSS file
Commented code
Free updates
Free support
* Payments are processed with PayPal.
* Advanced package also includes the basic package.

$15.00

Download

$25.00

Download