Transactional statements with mysqli - php

What is the proper syntax for preparing a transactional statement in mysqli? I've tried a number closest I've come is:
$conn->begin_transaction();
$stmt = $conn->prepare("INSERT INTO ARCHIVE_CLICKS_PATH SELECT * FROM CLICKS_PATH WHERE REFERER = ?");
$stmt->bind_param('i', $referer);
$stmt = $conn->prepare("DELETE FROM CLICKS_PATH WHERE REFERER = ?;");
$stmt->bind_param('i', $referer);
$stmt->close();
$conn->commit();
Doesn't throw errors, also doesn't seem to do anything.
Edit: I searched \ read the answer posted above before posting, it doesn't help me at all with prepared mysqli statement syntax specifically (which seems to be the issue). There is no errors being thrown, and the statement works fine when I directly input it to the database. I can get it to work fine unprepared, but I can't find the proper syntax of where to bind_params \ execute \ commit for a mysqli prepared statement example anywhere.
To add the following works fine:
BEGIN;
INSERT INTO ARCHIVE_CLICKS_PATH SELECT * FROM CLICKS_PATH WHERE REFERER = 15;
DELETE FROM CLICKS_PATH WHERE REFERER = 15;
COMMIT;
When I directly input it into the database.

You are supposed to use try catch block to throw the exception. see the example below:
$sql1 = "INSERT INTO ARCHIVE_CLICKS_PATH SELECT * FROM CLICKS_PATH WHERE REFERER = ?;";
$sql2 = "DELETE FROM CLICKS_PATH WHERE REFERER = ?;";
$stmt1 = $conn->prepare($sql1);
$stmt2 = $conn->prepare($sql2);
try{
$conn->query('BEGIN;');
if($stmt1 == false || $stmt2 == false || $stmt1->bind_param("i", $b) == false || $stmt2->bind_param("i", $a) == false || $stmt1->execute() == false || $stmt2->execute() == false){
throw new Exception($conn->error);
}
else{
echo "successful";
}
$conn->query('COMMIT;');
}
catch(Exception $e){
$conn->query("ROLLBACK;");
echo $e->getMessage();
}

This is what I figured out to solve it based on the answer above in case it ever helps anyone:
try
{
$conn->autocommit(FALSE);
$conn->begin_transaction();
$stmt1=$conn->prepare("INSERT INTO ARCHIVE_CLICKS_PATH SELECT * FROM CLICKS_PATH WHERE REFERER = ?;");
$stmt1->bind_param('i',$referer);
if ($stmt1->execute() == false) {
throw new Exception('Statement 1 Failed');
}
$stmt2=$conn->prepare("DELETE FROM CLICKS_PATH WHERE REFERER = ?;");
$stmt2->bind_param('i', $referer);
if ($stmt2->execute() == false) {
throw new Exception('Statement 2 Failed');
}
$stmt1->close();
$stmt2->close();
$conn->commit();
}
catch(Exception $e)
{
$conn->rollback();
throw $e;
}

Related

It keeps updating all of the rows as the samething

<?php
$method = strtoupper($_SERVER["REQUEST_METHOD"]);
if($method === "POST") {
$edittask = [
"TName"=>$_POST["TName"],
"description"=>$_POST["description"],
"status"=>$_POST["status"],
"duedate"=>$_POST["duedate"],
"userassign"=>$_POST["userassign"],
];
// use prepared statement to protect against SQL Injection
$sql ="UPDATE task_list SET task_name=:TName,description=:description,status=:status,due_date=:duedate,user_assign=:userassign WHERE id=:uid";
$statement = $DB->prepare($sql);
try {
// execute statement
$statement->execute($edittask);
header("location: /task/tasks");
} catch(PDOException $e) {
echo $e->getMessage();
}
}
?>
You need to add the parameters(bind) to the query object.
Please see the bindParam method.
$sql ="UPDATE task_list SET task_name=:TName,description=:description,status=:status,due_date=:duedate,user_assign=:userassign WHERE id=:uid";
$statement = $DB->prepare($sql);
$statement->bindParam(':uid',$userId);
BindParam Documentation

PHP mutiple queries no result in database

