prepared statements on loop and rollback if there are errors - php

I was hoping someone would guide me in the right direction. What I am trying to accomplish is the following:
user uploads a csv file the data is then stored in a multidimensional array $formatted_payments. Then I check the records on the file against the records on the DB. I need to check if the route from the file matches the route on DB if it does for all records then commit all the updates but if there is one mismatch then i need to rollback all the update. I hope this all makes sense. Here is what I did but I haven't tested yet.
Thank you
$conn->autocommit(FALSE);
$route_errors = [];
foreach($formatted_payments as $val){
$sql = "SELECT id, account_no, payment_amount, route_id, payment_date FROM car_payments WHERE payment_date = '".$date."' AND account_no = '".$val['account_no']. "'";
$res = $conn->query($sql);
$data = $res->fetch_object();
if($data){
if($val['amount'] > 0){
if($val['route_id'] != $data->route_id){
$route_errors[] = $val['account_no'];
}else{
$sql = "UPDATE car_payments SET payment_amount = ? charged = ? WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("sss", $val['amount'], 'Si', $data->id);
$stmt->execute();
}
}else{
$sql = "UPDATE car_payments SET payment_amount = ? charged = ?, pending = ? WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ssss", $val['amount'], 'No', 1, $data->id);
$stmt->execute();
}
}
}
if(!empty($route_errors)){
$conn->roll_back();
echo 'The following accounts do not match the route. Records not imported.<br>';
foreach($route_errors as $value){
echo '<li>' . $value . '</li>';
}
}else{
$conn->commit();
}

Related

php - Updating data in database base on id?

I am working on a project that takes students attendance in class and I want to update the database data through PHP whilst running a SQL function of UPDATE, but I want to be able to update it base on the id of the data.
This is the code that I am working with at the moment.
<?php
require_once './dba.php';
$status = "";
if(isset($_POST['time_in'])) {
$query = "INSERT INTO nameOfTable (datetime) VALUES (NOW())";
$d = $conn->prepare($query);
$d->execute();
} elseif(isset($_POST['time_out'])) {
$query = "UPDATE nameOfTable SET datetime = NOW() WHERE id = ? ";
$d = $conn->prepare($query);
$d->execute();
} else {
$status = "Can't time in!";
}
Use $conn->lastInsertId() to get the ID that was assigned when they clocked in. Save that in a session variable and use it when they clock out.
<?php
require_once './dba.php';
$status = "";
if(isset($_POST['time_in'])) {
$query = "INSERT INTO nameOfTable (datetime) VALUES (NOW())";
$d = $conn->prepare($query);
$d->execute();
$_SESSION['clock_id'] = $conn->lastInsertId();
} elseif(isset($_POST['time_out'])) {
if (!isset($_SESSION['clock_id'])) {
$status = "You need to clock in first!";
} else {
$query = "UPDATE nameOfTable SET datetime = NOW() WHERE id = :id ";
$d = $conn->prepare($query);
$d->execute(['id' => $_SESSION['clock_id']]);
}
} else {
$status = "Can't time in!";
}
You must remember to prepare the query and bind the parameters onto it.
Use the $id variable to prepare the query with the appropriate ID.
Make sure you authenticate the session before passing the ID to the query, otherwise an attacker can manipulate this data to pull anyone's data they wish.
// Its helpful to create elements within the code to bind onto. :id is ours.
$query = "UPDATE nameOfTable SET datetime = NOW() WHERE id = :id ";
$d = $conn->prepare($query);
// Run the query & bind id to :id
$d->execute(['id' => $id]);
You try update
$query = "UPDATE nameOfTable SET datetime = NOW() WHERE id = :id ";
$d = $conn->prepare($query);
$d->execute(['id' => $id ]);

Why the whole Table is locking during a MYSQL TRANSCTION? [duplicate]

transaction Query
mysqli_begin_transaction($conn);
$sql = "UPDATE foldertable SET trashed = 1 WHERE serverToken = (SELECT serverToken from servertoken where userToken = ? limit 1) and
(folderId = ?
or
RootFolderPath LIKE
CONCAT (
(SELECT RootFolderPath FROM foldertable WHERE serverToken = (SELECT serverToken from servertoken where userToken = ? ) AND folderid = ? limit 1)
,'/'
, ?
,'%'
)
)";
$stmt = mysqli_stmt_init($conn);
mysqli_stmt_prepare($stmt, $sql);
mysqli_stmt_bind_param($stmt, "sisii", $data["userToken"], $id, $data["userToken"], $id, $id);
if (!mysqli_stmt_execute($stmt)) {
echo mysqli_stmt_error($stmt);
$serverError = true;
return;
}
// echo "\n\n affected rows " . mysqli_affected_rows($conn);
if (mysqli_affected_rows($conn) > 0) {
sleep(15);
// Insert into bin folder
$sql = "INSERT INTO binfolder (serverToken , folderId) value ( (SELECT serverToken from servertoken where userToken = ? limit 1) , ?)";
$stmt = mysqli_stmt_init($conn);
mysqli_stmt_prepare($stmt, $sql);
mysqli_stmt_bind_param($stmt, "si", $data["userToken"], $id);
if (!mysqli_stmt_execute($stmt)) {
echo mysqli_stmt_error($stmt);
$serverError = true;
return;
}
if (mysqli_affected_rows($conn) > 0) {
$success = true;
mysqli_commit($conn);
}
}
Insert Query
INSERT INTO foldertable(serverToken) SELECT (123456)
Problem
if execute the insert query after transaction started but the insert does not have to wait for transaction complete . Because the update query on transaction does lock row involved with insert query.
What I wanted
the Insert query will run immediately if it does not contain the same serverToken needed in Insert query.
Thank You in Advance.

