title: Php shopping cart security
body: <p>i've managed to create a working shopping cart and my next concern is security. Mostly about the arcitechture and session security.</p>
  
  <ol>
  <li>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?</li>
  <li>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?</li>
  <li>Are the database queries safe or should i take some extra measures?</li>
  <li>Are there some high security risks with my approach, i should take into account?</li>
  </ol>
  
  <p>Thanks in advance! All help is appreciated. Also, if anyone find this cart useful, feel free to use it. : )</p>
  
  <p>session.php</p>
  
  <pre><code>// Check if session is created. If not, then create.
  if (session_status() == PHP_SESSION_NONE) {
      session_start();
  
  }
  </code></pre>
  
  <p>db_connect.php</p>
  
  <pre><code>$host = "localhost";
  $db_name = "xx";
  $username = "xx";
  $password = "xx";
  
  try {
      $con = new PDO("mysql:host={$host};dbname={$db_name}", $username, $password);
      $con-&gt;exec("set names utf8");
  }
  
  //to handle connection error
  catch(PDOException $exception){
      echo "Connection error: " . $exception-&gt;getMessage();
  }
  </code></pre>
  
  <p>products.php</p>
  
  <pre><code>        &lt;?php
          $query = "SELECT id, name, price, image FROM shoes ORDER BY id";
          $stmt = $con-&gt;prepare( $query );
          $stmt-&gt;execute();
  
                  $num = $stmt-&gt;rowCount();
  
                  while ($row = $stmt-&gt;fetch(PDO::FETCH_ASSOC)){
                  extract($row);
  
                      echo "
                          &lt;div class=\"item\"&gt;
  
                              &lt;div class=\"product-id\"&gt;{$id}&lt;/div&gt;
                              &lt;div class=\"category\"&gt;shoes&lt;/div&gt;
                              &lt;div class=\"image\"&gt; &lt;img src=\"images/{$image}\" class=\"product-image\" alt=\"product\"/&gt; &lt;/div&gt;
                              &lt;div class=\"name\"&gt; {$name} &lt;/div&gt;
                              &lt;div class=\"price\"&gt; {$price}&lt;/div&gt;
                              &lt;div class=\"quantity\"&gt;&lt;input type=\"text\" value=\"1\" class=\"maara\" /&gt;&lt;/div&gt;
                              &lt;input type=\"button\" class=\"lisaa\" value=\"Lisää\"/&gt;
  
                          &lt;/div&gt;
                          ";
                  }
      ?&gt;
  </code></pre>
  
  <p>ajax.js</p>
  
  <pre><code>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") &gt;= 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!");
                  }
      });
  });
  }
  </code></pre>
  
  <p>add_to_cart.php</p>
  
  <pre><code>// 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-&gt;prepare( $query );
              $stmt-&gt;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-&gt;rowCount() &lt;= 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-&gt;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 =&gt; $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;
  
          }
      }
  }
  }
  </code></pre>
  
  <p>cart.php</p>
  
  <pre><code>    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 "&lt;div class=\"shoppingcart\"&gt;";
  
                  // Loop through cart items
                  foreach ($_SESSION['cart']['id'] as $key =&gt; $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 "&lt;div class=\"shoppingcart-items\"&gt;";
                          echo("&lt;div class=\"shoppingcart-image\"&gt;&lt;img src=\"images/{$_SESSION['cart']['image'][$key]}\" class=\"shoppingcart-image\"/&gt;&lt;/div&gt;");                          
                          echo("&lt;div class=\"shoppingcart-itemname\"&gt;{$_SESSION['cart']['name'][$key]}&lt;/div&gt;");
                          echo("&lt;div class=\"shoppingcart-quantity\"&gt; {$_SESSION['cart']['quantity'][$key]} x &lt;/div&gt;");
                          echo("&lt;div class=\"shoppingcart-price\"&gt; {$multipleformat} €&lt;br /&gt; &lt;span class=\"singleproduct-price\"&gt; ({$singleproduct} / kpl)&lt;/span&gt;&lt;/div&gt;");
  
  
                          // 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 "&lt;/div&gt;";
  
                  // End foreach loop
                  }
  
          // End shopping cart div        
          echo "&lt;/div&gt;";
  
          // Create bottom for shopping cart, which contains total amount of items and total price
          echo "&lt;div class=\"shoppingcart-bottom\"&gt;
                      &lt;div class=\"summa\"&gt;&lt;a href=\"lomake.php\"&gt;Kori&lt;/a&gt;&lt;/div&gt;
                      &lt;div class=\"tuotteiden-maara\"&gt;{$counter} tuotetta &lt;br /&gt;{$totalsum}  €&lt;/div&gt;
                  &lt;/div&gt;";    
      }
  
      // if cart variable is empty, then show the following
      else {
          echo "&lt;div class=\"shoppingcart\"&gt;";
              echo "ostoskori on tyhjä";
          echo "&lt;/div&gt;";
      }
  
  }
  </code></pre>
  
  <p>test_input function</p>
  
  <pre><code>    function test_input($data)
      {
         $data = trim($data);
         $data = stripslashes($data);
         $data = htmlspecialchars($data);
         return $data;
      }
  </code></pre>