I'm working on an android app that requires connection to a database. I have the android part working but I'm having trouble with my php script.
<?php
$con = mysqli_connect(/This info is correct/) or die ("Unable to connect");
$gebruikersnaamOntvanger = $_POST["gebruikersnaamOntvanger"];
$idBetaler = $_POST["idBetaler"];
$bedrag = $_POST["bedrag"];
$saldoBetaler = $_POST["saldo"];
$response = array();
$response["success"] = "false";
$statement = mysqli_prepare($con, "SELECT idGebruiker, Saldo FROM Gebruikers WHERE Gebruikersnaam = ?");
mysqli_stmt_bind_param($statement, "s", $gebruikersnaamOntvanger);
mysqli_stmt_execute($statement);
mysqli_stmt_store_result($statement);
mysqli_stmt_bind_result($statement, $idGebruiker, $Saldo);
while($row = mysqli_stmt_fetch($statement)){
$idOntvanger = $idGebruiker;
$saldoOntvanger = $Saldo;
}
$saldoOntvanger += $bedrag;
$saldoBetaler -= $bedrag;
try {
$statement2 = mysqli_prepare($con, "INSERT INTO Transacties (idBetaler, idOntvanger, Bedrag, Datum, Uitgevoerd) VALUES(?, ?, ?, now(), 1)");
mysqli_stmt_bind_param($statement2, "iid", $idBetaler, $idOntvanger, $bedrag);
mysqli_stmt_execute($statement2);
$response["success"] = "success";
} catch(Exception $e) {
$response["success"] = $e->gettext;
}
echo json_encode($response);
?>
So the android part work and returns the JSON object correctly but nothing changes in the database. I have tried adding a try catch so I get what's the error but the try catch never works. The script alwayws returns success even if it didn't work. Please be aware I'm new to PHP and I have double checked the SQL queries and they should be correct. If you need more information please ask.
mysqli_* function dosn't throws exceptions. So your catch is never executed even on error. Change your code like this :
if(!mysqli_stmt_execute($statement2))
throw new Exception(mysqli_stmt_error($statement2));
When you'll see the error you can fix your code. May be add same error handling to mysqli_prepare and others
I think the issue was the use of iid in the binding for the insert query. It should either be iis or iii presumably. You tried using try/catch blocks but to my mind did not make full use of them - the creation of a prepared statement should be tested to see if it succeeds or fails ~ the outcome of which can be used in the try/catch logic to indicate faults. Excuse the mix of procedural and OOP style code
<?php
if( $_SERVER['REQUEST_METHOD']=='POST' && isset( $_POST["gebruikersnaamOntvanger"], $_POST["idBetaler"], $_POST["bedrag"], $_POST["saldo"] ) ){
try{
$con = mysqli_connect(/This info is correct/) or die ("Unable to connect");
$gebruikersnaamOntvanger = $_POST["gebruikersnaamOntvanger"];
$idBetaler = $_POST["idBetaler"];
$bedrag = $_POST["bedrag"];
$saldoBetaler = $_POST["saldo"];
$response = array('success'=>false);
$stmt=$conn->prepare( 'select `idgebruiker`, `saldo` from `gebruikers` where `gebruikersnaam` = ?' );
if( !$stmt ) throw new Exception('unable to prepare select query');
else {
$stmt->bind_param( 's', $gebruikersnaamOntvanger );
$result=$stmt->execute();
if( !$result )throw new Exception('No results from select query');
else {
$stmt->store_result();
$stmt->bind_result( $idGebruiker, $Saldo );
while( $stmt->fetch() ){
$idOntvanger = $idGebruiker;
$saldoOntvanger = $Saldo;
}
$saldoOntvanger += $bedrag;
$saldoBetaler -= $bedrag;
$stmt=$con->prepare('insert into `transacties` ( `idbetaler`, `idontvanger`, `bedrag`, `datum`, `uitgevoerd` ) values(?, ?, ?, now(), 1)');
if( !$stmt )throw new Exception('Unable to prepare insert query');
else {
/* What is the value of $bedrag? integer, string?? */
/*
The binding iid was incorrect - perhaps iis or iii
*/
$stmt->bind_param('iis', $idBetaler, $idOntvanger, $bedrag );
$result = $stmt->execute();
$response['success']=$result;
}
}
}
echo json_encode( $response );
}catch( Exception $e ){
echo $e->getMessage();
}
}
?>

Can I use try catch exceptions into PDO transactions?

