我已经设法创建了一个工作购物车,我的下一个问题是安全性。主要是关于架构和会话安全。
- 我应该使会话以某种方式安全,如果没有身份验证登录和会话被删除时浏览器关闭?或者在这种情况下session_start()是否足够?
- 服务器端验证在add_to_cart.php中是否足够强大,并且在出现错误时退出php代码是否正确?
- 数据库查询是安全的还是我应该采取一些额外的措施?
- 我的方法是否存在需要考虑的高安全风险?
提前感谢!感谢所有的帮助。另外,如果有人觉得这个推车有用,请随意使用它。:)
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 test_input($data)
{
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
您的购物车不能仅仅通过保持会话完整来保护,您需要遵循PCI合规性,以确保您的购物车是安全的。保护购物车流和满足PCI合规性的一些可能的方法是:
- 让您的购物车流通过ssl层即https协议。
- 确保您从未在数据库中存储用户付款详细信息(信用卡号码等)
- 如果您要加密持卡人姓名等,请确保使用标准加密格式加密。