Search code examples
phphtmlsessionshopping-cartcart

Create a one page shopping cart using PHP $_Session and NO SQL


I am learning some PHP and I am trying to create a all in one page shopping cart.

I have read into and can see the benefits of a SQL bases system, but I want to learn the basics first. In doing so I have create a all-in-one page that contains the products in an associated array, as well as a form that submits to itself.

What I want to achieve is:

  • A product can only be purchased once (buy button replaced with a remove button)
  • The item and its cost are added to the cart below
  • A user can either remove it from the cart, or the item list
  • The total cost should be updated as required.
  • The "checkout" button will submit item name and cost
  • The form posts to itself and does not require any SQL

My current problem is:

  • I cannot purchase more than one item at a time, i.e. the cart only contains the last purchased item
  • I cannot get it to "check" if an item has been purchased and if so, replace the "buy" with "remove"
  • I cannot display the item details in the cart
  • The checkout button does not pass any details to my test

Again, I am not looking for a SQL solution yet, just a pure PHP using $_SESSION and $_POST and would like to use buttons instead of <a href add?> type links.

Thanks for the lengthy read in advance here is the code:

<?php
session_start ();

$items = array (
        'A123' => array (
                'name' => 'Item1',
                'desc' => 'Item 1 description...',
                'price' => 1000 
        ),
        'B456' => array (
                'name' => 'Item40',
                'desc' => 'Item40 description...',
                'price' => 2500 
        ),
        'Z999' => array (
                'name' => 'Item999',
                'desc' => 'Item999 description...',
                'price' => 9999 
        ) 
);

if (! isset ( $_SESSION ['cart'] )) {
    $_SESSION ['cart'] = array ();
}

// Add
if (isset ( $_POST ["buy"] )) {
    $_SESSION ['cart'] = $_POST;
} 

// Delete Item
else if (isset ( $_POST ['delete'] )) { // a remove button has been clicked
    unset ( $_POST ['delete'] ); //
} 

// Empty Cart
else if (isset ( $_POST ["delete"] )) { // remove item from cart
    unset ( $_SESSION ['cart'] );
}

?>
<form action='<?php echo $_SERVER['PHP_SELF']; ?>' method='post'>
    <?php
        foreach ( $items as $ino => $item ) {
            $title = $item ['name'];
            $desc = $item ['desc'];
            $price = $item ['price'];

            echo " <p>$title</p>";
            echo " <p>$desc</p>";
            echo "<p>\$$price</p>";

            if ($_SESSION ['cart'] == $ino) {
                echo '<img src="carticon.png">';
                echo "<p><button type='submit' name='delete' value='$ino'>Remove</button></p>";
            } else {
                echo "<button type='submit' name='buy' value='$ino'>Buy</button> ";
            }
        }
    ?>
</form>

<?php
if (isset ( $_SESSION ["cart"] )) {
    ?>

<form action='(omitted link)'
target='_blank' method='post'
enctype='application/x-www-form-urlencoded'>
<table>
    <tr>
        <th>Product</th>
        <th>Price</th>
        <th>Action</th>
    </tr>
    <?php

    $total = 0;
    foreach ( $_SESSION ["cart"] as $i ) {
        ?>
    <tr>
        <td>
            <?php echo($_SESSION["cart"]); ?> <!--Item name-->
        </td>
        <td>price<?php echo($_SESSION["price"][$i] ); ?>
            <!--Item cost-->
        </td>
        <td><button type='submit' name='delete' value='$ino'>Remove</button>
            </p></td>
    </tr>
    <?php
        $total = + $_SESSION ["amounts"] [$i];
    }
    $_SESSION ["total"] = $total;
    ?>
    <tr>
        <td colspan="2">Total: $<?php echo($total); ?></td>
        <td><input type='submit' value='Checkout' /></td>
    </tr>
    <tr>
        <td><button type='submit' name='clear'>Clear cart</button></td>
    </tr>
</table>
</form>
<?php  } ?>

