Top Banner
Introduction The online shop we're makin here is a basic one without any sophisticated features and stuff. The shop has admin pages ( where the shop admin can create categories, add products, etc ) and the shopper pages ( a.k.a the shop itself ) where all the shopping process takes place. You will learn more about them in subsequent pages. By the way, i did call this tutorial as a shopping cart tutorial but actually we're building an online shop ( a really simple one ). The shopping cart is just part of the shop. But because the term 'shopping cart' is already common to define an online shop solution i just use it instead of naming this site a 'PHP MySQL Online Shop Tutorial'. I have to assume that you already know about PHP and MySQL so i won't explain every code in detail. The codes are not too complicated though, i'm sure you can understand it. I suggest you download the code first so you can run it on your computer. That way it's easier for you to understand this tutorial If you don't want to download the code that's fine but make sure you take a look at the demo site , this is what our shopping cart willl look like. After you browse around you will see that the basic flow of our shop is : 1. A customer visit the site 2. She browse the pages, clicking her way between categories 3. View the product details that she found interesting 4. Add products to shopping cart 5. Checkout ( entering the shipping address, payment info ) 6. Leave ( hopefully to return another time ) Nothing complex here. The customer doesn't need to register for an account. She just buy then leave.
71

Php Shoping Cart

Oct 27, 2014

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Php Shoping Cart

IntroductionThe online shop we're makin here is a basic one without any sophisticated features and stuff. The shop has admin pages ( where the shop admin can create categories, add products, etc ) and the shopper pages ( a.k.a the shop itself ) where all the shopping process takes place. You will learn more about them in subsequent pages.

By the way, i did call this tutorial as a shopping cart tutorial but actually we're building an online shop ( a really simple one ). The shopping cart is just part of the shop. But because the term 'shopping cart' is already common to define an online shop solution i just use it instead of naming this site a 'PHP MySQL Online Shop Tutorial'.

I have to assume that you already know about PHP and MySQL so i won't explain every code in detail. The codes are not too complicated though, i'm sure you can understand it. I suggest you download the code first so you can run it on your computer. That way it's easier for you to understand this tutorial

If you don't want to download the code that's fine but make sure you take a look at the demo site, this is what our shopping cart willl look like.

After you browse around you will see that the basic flow of our shop is :

1. A customer visit the site2. She browse the pages, clicking her way between categories3. View the product details that she found interesting4. Add products to shopping cart5. Checkout ( entering the shipping address, payment info )6. Leave ( hopefully to return another time )

Nothing complex here. The customer doesn't need to register for an account. She just buy then leave.

 

Features

Okay, here are the shop features ( or maybe i should call this restrictions )

1. Flat shipping cost. No complex shipping calculation for this shop right now and i don't have any plan to change this in near future.

2. Payment options including COD ( cash on delivery ) and PaypalFor now this shop can only handle COD and payment through Paypal IPN. The reason i pick paypal is because they provide excellent resource for developers so i can test the payment

Page 2: Php Shoping Cart

process easily.3. Configurable image and thumbnail size

You can restrict the product image width from the config file. You can also set the thumbnail width you want for all product images that you upload.

 

 

File Organization

The files in our shop will be organized like this :

The plaincart/library directory contain :

config.php : this is the main configuration file for our shop category-functions.php :functions required for fetching the categories product-functions.php : contain product related functions cart-functions.php : shopping cart specific functions checkout-functions.php : checkout processes are in here common.php : common functions required for the shop and admin pages database.php : contain the database abstraction functions

The plaincart/include contain :

header.php The shop common header.

top.phpYou can place your shop banner here.

footer.php Common footer, display the shop address, phone number and email. You can add more

Page 3: Php Shoping Cart

information here when needed. shop.css

Style sheet file for our shop leftNav.php

The left navigation you see on the shop categoryList.php

Show the top categories we have productList.php

Show the products in certain category productDetail.php

You know what this is for, right ? miniCart.php

Shown on the right portion of the shop pages, it shows the products in the shoping cart. shippingAndPaymentInfo.php

The form to enter shipping and payment info ( step 1 of checkout ) checkoutConfirmation.php

Show the order items, shipping & payment info ( step 2 of checkout )

The plaincart/include/paypal directory contain :

paypal.inc.phpThe configuration file for the paypal payment module

ipn.phpThe script that process payment verification

payment.phpContain the form that submit the payment information from this website to paypal website

The plaincart/admin folder will contain all the admin files.You can see that admin folder also contain include and library folder. These will contain specific library files for the admin pages

All images required in our shop will be put in plaincart/images directory. The category and product images are put in the category and product sub-folder respectively.

 

The Requirements

For this tutorial i'm using these :

Apache 2 PHP 4.3.10 with GD ( graphics library ) support ( you can also use lower version but >=

4.3.7 ) MySQL 4

If you don't have these ready check out this tutorial to install them : Installing Apache PHP &

Page 4: Php Shoping Cart

MySQL

 

What Configurations You Will Need

Database Configuration

When you install the shopping cart script you will need to modify library/config.php. You need to change the database connection info ( database host, username, password and name ) according to your own configurations.

Enabling GD Support

The next thing you may need to do is to enable the GD support. This is usually enabled by default by web hosting company but in case you test it on your own computer you may need to enable it manually.

First, open the php.ini file using a text editor ( notepad is okay ) and search for this line of code :

extension=php_gd2.dll

If you see that code preceded by a semicolon ( ; ) that means GD library is not enabled yet. Remove the semicolon to enable GD and then restart the web server ( apache ) for the changes to take effect.

I really hope this shopping cart tutorial is useful for you. Now to take the first step, let's start with the database design

Database Design

The database design for our shopping cart is quite simple. Below is the summary of what tables we need for this shopping cart plus the short description of each table. You can see the complete SQL needed to build the database here

Table Name   Description

tbl_category   Storing all product categories

tbl_product   The products ( what else )

tbl_cart  When the shopper decided to put an item into the shopping cart we'll add the item here

Page 5: Php Shoping Cart

tbl_order   This is where we save all orders

tbl_order_item   The items ordered

tbl_user   Store all shop admin user account

tbl_shop_config  Contain the shop configuration like name, address, phone number, email, etc

 

The ER ( Entity Relationship ) diagram is shown below.

 

Page 6: Php Shoping Cart

Now, let's take a better look at each table

tbl_category

This table store the product categories. From the ER diagram you can see that our current database design enables a category to have a child category and for the child category to have another child category and so on. But for this tutorial we make a restriction that the category will only two level deep like this "Top Category > Manga > Naruto". The reason is to reduce the number of clicks required by a visitor when browsing a category.

Another rule is that a product can only be added on the second level category. For example if we have this category structure :

Top Category > Manga > Naruto

then we can only add a product in "Naruto", not in "Manga". The top level categories will not contain any products and a product can only belong to one category.

 

tbl_product

In this table we store the product's name, category id, description, image and thumbnail. For now a product can only have one image. It may not be enough if you want to show a picture of you product from multiple angles so i plan to improve this on future version.

When adding a product image in the admin page we don't need to upload the thumbnail too. The script will generate the thumbnail from the main image. The thumbnail size is defined in library/config.php ( THUMBNAIL_WIDTH ) and currently it is set to 75 pixels.

 

tbl_cart

This table will store all items currently put by the customer. Here we have ct_session_id to save the id of a shopping session. We will explore this further when adding a product to shopping cart

 

tbl_order

Finally when the customer finally place the order, we add the new order in this table. The shipping

Page 7: Php Shoping Cart

and payment information that the customer provided during checkout are alos saved in this table including the shipping cost.