Here is my script:
$id = $_GET['id'];
$value = $_GET['val'];
// database connection here
try{
$db_conn->beginTransaction(); // this
$stm1 = $db_conn->prepare("UPDATE table1 SET col = "updated" WHERE id = ?");
$stm1->execute(array($value));
$done = $stm->rowCount();
if ($done){
try {
$stm2 = $db_conn->prepare("INSERT into table2 (col) VALUES (?)");
$stm2->execute(array($id));
} catch(PDOException $e){
if ((int) $e->getCode() === 23000) { // row is duplicate
$stm3 = $db_conn->prepare("DELETE FROM table2 WHERE col = ?");
$stm3->execute(array($id));
}
}
} else {
$error = true;
}
$db_conn->commit(); // this
}
catch(PDOException $e){
$db_conn->rollBack();
}
First of all, I have to say, my script works. I mean the result or it is as expected in tests. Just one thing scares me. I read the documention and seen this sentence:
Won't work and is dangerous since you could close your transaction too early with the nested commit().
I'm not sure what's the meaning of sentence above, just I understand maybe I shouldn't use nested try - catch between beginTransaction() and commit(). Well I got it right? doing that is dangerous?
Exceptions have no direct relation to transactions. You can add as many catch blocks in your code as you need.
So your code is all right, given you already set PDO error reporting to Exceptions.

Is it a good idea to nest Try/Catch for nested PDO operations?

i have several database checks with PDO before i insert some values on the DB and i don't know if one try/catch will catch all errors in the nested PDO or if i need one try/catch for every PDO. This is the code i got now:
try {
$db = connect_db();
$q = "query foobar";
$stm = $db->prepare($q);
$stm->bindParam(1, $foobar);
$status = $stm->execute();
if ($stm->rowCount() == 0) {
if ($def == 0) {
$q = "query foobar";
$stm = $db->prepare($q);
$stm->bindParam(1, $foobar);
$stm->bindParam(2, $foobar);
$stm->bindParam(3, $foobar);
$stm->bindParam(4, $foobar);
$status = $stm->execute();
if ($status) {
echo "<script>alert('foobar');window.location.assign('admin.php');</script>";
} else {
echo "<script>alert('foobar');window.location.assign('admin.php');</script>";
die();
}
} else {
$q = "query foobar";
$stm = $db->prepare($q);
$stm->bindParam(1, $nombre);
$status = $stm->execute();
if ($stm->rowCount() == 0) {
$q = "query foobar";
$stm = $db->prepare($q);
$stm->bindParam(1, $foobar);
$stm->bindParam(2, $foobar);
$stm->bindParam(3, $foobar);
$stm->bindParam(4, $user);
$status = $stm->execute();
if ($status) {
echo "<script>alert('foobar.');window.location.assign('admin.php');</script>";
} else {
echo "<script>alert('foobar.');window.location.assign('admin.php');</script>";
die();
}
}
}
} else {
echo "<script>alert('foobar.'); history.back();</script>";
die();
}
} catch (Exception $e) {
// Proccess error
$msg = $e->getMessage();
$timestamp = date("Y-m-d H:i:s");
$line = $e->getLine();
$code = $e->getCode();
handle_error($msg, $timestamp, $line, $code);
die("foobar");
}
PDO::ERRMODE_EXCEPTION
In addition to setting the error code, PDO will throw a PDOException and set its properties to reflect the error code and error information. This setting is also useful during debugging, as it will effectively "blow up" the script at the point of the error, very quickly pointing a finger at potential problem areas in your code (remember: transactions are automatically rolled back if the exception causes the script to terminate).
Exception mode is also useful because you can structure your error handling more clearly than with traditional PHP-style warnings, and with less code/nesting than by running in silent mode and explicitly checking the return value of each database call.
So, one is enough

Insert NULL in mysql (blob) using PHP

