Simple PHP Shopping Cart Without Database (FREE Download)

Welcome to a tutorial on how to create a simple PHP shopping cart. Without a database, that is. Need a simple “no database cart”? Well, it is possible, but it is still not a straightforward thing. So let us walk through an example, read on!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

TABLE OF CONTENTS

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

  • Open 1-products.php, set your own products.
  • In 2-ajax-cart.php, set the email to your own in the checkout section.
  • Launch 3a-shop.php in the browser.
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

SCREENSHOT

 

EXAMPLE CODE DOWNLOAD

Click here to download all the example source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

 

PHP SHOPPING CART

All right, let us now get into the steps of building a PHP shopping cart without a database.

 

PART 1) PRODUCTS LIST

1-products.php
$products = [
  1 => ["name" => "Apple", "price" => 1.23, "image" => "apple.png"],
  2 => ["name" => "Mango", "price" => 2.34, "image" => "mango.png"],
  3 => ["name" => "Orange", "price" => 3.45, "image" => "orange.png"],
  4 => ["name" => "Pear", "price" => 4.32, "image" => "pear.png"]
];

Since we don’t have a database, the only way is store products is to hardcode them in an array. This should be self-explanatory, the products are in the format of PRODUCT ID => [PRODUCT DETAILS].

 

PART 2) AJAX CART HANDLER

2-ajax-cart.php
<?php
if (isset($_POST["req"])) {
  // (A) INIT SHOPPING CART
  session_start();
  if (!isset($_SESSION["cartI"])) {
    $_SESSION["cartI"] = []; // cart items
    $_SESSION["cartC"] = 0;  // total quantity
  }

  // (B) UPDATE CART COUNT
  function ccount () {
    $_SESSION["cartC"] = 0;
    if (count($_SESSION["cartI"])!=0) {
      foreach ($_SESSION["cartI"] as $id=>$qty) { $_SESSION["cartC"] += $qty; }
    }
  }

  // (C) STANDARD SYSTEM RESPONSE
  function respond ($status=1, $msg="OK") {
    echo json_encode(["status"=>$status, "msg"=>$msg, "count" => $_SESSION["cartC"]]);
  }

  // (D) CART ACTIONS
  switch ($_POST["req"]) {
    // (D1) GET COUNT
    case "count": respond(); break;

    // (D2) ADD / CHANGE QUANTITY / REMOVE
    // send id only to add item
    // send id and qty to set quantity
    // send id and 0 qty to remove item
    case "set":
      $max = 99; // max allowed quantity per item
      $item = &$_SESSION["cartI"][$_POST["id"]];
      if (isset($_POST["qty"])) { $item = $_POST["qty"]; }
      else { if (isset($item)) { $item++; } else { $item = 1; } }
      if ($item<=0) { unset($_SESSION["cartI"][$_POST["id"]]); } if ($item > $max) { $item = $max; }
      ccount(); respond(); break;

    // (D3) NUKE
    case "nuke":
      $_SESSION["cartI"] = [];
      $_SESSION["cartC"] = 0;
      respond(); break;

    // (D4) GET ALL ITEMS IN CART
    case "get":
      // (D4-1) CART IS EMPTY
      if ($_SESSION["cartC"]==0) { respond(1, null); break; }

      // (D4-2) GET PRODUCTS + FILTER ILLEGAL
      require "1-products.php";
      $items = [];
      foreach ($_SESSION["cartI"] as $id=>$qty) {
        if (isset($products[$id])) {
          $items[$id] = $products[$id];
          $items[$id]["qty"] = $qty;
        } else {
          $_SESSION["cartC"] -= $_SESSION["cartI"][$id];
          unset($_SESSION["cartI"][$id]);
        }
      }
      if ($_SESSION["cartC"]==0) { respond(1, null); break; }
      respond(1, $items); break;

    // (D5) CHECKOUT
    case "checkout":
      // (D5-1) CART IS EMPTY
      if ($_SESSION["cartC"]==0) { respond(0, "Cart Empty"); break; }

      // (D5-2) EMAIL TO ADMIN
      require "1-products.php";
      $to = "admin@site.com";
      $subject = "Order Received";
      $body = "Name: " . $_POST["name"] . "\r\n";
      $body .= "Email: " . $_POST["email"] . "\r\n";
      foreach ($_SESSION["cartI"] as $id=>$qty) {
        $body .= sprintf("%s X %s\r\n", $qty, $products[$id]["name"]);
      }
      if (mail($to, $subject, $body)) {
        $_SESSION["cartI"] = [];
        $_SESSION["cartC"] = 0;
        respond();
      } else { respond(0, "ERROR SENDING MAIL"); }
      break;
  }
}