For the order id i decided to use an auto increment number starting from 1001.

Why start at 1001 ?

Because an order id looks ugly ( at least for me ^^ ) if it' s too short like 1, 2 or 3 so starting the order id from 1001 seems to be a good idea for me.

To make the order id start from 1001 we use the following sql :

CREATE TABLE tbl_order (   id int(10) unsigned NOT NULL auto_increment,   date datetime default NULL,   last_update datetime NOT NULL default '0000-00-00 00:00:00',   status enum('New', 'Paid', 'Shipped','Completed','Cancelled') NOT NULL default 'New',   memo varchar(255) NOT NULL default '',   shipping_first_name varchar(50) NOT NULL default '',   shipping_last_name varchar(50) NOT NULL default '',   shipping_address1 varchar(100) NOT NULL default '',   shipping_address2 varchar(100) NOT NULL default '',   shipping_phone varchar(32) NOT NULL default '',   shipping_city varchar(100) NOT NULL default '',   shipping_state varchar(32) NOT NULL default '',   shipping_postal_code varchar(10) NOT NULL default '',   shipping_cost decimal(5,2) default '0.00',   payment_first_name varchar(50) NOT NULL default '',   payment_last_name varchar(50) NOT NULL default '',   payment_address1 varchar(100) NOT NULL default '',   payment_address2 varchar(100) NOT NULL default '',   payment_phone varchar(32) NOT NULL default '',   payment_city varchar(100) NOT NULL default '',   payment_state varchar(32) NOT NULL default '',   payment_postal_code varchar(10) NOT NULL default '',   PRIMARY KEY (   id)) TYPE=MyISAM AUTO_INCREMENT=1001 ;

You see, we just need to add AUTO_INCREMENT = 1001 right after the create definition.

 

tbl_order_item

Page 8: Php Shoping Cart

All ordered items are put here. We simply copy the items from the cart table when the customer place the order.

 

tbl_shop_config

This table store the shop information. For now it only have the shop name, address, phone number, contact email address, shipping cost, the currency used in the shop and a flag whether we want to receive an email whenever a customer place an order.

 

tbl_user

This table save all the user or admin account. Currently all user is an admin and all can do everything to the shop. I'm planning to add permission level so one admin can do everything, while the other user can only add / update product, manage orders, etc.

By the way, we will be using indexes on the tables to speed up queries. As a matter of fact whatever application you make using indexes is a good idea because it can improve the database query performance.

Okay, next we talk about the database abstraction. It's not a difficult stuff so you can skim read it if you like.

Admin, Control Panel

Our shopping cart admin page consist of the following : Category

o Add CategoryAdd a new category.

o View CategoryList all the category we have. We can also see all the child categories and show many products in each category

o Modify CategoryUpdate a category information, the name, description and image

o Delete CategoryRemove a category. All products in it will be set to have cat_id = 0.

Page 9: Php Shoping Cart

Product o Add Product

Insert an item into our store. We also need to supply the product image and we'll create a thumbnail automatically from this image

o View ProductView all the products we have. Since our online shop can have many products we can view the products grouped by category.

o Modify ProductModify product information. We can also remove the product image from this page

o Delete ProductRemove a product from the shop

Order o View Orders

Here we can see all the orders we have and their status. When you click the "Order" link on the left navigation you will go straight to the "Paid" orders. The reason is so you can respond immediately upon your customers that already paid for their purchase.

o Modify OrdersSometimes a customer might contact us saying that she made the wrong order like specifying the wrong product quantity or simply want her order cancelled so she can repeat the buying process again. This page enables the admin to do such a thing.

Shop ConfigurationThis is where we can set and change our online shop appearance, behaviour and information ( like the shop name, main url, etc ).

Below is what admin main page ( admin/index.php ) look like.

 

Page 10: Php Shoping Cart

By the way the shopping cart name is PlainCart :-)

Each sub-module (category, product, etc) will have similar file structure. They are :

index.php list.php add.php modify.php process<sub-module name>.php

The admin/index.php only serves as a simple display when the admin enters the administrator section. On this page (and all other pages in the admin sections ) we check if the one requesting the file is already logged in or not. This way we can be sure that anyone who plays around with the admin pages are those who have the required permission.

All admin pages will be using the same template so they will all look alike. Basically each admin file will set the page title, what javascript to include and the main content. If you want to customize the look of the admin pages you only need to modify the template and the css file ( admin.css ) . Here is the code for template.php

Source code : admin/include/template.php

<?phpif (!defined('WEB_ROOT')) {   exit;}

$self = WEB_ROOT . 'admin/index.php';?><html><head><title><?php echo $pageTitle; ?></title><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><link href="<?php echo WEB_ROOT;?>admin/include/admin.css" rel="stylesheet" type="text/css"><script language="JavaScript" type="text/javascript" src="<?php echo WEB_ROOT;?>library/common.js"></script><?php$n = count($script);for ($i = 0; $i < $n; $i++) {if ($script[$i] != '') {echo '<script language="JavaScript" type="text/javascript" src="' . WEB_ROOT. 'admin/library/' . $script[$i]. '"></script>';}}?>

Page 11: Php Shoping Cart

</head><body><table width="750" border="0" align="center" cellpadding="0" cellspacing="1" class="graybox"><tr><td colspan="2"><img src="<?php echo WEB_ROOT; ?>admin/include/banner-top.gif" width="750" height="75"></td></tr><tr><td width="150" valign="top" class="navArea"><p>&nbsp;</p><a href="<?php echo WEB_ROOT; ?>admin/" class="leftnav">Home</a> <a href="<?php echo WEB_ROOT; ?>admin/category/" class="leftnav">Category</a><a href="<?php echo WEB_ROOT; ?>admin/product/" class="leftnav">Product</a> <a href="<?php echo WEB_ROOT; ?>admin/order/?status=New" class="leftnav">Order</a> <a href="<?php echo WEB_ROOT; ?>admin/config/" class="leftnav">Shop Config</a> <a href="<?php echo WEB_ROOT; ?>admin/user/" class="leftnav">User</a> <a href="<?php echo $self; ?>?logout" class="leftnav">Logout</a><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p></td><td width="600" valign="top" class="contentArea"><table width="100%" border="0" cellspacing="0" cellpadding="20"><tr><td><?phprequire_once $content; ?></td></tr></table></td></tr></table><p>&nbsp;</p><p align="center">Copyright &copy; 2005 - <?php echo date('Y'); ?> <a href="http://www.phpwebcommerce.com"> www.phpwebcommerce.com</a></p></body></html>

You see the bolded section on the top? All file that is meant to be included from another file will have this right at the beginning of the code. So if we request the file directly like this : plaincart/admin/include/template.php it won't display anything.

But first, we have to postpone making the admin pages and create the login page first. Because a shop admin certainly must login before doing anything to the shop.

Page 12: Php Shoping Cart

NOTE : When you play with the admin pages demo you will see that any changes you make doesn't have any effect at all. This is because i've commented some of the code in the demo. I do this just to make sure all the settings, products, and categories stay the same. The code for download, however, are not commented. So when you install it on your server you can make any changes as you wish

Admin, Login

All user account is saved in tbl_user. For simplicity the table will only contain the bare necessities such as user id and password. You can add more column if you want to.

This is how the login works

1. The admin enter it's username and password2. The script check whether that username and password combination do exist in the database3. If it is set the session then go the admin main page4. If it's not then show an error message

Below is the login page screenshot :

The default user name and password are "admin" ( without the quotes )

The login function is called doLogin() and it's located in admin/library/functions.php

Source code : admin/library/functions.php