Ive got the next code
if ($_FILES['intrebare_img']['size'] > 0) {
$tmpName = $_FILES['intrebare_img']['tmp_name'];
$intrebare_img=addslashes(file_get_contents($tmpName));
}
else
$intrebare_img = NULL;
if ($_FILES['opt1_img']['size'] > 0) {
$tmpName = $_FILES['opt1_img']['tmp_name'];
$opt1_img = addslashes(file_get_contents($tmpName));
}
else
$opt1_img = NULL;
if ($_FILES['opt2_img']['size'] > 0) {
$tmpName = $_FILES['opt2_img']['tmp_name'];
$opt2_img = addslashes(file_get_contents($tmpName));
}
else
$opt2_img = NULL;
if ($_FILES['opt3_img']['size'] > 0) {
$tmpName = $_FILES['opt3_img']['tmp_name'];
$opt3_img = addslashes(file_get_contents($tmpName));
}
else
$opt3_img = NULL;
$query = "INSERT INTO intrebari (intrebare_txt, intrebare_img, opt1_txt, opt1_img, opt2_txt, opt2_img, opt3_txt, opt3_img, raspuns_corect)
VALUES ('{$intrebare_txt}','{$intrebare_img}','{$opt1_txt}','{$opt1_img}','{$opt2_txt}','{$opt2_img}','{$opt3_txt}','{$opt3_img}','{$rsp_corect}')";
mysql_query($query) or die("Error, query failed");
When executed it's inserting values in the database, the only issue is that even when there is no file selected it's inserting [BLOB - 0 B] instead of NULL.
I think that my problem is generated by the ' ' around NULL values but can't figure a way around.
Thanks in advance !
The smart thing to do is use PDO or the like along with prepared statements. Let PDO do the heavy lifting and focus your efforts on solving other problems. It would also protect you from SQL injection vulnerabilities, which your code appears to be full of.
If you want to stick with depreciated mysql_ functions, you need to check each variable and remove the quotes from NULL values. Something along the lines of:
if ( $opt3_img !== NULL ) {
$opt3_img = "'".$opt3_img."'";
}
$query = sprintf('INSERT INTO intrebari SET opt3_img = %s', $opt3_img);
You would of course also want to put that functionality into a function to avoid repeating that code for every variable..
In the end, after a little research, I've rewritten the code so it uses PDO.
Here is the result :
$dbh = new PDO('mysql:dbname=dbname;host=127.0.0.1', user, password);
if ($stmt = $dbh->prepare ("INSERT INTO intrebari (intrebare_txt, intrebare_img, opt1_txt, opt1_img, opt2_txt, opt2_img, opt3_txt, opt3_img, raspuns_corect)
VALUES (:intrebare_txt, :intrebare_img, :opt1_txt, :opt1_img, :opt2_txt, :opt2_img, :opt3_txt, :opt3_img, :rsp_corect)"))
{
$stmt -> bindParam(':intrebare_txt', $_POST['intrebare_txt']);
$stmt -> bindParam(':opt1_txt', $_POST['opt1_txt']);
$stmt -> bindParam(':opt2_txt', $_POST['opt2_txt']);
$stmt -> bindParam(':opt3_txt', $_POST['opt3_txt']);
if ( isset ($_POST['rsp_corect']))
$stmt -> bindParam(':rsp_corect',$_POST['rsp_corect']);
else
echo '<script type="text/javascript">alert("Nu a fost selectat un raspuns valid!");window.location=\'intrebari.php\';</script>';
if ($_FILES['intrebare_img']['size'] > 0) {
$tmpName = $_FILES['intrebare_img']['tmp_name'];
$stmt -> bindParam(':intrebare_img', file_get_contents($tmpName));
}
else
$stmt -> bindValue(':intrebare_img', NULL);
if ($_FILES['opt1_img']['size'] > 0) {
$tmpName = $_FILES['opt1_img']['tmp_name'];
$stmt -> bindParam(':opt1_img', file_get_contents($tmpName));
}
else
$stmt -> bindValue(':opt1_img', NULL);
if ($_FILES['opt2_img']['size'] > 0) {
$tmpName = $_FILES['opt2_img']['tmp_name'];
$stmt -> bindParam(':opt2_img', file_get_contents($tmpName));
}
else
$stmt -> bindValue(':opt2_img', NULL);
if ($_FILES['opt3_img']['size'] > 0) {
$tmpName = $_FILES['opt3_img']['tmp_name'];
$stmt -> bindParam(':opt3_img', file_get_contents($tmpName));
}
else
$stmt -> bindValue(':opt3_img', NULL);
$stmt -> execute();
// close connection
$stmt->closeCursor();
$stmt = null;
$dbh = null;
sleep(60);
}
else echo "STM FAILED !!";
}
Due to a misleading answer from another question on this site first I've tried using a mysqli connection obviously that was a fail!
And another thing that I must mention for other people looking at the code is that in `
user and password are defined constants !

Categories