Notification for user group

I'm working on a event manager and I would like to create a notification system for a group of users.
When an admin creates a new event then php create a notification inside mysql with status 0 if not read and then it changes to status 1 if read.
The problem is that I'm using the group id instead of the user id, and when the first logged user click on the notification it updates the notification status so other users are not viewing the notification. Maybe inserting a row for each user into the database can solve this problem? do I need to use an array of user's ids?
This is what i've done so far:
session_start();
// admin id
$userid = $_SESSION['user_id'];
include('../../../config/database.php');
$event_title = $_POST['titleevent'];
$event_color = $_POST['eventcolor'];
$event_start = $_POST['startevent'];
$new_start_date = date('Y-m-d 00:00:00', strtotime($event_start));
$event_end = $_POST['endevent'];
$new_end_date = date('Y-m-d 23:59:00', strtotime($event_end));
$event_group = $_POST['usergroup'];
$event_description = $_POST['eventdescription'];
if ($create_event = mysqli_prepare($conn, "INSERT INTO user_events (event_title, event_description, event_start, event_end, event_color, event_group)
VALUES (?, ?, ?, ?, ?, ?)" )) {
mysqli_stmt_bind_param($create_event, 'sssssi', $event_title, $event_description, $new_start_date, $new_end_date, $event_color, $event_group);
mysqli_stmt_execute($create_event);
// get event id
$event_id = mysqli_insert_id($conn);
$event_start_date = date('d-m-Y', strtotime($new_start_date));
$notification = "Nuovo evento <span class='text-warning'><strong>$event_title</strong></span> inizia il $event_start_date";
$notification_status = "0";
$notification_category= "events";
$event_notification = mysqli_prepare($conn, "INSERT INTO event_notifications (e_notification_sent_by, e_notification_sent_to, e_notification_message, e_notification_time, e_notification_status, e_notification_category, e_notification_category_id) VALUES(?,?,?,now(),?,?,?)");
mysqli_stmt_bind_param($event_notification, 'iisisi', $userid, $event_group, $notification, $notification_status, $notification_category, $event_id);
mysqli_stmt_execute($event_notification);
mysqli_stmt_close($event_notification);
echo "event created";
mysqli_stmt_close($create_event);
}else{
echo "Ops, error";
}
Many thanks for you help
UPDATE i've managed to make it working using an array and foreach in this way:
$event_start_date = date('d-m-Y', strtotime($new_start_date));
$notification = "Nuovo evento <span class='text-warning'><strong>$event_title</strong></span> inizia il $event_start_date";
$notification_status = "0";
$notification_category= "events";
$sql = "SELECT user_join_id FROM user_group_join WHERE group_join_id='$event_group'";
$result= mysqli_query($conn,$sql);
$datas= array();
if(mysqli_num_rows($result) > 0){
while($row=mysqli_fetch_array($result, MYSQLI_ASSOC)){
$datas[]= $row;
}
}
foreach($datas as $data) {
$id_cliente = $data['user_join_id'];
$event_notification = mysqli_prepare($conn, "INSERT INTO user_notifications (notification_sent_by, notification_sent_to, notification_message, notification_time, notification_status, notification_category, notification_category_id) VALUES(?,?,?,now(),?,?,?)");
mysqli_stmt_bind_param($event_notification, 'iisisi', $userid, $id_cliente, $notification, $notification_status, $notification_category, $event_id);
mysqli_stmt_execute($event_notification);
mysqli_stmt_close($event_notification);
}
Now the question is how can i can i convert it with a prepared statement? And also it looks like i'm going to use a lot of server resources querying the database for each user id, is there any way to optimize the foreach loop?
Many thanks

how to use PDO rowCount() function in foreach?

i need some help , i have simple code like count rows in php, i use PDO ,
so i check if rowCount > 0 i do job if no other job but i have it in foreach function, in first step i get true result but in other i get invalid
so i think it is function like a closeCursor() in PDO but i try and no matter . maybe i do it wrong ?
it is part of my code
public function saveClinicCalendar($post){
$daysItm = '';
$Uid = $post['Uid'];
$ClinicId = $post['ClinicId'];
$type = $post['type'];
$resChck = '';
foreach($post['objArray'] as $arr){
foreach($arr['days'] as $days){
$daysItm = $days.",".$daysItm;
}
$daysItm = substr($daysItm, 0, -1);
$dateTime = $arr['dateTime'];
$sqlChck = 'SELECT * FROM clinic_weeks WHERE dates = :dates AND Uid = :Uid AND category = :category AND Cid = :Cid AND type = :type';
$resChck = $this->db->prepare($sqlChck);
$resChck->bindValue(":dates",$dateTime);
$resChck->bindValue(":Cid",$ClinicId);
$resChck->bindValue(":type",$type);
$resChck->bindValue(":Uid",$Uid);
$resChck->bindValue(":category",$Uid);
$resChck->execute();
$co = $resChck->rowCount();
if($co > 0){
/*UPDATE*/
$sql = 'UPDATE clinic_weeks SET dates = :dates ,time = :time, Cid = :Cid, type = :type, Uid = :Uid, category = :category ';
$res = $this->db->prepare($sql);
$res->bindValue(":dates",$dateTime);
$res->bindValue(":time",$daysItm);
$res->bindValue(":Cid",$ClinicId);
$res->bindValue(":type",$type);
$res->bindValue(":Uid",$Uid);
$res->bindValue(":category",$Uid);
}else{
/*INSERT*/
$sql = 'INSERT INTO clinic_weeks (dates,time, Cid,type,Uid,category) VALUES (:dates,:time, :Cid,:type,:Uid,:category)';
$res = $this->db->prepare($sql);
$res->bindValue(":dates",$dateTime);
$res->bindValue(":time",$daysItm);
$res->bindValue(":Cid",$ClinicId);
$res->bindValue(":type",$type);
$res->bindValue(":Uid",$Uid);
$res->bindValue(":category",$Uid);
}
$res->execute();
$resChck->closeCursor();
$resChck = null;
$daysItm = '';
}
}
what i am doing wrong?
many thanks to Barmar, he suggest me a true answer.
here is a code
$sql = "INSERT INTO clinic_weeks
(`timestam`,`time`,dates,Cid,type,Uid,category)
VALUES
('$timestamp','$daysItm','$dateTime','$ClinicId','$type','$Uid','$Uid')
ON DUPLICATE KEY UPDATE `time` = '$daysItm' ";
I use there "ON DUPLICATE KEY UPDATE" and it`s work perfectly!
instead a big code top of page i make a two line of code.

Why is my PDO::FETCH Statement Returning 0?

Here is my code below:
$barcode = $_POST['barcode'];
$year = $_POST['year'];
$movietitle = $_POST['movietitle'];
$stmt = $pdo->prepare("SELECT COUNT(movietitle) FROM movies WHERE movietitle LIKE '%:movie%'");
$stmt->bindParam(':movie', $movietitle);
$stmt->execute();
$fetch = $stmt->fetch();
if($fetch[0] == 0) {
$displaytitle = $_POST['displaytitle'];
$media = $_POST['media'];
$youtube = $_POST['youtube'];
$genre = $_POST['genre'];
$youtube = "www.youtube.com/embed/" . $youtube;
$stmtins = $pdo->prepare("INSERT INTO `movies` VALUES (null, :genre, :movietitle, :displaytitle, :year, :youtube, :media, :barcode)");
$stmtins->bindParam(':genre', $genre);
$stmtins->bindParam(':movietitle', $movietitle);
$stmtins->bindParam(':displaytitle', $displaytitle);
$stmtins->bindParam(':year', $year);
$stmtins->bindParam(':youtube', $youtube);
$stmtins->bindParam(':media', $media);
$stmtins->bindParam(':barcode', $barcode);
$stmtins->execute();
$message = "The movie was added to your database. - $fetch[0]";
} else {
$message = "Already owned.";
}
Every time it's run, $fetch[0] ALWAYS returns 0, despite the $stmt query returning more than 0. What's going on?
I suggest you run PDO in exception mode...
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Then you would see the query error.
The problem is, you can't use interpolate params like you have in your LIKE comparison. Try this instead...
"SELECT COUNT(movietitle) FROM movies WHERE movietitle LIKE CONCAT('%', :movie, '%')"
There's also an easier way to check for existence...
$stmt = $pdo->prepare("SELECT 1 FROM movies WHERE movietitle LIKE CONCAT('%', :movie, '%')");
$stmt->bindParam(':movie', $movietitle);
$stmt->execute();
if(!$stmt->fetch()) {
// fetch will return false if there are no rows

Categories