PHP Shopping Cart script (DB_cart)

DB_cart Class is a PHP shopping cart script that can be used with third party product catalogs and membership systems. The MySQL database structure is neutral to existing systems. It can handle the shopping cart (add, update, and empty) and checkout process (set the shipment address and email the order). For existing cart users, the shopping cart is still available upon the user’s next visit and is visible by checkout. The last option is configurable together with a given time period. The package includes all application file and example data to test all functions. Since version 1.10 its possible to use this class with product data where the stock value is variable.

PHP Script Download

Features

  • Standard class
    • Add, update and delete shopping cart
    • Cancel whole shopping cart
    • Remember old cart (with the configuration about how long)
    • Show whole cart
    • Show total (VAT) value of the cart
    • Shipment address handling (insert/update)
    • Checkout with mail confirmation
    • Support for different currencies
    • Continue shopping page (shows up after adding a product to the cart)
    • All (e-mail) messages in NL, EN and DE language
  • “on Stock” extension
    • Check and update the amount of old order rows against the the current stock and and price
    • Validation that not more products are bought then on stock while the customer adds a new amount to the cart

Documentation

PHP 4/5, MySQL 4 or higher, access to a SMTP server (windows only) and some knowledge in OOP

Installation

First of all, the examples files have all information, you only need to:

  1. Place all files into a directory structure like: your_root_dir/classes/db_cart/
  2. Install all sql files (use f.e. phpMyAdmin)
  3. Create a file called db.php (I place it into the folder classes which is one above the root), add this code with you database connection parameters:
    define("DB_SERVER", "localhost");
    define("DB_NAME", "database");
    define ("DB_USER", "user");
    define ("DB_PASSWORD", "password");

 

  1. Configure inside the file db_config.php the other variables
  2. Run this file: http://your.domain/classes/db_cart/db_cart_example.php
  3. Be sure that the the e-mail address which is used inside the db_cart_example.php is valid (the value from the database is not a valid address)

Please note that this class is supposed for mature PHP/MySQL enabled web hosts. It’s possible that the script will not work f.e. on free web hosts!

You can use this class on two ways:

  • Without a customer id, the cart is only active during the current session.
  • With a customer id, its possible to the user (customer) to continue an older shopping session if the old one is not expired

The example files:

In this manual are only the important files explained which are needed to use the class. If you like to try the other examples check the notes inside the files.

db_config.php

There are several constant variables defined, to use this class nothing but the database connection variables have to be changed. If you need to change them read the notes inside the file. The next values are important to modify:

define("CURRENCY", "£"); // use "€", "$", "£" or "¥"
define("RECOVER_ORDER", false); // if this value is true an old order is available for old orders from customers, use "false" to remove the old order while the next access
define("VALID_UNTIL", 7 * 86400); // the value of seconds how long an old order is valid (default 7 days) and will be recovered
define("SHOW_CONTINUE", true); // set this variable on true to show a continue page after the item is added to the cart (continue shopping or checkout)

db_cart_example.php

This file get the product information from the example table “db_cart_example_customer” and stores this data in a record set. The data can be used for the presentation on the page. The following information is used later by the class:The product ID, the name and the price.

The next code is optional and gets some customer data from the example table “db_cart_example_customer” and will store the customer number and the e-mail address into a session. You can use other variables for these session variables too.

One of the advantages of this class is the possibility to use product data which doesn’t belong to this class. You can handle the data for a product like this:

<?php while ($prod_obj = mysql_fetch_object($prod_result)) { ?>
<form action="<?php echo CONTINUE_SCRIPT; ?>" method="post">
<label for="prod_<?php echo $prod_obj->id; ?>">
<b><?php echo $prod_obj->name; ?></b><br>
<?php echo $prod_obj->description." - price: ".$myCart->format_value($prod_obj->price); ?>
</label>
<input type="text" name="quantity" size="5" value="0">
<input type="hidden" name="price" value="<?php echo $prod_obj->price; ?>">
<input type="hidden" name="art_no" value="<?php echo $prod_obj->art_no; ?>">
<input type="hidden" name="product" value="<?php echo $prod_obj->name; ?>">
<input type="submit" name="submit" value="Add to cart"><br clear="left">
</form>
<?php } ?>

This form is placed inside a loop (row 1 and 13) and will be submitted to the continue script (row 2, check the config file for the real name). Notice the presentation part on the rows 3 to 6. It’s possible to put here more content (images, further specs.) if in your data source is this information available. The input element “quantity” is required and is the only input field in this form (row 7). The rows 8 to 10 are holding other information which is used by the class. At last there is a submit button at row 11.

