PHP shopping cart array

Hey guys, check out this code:


<?php 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//       Section 1 (if user attempts to add something to the cart from the product page)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (isset($_POST['pid'])) {
    $pid = $_POST['pid'];
    $wasFound = false;
    $i = 0;
    // If the cart session variable is not set or cart array is empty
    if (!isset($_SESSION["cart_array"]) || count($_SESSION["cart_array"]) < 1) { 
        // RUN IF THE CART IS EMPTY OR NOT SET
        $_SESSION["cart_array"] = array(0 => array("item_id" => $pid, "quantity" => 1));
    } else {
        // RUN IF THE CART HAS AT LEAST ONE ITEM IN IT
        foreach ($_SESSION["cart_array"] as $each_item) { 
              $i++;
              while (list($key, $value) = each($each_item)) {
                  if ($key == "item_id" && $value == $pid) {
                      // That item is in cart already so let's adjust its quantity using array_splice()
                      array_splice($_SESSION["cart_array"], $i-1, 1, array(array("item_id" => $pid, "quantity" => $each_item['quantity'] + 1)));
                      $wasFound = true;
                  } // close if condition
              } // close while loop
           } // close foreach loop
           if ($wasFound == false) {
               array_push($_SESSION["cart_array"], array("item_id" => $pid, "quantity" => 1));
           }
    }
    header("location: cart.php"); 
    exit();
}
?>

I got this from an online tutorial and although I am not familiar with many of the php array manipulation functions, I got suspicious when I saw how the variable “i” was used in the arraysplice method.

I may be completely wrong but surely if you add one item to a cart first i stays as 0 because it is postfix. Then you add another “1” then you add a third so “i” is 2. If you then add a fourth item which happens to be a duplicate of the first then you want to replace the first array item quantity. Surely “i” is then 2-1 =1 which gives us the wrong index- we want [0] to replace the first item. This only seems to allow for a situation when the item and the duplicate item are next to one another and sure enough my script is crashing. Can anyone help?

Thanks

Will

Please wrap the code in [NOPARSE]


[/NOPARSE] tags.

Not really - look. Inside foreach the $i is incremented straight away. In the array_splice() call it then does $i -1 which will correct it.

At the end of the day though the only REAL way to find out whats going on is to debug it - creatively. You’ll be using a lot of echo and var_dump…

Hey I’m sorry I just don’t get the logic here, have read the php manual on this method and I can’t seem to grasp it, can anyone help me further. SOrry for being a little thick lol


<?php 
if (isset($_POST['pid'])) {
    $pid = $_POST['pid'];
    $wasFound = false;

    if (!isset($_SESSION["cart_array"]) || count($_SESSION["cart_array"]) < 1) { 
        $_SESSION["cart_array"] = array(array("item_id" => $pid, "quantity" => 1));
    } else {
        foreach ($_SESSION["cart_array"] as &$each_item) { 
            if ($each_item['item_id'] == $pid) {
                $each_item['quantity'] += 1;
                $wasFound = true;
                break;
            }
        }

        if ($wasFound == false) {
            array_push($_SESSION["cart_array"], array("item_id" => $pid, "quantity" => 1));
        }
    }
    header("location: cart.php"); 
    exit();
}

Removed the $i counter in favour of looping through the cart array using a reference. That means that the $each_item isn’t a copy of each element of the cart – it references it instead. And that means that by modifying $each_item you’re actually modifying the cart array.

Lastly, I removed comments because they were stating the obvious.

Hey thanks Decowski,
Thats great, working fine and so much easier to follow. I am more of a designer than a programmer but I’m getting there thanks to nice folk like yourself :slight_smile:

Well basically array_splice() allows you to remove part of an array and replace it with another.

Thats all that was being done in the code sample you posted. The array which contained the item ordered was being removed and replaced with a new array which had the quantity amended. The code supplied by decowski is almost certainly the best way forward for simplicities sake.

May I suggest that you take me up on my idea of debugging though? - You will learn a lot from it. You need to try these things in order to understand them and learn from them. Unfortunately we can’t just look at something, understand it and work with it perfectly first time around. Learning is about experimentation, trial and error.

Something I did when I first got into php after many years ‘tinkering’ with other peoples scripts for hours on end, was to create my own code testing script. It consisted of a textarea box to input my script text into and a submit button. When submitted my script would run the code through the eval function and output the result and also echo the original code back into the textarea (saving me creating a new .php file, uploading, testing, editing, reuploading etc). It has been tremendously useful to me and although very simple, it’s been incredibly useful. I almost never ask for help on forums like this now. I’ve given you the hints… :wink:

