SQL Query insertion check inside transaction with rollback - php

In my shop system I'm using this code to insert in the DB customer order details and the products that belongs to that o:
$connection->beginTransaction();
try
{
$sql = "INSERT INTO orders (customer_id, order_price, order_date, order_hour)
VALUES (?, ?, ?, ?)";
$query = $connection->prepare($sql);
$query->execute(array
(
$user['user_id'],
$order_price,
$date,
$hour
));
if($query)
{
$id_of_respective_order = $connection->lastInsertId();
$sql = "INSERT INTO purchased_products (order_id, product_name, product_price, quantity, extras)
VALUES (?, ?, ?, ?, ?)";
$query = $connection->prepare($sql);
foreach($_SESSION['cart'] as $product)
{
$extras = null;
$product_price = $product['product_price'] * $product['quantity'];
if($product['extras'] != NULL)
{
foreach($product['extras'] as $extra)
{
$extras .= $extra['extra_quantity'] ."x". $extra['extra_name'] ."<br/>";
$product_price += $extra['extra_total'] * $product['quantity'];
}
}
$query->execute(array
(
$id_of_respective_order,
$product['product_name'],
$product_price,
$product['quantity'],
$extras
));
}
unset($_SESSION['cart']);
echo "<script>alert('Your purchase was completed!');
window.location = '/my-orders.php';
</script>";
}
else
{
echo "<script>alert('An error ocurred while completing your purchase. Please try again!');
window.location = '/my-cart.php';</script>";
}
$connection->commit();
}
catch(PDOException $exception)
{
$connection->rollBack();
echo "<script>alert('An error ocurred while completing your purchase. Please try again!');
window.location = '/my-cart.php';</script>";
}
My question is in regards to code optimization for error checking.
It is recommended that I use if ($query) even with the catch and rollBack as I'm doing? It is necessary or I can use only catch and rollBack because it will check for erros by itself?

You don't need to use if if you have your PDO error set to throwing the exception.
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Related

update quantity of product after checkout

I am trying to update the item quantity after the finished transaction. I have quantity on my item and I wanted to lessen the item quantity depending on the item ordered. the transaction works fine but the problem is the update does not execute and it does not update the quantity of the item in my table.
the code:
<?php
include 'includes/session.php';
if(isset($_GET['confirmation'])){
$confirmation = $_GET['confirmation'];
$p_quantity = $_GET['p_quantity'];
$date = date('Y-m-d');
$conn = $pdo->open();
try{
$stmt = $conn->prepare("INSERT INTO sales (user_id, confirmation, status, sales_date) VALUES (:user_id, :confirmation, :status, :sales_date)");
$stmt->execute(['user_id'=>$user['id'], 'confirmation'=>$confirmation, 'status'=>1, 'sales_date'=>$date]);
$salesid = $conn->lastInsertId();
$stmt = $conn->prepare("UPDATE products SET p_quantity=p_quantity-:p_quantity WHERE id=:id");
$stmt->execute(['p_quantity'=>$p_quantity, 'id'=>$id]);
try{
$stmt = $conn->prepare("SELECT * FROM cart LEFT JOIN products ON products.id=cart.product_id WHERE user_id=:user_id");
$stmt->execute(['user_id'=>$user['id']]);
foreach($stmt as $row){
$stmt = $conn->prepare("INSERT INTO details (sales_id, product_id, quantity) VALUES (:sales_id, :product_id, :quantity)");
$stmt->execute(['sales_id'=>$salesid, 'product_id'=>$row['product_id'], 'quantity'=>$row['quantity']]);
}
$stmt = $conn->prepare("DELETE FROM cart WHERE user_id=:user_id");
$stmt->execute(['user_id'=>$user['id']]);
$_SESSION['success'] = 'Transaction successful. Thank you.';
}
catch(PDOException $e){
$_SESSION['error'] = $e->getMessage();
}
}
catch(PDOException $e){
$_SESSION['error'] = $e->getMessage();
}
$pdo->close();
}
header('location: profile.php');
?>

PHP prepared statement doesn't work with intval()

