PHP购物车安全

i've managed to create a working shopping cart and my next concern is security. Mostly about the arcitechture and session security.

  1. Should i make sessions somehow secure, if there's no authenticated login and sessions are deleted when browser closes? or is session_start() enough in this case?
  2. Would the server side validation be enough strong in the add_to_cart.php and is that proper way to exit php code in case of errors?
  3. Are the database queries safe or should i take some extra measures?
  4. Are there some high security risks with my approach, i should take into account?

Thanks in advance! All help is appreciated. Also, if anyone find this cart useful, feel free to use it. : )

session.php

// Check if session is created. If not, then create.
if (session_status() == PHP_SESSION_NONE) {
    session_start();

}

db_connect.php

$host = "localhost";
$db_name = "xx";
$username = "xx";
$password = "xx";

try {
    $con = new PDO("mysql:host={$host};dbname={$db_name}", $username, $password);
    $con->exec("set names utf8");
}

//to handle connection error
catch(PDOException $exception){
    echo "Connection error: " . $exception->getMessage();
}

products.php

        <?php
        $query = "SELECT id, name, price, image FROM shoes ORDER BY id";
        $stmt = $con->prepare( $query );
        $stmt->execute();

                $num = $stmt->rowCount();

                while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
                extract($row);

                    echo "
                        <div class=\"item\">

                            <div class=\"product-id\">{$id}</div>
                            <div class=\"category\">shoes</div>
                            <div class=\"image\"> <img src=\"images/{$image}\" class=\"product-image\" alt=\"product\"/> </div>
                            <div class=\"name\"> {$name} </div>
                            <div class=\"price\"> {$price}</div>
                            <div class=\"quantity\"><input type=\"text\" value=\"1\" class=\"maara\" /></div>
                            <input type=\"button\" class=\"lisaa\" value=\"Lisää\"/>

                        </div>
                        ";
                }
    ?>

ajax.js

function add() {

$(".lisaa").click(function(e) {
    var id = $(this).closest(".item").find(".product-id").text();
    var category = $(this).closest(".item").find('.category').text();
    var quantity = $(this).closest(".item").find('.maara').val();
    var action = "add";

    $.ajax({
        url: 'add_to_cart.php',
        type: 'POST',
        data: {'id': id, 'category': category, 'quantity': quantity, 'action': action},

            beforeSend: function() {
                $("#wait").show();
            },

            complete: function() {
                $("#wait").hide();
            },

            success: function(data) {

                    if(data.indexOf("error") >= 0) {
                        $(".success, .errors").hide();
                        $(".errors").html(data).slideDown();
                    }

                    else {
                        $(".shoppingcart-container").load("cart.php");
                        $(".errors, .success").hide();
                        $(".success").html(data).slideDown();
                    }
                },

            error: function(request, status, error) {
                    alert("error!");
                }
    });
});
}

add_to_cart.php

// Check server request method
if ($_SERVER["REQUEST_METHOD"] == "POST") {

// Check if action is set
if(isset($_POST['action']) ? $_POST['action'] : "") {

    // Check if action is "add"
    if($_POST['action'] == "add") {

        // Error variable.
        $error = "";

        // Success variable.
        $success = "";

        // VALIDATE ID
        if (isset($_POST['id']) ? $_POST['id'] : "") {

            // clean input
            $id = test_input($_POST["id"]);

            // Check if id is numerical
            if (!is_numeric($id)) {

                // Show invalid ID as a return data
                echo "error: Invalid ID. Not numerical.";

                // Add a value to error variable
                $error = "Error";

                // Exit php
                exit;
            }
        }

        // If id doesn't exist
        else {  

            // Show invalid ID as a return data
            echo "error: Invalid ID. Empty id.";

            // Add a value to error variable
            $error = "Error";

            // Exit php 
            exit;
        }


        // VALIDATE Category
        if (isset($_POST['category']) ? $_POST['category'] : "") {

            // clean input
            $category = test_input($_POST["category"]);

            // Category must match your product categories
            if(!preg_match('[shoes|shirts]', $category)) {

                    // Show invalid category as a return data
                    echo "error: invalid category.";

                    // Add a value to error variable        
                    $error = "Error";

                    // Exit php
                    exit;
            }
        }


        // If category doesn't exist
        else {

            // Show invalid category as a return data
            echo "error: Invalid category.";

            // Add a value to error variable    
            $error = "Error";

            // Exit php 
            exit;
        }

        // VALIDATE Quantity
        if (isset($_POST['quantity']) ? $_POST['quantity'] : "") {

            // clean input
            $quantity = test_input($_POST["quantity"]);

                // Check if quantity is numerical
                if (!is_numeric($quantity)) {

                    // Show invalid category as a return data
                    echo "error: Invalid quantity format.";

                    // Add a value to error variable
                    $error = "Error";

                    // Exit php
                    exit;
                }   
        }

        // Check if errors are false 
        if ($error == false) {

            // Connect to database and select row from table, which matches category variable
            $query = "SELECT id, name, price, image FROM {$category} WHERE id={$id}";
            $stmt = $con->prepare( $query );
            $stmt->execute();

        }

        else {

            // Show error as return data    
            echo "error: errors occurred with db.";

            // Add a value to error variable    
            $error = "Error";

            // Exit php     
            exit;
        }

        // Check if query contains a row
        if($stmt->rowCount() <= 0) {

            // Add a value to error variable
            $error = "Error";

            // exit php
            exit;
        }

        // Get values of the item, which matched our database search
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
            $name = $row['name'];
            $price = $row['price'];
            $image = $row['image'];
        }

        // Check if session variable "cart" exists. If not, then create.
        if (!isset($_SESSION['cart']) || empty($_SESSION['cart']))
        {
            $_SESSION['cart'] = array();
        }

        // Check if array is set
        if(isset($_SESSION['cart']['id'])) {

        // If array is set, check if our product id exists in cart already
            if(in_array($id, $_SESSION['cart']['id'])) {

                foreach($_SESSION['cart']['id'] as $key => $val)
                {       
                        if ($val == $id ) {

                            // Update product quantity
                            $_SESSION['cart']['quantity'][$key] = $quantity + $_SESSION['cart']['quantity'][$key];


                            // Show succesfull quantity update message as return data
                            echo "{$name} x {$quantity} quantity added";

                            // Add a value to success variable
                            $success = "{$name} x {$quantity} quantity added";

                            // Exit php
                            exit;
                        }
                }   
            }
        }


        // If product doesn't exist in cart and errors are false, add new item to cart
         if ($error == false) {
            $_SESSION['cart']['id'][] = $id;
            $_SESSION['cart']['category'][] = $category;
            $_SESSION['cart']['name'][] = $name;
            $_SESSION['cart']['price'][] = $price;
            $_SESSION['cart']['quantity'][] = $quantity;
            $_SESSION['cart']['image'][] = $image;

            // Show succesfully added message as return data
            echo "{$name} x {$quantity} succesfully added";

            // Add a value to success variable
            $success = "{$name} x {$quantity} succesfully added";

            // exit php
            exit;

        }
    }
}
}