Further you need to create an new instance of the class: $myCart = new db_cart($_SESSION[‘custom_num’]); The session variable is need to use it inside the current order.

At the end of the script is a link named “checkout”, if this link is used the following code is executed:

if (isset($_GET['action']) && $_GET['action'] == "checkout") {
    if ($myCart->get_number_of_records() > 0) {
        header("Location: ".CHECKOUT);
    } else {
        $myCart->error = "Your cart is currently empty!";
    }
}

First there is a check if there are products in the cart, if yes the user is redirected to the checkout page (row 3) and if not a message is set (row 5).

To show all messages use this code: <?php echo $myCart->error; ?>

The method $myCart->show_ordered_rows() is called for the table with ordered products at the end of the file. How to show order rows is described together with the checkout file next.

db_cart_continue.php

This file is new since version 1.12 and is used to make the order process more clear to the customer. After the customer has added a product to the cart this page will show up. On this page its possible to change the amount for the current product and there navigation links to the previous page or to the check out page.

$myCart = new db_cart($_SESSION['custom_num']);
$old_amount = $myCart->get_amount_from_row($_POST['art_no']);
if ($old_amount == 0) $old_amount = 1;
if (isset($_POST['add']) || isset($_POST['product'])) {
    if (isset($_POST['Submit'])) {
        $myCart->check_existing_row($_POST['art_no']);
        $myCart->update_row($myCart->curr_product, $_POST['new_amount']);
    } else {
        $myCart->handle_cart_row($_POST['art_no'], $_POST['product'], $old_amount, $_POST['price'], "yes");
        if (!SHOW_CONTINUE) {
            header("Location: ".PROD_IDX."?get_msg=11"); // the query string will create a message on the next page
            exit;
        }
    }
} else {
    header("Location: ".PROD_IDX);
    exit;
}

On row 2 there is a test to obtain the amount of an existing order row for the current product. Next if there is already an order row this one will only updated with the new amount (row 7 and 8). Otherwise the default method handle_cart_row is used to create a new order row. If the constant SHOW_CONTINUE is set to false the user is redirected to the product page other wise he will see the continue page again.

db_cart_checkout_example.php

This example file is used for several tasks:

  • showing existing order rows
  • Cancel the whole order
  • Update (delete) of the quantity from an existing order row
  • Update / setting the shipment address
  • The checkout process

To show dynamically the order rows in your own page its possible to store the data in array. This is done while calling this method:$myCheckout->show_ordered_rows() The data is showed with this code:

<table>
  ...// table header here
  <?php foreach ($myCheckout->order_array as $val) { ?>
  <tr>
    <td><?php echo $val['product_id']; ?></td>
    <td><?php echo $val['product_name']; ?></td>
    <td align="right"><?php echo $myCheckout->format_value($val['price']); ?></td>
    <td align="right"><?php echo $myCheckout->format_value($val['price'] * $val['quantity']); ?></td>
    <td>
      <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
        <input type="hidden" name="row_id" value="<?php echo $val['id']; ?>">
        <input type="text" name="quantity" size="5" value="<?php echo $val['quantity']; ?>">
        <input type="submit" name="add" value="Update">
      </form>
    </td>
  </tr>
  <?php } ?>
</table>

The table row with data is placed in a foreach loop (row 3) and all order row values are available in the $myCheckout->order_array. Notice the key names which are used to show the different values (row 5 to 12). Inside the last table cell is a small form with an input field and a submit button. This form is used to update each order row (row 12 and 13). If the new quantity value for a row is null, the row is automatically deleted.

If the update button is clicked the method $myCheckout->update_row($_POST[‘row_id’], $_POST[‘quantity’]) is used to update the order row.

If the user clicks on the “Cancel all” links the method $myCheckout->cancel_order() is called and all order rows, the order and the shipment data is removed. The user will be redirected to the product list.

This script shows an example how to obtain customer/shipment data from a third party data source, here from the example table “db_cart_example_customer”.