Please look my code:
$insertStmt = $conn->prepare("INSERT INTO orders (OrderID, OrderTrackingNumber, OrderTotal, CustomerID) VALUES (?, ?, ?, ?)");
$insertStmt->bind_param("ssdi", $orderID, strval("Not Ship Yet"), $orderTotal, $userID);
if ($insertStmt->execute()) {
$insertStmt = $conn->prepare("INSERT INTO ordersproducts (OrderID, ProductID, ProductSold) VALUES (?, ?, ?)");
$updateStmt = $conn->prepare("UPDATE products SET ProductQuantity = ? WHERE ProductID = ?");
foreach ($orderedProducts as $orderedProduct) {
$productQuantity = intval($orderedProduct->ProductQuantity) - intval($orderedProduct->ProductAddedQuantity);
$insertStmt->bind_param("sii", $orderID, intval($orderedProduct->ProductID), intval($orderedProduct->ProductAddedQuantity));
$updateStmt->bind_param("ii", intval($productQuantity), settype($orderedProduct->ProductID, "integer"));
if ($insertStmt->execute() && $updateStmt->execute()) {
if ($updateStmt->affected_rows == 1) {
$isSuccefull = TRUE;
} else {
$isSuccefull = FALSE;
break;
}
} else {
$isSuccefull = FALSE;
echo $insertStmt->error . " | " . $updateStmt->error;
break;
}
}
}
At the line of $updateStmt->bind_param, if I convert $orderedProduct->ProductID to int by intval($orderedProduct->ProductID), the updateStmt will not work ($updateStmt->affected_rows = 0). However, I use settype($orderedProduct->ProductID, "integer"); then it will work like a champ. And only this place gets that issue; others work very well.
Why?
Thanks for helping me.

getting error for mysql when i am using if else in there

getting error for mysql when i am using if else in there. i dont know what should i do and when i am using duplicate condition to update then it not woring i am not be able to find where is error
this is the error which is i am getting.
ERROR:SQLSTATE[HY093]: Invalid parameter number: parameter was not
defined
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt=$conn->prepare("SELECT uniqueid FROM hotelcarttemp WHERE uniqueid=:uniqueid");
$stmt->execute(array(':uniqueid'=>$uniqueid));
$count=$stmt1->rowCount();
echo "count-".$count;
if($count>0)
{
$sql = "UPDATE hotelcarttemp SET `hotelname`='".$hotelname."',`roomtype`='".$roomtype."',`checkin`='".$checkin."',`checkout`='".$checkout."',`Country`='".$Country."',`Destination`='".$Destination."',`price`='".$price."' WHERE uniqueid='".$uniqueid."'";
echo "sql- ".print_r($sql);
$stmt = $conn->prepare($sql);
// echo print_r($stmt);
$stmt->execute();
}
else
{
$sql = "INSERT INTO hotelcarttemp (timestamp, packageid, uniqueid, hotelname, roomtype, checkin, checkout, Country, Destination, hoteldetail, price)
VALUES ('"
.$timestamp."','"
.$packageid."','"
.$uniqueid."','"
.$hotelname."','"
.$roomtype."','"
.$checkin."','"
.$checkout."','"
.$Country."','"
.$Destination."','"
.addslashes($hoteldetail)."','"
.$price."'
)";
// echo "sql- ".print_r($sql);
$stmt = $conn->prepare($sql);
// echo print_r($stmt);
$stmt->execute();
}
}
catch(PDOException $e) {
echo 'ERROR:' . $e->getMessage();
} here
Your SELECT query where condition is WHERE uniqueid=:uniqueid
And you are binding username to it
$stmt->execute(array(':username'=>$uniqueid));//:username invalid parameter
Change this to
$stmt->execute(array(':uniqueid'=>$uniqueid));

Right way to check an database insertion and rollback with PDO