cart.php

    function showcart() {

    // If cart variable is not empty, then do the following
    if(!empty($_SESSION['cart'])) {

        // Few variables, to collect total amount of items and total price
        $total = "";
        $counter = "";

        // Start shoppingcart div
        echo "<div class=\"shoppingcart\">";

                // Loop through cart items
                foreach ($_SESSION['cart']['id'] as $key => $value) {

                    // Add product's price into variable
                    $singleproduct = $_SESSION['cart']['price'][$key];

                    // Add product's quantity into variable
                    $quantityproduct = $_SESSION['cart']['quantity'][$key];

                    // Replace , with . to make calculations
                    $singleformat = str_replace(',' , '.' , $singleproduct);

                    // Count product's amount x quantity
                    $multipleproducts = $singleformat * $quantityproduct;

                    // Change number formatting
                    $multipleformat = number_format($multipleproducts, 2, ","," ");

                    // Create html output, which contains the product information
                    echo "<div class=\"shoppingcart-items\">";
                        echo("<div class=\"shoppingcart-image\"><img src=\"images/{$_SESSION['cart']['image'][$key]}\" class=\"shoppingcart-image\"/></div>");                          
                        echo("<div class=\"shoppingcart-itemname\">{$_SESSION['cart']['name'][$key]}</div>");
                        echo("<div class=\"shoppingcart-quantity\"> {$_SESSION['cart']['quantity'][$key]} x </div>");
                        echo("<div class=\"shoppingcart-price\"> {$multipleformat} €<br /> <span class=\"singleproduct-price\"> ({$singleproduct} / kpl)</span></div>");


                        // Calculate total price of products
                        $total += $singleformat * $quantityproduct;

                        // Calculate total items amount
                        $counter += $quantityproduct;

                        // Change total price number format
                        $totalsum = number_format($total, 2, ","," ");


                    echo "</div>";

                // End foreach loop
                }

        // End shopping cart div        
        echo "</div>";

        // Create bottom for shopping cart, which contains total amount of items and total price
        echo "<div class=\"shoppingcart-bottom\">
                    <div class=\"summa\"><a href=\"lomake.php\">Kori</a></div>
                    <div class=\"tuotteiden-maara\">{$counter} tuotetta <br />{$totalsum}  €</div>
                </div>";    
    }

    // if cart variable is empty, then show the following
    else {
        echo "<div class=\"shoppingcart\">";
            echo "ostoskori on tyhjä";
        echo "</div>";
    }

}

test_input function

    function test_input($data)
    {
       $data = trim($data);
       $data = stripslashes($data);
       $data = htmlspecialchars($data);
       return $data;
    }

Your Shopping cart cannot be just secured by keeping your session intact, you need to follow PCI compliance in order to make sure your Shopping cart is secured. Some of the possible way of securing the cart flow and meeting PCI Compliance would be :

  1. Have your shopping cart flow go through ssl layer i.e. https protocol.
  2. Ensure that you are never storing user payment details (Credit card number etc. in your database)
  3. In case you are soring card holder name etc, please ensure they are encrypted with standard encryption form.