Building a simple PHP shopping cart


One of the most common requirements any web designer/developer will come across is likely to be that of the small business taking its first steps online; a client with an established widget-selling company now wants to move into the national market and sell their widgets to the world.
What they need to do this (apart from a great-looking, functional, usable and accessible website!) is some sort of shopping-cart system to allow their customers to add, remove and update the products they wish to buy.
This article will walk through the simple steps to achieve this, using the server-side language PHP and a MySQL database.

Setting up the database

Let’s take as our example a bookseller. They are not the best-stocked bookseller in the world, having as they do only three titles in stock, but it is enough for our example. Let’s create the database and add some stock:
  1. CREATE TABLE books (
  2. id int(6) unsigned NOT NULL auto_increment,
  3. title varchar(100) NOT NULL default '',
  4. author varchar(100) NOT NULL default '',
  5. price decimal(3,2) NOT NULL default '0.00',
  6. PRIMARY KEY (id)
  7. ) TYPE=MyISAM;
  8.  
  9. INSERT INTO books VALUES (1, 'Where God Went Wrong', 'Oolon Colluphid', '24.99');
  10. INSERT INTO books VALUES (2, 'Some More of God\'s Greatest Mistakes', 'Oolon Colluphid', '17.99');
  11. INSERT INTO books VALUES (3, 'Who Is This God Person Anyway?', 'Oolon Colluphid', '14.99');
  12. Download this code: /code/php-cart-1.txt 
Now that step is out of the way, let’s create our shopping cart.

Identify our requirements

The cart we are going to build should be pretty familiar to most internet users. It will provide a means of displaying a message on every page of the site (along the lines of “You have 5 items in your shopping cart”), which when clicked will take the customer to a list of the items in the cart; each item may be removed or have its quantity updated.
As all of our stock details are stored in the database, the only piece of information that we need to store about each customer is the id of each product they have added to their cart. To do this, we are going to use PHP’s built-in session handling capabilities.

Using sessions in PHP

PHP’s session handling is very easy to understand.
To ‘switch it on’, simply add session_start(); at the top of your code; you can then store values (or arrays) in session variables:
$_SESSION['name'] = 'Matthew'; $_SESSION['age'] = 31;
These $_SESSION variables will now be available to any PHP scripts on other pages (as long as you’ve included the session_start(); call first).

A short note on cookies

The default behaviour of PHP sessions is to store the session ID (a long string of numbers and letters that identifies you to the server) as a cookie on your computer; however, even if you have cookies disabled this functionality will still work – PHP will instead append the session ID to each link on the site (in the form ‘mypage.php?PHPSESSID=’) so that it can continue to accurately track visitors from page to page.

Creating the cart

We will store the contents of the shopping cart as a comma-separated list of product ids in a session named (unsurprisingly) ‘cart’ – for example, a cart containing “1,1,3,1,2” has four items; three of product #1, and one each of products #2 and #3.
Firstly, let’s create the code to display the “You have X items…” message on every page:
  1. function writeShoppingCart() {
  2. $cart = $_SESSION['cart'];
  3. if (!$cart) {
  4. return '<p>You have no items in your shopping cart</p>';
  5. } else {
  6. // Parse the cart session variable
  7. $items = explode(',',$cart);
  8. $s = (count($items) > 1) ? 's':'';
  9. return '<p>You have <a href="cart.php">'.count($items).' item'.$s.' in your shopping cart</a></p>';
  10. }
  11. }
  12.  
  13. Download this code: /code/php-cart-2.txt 
This function first gets the value of the ‘cart’ session variable into a local variable, mainly to save on typing. If the cart is empty, we return an appropriate message; if not, we use the explode() function to create an array of all the products in the cart, and then count() them and display the result (the $s variable is there to make plurals display correctly).
Now we can display the correct message anywhere on the site:
echo writeShoppingCart();
I hope that made sense; let’s move on to displaying the contents of the cart itself.

Show me the money

The shopping cart page itself (cart.php) can be arrived at in a couple of ways. The user may have clicked on the link created by thewriteShoppingCart() function above; or, they may have clicked an ‘Add to cart’ link on a product page.
If it was the latter, we need to intercept that click and update our cart contents before displaying the new list of products – simple enough, as all we need to do is append the id of the clicked product to the ‘cart’ session variable. Our product links are going to look like this:
<a href="cart.php?action=add&id=1">Add to cart</a>
Don’t worry about the ‘action=add’ bit, we’ll get to that later. The id can now be extracted from $_GET[‘id’] and added to our cart:
  1. $cart = $_SESSION['cart'];
  2. if ($cart) {
  3. $cart .= ','.$_GET['id'];
  4. } else {
  5. $cart = $_GET['id'];
  6. }
  7. $_SESSION['cart'] = $cart;
  8. Download this code: /code/php-cart-3.txt 