function doLogin(){   // if we found an error save the error message in this variable   $errorMessage = '';

   $userName = $_POST['txtUserName'];

Page 13: Php Shoping Cart

   $password = $_POST['txtPassword'];

   // first, make sure the username & password are not empty   if ($userName == '') {      $errorMessage = 'You must enter your username';   } else if ($password == '') {      $errorMessage = 'You must enter the password';   } else {      // check the database and see if the username and       // password combo do match      $sql = "SELECT user_id                  FROM tbl_user                   WHERE user_name = '$userName' AND                               user_password = PASSWORD('$password')";      $result = dbQuery($sql);

      if (dbNumRows($result) == 1) {            $row = dbFetchAssoc($result);            $_SESSION['plaincart_user_id'] = $row['user_id'];

            // log the time when the user last login            $sql = "UPDATE tbl_user                         SET user_last_login = NOW()                         WHERE user_id = '{$row['user_id']}'";            dbQuery($sql);

            // now that the user is verified we move on to the next page            // if the user had been in the admin pages before we move to            // the last page visited            if (isset($_SESSION['login_return_url'])) {              header('Location: ' . $_SESSION['login_return_url']);              exit;            } else {              header('Location: index.php');              exit;            }      } else {            $errorMessage = 'Wrong username or password';      }

  }

  return $errorMessage;}

If the login is successful this function will set the session variable $_SESSION['plaincart_user_id'].

Page 14: Php Shoping Cart

All admin pages will check for this session id using the checkUser() function. If the session id is not found then the function will set a redirection to the login page.

The checkUser() function look like this :

Source code : admin/library/functions.php

function checkUser(){   if (!isset($_SESSION['plaincart_user_id'])) {      header('Location: ' . WEB_ROOT . 'admin/login.php');   }

   if (isset($_GET['logout'])) {      doLogout();   }}

You see that if $_SESSION['plaincart_user_id'] is not set we just redirect to the login page. Very simple right?

Another thing that this function check is if there's a 'logout' in the query string. If it is then we call the doLogout() function which will remove the session id.

Source code : admin/library/functions.php

function doLogout(){   if (isset($_SESSION['plaincart_user_id'])) {      unset($_SESSION['plaincart_user_id']);      session_unregister('plaincart_user_id');   }

   header('Location: login.php');}Next we start making the category pages

Admin, View Category

Page 15: Php Shoping Cart

All the product categories for the online shop are listed here. The sql query for it is pretty simple. We just select category id, parent id and name and using a while loop we show the category one by one.

Below is the screenshot for the category list page. You ca see that on each row there's a Modify link and Delete link. Clicking on the Modify link will take you to the category modification page ( admin/category/modify.php ) where you can update the category name, description and image. Clicking on the Delete link will pop a javascript confirmation box asking whether you are sure to delete the category. Using a confirmation is a must when you want to delete something. This will prevent stupid accident where you unknowingly click on the delete link and suddenly the category disappear before you even realize what's going on.

 

Take a look at the code snippet below :

Source code : admin/category/list.php

<?php// ...$catId = (isset($_GET['catId']) && (int)$_GET['catId'] >= 0) ? (int)$_GET['catId'] : 0;//...?>

When the page loads we check for the existence of catId ( category id ) in the query string. This category id is then used as the paramater for the javascript function addCategory() . When you click on the 'Add Category' button the parent id will be sent to category/add.php.

Page 16: Php Shoping Cart

Go look at the source code and scroll to the bottom you will see this code :

Source code : admin/category/list.php

<input name="btnAddCategory" type="button" id="btnAddCategory" value="Add Category" class="box" onClick="addCategory(<?php echo $catId; ?>)">

 

The addCategory() function is defined in admin/library/category.js. It simply perform a redirect to show the add category page. More detail on adding a category can be found on the next page.

Admin, Add Category

Here the admin can add new product category for the online shop. The information we need are the category name, description, image. Both the name and description are mandatory but the image is not. If we don't have the category image we can leave the field blank. Of course it's not recommended because when the customer come to the shop she will see the default image.

The category description here will not be shown anywhere on the shop. It's only purpose is to let the shop owner / admin to know what the category is all about.

Take a look at the snapshot below, nothing fancy right?

Take a look at the form source code. The form has a hidden variable called hidParentId. The value is set from category/list.php as explained on the previous page. Go look at the source code and scroll to the bottom you will see this code :

<input name="btnAddCategory" type="button" id="btnAddCategory"

Page 17: Php Shoping Cart

value="Add Category" class="box" onClick="addCategory(<?php echo $catId; ?>)">

When you submit the form the process then handed to processCategory.php. All kind of category processing ( add, modify, delete ) are done in this file. On top of the script there's a simple switch to call the appropriate function based on the action required.

$action = isset($_GET['action']) ? $_GET['action'] : '';