if (!$myCheckout->check_return_shipment()) {
    $cust_conn = mysql_connect(DB_SERVER, DB_USER, DB_PASSWORD);
    mysql_select_db(DB_NAME, $cust_conn);
    $cust_sql = sprintf("SELECT name, address, postal_code, place, country FROM db_cart_example_customer WHERE cust_no = %d", $cust_no);
    $cust_result = mysql_query($cust_sql) or die(mysql_error());
    $cust_obj = mysql_fetch_object($cust_result);
    $myCheckout->ship_name = $cust_obj->name;
    $myCheckout->ship_name2 = $cust_obj->name2;
    $myCheckout->ship_address = $cust_obj->address;
    $myCheckout->ship_address2 = $cust_obj->address2;
    $myCheckout->ship_pc = $cust_obj->postal_code;
    $myCheckout->ship_city = $cust_obj->place;
    $myCheckout->ship_country = $cust_obj->country;
    mysql_free_result($cust_result);
    $myCheckout->insert_new_shipment();
} else {
    $myCheckout->set_shipment_data();
}

Inside the script there is a check if a shipment record already exists. If not the the example table is used to get this data which will be stored in a record set (row 2 to 5). In the next rows the class variables are filled with the data from the record set (row 7 to 11). At last the new data will be stored in the shipment table with the method $myCheckout->insert_new_shipment(). If a shipment record already exists the method $myCheckout->set_shipment_data() is called.

If you click on “Order now” or “Continue shopping” the shipment data is automatically saved while calling this code:

if (isset($_POST['submit'])) {
    $myCheckout->update_shipment($_POST['name'], $_POST[name2], $_POST[address], $_POST['address2'], $_POST['postal_code'], $_POST['place'], $_POST['country'], $_POST['message']);
    if ($_POST['submit'] == "Order now!") {
        $myCheckout->check_out($cust_email);
    } else {
        header("Location: ".PROD_IDX);
    }
}

If the submit value is “Order now!” the order is processed by calling the method $myCheckout->check_out($cust_email) (use an additional form field for the $cust_email variable or use it from the external customer table) otherwise the user is redirected to the product list.

There are two functions at the top of the script, this functions are used to create dynamically form elements. If you need more information about this functions check this url: PHP scripts

The values of the total amount and the VAT amount are showed by calling the methods $myCheckout->format_value($myCheckout->show_total_value()) and $myCheckout->format_value($myCheckout->create_total_VAT()). Both values are formatted by the method “format_value()”.

db_cart_confirm.php

This file is only used to show the data after the order is mailed to the user and the admin. Use this kind of pages to give more information to the user about what is happen.

Example files “on stock” extension

These example files are extended versions from the examples above. Only the new additional functions and code is explained here. If you need to know something about the other code check the parent examples above. First you have to use for all you application files this included file: require($_SERVER[‘DOCUMENT_ROOT’].”/classes/db_cart/db_cart_4stock.php”);

Further you have to create objects like this: $myCart = new db_stock_cart($_SESSION[‘custom_num’]);

db_cart_stock_example.php

The code to obtain the example product data is a little bit different since we need the stock value: $query_new = “SELECT art_no, amount AS on_stock, price, art_descr FROM db_cart_stock_article_example ORDER BY art_no”;

The next important code is used to the new stock and price value to test them against existing open order rows for the current customer.

if (!$_SESSION['checked_cart']) {
  $search_in = $myCart->get_order_num_string();
  $query_stock = sprintf("SELECT art_no, amount AS on_stock, price FROM db_cart_stock_article_example WHERE art_no IN (%s) ORDER BY art_no", $search_in);
if ($res_stock = mysql_query($query_stock)) {
    $i = 0;
    while ($stock = mysql_fetch_assoc($res_stock)) {
      $stock_array[$i]['new_stock'] = $stock['on_stock'];
      $stock_array[$i]['new_price'] = $stock['price'];
      $stock_array[$i]['prod_id'] = $stock['art_no'];
      $i++;
    }
    $myCart->update_stock_values($stock_array);
    mysql_free_result($res_stock);
  }
}

In the first row is a check against a session if the check was already done before. If not then the script will build a string with the article numbers from the existing order rows (row 2). This string is used to query the product example table. Inside the loop (row 6 to 11) the array $stock_array is filled with values from database, don’t change the key names of this array!. On row 12 is the method update_stock_values called. This is used to update the existing order rows. Notice the additional code later in the html table will show the stock value from the result set <?php echo $row_new[‘on_stock’]; ?>

db_cart_checkout_stock_example.php

In this field is not so much changed because there is only a check to prevent orders with amount bigger then the stock value and the stock value is listed in the table.

if (isset($_POST['add']) && $_POST['add'] == "Update") {
  if ($myCheckout->check_against_stock($_POST['stock'], $_POST['quantity'])) {
    $myCheckout->update_row($_POST['row_id'], $_POST['quantity']);
  }
}