Now, on to the contents of our cart!

Multiple items, one product

As in our example above, it is entirely possible that a customer might have more than one of a certain product in their cart. As we don’t want to list duplicate items when we display the contents, we need to figure out a way to combine any of the same product into one entry (with a corresponding quantity attached).
  1. $cart = $_SESSION['cart'];
  2. if ($cart) {
  3. $items = explode(',',$cart);
  4. $contents = array();
  5. foreach ($items as $item) {
  6. $contents[$item] = (isset($contents[$item])) ? $contents[$item] + 1 : 1;
  7. }
  8. Download this code: /code/php-cart-4.txt 
This time, after exploding the list of product ids, we have iterated through them to create a new array named $contents, which consists of key=>value pairs where the key is the product id and the value is the quantity of that product in the shopping cart. So to take our example above, a cart containing “1,1,3,1,2” would become an array where ‘1’=>3, ‘2’=>1, ‘3’=>1.
Now that we have an accurate count of unique products, let’s query the product database for each one and output its details into a table:
  1. $total = 0;
  2. $output[] = '<table>';
  3. foreach ($contents as $id=>$qty) {
  4. $sql = 'SELECT * FROM books WHERE id = '.$id;
  5. $result = $db->query($sql);
  6. $row = $result->fetch();
  7. extract($row);
  8. $output[] = '<tr>';
  9. $output[] = '<td><a href="cart.php?action=delete&id='.$id.'" class="r">Remove</a></td>';
  10. $output[] = '<td>'.$title.' by '.$author.'</td>';
  11. $output[] = '<td>&pound;'.$price.'</td>';
  12. $output[] = '<td><input type="text" name="qty'.$id.'" value="'.$qty.'" size="3" maxlength="3" /></td>';
  13. $output[] = '<td>&pound;'.($price * $qty).'</td>';
  14. $total += $price * $qty;
  15. $output[] = '</tr>';
  16. }
  17. $output[] = '</table>';
  18. $output[] = '<p>Grand total: &pound;'.$total.'</p>';
  19.  
  20. Download this code: /code/php-cart-5.txt 
(*Note*: I’m using a PHP class to handle my database connections, so your code may need to be slightly different).
Pretty simple stuff – we iterate through the new $contents array and query the database for each product id. Then we output the relevant details for each product; title, author and price, and at the bottom we show the grand total for the order. For each item, we’ve also included a link to remove the item from the cart, a textbox containing the current quantity of that item, and a total price (obviously this will only differ from the base price if the quantity is not 1).
The reason I’m using $output[] = ... is that I am buffering the output into an array to print to the screen later.
So far so good – now how about removing products from the cart?

Deleting a product

As shown above, the link to delete a product from the cart follows the same format as the ‘add a product’ link:
<a href="cart.php?action=delete&id=1">Remove</a>
Let’s expand on the code from earlier by adding a switch() statement to handle the different things that might happen to our cart:
  1. $cart = $_SESSION['cart'];
  2. $action = $_GET['action'];
  3. switch ($action) {
  4. case 'add':
  5. if ($cart) {
  6. $cart .= ','.$_GET['id'];
  7. } else {
  8. $cart = $_GET['id'];
  9. }
  10. break;
  11. case 'delete':
  12. if ($cart) {
  13. $items = explode(',',$cart);
  14. $newcart = '';
  15. foreach ($items as $item) {
  16. if ($_GET['id'] != $item) {
  17. if ($newcart != '') {
  18. $newcart .= ','.$item;
  19. } else {
  20. $newcart = $item;
  21. }
  22. }
  23. }
  24. $cart = $newcart;
  25. }
  26. break;
  27. }
  28. $_SESSION['cart'] = $cart;
  29. Download this code: /code/php-cart-6.txt 
The new ‘delete’ case iterates through the ‘cart’ session, looking for any product ids that AREN’T the one we’re deleting, and adding them to a temporary variable called $newcart. When it’s finished, it puts the revised cart contents back into $cart.

Updating a product

Lastly, we are going to allow customers to update the contents of their shopping cart by manually changing the value in the quantity box for each product.
To make this work, we’ll wrap the shopping cart table in a <form> so that the ‘update cart’ button will submit the form:
  1. $output[] = '<form action="cart.php?action=update" method="post" id="cart">';
  2. $output[] = '<table>';
  3. foreach ($contents as $id=>$qty) {
  4. $sql = 'SELECT * FROM books WHERE id = '.$id;
  5. $result = $db->query($sql);
  6. $row = $result->fetch();
  7. extract($row);
  8. $output[] = '<tr>';
  9. $output[] = '<td><a href="cart.php?action=delete&id='.$id.'" class="r">Remove</a></td>';
  10. $output[] = '<td>'.$title.' by '.$author.'</td>';
  11. $output[] = '<td>&pound;'.$price.'</td>';
  12. $output[] = '<td><input type="text" name="qty'.$id.'" value="'.$qty.'" size="3" maxlength="3" /></td>';
  13. $output[] = '<td>&pound;'.($price * $qty).'</td>';
  14. $total += $price * $qty;
  15. $output[] = '</tr>';
  16. }
  17. $output[] = '</table>';
  18. $output[] = '<p>Grand total: &pound;'.$total.'</p>';
  19. $output[] = '<div><button type="submit">Update cart</button></div>';
  20. $output[] = '</form>';
  21. Download this code: /code/php-cart-7.txt 
Note that, even though the form uses the POST method, its action includes a GET variable, “action=update”. Again, we can expand our previous code to process any quantity updates:
  1. case 'update':
  2. if ($cart) {
  3. $newcart = '';
  4. foreach ($_POST as $key=>$value) {
  5. if (stristr($key,'qty')) {
  6. $id = str_replace('qty','',$key);
  7. $items = ($newcart != '') ? explode(',',$newcart) : explode(',',$cart);
  8. $newcart = '';
  9. foreach ($items as $item) {
  10. if ($id != $item) {
  11. if ($newcart != '') {
  12. $newcart .= ','.$item;
  13. } else {
  14. $newcart = $item;
  15. }
  16. }
  17. }
  18. for ($i=1;$i<=$value;$i++) {
  19. if ($newcart != '') {
  20. $newcart .= ','.$id;
  21. } else {
  22. $newcart = $id;
  23. }
  24. }
  25. }
  26. }
  27. }
  28. $cart = $newcart;
  29. break;
  30.  
  31. Download this code: /code/php-cart-8.txt 
This looks quite complicated, but it’s fairly straightforward; we interrogate the contents of the $_POST array (which holds all our quantity values) and extract the relevant id and value pairs. For each product, we then delete all the existing instances of it, and re-insert the new quantity.
There are a number of ways this could have been done – for example, by counting the existing number of each product present in the cart and figuring out whether we needed to add or remove items – but this seemed the easiest way to process the quantity updates.

Summary

And that’s about it! A functional and easy shopping cart script – here’s the final function to display the contents of the cart:
  1. function showCart() {
  2. $cart = $_SESSION['cart'];
  3. if ($cart) {
  4. $items = explode(',',$cart);
  5. $contents = array();
  6. foreach ($items as $item) {
  7. $contents[$item] = (isset($contents[$item])) ? $contents[$item] + 1 : 1;
  8. }
  9. $output[] = '<form action="cart.php?action=update" method="post" id="cart">';
  10. $output[] = '<table>';
  11. foreach ($contents as $id=>$qty) {
  12. $sql = 'SELECT * FROM books WHERE id = '.$id;
  13. $result = $db->query($sql);
  14. $row = $result->fetch();
  15. extract($row);
  16. $output[] = '<tr>';
  17. $output[] = '<td><a href="cart.php?action=delete&id='.$id.'" class="r">Remove</a></td>';
  18. $output[] = '<td>'.$title.' by '.$author.'</td>';
  19. $output[] = '<td>&pound;'.$price.'</td>';
  20. $output[] = '<td><input type="text" name="qty'.$id.'" value="'.$qty.'" size="3" maxlength="3" /></td>';
  21. $output[] = '<td>&pound;'.($price * $qty).'</td>';
  22. $total += $price * $qty;
  23. $output[] = '</tr>';
  24. }
  25. $output[] = '</table>';
  26. $output[] = '<p>Grand total: &pound;'.$total.'</p>';
  27. $output[] = '<div><button type="submit">Update cart</button></div>';
  28. $output[] = '</form>';
  29. } else {
  30. $output[] = '<p>You shopping cart is empty.</p>';
  31. }
  32. return join('',$output);
  33. }
  34. Download this code: /code/php-cart-9.txt 
Note that if the cart is empty, a suitable message is displayed.
working demo can be seen (excuse the lack of design!), or please feel free to download a .zip of all the files  – any questions, comments or suggestions on how the code could be improved gratefully received.

No comments:

Post a Comment