Next, we build the shopping cart, the backbone of the system. It looks intimidating, but keep calm and look closely.

  • (A) We keep the user’s shopping cart items in the PHP session.
    • $_SESSION["cartI"] An array that contains the cart items in the format of PRODUCT ID => QUANTITY.
    • $_SESSION["cartC"] The total items quantity.
  • (D) How the script work is very simple, just send the request $_POST["req"] and required parameters. For example, $_POST["req"]="set" and $_POST["id"]=1 to add product ID 1 to the cart.
Request Notes & Parameters
count Get the total items quantity.
set
  • id only – Add item to cart.
  • id and qty – Set item quantity.
  • id and qty=0 – Remove item.
nuke Remove all items.
get Get all items in cart.
checkout
  • name Customer’s name.
  • email Customer’s email.

 

 

PART 3) SHOPPING PAGE

3A) HTML SHOPPING PAGE

3a-shop.php
<!-- (A) PRODUCTS + SHOPPING CART -->
<div id="wrap">
  <!-- (A1) HEADER -->
  <div id="head">
    <div id="iCart" onclick="cart.show()">
      My Cart <span id="cCart">0</span>
    </div>
  </div>
 
  <!-- (A2) PRODUCTS -->
  <div id="products"><?php
    require "1-products.php";
    foreach ($products as $i=>$p) { ?>
    <div class="pCell">
      <img class="pImg" src="images/<?=$p["image"]?>">
      <div class="pName"><?=$p["name"]?></div>
      <div class="pPrice">$<?=$p["price"]?></div>
      <input class="pAdd button" type="button" value="Add To Cart" onclick="cart.add(<?=$i?>)">
    </div>
    <?php } ?>
  </div>
 
  <!-- (A3) CART ITEMS -->
  <div id="wCart">
    <span id="wCartClose" class="button" onclick="cart.toggle(cart.hWCart, false)">&#8678;</span>
    <h2>SHOPPING CART</h2>
    <div id="cart"></div>
  </div>
</div>
 
<!-- (B) CHECKOUT FORM -->
<div id="checkout"><form onsubmit="return cart.checkout()">
  <div id="coClose" class="button" onclick="cart.toggle(cart.hCO, false)">X</div>
  <label>Name</label>
  <input type="text" id="coName" required value="Jon Doe">
  <label>Email</label>
  <input type="email" id="coEmail" required value="jon@doe.com">
  <input class="button" type="submit" value="Checkout">
</form></div>

With the PHP foundations ready, we can now build the HTML page. This looks confusing once again, but the essential parts are:

  • (A2) <div id="products"> We load 1-products.php and draw the HTML products here.
  • (A3) <div id="cart"> The current shopping cart.
  • (B) <div id="checkout"> Checkout form.

 

 

3B) SHOPPING CART JAVASCRIPT