Solution

  • There's a few things that need fixing in your script, so I'll break them down into their individual parts.

    There's a lot of security error checks that should also be done with the code, but as a pure learning exercise, I'm bypassing those factors.

    Defining the cart

    You're defining the shopping cart as an array:

    if (! isset ( $_SESSION ['cart'] )) {
        $_SESSION ['cart'] = array ();
    }
    

    However, when you add an item to the cart, you're replacing the cart:

    // Add
    if (isset ( $_POST ["buy"] )) {
        $_SESSION ['cart'] = $_POST; // 
    } 
    

    To add an item to the cart, you should be using $cart[] = $_POST, but, there are additional things to take into account.

    Adding to cart

    The $cart[] = $_POST adds the full $_POST data to the cart, when you only need the product ID. The correct way would be:

    // Add
    if (isset ( $_POST ["buy"] )) {
        // Check the item is not already in the cart
        if (!in_array($_POST ["buy"], $_SESSION['cart'])) {
            // Add new item to cart
            $_SESSION ['cart'][] = $_POST["buy"];
        }
    }
    

    This would result in the cart storing multiple values. For example, a print_r($_SESSION['cart']) might show:

    array (
        0 => 'A123',
        1 => 'B456'
    );
    

    Each item in this array would be an item that has been added to your cart.

    Removing an item from your cart

    Now that the structure of $_SESSION['cart'] has been changed, the "remove from cart" action requires updates too. Using a little snippet of code, we can check if the value exists in the array, find its key, and remove it.

    // Delete Item
    else if (isset ( $_POST ['delete'] )) { // a remove button has been clicked
        // Remove the item from the cart
        if (false !== $key = array_search($_POST['delete'], $_SESSION['cart'])) {
            unset($_SESSION['cart'][$key]);
        }
    }
    

    Check if the item is in your cart

    Further changes to your code would be required to support the new array structure. You can use in_array to check if your product is contained in the cart array.

    <?php
        foreach ( $items as $ino => $item ) {
            // ... snipped for brevity
    
            // Check if an item is in the cart by checking for the existence of its ID:
            if (in_array($ino, $_SESSION['cart'])) { // The $ino would be 'a123' for your first product
                echo "<p><button type='submit' name='delete' value='$ino'>Remove</button></p>";
            } else {
                echo "<button type='submit' name='buy' value='$ino'>Buy</button> ";
            }
        }
    ?>
    

    Simplifying your code

    In the above code, I've removed some of the code. You are doing the following:

    $title = $item ['name'];
    $desc = $item ['desc'];
    $price = $item ['price'];
    
    echo " <p>$title</p>";
    echo " <p>$desc</p>";
    echo "<p>\$$price</p>";
    

    This can be simplified to:

    echo "<p>$item['name']</p>";
    echo "<p>$item['desc']</p>";
    echo "<p>\$$item['price']</p>";
    

    Rather than the double $$ in the last line, I personally would use:

    echo '<p>$' . number_format($item['name']) . '</p>';
    

    This allows you to format the display of the number easier. Alternatively, you could use money_format.

    Displaying the shopping cart

    There are a few problems with this code.

    1. You're attempting to echo($_SESSION['cart']) which won't work. You cannot echo an array
    2. You're using foreach ($_SESSION ["cart"] as $i) incorrectly when attempting to display the values using <?php echo($_SESSION["price"][$i] ); ?>
    3. You're complicating the code used for the $total value
    4. The HTML isn't valid due to a random </p> thrown into the mix

    The correct way to display this would be:

    <?php
    // Set a default total
    $total = 0;
    foreach ( $_SESSION['cart'] as $ino ) {
        ?>
    <tr>
        <td>
            Name: <?php echo $items[$ino]['name']; ?>
        </td>
        <td>
            Price: <?php echo $items[$ino]["price"]; ?>
        </td>
        <td>
            <button type='submit' name='delete' value='<?php echo $ino; ?>'>Remove</button>
        </td>
    </tr>
    <?php
        $total += $items[$ino]['price'];
    } // end foreach
    ?>
    
    Total: $<?php echo $total; ?>