Building a simple PHP shopping cart
Update 21/11: I’ve added a demo and downloadable .zip file at the end of the article.
Update 07/12: Thanks to Greg and Rob Shan Lone for spotting a bug in the cart update code – I’ve now fixed this and updated the demo and .zip file; thanks guys!
One of the most common requirements any web designer/developer will come across is likely to be that of the small business taking its first steps online; a client with an established widget-selling company now wants to move into the national market and sell their widgets to the world.
What they need to do this (apart from a great-looking, functional, usable and accessible website!) is some sort of shopping-cart system to allow their customers to add, remove and update the products they wish to buy.
This article will walk through the simple steps to achieve this, using the server-side language PHP and a MySQL database.
Setting up the database
Let’s take as our example a bookseller. They are not the best-stocked bookseller in the world, having as they do only three titles in stock, but it is enough for our example. Let’s create the database and add some stock:
CREATE TABLE books (id int(6) unsigned NOT NULL auto_increment,title varchar(100) NOT NULL default '',author varchar(100) NOT NULL default '',price decimal(3,2) NOT NULL default '0.00',PRIMARY KEY (id)) TYPE=MyISAM;INSERT INTO books VALUES (1, 'Where God Went Wrong', 'Oolon Colluphid', '24.99');INSERT INTO books VALUES (2, 'Some More of God\'s Greatest Mistakes', 'Oolon Colluphid', '17.99');INSERT INTO books VALUES (3, 'Who Is This God Person Anyway?', 'Oolon Colluphid', '14.99');- Download this code: /code/php-cart-1.txt
Now that step is out of the way, let’s create our shopping cart.
Identify our requirements
The cart we are going to build should be pretty familiar to most internet users. It will provide a means of displaying a message on every page of the site (along the lines of “You have 5 items in your shopping cart”), which when clicked will take the customer to a list of the items in the cart; each item may be removed or have its quantity updated.
As all of our stock details are stored in the database, the only piece of information that we need to store about each customer is the id of each product they have added to their cart. To do this, we are going to use PHP’s built-in session handling capabilities.
Using sessions in PHP
PHP’s session handling is very easy to understand.
To ‘switch it on’, simply add session_start(); at the top of your code; you can then store values (or arrays) in session variables:
$_SESSION['name'] = 'Matthew';
$_SESSION['age'] = 31;
These $_SESSION variables will now be available to any PHP scripts on other pages (as long as you’ve included the session_start(); call first).
A short note on cookies
The default behaviour of PHP sessions is to store the session ID (a long string of numbers and letters that identifies you to the server) as a cookie on your computer; however, even if you have cookies disabled this functionality will still work – PHP will instead append the session ID to each link on the site (in the form ‘mypage.php?PHPSESSID=
Creating the cart
We will store the contents of the shopping cart as a comma-separated list of product ids in a session named (unsurprisingly) ‘cart’ – for example, a cart containing “1,1,3,1,2” has four items; three of product #1, and one each of products #2 and #3.
Firstly, let’s create the code to display the “You have X items…” message on every page:
function writeShoppingCart() {$cart = $_SESSION['cart'];if (!$cart) {return '<p>You have no items in your shopping cart</p>';} else {// Parse the cart session variable$items = explode(',',$cart);$s = (count($items) > 1) ? 's':'';return '<p>You have <a href="cart.php">'.count($items).' item'.$s.' in your shopping cart</a></p>';}}- Download this code: /code/php-cart-2.txt
This function first gets the value of the ‘cart’ session variable into a local variable, mainly to save on typing. If the cart is empty, we return an appropriate message; if not, we use the explode() function to create an array of all the products in the cart, and then count() them and display the result (the $s variable is there to make plurals display correctly).
Now we can display the correct message anywhere on the site:
echo writeShoppingCart();
I hope that made sense; let’s move on to displaying the contents of the cart itself.
Show me the money
The shopping cart page itself (cart.php) can be arrived at in a couple of ways. The user may have clicked on the link created by the writeShoppingCart() function above; or, they may have clicked an ‘Add to cart’ link on a product page.
If it was the latter, we need to intercept that click and update our cart contents before displaying the new list of products – simple enough, as all we need to do is append the id of the clicked product to the ‘cart’ session variable. Our product links are going to look like this:
<a href="cart.php?action=add&id=1">Add to cart</a>
Don’t worry about the ‘action=add’ bit, we’ll get to that later. The id can now be extracted from $_GET[‘id’] and added to our cart:
$cart = $_SESSION['cart'];if ($cart) {$cart .= ','.$_GET['id'];} else {$cart = $_GET['id'];}$_SESSION['cart'] = $cart;- Download this code: /code/php-cart-3.txt
Now, on to the contents of our cart!
Multiple items, one product
As in our example above, it is entirely possible that a customer might have more than one of a certain product in their cart. As we don’t want to list duplicate items when we display the contents, we need to figure out a way to combine any of the same product into one entry (with a corresponding quantity attached).
$cart = $_SESSION['cart'];if ($cart) {$items = explode(',',$cart);$contents = array();foreach ($items as $item) {$contents[$item] = (isset($contents[$item])) ? $contents[$item] + 1 : 1;}- Download this code: /code/php-cart-4.txt
This time, after exploding the list of product ids, we have iterated through them to create a new array named $contents, which consists of key=>value pairs where the key is the product id and the value is the quantity of that product in the shopping cart. So to take our example above, a cart containing “1,1,3,1,2” would become an array where ‘1’=>3, ‘2’=>1, ‘3’=>1.
Now that we have an accurate count of unique products, let’s query the product database for each one and output its details into a table:
$total = 0;$output[] = '<table>';foreach ($contents as $id=>$qty) {$sql = 'SELECT * FROM books WHERE id = '.$id;$result = $db->query($sql);$row = $result->fetch();extract($row);$output[] = '<tr>';$output[] = '<td><a href="cart.php?action=delete&id='.$id.'" class="r">Remove</a></td>';$output[] = '<td>'.$title.' by '.$author.'</td>';$output[] = '<td>£'.$price.'</td>';$output[] = '<td><input type="text" name="qty'.$id.'" value="'.$qty.'" size="3" maxlength="3" /></td>';$output[] = '<td>£'.($price * $qty).'</td>';$total += $price * $qty;$output[] = '</tr>';}$output[] = '</table>';$output[] = '<p>Grand total: £'.$total.'</p>';- Download this code: /code/php-cart-5.txt
(*Note*: I’m using a PHP class to handle my database connections, so your code may need to be slightly different).
Pretty simple stuff – we iterate through the new $contents array and query the database for each product id. Then we output the relevant details for each product; title, author and price, and at the bottom we show the grand total for the order. For each item, we’ve also included a link to remove the item from the cart, a textbox containing the current quantity of that item, and a total price (obviously this will only differ from the base price if the quantity is not 1).
The reason I’m using $output[] = ... is that I am buffering the output into an array to print to the screen later.
So far so good – now how about removing products from the cart?
Deleting a product
As shown above, the link to delete a product from the cart follows the same format as the ‘add a product’ link:
<a href="cart.php?action=delete&id=1">Remove</a>
Let’s expand on the code from earlier by adding a switch() statement to handle the different things that might happen to our cart:
$cart = $_SESSION['cart'];$action = $_GET['action'];switch ($action) {case 'add':if ($cart) {$cart .= ','.$_GET['id'];} else {$cart = $_GET['id'];}break;case 'delete':if ($cart) {$items = explode(',',$cart);$newcart = '';foreach ($items as $item) {if ($_GET['id'] != $item) {if ($newcart != '') {$newcart .= ','.$item;} else {$newcart = $item;}}}$cart = $newcart;}break;}$_SESSION['cart'] = $cart;- Download this code: /code/php-cart-6.txt
The new ‘delete’ case iterates through the ‘cart’ session, looking for any product ids that AREN’T the one we’re deleting, and adding them to a temporary variable called $newcart. When it’s finished, it puts the revised cart contents back into $cart.
Updating a product
Lastly, we are going to allow customers to update the contents of their shopping cart by manually changing the value in the quantity box for each product.
To make this work, we’ll wrap the shopping cart table in a <form> so that the ‘update cart’ button will submit the form:
$output[] = '<form action="cart.php?action=update" method="post" id="cart">';$output[] = '<table>';foreach ($contents as $id=>$qty) {$sql = 'SELECT * FROM books WHERE id = '.$id;$result = $db->query($sql);$row = $result->fetch();extract($row);$output[] = '<tr>';$output[] = '<td><a href="cart.php?action=delete&id='.$id.'" class="r">Remove</a></td>';$output[] = '<td>'.$title.' by '.$author.'</td>';$output[] = '<td>£'.$price.'</td>';$output[] = '<td><input type="text" name="qty'.$id.'" value="'.$qty.'" size="3" maxlength="3" /></td>';$output[] = '<td>£'.($price * $qty).'</td>';$total += $price * $qty;$output[] = '</tr>';}$output[] = '</table>';$output[] = '<p>Grand total: £'.$total.'</p>';$output[] = '<div><button type="submit">Update cart</button></div>';$output[] = '</form>';- Download this code: /code/php-cart-7.txt
Note that, even though the form uses the POST method, its action includes a GET variable, “action=update”. Again, we can expand our previous code to process any quantity updates:
case 'update':if ($cart) {$newcart = '';foreach ($_POST as $key=>$value) {if (stristr($key,'qty')) {$id = str_replace('qty','',$key);$items = ($newcart != '') ? explode(',',$newcart) : explode(',',$cart);$newcart = '';foreach ($items as $item) {if ($id != $item) {if ($newcart != '') {$newcart .= ','.$item;} else {$newcart = $item;}}}for ($i=1;$i<=$value;$i++) {if ($newcart != '') {$newcart .= ','.$id;} else {$newcart = $id;}}}}}$cart = $newcart;break;- Download this code: /code/php-cart-8.txt
This looks quite complicated, but it’s fairly straightforward; we interrogate the contents of the $_POST array (which holds all our quantity values) and extract the relevant id and value pairs. For each product, we then delete all the existing instances of it, and re-insert the new quantity.
There are a number of ways this could have been done – for example, by counting the existing number of each product present in the cart and figuring out whether we needed to add or remove items – but this seemed the easiest way to process the quantity updates.
Summary
And that’s about it! A functional and easy shopping cart script – here’s the final function to display the contents of the cart:
function showCart() {$cart = $_SESSION['cart'];if ($cart) {$items = explode(',',$cart);$contents = array();foreach ($items as $item) {$contents[$item] = (isset($contents[$item])) ? $contents[$item] + 1 : 1;}$output[] = '<form action="cart.php?action=update" method="post" id="cart">';$output[] = '<table>';foreach ($contents as $id=>$qty) {$sql = 'SELECT * FROM books WHERE id = '.$id;$result = $db->query($sql);$row = $result->fetch();extract($row);$output[] = '<tr>';$output[] = '<td><a href="cart.php?action=delete&id='.$id.'" class="r">Remove</a></td>';$output[] = '<td>'.$title.' by '.$author.'</td>';$output[] = '<td>£'.$price.'</td>';$output[] = '<td><input type="text" name="qty'.$id.'" value="'.$qty.'" size="3" maxlength="3" /></td>';$output[] = '<td>£'.($price * $qty).'</td>';$total += $price * $qty;$output[] = '</tr>';}$output[] = '</table>';$output[] = '<p>Grand total: £'.$total.'</p>';$output[] = '<div><button type="submit">Update cart</button></div>';$output[] = '</form>';} else {$output[] = '<p>You shopping cart is empty.</p>';}return join('',$output);}- Download this code: /code/php-cart-9.txt
Note that if the cart is empty, a suitable message is displayed.
A working demo can be seen (excuse the lack of design!), or please feel free to download a .zip of all the files – any questions, comments or suggestions on how the code could be improved gratefully received.
Technorati tags: php mysql php shopping cart
Bookmark this article with del.icio.us
Previously: Today I have mostly been learnin'...
Next: Random song lyrics: Update
Comments
- Matthijs
- 988 days ago
- Nice article! A good explanation for how the basics of a shopping cart work. That’ll help us on our way. Thanks.
- #1
- Christian Montoya
- 985 days ago
- Awesome. I bookmarked this for later.
- #2
- Hamish Keith
- 979 days ago
- Very very good – prob the best i have seen on the web
- #3
- Greg Hamilton
- 975 days ago
- First of all wicked article, very helpful. Whats the best way to attempt the checkout ? Thanks
- #5
- Matthew Pennell
- 975 days ago
- Greg: Funny you should ask that, as I wrote an article that kind of touches on the subject – it is specific to Textpattern, but there is a section on ‘Shopping Integration’ that covers using PayPal to handle payment.
As we’re doing the shoppng cart bit ourselves, we could use PayPal’s new API to simply send the payment details and receive back the response (or whatever other payment processor we’re using). - #6
- Greg Hamilton
- 974 days ago
- Hey Matt thanks for the with the checkout help, quick question about the update function..when you try to update an id that isn’t qty1 it doesnt update…not sure if I messed up the demo file or not :( thanks
- #7
- Greg Hamilton
- 974 days ago
- Sorry Matt I mean if you have, lets say two products in yer cart and you try to update the top one it doesnt, but the bottom one will. I think it does it in the demo as well….thanks bud
- #8
- Matthew Pennell
- 974 days ago
- Thanks, Greg – I’ve fixed the problem and updated the demo and .zip.
- #9
- Greg Hamilton
- 971 days ago
- Hey again Matt
Quick question about quantities, is ti possible to add a function that also allows the user to add quantities inside the product view before adding to cart. Thanks bud - #10
- Matthew Pennell
- 971 days ago
- It would be very easy, Greg, although I don’t have time to do it right now – perhaps a later expansion, unless you want to add it in and publish your changes?
- #11
- Greg Hamilton
- 971 days ago
- Ya I’m gonna give it a go. I’ll publish when I get it all set to go.
- #12
- Andrew
- 970 days ago
- Hi,
Thanks for the tutorial!
i have changed the cart.php page a little. on the cart.php page, if the user clicks re-fresh, an item is added to the the cart as the ID ifor the product is stored in the querystring. its easily fixed.
Just a heads up for some.
Once again thanks for the demo! - #13
- Franco
- 948 days ago
- Hi Matthew,
I test your script
but when i add to cart
this is message page:
Please check quantities…
You shopping cart is empty
I don’t see any product choice.
Can you help me?
Regards and happy New year
Franco - #16
- Matthew Pennell
- 948 days ago
- Hi Franco – I’d need a bit more information to work out what might be wrong; the first thing to try though would be to echo the $id and $cart variables as the code progresses through the ‘add’ routine to see what is happening.
- #17
- The Illumidigerati
- 941 days ago
- Matt, does this cart form allow enough security for actual business transactions in the form of moneyorder/personal check? I’ll be webmastering my girlfriends home business and starting out neither of us are really keen on dealing with credit or any online payment ventures, i.e. paypal. Is there a reason for anything more secure when moneyorders/personal checks are the only payment methods since only user information will be logged, not CC info or bank account info?
- #18
- Matthew Pennell
- 940 days ago
- This cart script doesn’t handle any kind of payment; it is only for keeping track of what is in the shopping cart.
- #19
- dreamer85
- 940 days ago
- good tutorial well done
if it explaines how to display image with the products will be greate tutorial
take care - #20
- Momotaro
- 931 days ago
- Excellent tutorial.
I’d like to know how to display the result in a Form that could then be saved to .csv file server-side? Ultimately, even send me an email when order Form was submited. The tutorials I’ve come across in past were too full of tech-speak that I couldn’t understand. - #21
- Aneurin
- 926 days ago
- Thank You for the tutorial…
i was wondering if i could add product option to this shopping cart..eg. same item(same product id) but different options (size,colour)...i would appreciate some ideas…thanks in advance… - #22
- Matthew Pennell
- 925 days ago
- Aneurin: Yes, that’s certainly an option; the project that I developed this cart code for does just that.
I used certain characters to split the product that was added to the cart, so to take your example of something with a certain size and colour, I would store the sizes and colours in their own tables in the database, then add products in the format “123c6s3”, which would translate as “Product #123, colour #6, size #3”.
The show-cart page would then lookup that colour and size from the table as part of the SQL statement and display the correct description of the product. - #23
- Matthew Pennell
- 925 days ago
- Momotaro: Sending an email when the order is submitted would be pretty simple – the PHP mail() function covers that in detail.
- #24
- Aneurin
- 925 days ago
- Thank You very much…...
- #25
- momotaro
- 923 days ago
- Thanks for the link
- #26
- junwei
- 915 days ago
- nice! It help me alot, u mind adding add to cart and login function . thank
- #27
- Cormac
- 914 days ago
- are there anyother api’s that could be intergrated fairly easily with this shopping cart other than PayPal’s ?
- #28
- Matthew Pennell
- 914 days ago
- Cormac: There are quite a few online payment mechanisms that are as easy to integrate with as PayPal. WorldPay is probably the next best known one, but there are plenty around.
- #29
- Matt Cooper
- 908 days ago
- Nice code, and I very much like your website too, very fresh design. One disappointment (only a small one!) is that you haven’t provided further code for a checkout…is this on the cards? Good luck…
- #30
- Tan
- 906 days ago
- Great Demo, the best on the web!
I have one problem, same as franco above, I select add item and it displays check quantities on the cart page, with no items passed through. I have had a look over every page to no avail, would it be a function issue? It passes the id through the url but does not display it. - #31
- James
- 901 days ago
- Hi Matt,
I’m new to all this and am pulling my hair out! – it just won’t work for me – getting messages such as:
Query failed: Unknown column ‘Array’ in ‘where clause’ SQL: SELECT * FROM book WHERE id = Array
or…
Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result
or…
Warning: mysql_num_rows(): supplied argument is not a valid MySQL
Where am I going wrong – from the other comments it seems to be pretty easy so it must be something I’m doing wrong!
Thanks for any help – very frstrated at the moment!
James - #32
- Matthew Pennell
- 901 days ago
- James: That sounds as if the id is not being passed through in the querystring correctly. Check that you have populated the database correctly and have configured your database connection information properly.
- #33
- tan
- 900 days ago
- Just me again, why would it not display in the cart. Please note above note.
- #34
- Matthew Pennell
- 899 days ago
- Tan: It sounds as if the id variable in the querystring is not being picked up by the code (php-cart-3 in the code above) and added to the cart.
You could try adding a loop through all the items in the GET collection:
foreach ($_GET as $key => $value) { echo $key . ’ contains ’ . $value . '<br />'; }That will list everything all the variables in the querystring; if nothing is there, it may be that you’ve changed the form method to “post” instead of “get”? Or possibly you're using a very old version of PHP that doesn't support $_GET - you could try the above code with $HTTP_GET_VARS instead; if that works you'll have to change all instances of $_GET to $HTTP_GET_VARS (or upgrade to a host supporting a more modern version of PHP!) - #35
- CHiNo4ReaL
- 897 days ago
- Nice tutorial, I’m gonna use it, but I have a question, is it possible to create catogory’s,
- #36
- Matthew Pennell
- 897 days ago
- Chino: Do you mean in the products listings, or in the cart session variable?
It depends how your database is set up whether you’d need any additional work to cope with categories. - #37
- G
- 897 days ago
- Hello,
I have installed your cart on my website, but I have a problem. When I navigate between cart.php and index.php it appears this error message:
“Warning: session_start(): Cannot send session cache limiter – headers already sent (output started at ….global.inc.php:9) in cart.php on line 9”
“Warning: session_start(): Cannot send session cache limiter – headers already sent ”...
Can you please help me to solve it out?
Regards,
G. - #38
- CHiNo4ReaL
- 897 days ago
- @Matthew
Yes, because i’m creating a webshop, with carparts, so there are a few catorgies, like exterior, frontbumpers, rims etc. - #39
- CHiNo4ReaL
- 896 days ago
- Oh and another question, How can I finish the order?
- #40
- Matthew Pennell
- 896 days ago
- G: The session_start() command has to appear in the code before any output has been sent to the browser. As your error says, there is output being sent at line 9 of global.inc.php – you must have changed the source files, as my originals only have database connection variables in that file.
- #41
- Matthew Pennell
- 896 days ago
- Chino: Bear in mind that the id of the product that is held in the cart doesn’t have to include any reference to the category it is in.
You just have to alter the products database to include a category field; you can then use that when listing products, but just use the product id to hold it in the cart.
To finish the order, you’re going to have to decide what you want to do with it – either have it saved to a database, emailed to you, or processed by an online payment processor like PayPal. That’s beyond the scope of this tutorial, though. - #42
- CHiNo4ReaL
- 896 days ago
- Ok, Do you have an example for the catorgyfield in the database?
- #43
- jatty5
- 895 days ago
- Hi all, I am new to this php and am trying to buid a shopping cart for my business myself. I have installed easyphp which has given me apache mysql and php, and am trying to work through this tutorial which I think is excellent for somebody like me a total novice! I have managed to create the database succesfully by copy the complete script and putting it through phpmyadmin. I tried to download the complete zip files, but where do i put them and how on earth do i set the database connection files up. Please help as I am getting alittle lost. I have also downloaded each script but agian where does it go, i know it would be in the WWW directory of my easyphp folder. Please help
- #44
- Matthew Pennell
- 895 days ago
- Chino: Just add a category field into your database using whatever MySQL admin tool you’re using.
- #45
- Matthew Pennell
- 895 days ago
- jatty5: If you have downloaded the zip you don’t need the individual scripts; just unpack the zip file to a folder under your www directory (e.g. “cart”). The database connection settings are in inc/global.inc.php if you need to change them, but if you’re running it locally the settings should be fine.
Then visit http://localhost/cart/ and it should all be working (you may have to start the PHP and MySQL services, depending on the package you are using). - #46
- jatty5
- 895 days ago
- Hi Mathew, thanks for your swift reply, i have done what you said but still get the following reply:
I take it it has something to do with the database i created the database under phpmyadmin and called the database wtchproject and then run your script under that which created your tables under this database.
What do i change in the gobal file and is it possible for you to show where i can make those changes if possible.
Notice: Could not select database in c:\program files\easyphp1-8\www\cart-demo\inc\mysql.class.php on line 80
Warning: session_start(): Cannot send session cookie – headers already sent by (output started at c:\program files\easyphp1-8\www\cart-demo\inc\mysql.class.php:80) in c:\program files\easyphp1-8\www\cart-demo\index.php on line 9
Warning: session_start(): Cannot send session cache limiter – headers already sent (output started at c:\program files\easyphp1-8\www\cart-demo\inc\mysql.class.php:80) in c:\program files\easyphp1-8\www\cart-demo\index.php on line 9
Your Shopping Cart
Notice: Undefined index: cart in c:\program files\easyphp1-8\www\cart-demo\inc\functions.inc.php on line 3
You have no items in your shopping cart
Books In Our Store
Notice: Query failed: No database selected SQL: SELECT * FROM books ORDER BY id in c:\program files\easyphp1-8\www\cart-demo\inc\mysql.class.php on line 109
Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in c:\program files\easyphp1-8\www\cart-demo\inc\mysql.class.php on line 151
Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in c:\program files\easyphp1-8\www\cart-demo\inc\mysql.class.php on line 167 - #47
- ScopAL
- 895 days ago
- Notice: Undefined index: cart in z:\home\cart\www\inc\functions.inc.php on line 3
You have no items in your shopping cart
:(((( - #48
- CHiNo4ReaL
- 895 days ago
- Jatty5
I think that you have selected the wrong database, your database is called wtchprojec, but in the script its selecting books - #49
- Matthew Pennell
- 894 days ago
- jatty5: I would suggest that if you’re trying to learn to use PHP/MySQL, it would be a good idea to learn all about creating database connections, but here is how to fix your problem:
In global.inc.php, you have four variables that are used to create the database connection:
$host = ‘localhost’;
$user = ‘root’;
$pass = ‘’;
$name = ‘’;
These correspond to your host name (usually ‘localhost’), the username and password you are using, and the name of your database.
So in your case, just change the last line to $name=’wtchproject’; and the database connection class object will then be pointing at your database. - #50
- CHiNo4ReaL
- 893 days ago
- If I want the order mailed to me, how can I do that?
I have tried to do that, but i cant find any good ones, can u help me? - #51
- Matthew Pennell
- 892 days ago
- I suppose you’d have to build in some data capture for the customer’s details, and then use mail() to send everything.
I’m not building the whole site for you, though..! ;) - #52
- CHiNo4ReaL
- 892 days ago
- ok, thanks anyway
- #53
- Greg Hamilton
- 889 days ago
- Hey again Matt, what are your feelings on using cookies instead of sessions to remember the items that are in the shopping cart, do you think its necessary at all ?
- #54
- Matthew Pennell
- 889 days ago
- Greg: The benefit would obviously be that you would be able to leave the site and come back to the same basket; an approach using both sessions and cookies would probably be a good idea (with a fairly short expiration period).
- #55
- Juilius
- 888 days ago
- Hi I am having problems with the cart.php, whenever I hit the refresh button it adds another quantity to the cart? Any ideas?
Oh by the way, great, great example! - #56
- Matthew Pennell
- 888 days ago
- Juilius: Yes, refreshing the page will add another item to the cart due to its use of the querystring ($_GET collection) to handle addition.
You can get around it by adding an extra session variable and storing the last item added and the time it was added, then checking against that to see if it is a repeated entry within a certain timeframe. - #57
- Steven
- 863 days ago
- I’ll be messing around with this on XAMPP soon! I’m a bit of a PHP beginner but I thinks it’s important to dive in at the deep end!
- #58
- Steven
- 863 days ago
- I’ll be messing around with this on XAMPP soon! I’m a bit of a PHP beginner but I thinks it’s important to dive in at the deep end!
PS. Edited to ask, does a shopping cart system like this have to be bolted onto a dynamic website or can I add it to static product pages? - #59
- Matthew Pennell
- 862 days ago
- Steven: I’m not sure how you’d use it with static pages, as it relies on a database of product details – I suppose you could copy your static data into the database, but if you’re doing that you may as well be using the database to output your product info as well!
- #60
- Fred
- 846 days ago
- I’m just curious, since this code connect to the db and all. Is this vulnerable to sql injection at all?
Can users modify the input variables or the session cookie to inject special characters that could cause buffer overflow in the SQL sequence?
I don’ recall seeing anywhere that inputs are scrubbed, but I could be wrong or the way the code is written, input scrubbing might be a non-issue.
Any confirmation on this? - #61
- Matthew Pennell
- 846 days ago
- Fred: You are correct that if you wanted to use this in a commercial setting it would be a good idea to add some validation of the session data when it is read to output the contents of the cart. This could be as simple as using preg_match to check that the ID of the product is numeric.
- #62
- Fred
- 846 days ago
- This was some amazingly great cart code which gave me a good jump on what I wanted to create. Thanks Matt.
I did add some basic sanitization code to keep the db safe from SQL injects. You can take from the following.
I added a sanitization function and then called it on certain variable inputs used in the cart program:
function sanitize_system_string($string, $min=’’, $max=’’) {
$pattern = ’/(;|\||`|>| $max)))
return FALSE;
return $string;
}
// these occur in various places
sanitize_system_string($_GET[‘id’],1,50)
$cart = sanitize_system_string($_SESSION[‘cart’]);
$action = sanitize_system_string($_GET[‘action’],1,50);
// assigned right underneath the update switch foreach loop
$key = sanitize_system_string($key,1,50); - #63
- Fred
- 845 days ago
- Sorry the sanitize_system_string function got partially truncated by the comment submit form. The other examples of variable sanitization remained in tact though.
Anyway, folks can get the point. Find a sanitization function, insert it in the functions php document and then employ it throughout the cart code as needed.
I identified several good places in the last post :)
I love this cart code matt provided! It has provided me the basis to do some wonders with it! - #65
- Ella
- 844 days ago
- Hi There,
I am fairly new to php etc and am trying to do a shopping cart as part of my final project for my degree. I am getting an error when I click the add to cart link it goes through to the cart page but has the following error:
Parse error: parse error in c:\LocalUser\fashuti\public_html\cart.php on line 174
it is erroring on the last line of code on the page which is obciously not the problem. I have adapted the code on your size so that i can distinguish by id, size and colour. My id’s are both letter and charactger based. I can understand all of the code apart from one line which confuses me and I wonder if it could relate to that?
It seems you are comparing qty which is created here to the id?
foreach ($contents as $id=>$qty) {
I wondered if this could be my problem?
I will post my cart code below:
Hi There,
I am fairly new to php etc and am trying to do a shopping cart as part of my final project for my degree. I am getting an error when I click the add to cart link it goes through to the cart page but has the following error:
Parse error: parse error in c:\LocalUser\fashuti\public_html\cart.php on line 174
it is erroring on the last line of code on the page which is obciously not the problem. I have adapted the code on your size so that i can distinguish by id, size and colour. My id’s are both letter and charactger based. I can understand all of the code apart from one line which confuses me and I wonder if it could relate to that?
It seems you are comparing qty which is created here to the id?
foreach ($contents as $id=>$qty) {
I wondered if this could be my problem?
I will post my cart code below:
$total = 0;
$output[] = ‘’;
$conn=odbc_connect(‘danum_fashu’,’’,’’);
foreach ($contents as $id=>$qty) {
$sql = ‘SELECT * FROM products, product_line WHERE products.product_id = ’.$id.’ AND products.product_id = product_line.product_id AND product_line.product_size= ’.$sz.’ AND product_line.product_colour = ’.$col;
$rs=odbc_exec($conn,$sql);
$pid=odbc_result($rs,”product_line.product_id”);
$size=odbc_result($rs,”product_line.product_size”);
$name=odbc_result($rs,”products.product_name”);
$colour=odbc_result($rs,”product_line.product_colour”);
$cost=odbc_result($rs,”products.product_costprice”);
$endcost = number_format($cost * 2.6, 2, ’.’, ’,’);
$output[] = ‘’;
$output[] = ‘’.$pid.’ by ’.$name.’’;
$output[] = ‘’.$size.’ ’.$colour.’’;
$output[] = ’£’.$endcost.’’;
$output[] = ‘’;
$output[] = ’£’.($endcost * $qty).’’;
$output[] = ‘Remove’;
$total += $endcost * $qty;
$output[] = ‘’;
}
$output[] = ‘’;
$output[] = ‘Grand total: £’.$total.’’;
odbc_close($conn);
Any help would be gratefully recieved - #66
- Matthew Pennell
- 844 days ago
- Usually if a script throws an error on the very last line it is due to an unclosed bracket somewhere. I can’t see anything obvious in the code you posted; maybe check the rest of that page to see if you have left a bracket open?
- #67
- Ella
- 844 days ago
- Ok ive picked it all apart and i think i now know the problem but am unsure of how to fix it.
Like I said I have adapted your code to pass through the id,colour and size of a product. do on the product page the add to cart link is as follows:
echo ‘Add to cart’;
and then when it goes into cart i need these three values for my select statement so that io retrieve the correct record and this is what i have been coding:
$sql = ‘SELECT * FROM products, product_line WHERE products.product_id = ’.$id.’ AND products.product_id = product_line.product_id AND product_line.product_size= ’.$sz.’ AND product_line.product_colour = ’.$col;
Is that correct what i mean is are these variable available to me once i have used this code?
$cart = $_SESSION[‘cart’];
if ($cart) {
$cart .= ’,’.$_GET[‘id’].$_GET[‘sz’].$_GET[‘col’];
} else {
$cart = $_GET[‘id’].$_GET[‘sz’].$_GET[‘col’];
}
$_SESSION[‘cart’] = $cart;
The other thing is if i cannot do this i am not sure how to distinguish one form the other as they can all vary in length.
Thank you for your quick response. - #68
- Ella
- 844 days ago
- sorry my pad add to cart link is as follows:
Add to cart - #69
- Ella
- 844 days ago
- sorry my add to cart link is as follows:
Add to cart - #70
- Ella
- 844 days ago
- sorry my add to cart link is as follows:
I have cut the and opening < so it displays
a href=”shopcart.php?action=add&id=’ . $id .’&sz=’ . $size . ‘&col=’ . $colour .’”>Add to cart - #71
- Ella
- 844 days ago
- i have found one problem which is that for step 4 php-cart4 there is a closing brace missing from the end of the code:
$cart = $_SESSION[‘cart’];
if ($cart) {
$items = explode(’,’,$cart);
$contents = array();
foreach ($items as $item) {
$contents[$item] = (isset($contents[$item])) ? $contents[$item] + 1 : 1;
}
} - #73
- Ella
- 844 days ago
- having discovered this problem i am now getting an understandable error:
Warning: odbc_exec(): SQL error: [Microsoft][ODBC Microsoft Access Driver] Syntax error (missing operator) in query expression ‘products.product_id = 4THYNGreen12 AND products.product_id = product_line.product_id AND product_line.product_size= AND product_line.product_colour =’., SQL state 37000 in SQLExecDirect in
ass you can see the size colour and id have been grouped together:
products.product_id = 4THYNGreen12
under the value $id and then further into the sql there is no value placed in $colour:
product_line.product_colour =’.,
But i have put in seperate values for the add to basket link:
a href=”shopcart.php?action=add&id=’ . $id .’&sz=’ . $size . ‘&col=’ . $colour .’”>Add to cart - #74
- Fred
- 844 days ago
- I’m having no problems with the base code whatsoever. My cart works like a charm: http://www.feetcore.com/Products/Token-Store.html
- #75
- Ella
- 843 days ago
- does anybody else get an error with their select statement for the cart giving warnings when you add a second product?? the warnings are:
Warning: odbc_exec(): SQL error: [Microsoft][ODBC Microsoft Access Driver] Syntax error (missing operator) in query expression ‘product_line.listing_no= AND product_line.product_id = products.product_id’., SQL state 37000 in SQLExecDirect in c:\LocalUser\fashuti\public_html\includes\cart_functions.php on line 41
Warning: odbc_fetch_row(): supplied argument is not a valid ODBC result resource in c:\LocalUser\fashuti\public_html\includes\cart_functions.php on line 43
the php code is:
$conn=odbc_connect(‘danum_fashu’,’’,’’);
$sql =”SELECT * FROM products, product_line WHERE product_line.listing_no= $id AND product_line.product_id = products.product_id”;
$rs=odbc_exec($conn,$sql);
while (odbc_fetch_row($rs))
{
i have echoed out the value in $id and it works fine and the correct outcome is still displayed but these horrid warnings appear, anyone know if i can get rid of them? - #76
- FrozenPeas
- 839 days ago
- Nice script,
but I would make the add to cart a button with a form post.
Otherwise, Google may add items to the cart when spidering your site.
This used to happen with Oscommerce and the buy now button which was not a form action but a href. - #77
- Fred
- 839 days ago
- So maybe the spider engine will make a purchase then.
It should affect any other surfer’s session though if a spider adds an item to it’s own cart.
If I’m correct this cart individualizes content based on individual surfer sessions. Don’t see any harm to the search engine spidering this at all.
I think this cart was very well written aside from the input variable sanitizations - #78
- dario
- 794 days ago
- So far the best design and useful info i’ve seen ever.
I’m the newest of all of you in PHP and built a user registration form with Java, MySQL checkers, actiivation link sent to mail of user
and seeking for Shopping Cart interaction.
I hope to make it work with the session variable i’ve already made.
My best wishes to you Matthew,
thank you for the full working ZIP download.
I hope to find more of your work. - #79
- koTo
- 781 days ago
- Hi ella…I know why does your ID and SIZE and COLOR splitted together..The problem is here..
$cart = $_SESSION[‘cart’];
if ($cart) {
$cart .= ’,’.$_GET[‘id’].$_GET[‘sz’].$_GET[‘col’];
} else {
$cart = $_GET[‘id’].$_GET[‘sz’].$_GET[‘col’];
}
$_SESSION[‘cart’] = $cart;
Look at the 3rd line…where there is:
$cart = $_GET[‘id’].$_GET[‘sz’].$_GET[‘col’];
by thsi code you are splitting this values together.. I will recomend you to do like i did: $cart .= ’,’.$_GET[‘id’].’:’.$_POST[‘color’].’:’.$_POST[‘size’].’:’.$_POST[‘qty’];
Here I have defined: id1:size1:color1:qty1, id2:size2:color2:qty2, etc…
Now i Hope that i helped you :) - #80
- wingsfan
- 768 days ago
- Has anybody actually found a way to get options to work, ie: size, color, etc? Like if somebody wanted to chose a color out of a product drop down.
- #81
- charrik
- 750 days ago
- Hi,
First of all… really a great tutorial. Very helpful
I have just once concern.
I am ab;e to make shopping cart however I am clueless how to store the shopping cart data into may database.
Can some body please help me with that - #83
- Matthew Pennell
- 750 days ago
- charrik: To output the data for storing in a database, you could either use the contents of the cart session variable ($_SESSION[‘cart’]) and store that (obviously you would then need to break it up and look up the ids against your database when examining the data); or, you could adapt the showCart() function to store more verbose cart contents information in your database.
- #84
- Scott
- 749 days ago
- Hi Matthew,
Great tut, has helped me heaps! Im just now trying to send the variable $total to paypal for processing but it seams tied up in the showcart function and wont print anything to screen when I put echo $total…how do i release the variable from the function? - #85
- Matthew Pennell
- 748 days ago
- Scott: Probably the easiest way would be to put it into a session variable at the point it is calculated in the showCart() function:
$_SESSION[‘total’] = $total;
Then you can echo the session variable in your PayPal form. - #86
- Scott
- 736 days ago
- Thankyou Matthew :)
- #87
- Paul Drewett
- 731 days ago
- May I say what a fantastic article this was. I am trying to build my own php shopping cart and this was a perfect introduction/explanation.
I have learned lots about PHP as well and you have really really helped me – thank you.
This is a superb website design too. Fantastic user experience. Everything just where you would expect it. Wonderful work. I shall be adding a link from my site Monday morning.
Can’t wait to see whats on the rest of the watchmaker project.
Thank you again
Paul - #88
- Prosadia Blue2
- 722 days ago
- Great Example
How Careful were you, the code is clear and easy to understand.
Another line, your site looks pretty, i love its style - #89
- Jono
- 710 days ago
This looks like a really cool tutorial, I’ll have to check it out again some time. It looks good for beginners and I’m a total beginner so thanks a lot.
I did notice one problem with the working example: After adding a bunch of products to the cart I clicked the back button a few times and it kept adding more products each time it went back to the view cart page.
Maybe that’s just me?
- #90
- Mike lawrence
- 702 days ago
Fantastic tutorial i’m ready to have a go at – except for one thing – i cannot see how callbacks are handled – i understand they come back from, for example, Worldpay and then they have to be processed, to alter stock quanities etc. how are callbacks done and is there a tutorial?
Thanks
- #91
- Matthew Pennell
- 702 days ago
Hi Mike – you would need a whole separate tutorial for that area, as it’s quite a big subject.
Most companies that do this sort of thing (e.g. PayPal, WorldPay, Protx, etc.) offer API documentation and example files/code to handle callbacks, so maybe check those out?
- #92
- Nick Tabram
- 702 days ago
Fantastic tutorial sir. Helped me immensely. Thanks.
- #93
- Lya
- 700 days ago
Hi,
Thanks for the tutorial. I have a problem, the session ($cart) is always false. When I add 1 product, it adds for first time, but when I go to cart.php it will shows that my shopping cart is empty. Any ideas?Thanks
- #94
- Lya
- 700 days ago
Hi,
Anyway is there anybody who ever try this shopping cart in opera and ie? I dunno but its only work in firefox in my comp >- #95
- Matthew Pennell
- 700 days ago
Lya: The demo works in all modern browsers. Make sure you have cookies enabled, as otherwise the session variables may not work properly.
- #96
- Lya
- 700 days ago
I’ve enabled cookies and erase my prev cookies, but nothing work.
Can you help me to check
http://fleea.nl/Catwalk/user/index.phpIf possible, use opera or ie. Thanks a lot
- #97
- Matthew Pennell
- 700 days ago
Your site behaves exactly the same for me in Firefox, IE and Opera – it doesn’t work correctly in any of them.
Whatever you’ve done when you changed the target of the ‘add’ links to point to index.php instead of cart.php has screwed up the way the cart keeps track of its contents. You’ve also removed the table of items from the cart.php page.
I suggest you go back to the original code, then make your changes and see at what point it breaks.
- #98
- Lya
- 699 days ago
Hi Matthew,
thanks a lot for fast response. I think I fix it already. I will test it in other computer tomorrow, but now in my comp, when I delete cookies and do somethings, its still going well, either in opera, ie and firefox.Thanks for suggesting me come back to original code, I think I screw up session_start() and return from function.inc.php
This website is only for internal school, but I will make sure I provide some link to this web ^^
- #99
- Rob
- 690 days ago
Thanks for a great tutorial. I’m nearly there with it, but I want to be able to access the cart from various pages and directores on my site – more of a shortlist facilty than a ashopping basket. At the moment, the cart page is automatically loaded when a selection is made. Is there any way to stop that?
Thanks agian
- #101
- Matthew Pennell
- 690 days ago
Rob: To stop the addition buttons automatically going to the cart page, you could just direct them to the current page – you would need to replicate the ‘adding items’ functionality on each page – or I guess you could do it with Ajax instead if you knew your Javascript.
- #102
- Rob
- 689 days ago
Hi Matthew,
Thanks for getting back to me. Where and how do I change the redirection you mentioned. As you may have gathered I’m not exactly an expert at all this!Thanks again,
Rob
- #103
- Matthew Pennell
- 688 days ago
Rob: You need to change the <a href="cart.php"> links to instead point to the page they are on.
- #104
- Jonathan
- 680 days ago
This is awesome! Only… is it also possible to check out; can you automatically mail the contents of the basket with shipping details?
- #105
- Matthew Pennell
- 680 days ago
Jonathan: You’d have to build that functionality yourself!
- #106
- adrian
- 680 days ago
great tutorial! having a problem with one error.. cart is always undefined
on the first addition to the basket..once the page is refreshed or another item is added to the cart the variable is defined..any ideas??Notice: Undefined index: cart in c:\program files\easyphp1-8\www\cart.php on line 12
the same occurs when visiting the cart.php through a direct link without adding anything to the cart with the variable ‘action’
Notice: Undefined index: action in c:\program files\easyphp1-8\www\cart.php on line 13
any help would be great
- #107
- adrian
- 675 days ago
i got round this by turning off php warnings as there is no aparent problem with the code
- #108
- tom
- 665 days ago
I installed exatly, but when I add an item, then go back add another item again, the previous is lost. Can you explain. Thanks.
- #109
- Tyler Pederson
- 664 days ago
I tried for a couple days to make the exploding strings method work with passing quantities from the getgo, but in the end I made the cart session variable an array.
switch ($action) {
case ‘add’:
if ($cart) {
if ($cart[$id]) {
$cart[$id] += $_POST[‘quantity’];
} else {
$cart[$id] = $_POST[‘quantity’];
}
} else {
$cart = array();
$cart[$id] = $_POST[‘quantity’];
}
break;
case ‘delete’:
if ($cart) {
unset($cart[$id]);
}
break;
case ‘update’:
if ($cart) {
foreach ($_POST as $key=>$value) {
if (stristr($key,’qty’)) {
$id = str_replace(‘qty’,’’,$key);
$cart[$id] = $value;
}
}
}
break;
}
$_SESSION[‘cart’] = $cart;The functions were also changed.
function writeShoppingCart() {
$cart = $_SESSION[‘cart’];
if (!$cart) {
return ‘0 items’;
} else {
// Parse the cart session variable
$s = (count($items) > 1) ? ’s’:’’;
return ‘You have ’.count($cart).’ item’.$s.’ in your shopping cart’;
}
}And showCart() was mostly the same except I changed:
# if ($cart) {
# $items = explode(’,’,$cart);
# $contents = array();
# foreach ($items as $item) {
# $contents[$item] = (isset($contents[$item])) ? $contents[$item] + 1 : 1;
# }
# $output[] = ‘’;
# $output[] = ‘’;
# foreach ($contents as $id=>$qty) {
into:
$cart = $_SESSION[‘cart’];
if ($cart) {
$output[] = ‘’;
$output[] = ‘’;
foreach ($cart as $id=>$qty) {I hope this is helpfull to someone, I appologise if this is outside the original intent of the article.
- #110
- Carlos
- 657 days ago
Your scrit & tutorial are excellent. I was looking for a VERY simple Shopping Cartt and yours is the simplest I have found..
I have found a problem. If I turn Cookies off, the script will only add one item at a time to the cart, deleting the one that was there before..
For my uses I would like to have something that works without cookies, if at all possible.
Thank you again for a great tutorial & script.
- #111
- Carlos
- 649 days ago
I found the source of the problem, i.e. why turning off cookies the cart would not work. It has nothing to do with the script it was the settings in php.ini.
I had trouble locating the real php.ini to edit it. I’m using Mac OS X as my development server.
- #112
- Matthew Pennell
- 641 days ago
I’m closing comments on this article due to the volume of comment spam it is attracting. If you really can’t find the answer you need elsewhere, my contact details are on the contact page of this site.
- #113