Hey,
Thats a great way of doing things, as soon as I finish this little project, I will develop that script. Thanks for the tip :wink:

This is a VERY basic version of what I use which should help you get started.

<?
//Turn on output buffering - so anything printed/echoed is kept in buffer
ob_start();

//If mode is run (button pressed)
if ($_POST['mode'] == 'run')
   {
   //Check for magic_quotes
   If (ini_get('magic_quotes_gpc'))
      {
      //Strip slashes from quotes
      $_POST['code'] = stripslashes($_POST['code']);
      }
   
   //Evaluate code - any output will be held in buffer
   eval("$_POST

");
//Grab anything the code outputs from buffer and store in variable for printing below
$Content = ob_get_contents();
}

//Clear output buffer and turn off buffering - otherwise it will print to browser if just turning off.
ob_end_clean();
?>

<html>
<head>
<title>Code tester</title>
</head>
<body>
<form method=“post” action=“<? print $_SERVER[PHP_SELF]; ?>”>
<table width=“80%” border=“1” align=“center”>
<tr>
<td align=“center”>
<!–Hidden element saves hassle hitting return in a text box–>
<input type=“hidden” name=“mode” value=“run”>
<textarea name=“code” rows=“8” cols=“50”><? print $_POST[‘code’]; ?></textarea><br>
<input type=“submit” value=“Submit”>
</td>
</tr>

        &lt;tr&gt;
           &lt;td&gt;
           &lt;? print $Content; ?&gt;
           &lt;/td&gt;
        &lt;/tr&gt;
     &lt;/table&gt;
  &lt;/form&gt;

</body>
</html>



I'm sorry I can't supply you with my more advanced version but its a module for a larger CMS I'm working on and would take me a while to make it a standalone script.

If you're going to use it directly on your public server then I would highly recommend adding a username and password box and some php verification to stop people abusing it otherwise it will be abused senseless if you've not secured it when the bots find it (and believe me they do). You can hard code the username and password into the script if it makes it easier. If you do that, leave the hidden form element there - because if you hit enter in a text box not all browsers will submit the value of the button (EG if you called it mode and set the value to run it wouldn't be submitted and then the code would never be executed). You might also want to consider adding a save and open feature so you can save bits of code you're working on / testing and reopen them later. That way you can also use it for site maintenance (EG optimizing tables) etc.

I never managed to print html using mine due to the template system I created but in theory this being a basic version you should be able to.

It should get you started and while it seems very basic, it allows you to run almost any code you want. The only skill you'll need to use it is getting creative with how you use it (EG if you want to test form processing code you might want to hard code an array at the top and just use that).

Hope that helps ;)

Hey that’s excellent, thanks again :):slight_smile:

I just used it actually for helping someone on another forum and I’m glad to say you can print html using it (unlike my main version) but you must put it between ?><?

Hey,

Is there any adivce that you could give me about security for my ecommerce site? I’ve really enjoyed building it from scratch because I didn’t want to use an out-of-the-box shopping cart like zencart. I think that I will be a better programmer for it and I also believe that trying to hack someone else’s API restricts creativity. Look at blogger for an example, just awkward.

Anyway, I have been developing it from an online tutorial which is excellent and it all works ok but I doubt that it has the kind of security that an out of the box system has. I am aware of ssl authenticated https certificates and how they can be used to encrypt sensitive payment/personal info but I was thinking more about how to protect my databases. I have heard horror stories about sql inject and other nasty hacking methods.

thanks

Will

Hi

You always need to sanitize ANY input (including arrays and hidden form elements - people can tinker with html before clicking the button).

Basically (I’m no expert on php security) as I understand it the weakness with mysql is the quotation marks. ’ and " can be abused. Basically someone can insert say a user id in a login box followed by a quotation mark and then more SQL - in that same text box. Thats called sql injection (so don’t go imagining any needles or anything - its nothing that complex just an abuse of the basics). This is why you must sanitize ANY thing that has been transmitted to your site either by _GET or _POST - and I do mean ANYTHING.

mysql_real_escape_string() will usually do the job by adding a back slash in front of any quotation marks (which mysql like php will then understand as ignore the next character) and mysql will execute the statement ignoring any injected sql and treating it as input which will be stored with the rest.