switch ($action) { case 'addCategory' : addCategory(); break; case 'modifyCategory' : modifyCategory(); break; case 'deleteCategory' : deleteCategory(); break; case 'deleteImage' : deleteImage(); break; default : // if action is not defined or unknown // move to main category page header('Location: index.php');}

 

On the add category form the form action is set as processCategory.php?action=addCategory so if you look at the code above the script will call addCategory();. If no action is defined we just redirect to category main page.

When saving the product image there is a possibility of name conflict. It may seem weird for two categories to have the same image name, but in some cases it can happen. To avoid such conflict we will generate a new name for each category image we upload using the combination of rand(), time() and md5() functions like this :

// get the image extension$ext = substr(strrchr($image['name'], "."), 1);

// generate a random new file name to avoid name conflict$imagePath = md5(rand() * time()) . ".$ext";

Page 18: Php Shoping Cart

The image name wil then become something like 6c444ed816ce251d610c25154dc28462.jpg. Now it's almost impossible for us to ever hit the name conflict problem. We will use the same name generation for the product image and thumbnail.

How does it work ?

The time() function will return the number of seconds elapsed since the beginning of ( computer ) time which is January 1, 1970. Using rand() function we get a random value less or equal to the number of seconds. We need to use rand() because this shopping cart can have more than one admin. If two admins happen to submit the form at the same second the result of time() will be the same.

As the final step md5() use the random value and return the hash ( a string with 32 characters ). If you feel that using 32 characters for a filename is too much you can use substr() function to cut it like this :

// get the image extension $ext = substr(strrchr($image['name'], "."), 1);

// generate a random new file name to avoid name conflict $imagePath = substr(md5(rand() * time()), 0, 10) . ".$ext";

The code above will use only the first ten characters as the file name.

Next is the modify category page.

Admin, Edit Category

This page is where you can modify a category information. You can see that the form is just a lame copy from add.php. The difference is that in this page we need to fetch the category information first so we can show it in the input boxes.

Page 19: Php Shoping Cart

Another difference is that in this form we also display the category image. If you change the category image then the old image will be deleted from the server and the new image is uploaded.

Take a look a the code below. To get the category info from database we need the category id from the query string. If $_GET['catId'] is not present or empty we just redirect to index.php. If it's present and not empty we fetch the category info.  

Source code : admin/category/modify.php

<?phpif (!defined('WEB_ROOT')) {   exit;}

// make sure a category id existsif (isset($_GET['catId']) && (int)$_GET['catId'] > 0) {   $catId = (int)$_GET['catId'];} else {   header('Location:index.php');}

$sql = "SELECT cat_id, cat_name, cat_description, cat_image        FROM tbl_category        WHERE cat_id = $catId";$result =& dbQuery($sql);$row =& dbFetchAssoc(&$result);

Page 20: Php Shoping Cart

extract($row);

// ... put the form down here?>

On the screenshot you can see that we next to the category image we have a delete link. Clicking on the link will call the javascript function deleteImage(). This function will pop a confirmation box and if you confirm the deletion the function will redirect you to processCategory.php where all category related process is taken care of.

Below is the code that perform the image deletion

Source code : admin/category/processCategory.php

function deleteImage(){   if (isset($_GET['catId']) && (int)$_GET['catId'] > 0) {      $catId = (int)$_GET['catId'];   } else {      header('Location: index.php');   }

   _deleteImage($catId);

   // update the image name in the database   $sql = "UPDATE tbl_category           SET cat_image = ''           WHERE cat_id = $catId";   dbQuery($sql);

   header("Location: index.php?view=modify&catId=$catId");}

To delete the image from the server the deleteImage() function calls _deleteImage(). Please excuse this lame function naming. I just cant' find other name that fit perfectly for this function.

After deleting the image we update the category information in database. We only need to set cat_image to an empty string and we're done. The final thing that deleteImage() do is redirect back to the category modification page. We don't redirect to category listing page because the admin may still want to modify the category further.

Admin, Delete Category

Page 21: Php Shoping Cart

When you decide that a category is no longer needed you can remove it from the database. To delete a category go to the category listing page and click on the 'delete' link on the category you wish to delete

Deleting a category will delete all product in that category and in all it's children. For example if you delete the "Manga" category than alll product in "Naruto" and "HunterxHunter" will also be deleted. The function used to delete category is called deleteCategory() and it's located in admin/category/processCategory.php

The deletion process is like this :

1. Update the cat_id for all products in that category to zero2. Remove the category image ( if exist ) 3. Delete the category from database

Pretty easy huh? I don't think we need to dive into the source code here because it is quite simple. Just take a look at the code and you will understand

Okay, now the category stuff is done we start playing with the next sub modul, the product pages.

Admin, View Products

This page list all the products we have. We can see all products or just products from certain category. From this page we can see the product detail , add new product, modify and delete.

Below is what the page look like. The table shows the product name, thumbnail, category, and modify and delete link. We show the product image if it exist. In case we haven't supply the image the default image is shown instead.

Page 22: Php Shoping Cart

There's a javascript function called viewProduct() attached to the combo box on the top right portion of the page. If you select a category then the page will show product list only from that category. For example if you choose "Naruto" the this page will look like this :

Page 23: Php Shoping Cart

If you wish to view all products again just choose "All Category" from the combo box

The code for this page is in admin/product/list.php. It's a very simple page really. It just perform a simple SELECT query and loop through the result to print the contents. If the products returned from the query is more than five we print the paging links to navigate from one result page to another. The code snippet below shows how the paging is done.

Source code : admin/product/list.php

<?phpif (!defined('WEB_ROOT')) {   exit;}

if (isset($_GET['catId']) && (int)$_GET['catId'] > 0) {   $catId = (int)$_GET['catId'];   $sql2 = " AND p.cat_id = $catId";   $queryString = "catId=$catId";} else {   $catId = 0;   $sql2 = '';   $queryString = '';}

// for paging

Page 24: Php Shoping Cart

// how many rows to show per page$rowsPerPage = 5;

$sql = "SELECT pd_id, c.cat_id, cat_name, pd_name, pd_thumbnail            FROM tbl_product p, tbl_category c            WHERE p.cat_id = c.cat_id $sql2            ORDER BY pd_name";$result = dbQuery(getPagingQuery($sql, $rowsPerPage));$pagingLink = getPagingLink($sql, $rowsPerPage, $queryString);

$categoryList = buildCategoryOptions($catId);

?>

Instead of executing the query directly like this dbQuery($query) we add some paging code first to the sql query by feeding it to getPagingQuery() along with how many results that we want to show on each page. The getPagingQuery() function is located in library/common.php. Here is the code :

Source code : library/common.php

function getPagingQuery($sql, $itemPerPage = 10){   if (isset($_GET['page']) && (int)$_GET['page'] > 0) {      $page = (int)$_GET['page'];   } else {      $page = 1;   }

   // start fetching from this row number   $offset = ($page - 1) * $itemPerPage;

   return $sql . " LIMIT $offset, $itemPerPage";}

This function first check the page number. When you click on a paging link there's a page variable embedded in the query string. If the function can't find any page variable on the query string then it just assume that the first page is wanted.

Paging on MySQL is done using the LIMIT keyword. The offset is the index where we want to start fetching the result. We also supply how many result that we want .

Now after we get the paging query and execute it the next thing we must do is making the page links. This is done by getPagingLink() function. This function is the one responsible for printing the paging link you see on the bottom of the product list. The function only does the followings :

Page 25: Php Shoping Cart

1. Find out how many total results returned by a query2. Calculate how many pages the results should be split into3. Determine the first and last page4. Print page link from first to last.

Somehow i don't feel like explaining the paging process in detail here. If you're interested you can read the full tutorian on pagination here : paging tutorial on www.php-mysql-tutorial.com

Next we discuss about adding a new product. When you click on the "Add Product" button you will be taken to the add product screen. 

Admin, Add Product

Adding a product for the online shop is a straightforward process. Just enter the product information and hit the 'Add Product' button. When adding a product we will require these information :

Category Product name Description Price Quantity in stock Image

All is mandatory except for the image. We can add the product image later.The add product form look like this :

Page 26: Php Shoping Cart

Not much difference from the add category form. We just have more input box. On top of the form you can see the category combo box. We build this so that you can only select the second level category. This is to ensure that all product are added on the second level category and not put in the top level category by mistake.

The one responsible to build the list is the buildCategoryOptions() in admin/library/function.php. Below is the snippet for the code that build the combo box. Just in case you will need the ability to add some product to the first level category you can replace the buildCategoryOptions() with the commented function code written below it.

If you happen to click the "Add Product" button while viewing the product list in a category you can see that the category list is pre-selected to the right category. When the function is building the list options it always check if the current category id is the same as the category id in the function parameter.

Source code : admin/library/functions.php

<?php// ... some code to fetch the categories from database

// build combo box options$list = '';

Page 27: Php Shoping Cart

foreach ($categories as $key => $value) {   $name = $value['name'];   $children = $value['children'];

   $list .= "<optgroup label=\"$name\">";

   foreach ($children as $child) {      $list .= "<option value=\"{$child['id']}\"";      if ($child['id'] == $catId) {         $list.= " selected";      }

      $list .= ">{$child['name']}</option>\r\n";   }

   $list .= "</optgroup>";}

// ... more code here

?>

The product quantity is limited to 65,535 since in the table definition we only use smallint(5) . I find this number adequate for most online shops. But if do carry more than that amount for an item just change the data type to something bigger like mediumint(8).

The product image you need to supply is the large size product image which will be shown in the product detail page. The script will generate a thumbnail for it to be shown in the product browsing page. We define the maximum image size and the thumbnail size in config php.

We need to restrict the image size so it won't destroy the site layout. Imagine if the image is 1000 pixels wide and 2000 pixels high. It will make the product detail page look awful. Image resizing can be turned on or off. If you set LIMIT_PRODUCT_WIDTH to false on config.php the script will just upload the image without worying about it's size. It's not recommended though.

Please note that the image resizing function can only handle jpeg and gif image. That function was actually taken from the php documentation and i don't know how to improve it yet.

Admin, Edit Product

Page 28: Php Shoping Cart

I don't think i need to explain this because it's the same as modifying a category. We show the form where we can change the product information. Display the image thumbnail if the product has an image and put a delete link right next to it.

Here is the form snapshot :

The process of updating the product information is also the same as the category. So we better move on and working on the process of deleting a product.

Admin, Delete ProductThis part also don't need much explanation. The process is simple. First we delete any references to this product from tbl_cart and tbl_order_item to maintain data integrity. Then remove the product images and thumbnail and finally remove the product from database.

The delete process is like this :

Page 29: Php Shoping Cart

1. Delete all references to this product from tbl_order_item2. Delete all references from tbl_cart3. Delete the product image and thumbnail4. Delete the product from database

And here is the code for deleteProduct() function that responsible for this process :

Source code : admin/product/processProduct.php

function deleteProduct(){   if (isset($_GET['productId']) && (int)$_GET['productId'] > 0) {      $productId = (int)$_GET['productId'];   } else {      header('Location: index.php');   }

   // remove any references to this product from   // tbl_order_item and tbl_cart   $sql = "DELETE FROM tbl_order_item           WHERE pd_id = $productId";   dbQuery($sql);

   $sql = "DELETE FROM tbl_cart           WHERE pd_id = $productId";    dbQuery($sql);

   // get the image name and thumbnail   $sql = "SELECT pd_image, pd_thumbnail           FROM tbl_product           WHERE pd_id = $productId";

   $result =& dbQuery($sql);   $row =& dbFetchAssoc($result);

   // remove the product image and thumbnail   if ($row['pd_image']) {      unlink(SRV_ROOT . 'images/product/' . $row['pd_image']);      unlink(SRV_ROOT . 'images/product/' . $row['pd_thumbnail']);   }

   // remove the product from database;   $sql = "DELETE FROM tbl_product            WHERE pd_id = $productId";   dbQuery($sql);

Page 30: Php Shoping Cart

   header('Location: index.php');}

Admin, Order ManagementAll customer order will be shown here. You can see the orders and take appropriate action. For example all orders initially have the status "New". When you pack the product and ship it to the customer you can then change the order status to "Shipped".

The order status are :

New Paid Shipped Completed Cancelled

Let's take a better look at each status

New

All orders initially have this status

Paid

An order's status is changed from "New" to "Paid" by the IPN script after completing the payment process.

Shipped

After we pack the ordered items and ship it we can change the order status to "Shipped"

Completed

We got the payment, the customer receveived the goods that mean the order is completed

Cancelled

In case you see a suspicious order and you feel that it's a fraud you can set the status to "Cancelled".

Page 31: Php Shoping Cart

Or in some case a customer calls you and for some reason she ask you to cancel her order.

Here is what the order page look like :

Using the combo box on the top right corner we can view the orders with a certain status. Clicking on an order number will take you to the order detail page. On this page we can also modify the order status

Page 32: Php Shoping Cart

 

Admin, Shop ConfigurationHere we can set some settings which are used sitewide. They are

Online shop information o Shop Nameo Real world addresso Phone numbero Contact email

Shipping cost Currency A flag whether to send a notification email to admin when a customer place an

order

The shop information is shown on the footer ( include/footer.php ). You really shouldn't leave any field blank. Having these information can assure the customers that your online shop is a real business. This can improve customer trust and also improve your credibility and without those two you really can't expect anyone to buy.

Page 33: Php Shoping Cart

The currency chooser is simply a drop down box where you can choose between Dollar, Euro, Poundsterling or Yen.

Why only four currencies ?

Because i'm making the shop using Dreamweaver and the only special characters for currency that i can find are €, £, and ¥. Plus the dollar sign ( $ ) that makes four currencies.

Under the currency list is the shipping cost. Since this shop use flat shipping cost a simple text box is sufficient. If you plan to offer different shipping cost like depending on the product weight or shipping courier then you really have to change it to suit your need.

The last setting is for sending email whenever a new order is placed.The notification email is sent to the address you specify as the contact email ( in the screenshot above it's [email protected] ). If you run a super busy shop it would be better to turn this off otherwise you will be flooded with emails and your mail server might think someone is spamming you.

 

Admin, User Management

Page 34: Php Shoping Cart

A user of the shop is actually the shop admin itself. Currently all user are granted the permission to do all administration task. In future version i'll modify this so one user can be assigned to specific task such as managing the products or managing the orders, etc.

View User List

This display just display all user on the shop

 

Add User

The only information needed are the user name and password.

Here is the code for adding a user.

Source code : admin/user/processUser.php

function addUser(){   $userName = $_POST['txtUserName'];   $password = $_POST['txtPassword'];

   // check if the username is taken   $sql = "SELECT user_name           FROM tbl_user           WHERE user_name = '$userName'";   $result =& dbQuery($sql);

   if (dbNumRows($result) == 1) {      header('Location: index.php?view=add&error=' .       

Page 35: Php Shoping Cart

          urlencode('Username already taken. Choose another one'));    } else {       $sql = "INSERT INTO tbl_user (user_name, user_password,                                     user_regdate)              VALUES ('$userName', PASSWORD('$password'), NOW())";

      dbQuery($sql);      header('Location: index.php');    }}

Before adding the new user info we need to check if the username is taken or not. We just query the database looking for that username. If a row is found that mean the username is already used and we set a redirect to go back to the 'add user' page and send an error message.

Since the error message is put in the query string we need to use urlencode(). This function is commonly used when passing a string to a url. Using the above example the url will look like this :

index.php?view=add&error=Username+already+taken.+Choose+another+one

If the username is still available we just insert the new user info to database. You see that in the insert query we use PASSWORD() function. This is a MySQL function that will encrypt the given password.

 

Modify User Password

For simplicity the user name cannot be changed. Only the password can be changed. The function used for modifying the password simply perform an UPDATE query to update the password

 

Delete User

Page 36: Php Shoping Cart

The deleteUser() function just remove a user from database. No extra steps needed.

Shop, Main page

This page is usually what the visitor see for the first time when she visit our shop. It consist of five parts. On the left is the category browser. The shopper can click here way through categories to find the product. The right side is where we put the mini shopping cart. If the visitor add a product, this mini cart will show the item. At the very top and bottom are the common header an footer. The top area is usually where we put our store logo. For this tutorial the bottom area is used for displaying the store information (address, email, phone )

The center part is the main area. Here we show the product categories and products. The visitor will ( hopefully ) find her way through the shop, find the item she want, put it into the shopping cart and then buy.

What we show in the main area depends on the visitor action. When she first arrive to main page she get the category list. If she click on one of the category then we show the product list for that category. And if she click on a product from the list we show the product detail.

 Take a look at the code below, it's the code for index.php, the main page

Source code : index.php

<?phprequire_once 'library/config.php';require_once 'library/category-functions.php';require_once 'library/product-functions.php';require_once 'library/cart-functions.php';

$_SESSION['shop_return_url'] = $_SERVER['REQUEST_URI'];

Page 37: Php Shoping Cart

$catId = (isset($_GET['c']) && $_GET['c'] != '1') ? $_GET['c'] : 0;$pdId = (isset($_GET['p']) && $_GET['p'] != '') ? $_GET['p'] : 0;

// ... more code here?>

First we load the required libraries. The config.php file contain all kind of initialization like setting the database connection, defining constants, and it also load the common libraries. I won't explain the detail, just take a look at the file and i'm sure you will understand what it does.

Next is category-functions.php. This file contain the several functions, they are :

formatCategories()This function is used by include/leftNav.php. It's job is to generate the category list where the currently selected category will expand and show the children categories ( if it have any ).

getCategoryList()Get a list of first level categories ( i.e. the parent id is zero )

getChildCategories()Get all children categories

fetchCategories()Get all categories ( first and second level )

After finish loading the libraries we set a session variable $_SESSION['shop_return_url']. The value for this session is the url of the page that we currently see. This variable is used by the shopping cart. When you click on the 'Continue Shopping' button it will redirect to the url pointed by this session variable.

Next step is checking the existence of $_GET['c'] ( category id ) and $_GET['p'] ( product id ). If none exist in the query string we show the category list ( categoryList.php ). If only the category id exist then we show all product in that category ( productList.php ). And if the product id also exist we show that product information ( productDetail.php ).

Source code : index.php

<?php// ... previous code

include 'header.php';?><table width="780" border="1" align="center" cellpadding="0" cellspacing="0"><tr> <td colspan="3"><?php include 'top.php'; ?></td>

Page 38: Php Shoping Cart

</tr><tr valign="top"> <td width="150" height="400" id="leftnav"> <?phpinclude 'leftNav.php';?></td><td><?phpif ($pdId) {   include 'productDetail.php';} else if ($catId) {   include 'productList.php';} else {   include 'categoryList.php';}?> </td><td width="130" align="center"><?php include 'miniCart.php'; ?></td></tr></table><?phpinclude 'footer.php';?>

As you can see from the above code, the main page doesn't do much. It "out sourced" almost everything. The header, navigation, content, mini cart and the footer. Of course this is a good thing because if we need to modify some part ( like the left navigation ) we can do it wit less risk of messing with the other part.

Now, lets take a deeper look at the header file. One important usage of this file is to set the page title. You may have noticed it that when you're browsing the categories and products the page title change accordingly. Setting up a descriptive page title is especially important when you consider SEO ( search engine optimization ). You see, search engine put heavy emphasize on the page title so we better get this one thing right.

Here how it works. By default we set the page title as "My Online Shop" but if a product id is detected in the query string we search the database to find the name of the product. Then we use the product's name as the page title.

If we can't find any product id in the query string we do another test to see if there's a category id in there. If we found one we fetch the category name from the database and use it as the page title.

Here is the code :

Page 39: Php Shoping Cart

Source : include/header.php

<?phpif (!defined('WEB_ROOT')) {   exit;}

// set the default page title$pageTitle = 'My Online Shop';

if (isset($_GET['p']) && (int)$_GET['p'] > 0) {   $pdId = (int)$_GET['p'];   $sql = "SELECT pd_name           FROM tbl_product           WHERE pd_id = $pdId";

   $result    = dbQuery($sql);   $row       = dbFetchAssoc($result);   $pageTitle = $row['pd_name'];

} else if (isset($_GET['c']) && (int)$_GET['c'] > 0) {   $catId = (int)$_GET['c'];   $sql = "SELECT cat_name           FROM tbl_category           WHERE cat_id = $catId";

   $result    = dbQuery($sql);   $row       = dbFetchAssoc($result);   $pageTitle = $row['cat_name'];}

?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title><?php echo $pageTitle; ?></title><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><link href="include/shop.css" rel="stylesheet" type="text/css"><script language="JavaScript" type="text/javascript" src="library/common.js"></script></head><body>

Next we explore further about the category browsing ( that navigation links on the left section of the page ).

Page 40: Php Shoping Cart

Shop, Browse Categories

On the left side of the shop pages we show the category list. When the customer clicks on a category on the left side she can see all products in that category. The shop main page include this navigation from include/leftNav.php and as mentioned before, the one responsible to get the list of categories for this navigation is the formatCategories() function in library/category-functions.php

In summary here is what formatCategories() do :

1. Get all the children categories2. Get the parent category and other categories on the same level as the parent3. Keep looping to get the parent's parent until we reach the top level category

This function is actually a bit too complex for handling two level deep categories. However in the future i want this shop to handle categories more than two level deep so i made this function so it can cope with that.

Okay, let's not talk about this function too much and move on with the code for leftNav.php

Source code : include/leftNav.php

<?phpif (!defined('WEB_ROOT')) {   exit;}

// get all categories$categories = fetchCategories();

// format the categories for display$categories = formatCategories($categories, $catId);?><ul><li><a href="<?php echo $_SERVER['PHP_SELF']; ?>">All Category</a></li><?phpforeach ($categories as $category) {   extract($category);   // now we have $cat_id, $cat_parent_id, $cat_name

   $level = ($cat_parent_id == 0) ? 1 : 2;   $url = $_SERVER['PHP_SELF'] . "?c=$cat_id";

   // for second level categories we print extra spaces to give   // indentation look

Page 41: Php Shoping Cart

   if ($level == 2) {      $cat_name = '&nbsp; &nbsp; &raquo;&nbsp;' . $cat_name;   }

   // assign id="current" for the currently selected category   // this will highlight the category name   $listId = '';   if ($cat_id == $catId) {      $listId = ' id="current"';   }?><li<?php echo $listId; ?>><a href="<?php echo $url; ?>"><?php echo $cat_name; ?></a></li><?php}?></ul>

 

The categories are printed as unordered lis ( <ul> ). I guess you already know that unordered list usually shows up like this :

list one list two

o child 1o child 2

But thanks to CSS ( Cascading Style Sheet ) we can alter how the browser display the list and give them than boxy look. I must admit that i'm a beginner to css and i learn this from projectseven.com, so if you want to know how the css works you can visit the site later.

Next up is the product browsing. 

Shop, View Product List

When you click one of the category from the left navigation the main content area will show all product contained in that category. For example if you click on Manga then all four products in this category will be shown. Actually "Manga" doesn't have any product. Those product are belong to it's children categories ( Naruto and HunterXHunter).

If you checkout the source code for productList.php you can see that it first call getChildCategories()

Page 42: Php Shoping Cart

function so if you browse "Manga" productList.php will show all products in "Manga" ( zero products ) and it's children "Naruto" and "HunterXHunter" ( four products ).

Source code : include/productList.php

<?phpif (!defined('WEB_ROOT')) {exit;}

$productsPerRow = 2;$productsPerPage = 4;

$children = array_merge(array($catId), getChildCategories(NULL, $catId));$children = ' (' . implode(', ', $children) . ')';

$sql = "SELECT pd_id, pd_name, pd_price, pd_thumbnail, pd_qty, c.cat_idFROM tbl_product pd, tbl_category cWHERE pd.cat_id = c.cat_id AND pd.cat_id IN $children ORDER BY pd_name";$result = dbQuery(getPagingQuery($sql, $productsPerPage));$pagingLink = getPagingLink($sql, $productsPerPage, "c=$catId");

// ... we got more codes here?>

The rest of this page code should be pretty clear to you. There's a SELECT query and since we also want to use paging we feed the query to getPagingQuery(). If you don't know what getPagingQuery() does you should go back and read the page about product list in admin section.

Below is a snapshot of the product listing

Page 43: Php Shoping Cart

On productList.php the products are displayed so one row display three products like shown above. The number of product in one row can be changed. You just need to modify the value of $productsPerRow. For example modifying this value into 2 give this look :

Page 44: Php Shoping Cart

And here is the code that make this happen

Source code : include/productList.php

<?php

// ... previous code

$numProduct = dbNumRows($result);

$columnWidth = (int)(100 / $productsPerRow);?><table width="100%" border="0" cellspacing="0" cellpadding="20"><?php if ($numProduct > 0 ) {

$i = 0;while ($row = dbFetchAssoc($result)) {

extract($row);if ($pd_thumbnail) {$pd_thumbnail = WEB_ROOT . 'images/product/' . $pd_thumbnail;} else {$pd_thumbnail = WEB_ROOT . 'images/no-image-small.png';}

if ($i % $productsPerRow == 0) {echo '<tr>';}

// format how we display the price$pd_price = displayAmount($pd_price);

echo "<td width=\"$columnWidth%\" align=\"center\"><a href=\"" . $_SERVER['PHP_SELF'] . "?c=$catId&p=$pd_id" . "\"><img src=\"$pd_thumbnail\" border=\"0\"><br>$pd_name</a><br>Price : $pd_price";

// if the product is no longer in stock, tell the customerif ($pd_qty <= 0) {echo "<br>Out Of Stock";}

echo "</td>\r\n";

if ($i % $productsPerRow == $productsPerRow - 1) {

Page 45: Php Shoping Cart

echo '</tr>';}

$i += 1;}

if ($i % $productsPerRow > 0) {echo '<td colspan="' . ($productsPerRow - ($i % $productsPerRow)) . '">&nbsp;</td>';}

} else {?><tr><td width="100%" align="center" valign="center">No products in this category</td></tr><?php } ?>

// .. more code down here?>

 

 

 Before printing the product we first check we actually have any product at all. If dbNumRows($result) returns zero that means we have no product in current category. So we show a message saying that there are no products in that category.

If we do have some products to show we display them in a table where each column's width depend on how many products to show in a row. Using the above example the column width is 100 / 3 = 33%. Next thing we do is loop through the product list and print each product.

If the value of ($i % 3) == 0 we start a new row by printing <tr> and if ($i % 3) == 2 end that row using </tr>.

When printing the product info we use displayAmount() function to format the look of the product price. This function is located in library/common.php. Here is what the function look like :

Source code : library/common.php

function displayAmount($amount){   global $shopConfig;   return $shopConfig['currency'] . number_format($amount);

Page 46: Php Shoping Cart

}

What this function does is concat the currency symbol with the formattted amount. So if the amount is 123456 it will be displayed as $123,456. If the product price contains fraction ( like cents ) you need to change this function to this :

function displayAmount($amount){   global $shopConfig;   return $shopConfig['currency'] . number_format($amount, 2);}

Notice that we add extra parameter to number_format(). This extra parameter will make the function display the amount with two decimal point such as $19.95

Back to productList.php. After printing the product price we check if we already run out of that product in inventory. If so we print additional message saying that the product is no longer in stock.

Since there is always a possibility that the last row we print does not contain three products we check the value of $i % 3 after the loop . If it's greater than zero that means the last row does not have three products in it so we need to print the empty column like shown on the first snapshot.

In case the picture isn't clear enough here is the same snapshot but the table border is set to 1. You can see that on the last row we have 2 empty ( merged ) columns

Page 47: Php Shoping Cart

Shop, View Product DetailWhen you click on one of the product from the product list. The product detail page will show up. For each product we display the full-sized image, name, price and 'Add to cart' button. When you want to customize this page remember NOT to change the button to 'Buy Now' because the visitor may not ready to buy yet so don't scare her away.

Here is the snapshot of the product detail page. We have full size image on top left corner, the description at the bottom, then the product name, price and an 'Add To Cart' button on the right.

Page 48: Php Shoping Cart

No weird stuff here. This kind of layout is actually very common to see on shopping sites across the internet. And by following the common stuff we can be sure that the visitor won't be confused with this layout.

There's one more important thing about the 'Add To Cart' button. We only show this if we still have this product in stock. After we run out of this product we just display 'Out Of Stock' . Here is the code snippet from include/productDetail.php

Source code : include/productDetail.php

<?php// if we still have this product in stock// show the 'Add to cart' buttonif ($pd_qty > 0) {?><input type="button" name="btnAddToCart" value="Add To Cart" onClick="window.location.href='<?php echo $cart_url; ?>';" class="box"><?php} else {   echo 'Out Of Stock';}?>

Shop, Add to Cart

If you click on the 'Add To Cart' button on the product detail page you will be redirected to the shopping cart page ( cart.php ). For example if you want to buy Naruto Volume 2 you will go to : cart.php?action=add&p=19.

Page 49: Php Shoping Cart

The code for cart.php is like this :

Source code : cart.php

<?phprequire_once 'config.php';require_once 'cart-functions.php';

$action = (isset($_GET['action']) && $_GET['action'] != '') ? $_GET['action'] : 'view';

switch ($action) {   case 'add' :      addToCart();      break;   case 'update' :      updateCart();      break;    case 'delete' :      deleteFromCart();      break;   case 'view' :}

// ... more code here to display the cart content

?>

Since we have action=add in the query string the addToCart() function will be called. In short the function will do these :

1. Check if the product exist in database2. Check if we still have this product in stock ( quantity > 0 )3. If the product is already in cart increase the quantity4. If not add the product to cart

The addToCart() function is located in library/cart-functions.php and the content can be seen below.

Source code : library/cart-functions.php

function addToCart(){   // make sure the product id exist   if (isset($_GET['p']) && (int)$_GET['p'] > 0) {      $productId = (int)$_GET['p'];

Page 50: Php Shoping Cart

   } else {      header('Location: index.php');   }

   // does the product exist ?   $sql = "SELECT pd_id, pd_qty           FROM tbl_product           WHERE pd_id = $productId";   $result = dbQuery($sql);

   if (dbNumRows($result) != 1) {      // the product doesn't exist      header('Location: cart.php');   } else {      // how many of this product we      // have in stock      $row = dbFetchAssoc($result);      $currentStock = $row['pd_qty'];

      if ($currentStock == 0) {         // we no longer have this product in stock         // show the error message         setError('The product you requested is no longer in stock');         header('Location: cart.php');         exit;      }   }

   // current session id   $sid = session_id();

   // check if the product is already   // in cart table for this session   $sql = "SELECT pd_id           FROM tbl_cart           WHERE pd_id = $productId AND ct_session_id = '$sid'";   $result = dbQuery($sql);

   if (dbNumRows($result) == 0) {      // put the product in cart table      $sql = "INSERT INTO tbl_cart (pd_id, ct_qty, ct_session_id, ct_date)              VALUES ($productId, 1, '$sid', NOW())";      $result = dbQuery($sql);   } else {      // update product quantity in cart table

Page 51: Php Shoping Cart

      $sql = "UPDATE tbl_cart               SET ct_qty = ct_qty + 1              WHERE ct_session_id = '$sid' AND pd_id = $productId";

      $result = dbQuery($sql);    }

   deleteAbandonedCart();

   header('Location: ' . $_SESSION['shop_return_url']); }

After finish placing an item into the cart this function do something else. It calls deleteAbandonedCart(). I know it's kind of weird to call this function here but currently it is the best place to call it. We actually have at least three options on how and when to delete abandoned:

1. Call deleteAbandonedCart() when adding a product into cart like shown above2. Make a new submodul on admin page where we have a button saying 'Delete All Abandoned

Cart'3. Using cron job to remove the abandoned cart periodically.

The first option is what i see as the best option right now, because adding an admin submodul requires extra work, and using cron means installing the shop will become a hassle. Before i forget here is what deleteAbandonedCart() look like :

Source code : library/cart-functions.php

function deleteAbandonedCart(){   $yesterday = date('Y-m-d H:i:s',                 mktime(0,0,0, date('m'), date('d') - 1, date('Y')));   $sql = "DELETE FROM tbl_cart           WHERE ct_date < '$yesterday'";   dbQuery($sql); }

We consider a cart is abandoned if it's older than one day. So first we find out what date yesterday was and send a query to database to remove any cart entry where the cart date is less than yesterday date.

Okay, after adding the product and removing all abandoned carts we don't send the customer to the shopping cart page. She will stay on the product detail page. But this time the mini cart on the right side will show the product in her shopping cart.

The mini cart is included from include/miniCart.php. It displays all product currently in shopping

Page 52: Php Shoping Cart

cart. It also show the total amount after the shipping cost.

This behaviour ( sending the customer to product page after adding a product ) is actually depend on what kind of shop we're running. If it's a shop where people usually buy more than one kind of product then it's better if we skip showing the shopping cart page and display the product page. But if people on this kind of shop usually only buy one product in a shopping session then it's best if we display the shopping cart page. You just need to modify the redirection to

header('Location: cart.php?action=view');

If you're still not sure where to send the shopper after add to cart there's a discussion thread in Webmasterworld forum discussing this issue, check it out.

Next we start working on the shopping cart page.

View Shopping Cart

The shopping cart interface is made more simple than the shop pages. Studies have shown that removing any distraction from the shopping cart page ( and from the checkout pages too ) can lead to higher conversion rates. So for this page the left navigation is removed, the mini cart display is also gone.

If the visitor come to this page and the shopping cart is still empty there is a chance that she go there by accident or feeling confused. So now we present her with simple instruction on how to buy stuff in our shop .

"Your shopping cart is empty"

"If you find you are unable to add anything to your cart, please ensure that your internet browser has cookies enabled and that any other security software is not blocking your

shopping session."

 

Now if there are already items in the cart we present it to the customer like shown below. Each row shows the product thumbnail name, unit price, quantity and sub total. On each row we have a delete button so the customer can easily remove the item. If you plan to

Page 53: Php Shoping Cart

customize the shopping cart interface do not remove the delete button. It will make the delete process difficult for the customer and it certainly not a good thing.

You may have seen it on another shopping cart solution that to remove an item the customer must set the quantity to zero then click the 'Update Cart' button. That is the wrong way to do it because it makes a very simple action difficult.

Shop, Checkout There are three steps to complete the checkout

1. Fill out the shipping and payment info 2. Confirm the ordered items, shipping and payment info and enter the payment

method. 3. Save the order information to the database. If the payment method is COD ( cash

on delivery ) go straight to the thank you page. If the customer choose to pay with paypal submit the payment info to paypal server.

Below is the code for checkout.php

Source code : checkout.php

<?phprequire_once 'library/config.php';require_once 'library/cart-functions.php';require_once 'library/checkout-functions.php';

Page 54: Php Shoping Cart

if (isCartEmpty()) {   // the shopping cart is still empty   // so checkout is not allowed   header('Location: cart.php');} else if (isset($_GET['step'])            && (int)$_GET['step'] > 0            && (int)$_GET['step'] <= 3) {   $step = (int)$_GET['step'];

   $includeFile = '';   if ($step == 1) {      $includeFile = 'shippingAndPaymentInfo.php';      $pageTitle = 'Checkout - Step 1 of 2';   } else if ($step == 2) {      $includeFile = 'checkoutConfirmation.php';      $pageTitle = 'Checkout - Step 2 of 2';   } else if ($step == 3) {      $orderId = saveOrder();      $orderAmount = getOrderAmount($orderId);

      $_SESSION['orderId'] = $orderId;

      // our next action depends on the payment method      // if the payment method is COD then show the       // success page but when paypal is selected      // send the order details to paypal      if ($_POST['hidPaymentMethod'] == 'cod') {         header('Location: success.php');         exit;      } else {         $includeFile = 'paypal/payment.php';       }   }} else {   // missing or invalid step number, just redirect   header('Location: index.php');}

require_once 'include/header.php';?><script language="JavaScript" type="text/javascript" src="library/checkout.js"></script><?phprequire_once "include/$includeFile";require_once 'include/footer.php';?>

Page 55: Php Shoping Cart

On top of this file we check if the shoppping cart is empty. If it is empty the customer is redirected to the cart page. Just to let her know that her shopping cart is still empty and so she cannot checkout.

Just like the main page ( index.php ) the checkout page "out sourced" almost everything to other pages. The main part of this file is the switch to load appropriate file depending on which checkout step the customer is on.

And now, let's take a better look at these checkout processes one step at a time.

  ResourcesHere are a few online resources that you may find useful when building a shopping cart / e-commerce website.

1. E-commerce User Experience 207 Guidelines for E-commerce Sites This report is compiled by Nielsen Norman Group. It contain guidelines on designing a more usable e-commerce website.

2. Marketing Sherpa If you want to run a successful business you must never stop learning. Marketing Sherpa contains extensive articles related to e-commerce. These articles are free usually for a week or two so make sure you signup for their newsletter so when a new article is posted you can grab it before they change it to paid status.

3. WebmasterWorld Forum A very respective and useful site. You really should hang out in the forums. There are plenty useful information here.

4. WilsonWeb Claim to be "The Trusted Guide to Internet Marketing since 1995". The site has plenty of tutorials on building a successful online bussiness

5. Conversion Chronicles Plenty articles about increasing your online shop conversion.

6. Site Build It! All in one solution for creating websites that get traffic.You can use SBI to create content sites that warm up your potential customers before sending them to your online shop

7. PHP MySQL Tutorial My other site. I'm sure you know what this site has to offer from reading the name :-)

Source codeYou can download the whole script as a zip file here. To install the shopping cart you need to do these :

Page 56: Php Shoping Cart

1. Extract the zip file ( ex. to C:\Webroot\plaincart )2. Create a new MySQL database ( ex. 'plaincart' );3. Create the tables using the SQL in plaincart.sql. On windows just open a command prompt

window ( Start > Run > cmd.exe ) and go to the directory where you unzip the files then type this :

C:\mysql\bin\mysql plaincart < plaincart.sql

I'm assuming you install mysql in C:\MySQL4. Modify the database connection settings in library/config.php.

By the way, someone asked me about the license for the code so here it is :

The code is free to use, modify, or enhance. If you want to show you appreciation by placing a link to this site then i'll be very very very grateful :-). If you don't want to link to this site it's allright because the code was meant to be free anyway.

Below is the list of the shopping cart files. I only list the php files excluding the css and javascript files. 

source/include/productDetail.php source/include/miniCart.php source/include/paypal/ipn.php source/include/paypal/paypal.inc.php source/include/paypal/error_log source/include/paypal/payment.php source/include/checkoutConfirmation.php source/include/categoryList.php source/include/productList.php source/include/leftNav.php source/include/thankyou.php source/include/footer.php source/include/shippingAndPaymentInfo.php source/include/header.php source/include/top.php source/library/errorMessage.php source/library/product-functions.php source/library/config.php source/library/common.php source/library/category-functions.php source/library/database.php source/library/cart-functions.php source/library/checkout-functions.php source/plaincart.sql source/checkout.php source/success.php

Page 57: Php Shoping Cart

source/db/db.sql source/error.php source/index.php source/cart.php source/admin/include/template.php source/admin/include/footer.php source/admin/include/header.php source/admin/library/functions.php source/admin/login.php source/admin/config/index.php source/admin/config/processConfig.php source/admin/config/main.php source/admin/user/list.php source/admin/user/modify.php source/admin/user/processUser.php source/admin/user/add.php source/admin/user/index.php source/admin/user/changePass.php source/admin/user/error_log source/admin/category/list.php source/admin/category/modify.php source/admin/category/processCategory.php source/admin/category/add.php source/admin/category/index.php source/admin/category/error_log source/admin/index.php source/admin/product/list.php source/admin/product/modify.php source/admin/product/detail.php source/admin/product/processProduct.php source/admin/product/add.php source/admin/product/index.php source/admin/main.php source/admin/order/list.php source/admin/order/detail.php source/admin/order/processOrder.php

source/admin/order/index.php