3b-cart.js
var cart = {
  // (A) HELPER - AJAX FETCH
  ajax : (data, after) => {
    // (A1) FORM DATA
    let form = new FormData();
    for (let [k, v] of Object.entries(data)) { form.append(k, v); }
 
    // (A2) FETCH
    fetch("2-ajax-cart.php", { method:"POST", body:form })
    .then(res => res.json())
    .then(res => {
      if (res.status==1) { after(res); }
      else { alert(res.msg); }
    })
    .catch(err => console.error(err));
  },
 
  // (B) HELPER - TOGGLE HTML SECTIONS
  toggle : (target, show) => {
    if (show) { target.className = "show"; }
    else { target.className = ""; }
  },
 
  // (C) INITIALIZE
  hCart : null, // html cart
  hWCart : null, // html cart wrapper
  hCCart : null, // html cart count
  hCO : null, // html checkout wrapper
  init : () => {
    // (C1) GET HTML ELEMENTS
    cart.hCart = document.getElementById("cart");
    cart.hWCart = document.getElementById("wCart");
    cart.hCCart = document.getElementById("cCart");
    cart.hCO = document.getElementById("checkout");
 
    // (C2) UPDATE CART COUNT
    cart.ajax({ req : "count" }, res => cart.count(res.count));
  },
 
  // (D) UPDATE CART COUNT
  count : qty => {
    cart.hCCart.innerHTML = qty;
    if (cart.hWCart.classList.contains("show")) { cart.show(); }
  },
 
  // (E) SHOW CART ITEMS
  show : () => {
    // (E1) RESET
    cart.toggle(cart.hWCart, true);
    cart.hCart.innerHTML = "";
 
    // (E2) LOAD & GENERATE HTML
    cart.ajax({ req : "get" }, items => {
      // (E2-1) ITEMS IN CART
      items = items.msg;
 
      // (E2-2) CART IS EMPTY
      if (items==null) {
        cart.hCart.innerHTML = `<div class="cCell empty">Cart is empty</div>`;
      }
 
      // (E2-3) DRAW CART ITEMS
      else {
        let row, subtotal, total = 0;
        for (let [id, item] of Object.entries(items)) {
          // CALCULATE SUBTOTAL
          subtotal = item["price"] * item["qty"];
          total += subtotal;
 
          // ITEM ROW
          row = document.createElement("div");
          row.className = "cCell";
          row.innerHTML = `<input class="cQty" type="number" value="${item["qty"]}" 
          min="0" max="99" onchange="cart.change(${id}, this.value)">
          <div class="cInfo">
            <div class="cName">${item["name"]}</div>
            <div class="cPrice">$${subtotal.toFixed(2)}</div>
          </div>
          <input class="cDel button" type="button" value="X" onclick="cart.remove(${id})">`;
          cart.hCart.appendChild(row);
        }
 
        // CART TOTALS
        row = document.createElement("div");
        row.className = "cCell";
        row.innerHTML = `<input class="cDel button" type="button" value="X" onclick="cart.empty()">
        <div class="cInfo">
          <div class="cName">Total</div>
          <div class="cPrice">$${total.toFixed(2)}</div>
        </div>
        <input class="cDel button" type="button" value="&gt;" onclick="cart.toggle(cart.hCO, true)">`;
        cart.hCart.appendChild(row);
      }
    });
  },
 
  // (F) ADD ITEM TO CART
  add : id => cart.ajax(
    { req : "set", id : id },
    res => cart.count(res.count)
  ),
 
  // (G) CHANGE ITEM QTY
  change : (id, qty) => cart.ajax(
    { req : "set", id : id, qty : qty },
    res => cart.count(res.count)
  ),
 
  // (H) REMOVE ITEM
  remove : id => cart.ajax(
    { req : "set", id : id, qty : 0 },
    res => cart.count(res.count)
  ),
 
  // (I) NUKE
  empty : () => { if (confirm("Reset cart?")) {
    cart.ajax(
      { req : "nuke" },
      res => cart.count(res.count)
    ); 
  }},
 
  // (J) CHECKOUT
  checkout : () => {
    cart.ajax({
      req : "checkout",
      name : document.getElementById("coName").value,
      email : document.getElementById("coEmail").value
    }, res => location.href = "3c-thank-you.html"); 
    return false;
  }
};
window.onload = cart.init;

Not going to explain line by line, so here’s a quick summary.

  • (A) ajax() A helper function to do an AJAX call to 2-ajax-cart.php.
  • (B) toggle() A helper function to toggle show/hide for the cart and checkout form.
  • (C) init() Runs on window load, pretty much just getting the HTML elements.
  • (D To J) All the cart actions.
    • count() Update the total cart quantity.
    • show() Show the cart items.
    • add() Add an item to the shopping cart.
    • change() Change item quantity.
    • remove() Remove item from cart.
    • empty() Empty the entire cart.
    • checkout() Checkout.

 

 

3C) THANK YOU PAGE

3c-thank-you.html
<h1>Thank You</h1>
<p>Order received.</p>

Lastly, a dummy “thank you” on successful order.

 

 

EXTRA BITS & LINKS

That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.

 

LINKS & REFERENCES

 

A BETTER SHOPPING CART

Need a shopping cart with product options? Product categories? Discount coupons? User system and admin panel? Click here to check out my eBook!

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

Leave a Comment

Your email address will not be published. Required fields are marked *