There are also other things to consider - like not giving away which language you’re using. You can change the .php extension to another (as long as you can edit apaches httpd.conf to support this or a .htaccess file) which will mask the usage of php. Alternatively just call the directory without the filename - the server will automatically serve any file named index with an extension of .htm, .html, .php etc. So if you want to send someone to accounts.php in the accounts directory… /accounts/ would be the hyperlink and accounds.php could be renamed to index.php. Not the best defence but every little helps.

Captcha is another method… its breakable using some special techniques combined with OCR but still good enough to stop the average bot abuse.

Also, over time you’ll notice the same IPs making repeated requests to your site looking for weaknesses. It might start off (as with mine) trying to post a simple link to google to a guestbook once a day - to see how quick its detected and dealt with. If nothing is done they move onto their next steps… which with me was bb code links and javascript page hacking (inserting a javascript to redirect any visitor to the page to their page - some guestbooks don’t filter it out and the javascript is then inserted into the page). I’d recommend you create a blacklist table of IPs and then add them all to it. Function at the top of your script to check if the remote ip is in this table and if it is exit with no ouput at all (why waste you bandwidth?) - Instead just error code them with a 403 header or 404 and then sleep(300) :lol:. Most will abort after a few seconds but you never know… you might put someones bot to sleep waiting :wink:

Generally obfuscate everything - IE make it as hard as possible for other coders, attackers etc to understand or abuse.

Even swap field names for MD5 hashes on forms so that attackers can never be sure of the same field name twice (note that advanced bots will still parse the form and use the random names but it still deters SOME).

I’m not a pro developer I’m still learning myself but its basically a case of making things as difficult as possible for an attacker. I had a few problems with bots repeatedly trying to abuse my website a few months back and they’re still trying now but using the above techniques (and some others) I’ve managed to hold off any further advances in their tactics.

Also if you’re creating a shopping cart, NEVER allow the prices to be transmitted in any form on your site. Just use the id for the items row in the database and then take the price directly from your database - otherwise the price could be edited and then the form submitted, transaction processed and you’ve just lost money.

Hey ,

Wow thanks for all of that, some great knowledge there, will take me a while to adjust it but its all very helpful. What is your name tangoforce and how long have you been developing? Are you in the US or UK?

I am working on an ecommerce site at the moment with a business partner who keeps pushing to use and out-of-the-box api. Unfortunately he has no knowledge of programming and seems to think that just because zencart etc are developed by pro teams, that they are the most secure and best way to go. OUr site requires a number of custom pages and if we do go with a 3rd party api, I will have to hack the code to get us what we need. Also, I am a good css/html/flash designer and I just feel so resticted when I have to try and play around with other peoples code just to present things as I want them. That is why I am going to try and build my own and make it as secure as possible.

What is your opinion, of these sort of ecommerce solutions? I have read up on things like the ZEND framework, whos MVC decoupled structure allows maximum front-end fiddling wihtout affecting the CMS engine but for a simple business site I just thought it overkill. I think I need to explain to my business partner that I am a control freakand I don’t want to use anyone else’s API for this project. LOL

If I’m honest I’ve no idea. I’ve never used any frameworks. Like I said I’m still technically learning myself but I’ve had to adapt and learn to tackle some unusual situations.

Not going to give my name away really on an open forum am I :stuck_out_tongue: Been into php on and off for several years now… I’m actually quite a lazy coder BUT… when I put some effort into it I can sometimes come up with some pretty good code. Unfortunately my html / css is rather bad lol. I’m UK based.

Using other peoples frameworks or carts might not be such a bad idea… they’ve had time to try, test, test, test, patch, fix and test their code a lot more than you could hope for but I understand your desire to DIY - it’s how you learn and become a better programmer.

Ah thats cool,

Is good to know that someone else struggles to master all the fontr and back end disciplines as there just arent enough hours in the day. Was only after a first name don’t worry, my name is Will anyway and if you ever have any problems with CSS, HTML or Flash/ActionScript then don’t hesitate to message me :wink:

You shouldn’t of said that, I’m almost certain to take you up on it as my web design is useless :wink:

Haha, No worries I am sure I can write enough dodgy Javascript and PHP to harass you back with. Do you do JQUERY? I’m just finishing the SITEPOINT Ninja book, can build some awesome UI stuff with it .

Nope, never touched jquery :frowning: I’m not great with javascript… I find it a pain to debug. At least with php you can print and var_dump stuff… with javascript there’s no easy way.

Yeah I don’t disagree there. That’s another discipline again using firebug and outputting JS variables with console commands. Firebug scared the living daylights out of me the first time I saw it TBH, so many features and not enough time! It is great for inspecting CSS tho, realy easy to find out what each of a page element is called.