Notice the additional row no. 2, there is test for the current order amount and the stock value.

Next some code to get the stock values from the example table:

$myCheckout->show_ordered_rows();
$search_in = $myCheckout->get_order_num_string();
$query_stock = sprintf("SELECT art_no, amount AS on_stock FROM db_cart_stock_article_example WHERE art_no IN (%s) ORDER BY art_no", $search_in);
$res_stock = mysql_query($query_stock);
while ($stock = mysql_fetch_assoc($res_stock)) {
  $stock_array[$stock['art_no']] = $stock['on_stock'];
}

There is again the function called to build the string with the article number to search the records from the product example table. Inside the loop is an array build with the article number as key and the stock value as value.

This stock value is placed in order table like this: $stock_array[$val[‘product_id’]];

db_cart_stock_confirm.php

In this file is an additional function to update the stock values after the order is processed:

$myConfirm->set_shipment_data();
$sql_errors = 0;
foreach ($myConfirm->order_array as $val) {
  $update_stock = sprintf("UPDATE db_cart_stock_article_example SET amount = amount - %d, last_buy = NOW() WHERE art_no = '%s'", $val['quantity'], $val['product_id']);
  if (!mysql_query($update_stock)) {
    $sql_errors++;
  }
}
if ($sql_errors == 0) {
  $myConfirm->close_order();
} else {
  $myConfirm->error = $myConfirm->messages(1);
}

First get the shipment information for this order (row 1) then loop through the array with order rows to update the related product row with the new quantity of the product.

Using  the shopping cart script without a customer ID

In many web shops the customer has to login/register after the product selection is done. With the db_cart class it’s possible to handle shopping carts with and without a customer ID.
Important: If you don’t want to use a customer ID you need to leave the property in the constructor empty (or use a zero) $object = new db_cart(); or if you don’t know if a customer is logged in use the code like:

if (empty($customer)) $customer = 0;
$object = new db_cart($cutomer);

Change log for the PHP Shopping Cart script

Version 1.13

This version is a bigger update for the PHP shopping cart script, there modifications and improvements inside the main class file, several examples and also the table structure is extended. In this version there two additional fields for the shipment values (name2 and address2). All messages are available in German, English and Dutch language. The standard text inside the e-mail messages is in external files now, this content is parsed inside the improved e-mail method.

Version 1.12

There was bug inside the method remove_old_orders(), this error is fixed in this version. I removed also some small bugs inside the “stock” extension. It’s possible to add products to the shopping cart on a different way: If the setting SHOW_CONTINUE = true a continue page will show up. All example pages are using this new feature. To make this feature complete there are new example files included (for the regular and the stock version). The manual is updated too, to catch this new functions.

Version 1.11

In older version it wasn’t possible to delete a single row via the checkout page. From now on, if the value of the quantity is “0” after submit the row will be deleted. Check these modified methods: messages(), update_row() and the new method delete_row().

Version 1.10

The new extension “db_stock_cart” make it possible to handle shops where the “on Stock” amount is important. With this extension it’s possible to handle old orders if the stock of a product is changed (the same to the price). Order rows where the stock is on zero will be removed and order values higher then the stock will be updated. The user gets information about how many rows are updated.

Version 1.04

There was a small bug inside the handle_cart_row() method, it was not possible to change the variable $replace. This is fixed now and the update_row() can handle this parameter too. I added an option to recover old orders for customer during the next access. Check the methods db_cart() and remove_old_orders() and notice the new constant RECOVER_ORDER. The new constant VALID_UNTIL defines how much time an old order will be recovered. There will be a new method to remove old unused orders in the next version(s).

Version 1.03

Because there are problems with the euro sign I modified the method format_value() a little, the methods messages() and mail_order() are modified too. With this release I created the manual about how to use this class with explanations about how the files “db_cart_example.php” and “db_cart_checkout_example.php” are used.

Version 1.02

To make it possible to add some message to an order, there is an additional field inside the shipment table. the checkout example has some new text area. The following methods are modified: messages(), set_shipment_data(), update_shipment() and mail_order(). Check also the conformation example file.

Version 1.01

I replaced the variable “total_rows” with a new method that get the records from the database. The method show_ordered_rows() and the examples are affected by this modification. I changed the datatype for the product id (length = 20) to handle also not number types, affected methods: mail_order(), messages(), check_existing_row() and insert_row(). There is a new example available with only “Add to cart” image buttons.