I have here a code to insert the order of the customer in the orders table and insert the purchased products in that order in the purchased_products table. I want to check if the insertions were made, otherwise undo the changes with PDO rollback(). My code is:
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false
];
try
{
$connection = new PDO("mysql:host={$HOST};dbname={$DB_NAME}", $USERNAME, $PASS, $options);
}
$connection->beginTransaction();
try
{
$sql = "INSERT INTO orders (customer_id, customer_name, order_value, order_date)
VALUES (?, ?, ?, ?)";
$query = $connection->prepare($sql);
$query->execute(array
(
$user_id,
$user['user_name'],
$order_value,
$date
));
$id_of_respective_order = $connection->lastInsertId();
}
catch(PDOException $exception)
{
$connection->rollback();
echo "<script>alert('An error occurred while completing your purchase. Please try again later.');</script>";
}
try
{
$sql = "INSERT INTO purchased_products (order_id, product_name, product_price, quantity)
VALUES (?, ?, ?, ?)";
$query = $connection->prepare($sql);
foreach($_SESSION['cart'] as $product)
{
$query->execute(array
(
$id_of_respective_order,
$product['product_name'],
$product['product_price'],
$product['quantity']
));
}
}
catch(PDOException $exception)
{
$connection->rollback();
echo "<script>alert('An error occurred while completing your purchase. Please try again later.');</script>";
}
$connection->commit();
Is this way safe? I use a transaction to lock the tables and lastInsertId () to assign the ID of the order to the products that belongs to it. I check the insertions and if something went wrong undo the changes with rollback(). Is my checkout system well prepared and totally safe?
It makes more sence to do all your inserts inside the same Try/Catch and then if the order insert or the order_item insert fails a single catch block will deal with the rollback and any cleanup/reporting that may be required.
The way you had it the order insert could fail and then the order_item insert would still try and run, possibly creating items without a owning order.
try {
$connection = new PDO("mysql:host={$HOST};dbname={$DB_NAME}",
$USERNAME, $PASS);
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e ) {
echo 'Connection failed: ' . $e->getMessage();
exit;
}
$connection->beginTransaction();
try {
$sql = "INSERT INTO orders
(customer_id, customer_name, order_value, order_date)
VALUES (?, ?, ?, ?)";
$query = $connection->prepare($sql);
$query->execute(array( $user_id,
$user['user_name'],
$order_value,
$date
)
);
$id_of_respective_order = $connection->lastInsertId();
$sql = "INSERT INTO purchased_products
(order_id, product_name, product_price, quantity)
VALUES (?, ?, ?, ?)";
$query = $connection->prepare($sql);
foreach($_SESSION['cart'] as $product) {
$query->execute(array( $id_of_respective_order,
$product['product_name'],
$product['product_price'],
$product['quantity']
)
);
}
$connection->commit();
}
catch(PDOException $e) {
$connection->rollBack();
echo 'Order creation failed: ' . $e->getMessage();
echo "<script>alert('An error occurred while completing your purchase. Please try again later.');</script>";
exit;
}

PHP Prepared Statements handle duplicate entry

I have a problem, I am not able to handle a duplicate entry with prepared statements.
I want to end the program when a duplicate entry appears. This is what I have been trying to do:
function insert_vulnerability ($CVE, $Description, $Date, $Score, $Type){
$conn = connection();
$stmt = $conn->prepare("INSERT INTO Vulnerabilities (CVE, Description, Date, Score, Type)
VALUES (?, ?, ?, ?, ?)");
$stmt->bind_param("sssis", $CVE, $Description, $Date, $Score, $Type);
if ( false === $stmt ) {
die('prepare() failed: ' . htmlspecialchars($mysqli->error));
}
$stmt->execute();
$conn->close();
}
When not using prepared statements I handled the error this way and everything worked perfectly:
function insert_vulnerability ($CVE, $Description, $Date, $Score, $Type){
$conn = connection();
$Description = htmlspecialchars($Description);
$sql = "INSERT INTO Vulnerabilities (CVE, Description, Date, Score, Type)
VALUES ('".$CVE."', '".$Description."', '".$Date."', '".$Score."', '".$Type."')";
if ($conn->query($sql) === TRUE) {
//echo "New record created successfully";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
$conn->close();
die();
}
$conn->close();
}
So how do I get the same result with prepared statements ¿?
Thank you in advance.
You could just connect the checking inside the $stmt->execute() to see if the prepared statement did work properly.
function insert_vulnerability ($CVE, $Description, $Date, $Score, $Type){
$conn = connection();
$stmt = $conn->prepare('
INSERT INTO Vulnerabilities (CVE, Description, Date, Score, Type)
VALUES (?, ?, ?, ?, ?)
');
$stmt->bind_param('sssis', $CVE, $Description, $Date, $Score, $Type);
if($stmt->execute()) { // true, success, else error
echo 'New record created successfully';
} else {
echo $conn->error;
}
$conn->close();
}
Just to note, you have an undefined variable on your prepared statement side:
$mysqli->error

Categories