My goal is to use a transaction and a prepared statement simultaneously, to achieve both integrity of data, and prevention of SQL injection.
I have this:
try {
$cnx = new PDO($dsn,$dbuser,$dbpass);
$cnx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$cnx->beginTransaction();
$cnx->query("SELECT * FROM users WHERE username=$escaped_input");
$cnx->query("SELECT * FROM othertable WHERE some_column=$escaped_input_2");
$cnx->commit();
}
catch (Exception $e){
$cxn->rollback();
echo "an error has occured";
}
I would like to incorporate the query as one would with a prepared statement:
$stmt=$cxn->prepare("SELECT * FROM users WHERE username=?");
$stmt->execute(array($user_input));
$stmt_2=$cxn->prepare("SELECT * FROM othertable WHERE some_column=?");
$stmt_2->execute(array($user_input_2));
How can I achieve that?
Edit
I get this error:
PHP Parse error: syntax error, unexpected T_CATCH
Here is my updated code:
try
{
$cnx = new PDO($dsn,$dbuser,$dbpass);
$cnx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$cnx->beginTransaction();
$stmt=$cnx->prepare("SELECT * FROM users WHERE username=?");
$stmt->execute(array($username));
$cnx->commit();
while ($row=$stmt->fetch(PDO::FETCH_OBJ)){
echo $stmt->userid;
}
catch(Exception $e) {
if (isset($cnx))
$cnx->rollback();
echo "Error: " . $e;
}
Just call "execute" after you call "beginTransaction".
Where you call "prepare" doesn't really matter.
Here's a complete example:
http://php.net/manual/en/pdo.begintransaction.php
EXAMPLE:
try {
$cnx = new PDO($dsn,$dbuser,$dbpass);
$cnx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$cnx->beginTransaction();
$stmt=$cxn->prepare("SELECT * FROM users WHERE username=?");
$stmt->execute(array($user_input));
$stmt_2=$cxn->prepare("SELECT * FROM othertable WHERE some_column=?");
$stmt_2->execute(array($user_input_2));
$cnx->commit();
}
catch (Exception $e){
$cxn->rollback();
echo "an error has occurred";
}
PS:
1) I'm assuming, of course, that $user_input and $user_input_2 are available immediately. You don't want your transaction hanging open unnecessarily long ;)
2) Based on your comment reply above, I think you might be confusing "execute" and "begin tran/commit". Please look at my link.
3) Do you even need a transaction? You're just doing two "select's".
4) Finally, why not do one "join" (or union, if compatible) instead of two "select's"?
try
{
$cnx = new PDO ($dsn,$dbuser,$dbpass);
$cnx->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$cnx->beginTransaction ();
$stmt = $cnx->prepare ("SELECT * FROM users WHERE username=?");
$stmt->execute(array($username));
$cnx->commit();
while ($row = $stmt->fetch (PDO::FETCH_OBJ)){
echo $row->userid;
}
}
catch (Exception $e) {
if (isset ($cnx))
$cnx->rollback ();
echo "Error: " . $e;
}
}
Did you mean this?
try {
$cnx = new PDO($dsn,$dbuser,$dbpass);
$cnx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$cnx->beginTransaction();
$stmt=$cnx->prepare("
SELECT * FROM users, othertable
WHERE users.username=?
AND othertable.some_column=?");
$stmt->execute(array($user_input,$user_input_2));
$cnx->commit();
}
catch (Exception $e){
$cnx->rollback();
echo "an error has occured";
}
That is assuming that the two tables data does not have duplicate field names, otherwise you're going to have to use:
SELECT users.field1 as u_field1, othertable.field1 as o_field1 FROM users, othertable
WHERE users.username=?
AND othertable.some_column=?
Related
How do I get the prepared statement of the mysqli_stmt-object?
If there is an error while executing the mysql-statement I want to return the statement.
$id = "89c483c8";
$query = "SELECT * FROM database WHERE id = ?";
if (!($stmt = $database->prepare($query) { ... }
else {
$stmt->bind_param("s", $id);
if (!$stmt->execute())
return $stmt->get_statement; //doesn't exist
}
"$stmt->get_statement" of course doesn't work. So how do I get the full query? In this example:
"SELECT * FROM database WHERE id = 89c483c8"
This is the best way to catch sql errors :
try {
$res = $mysqli_instance->query($query);
}catch (mysqli_sql_exception $e) {
print "Error Code <br>".$e->getCode();
print "Error Message <br>".$e->getMessage();
print "Strack Trace <br>".nl2br($e->getTraceAsString());
}
Or the simplest way :
echo $stmt->error
http://php.net/manual/en/mysqli.error.php
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.
I'd like to execute some queries that doesn't return result set, and then execute a real query, and fetch its result.
Here is an exemple that doesn't work :
<?php
try {
$db = new PDO('dblib:host=myhost;dbname=master','user','password');
$query = "declare #entier int = 1;";
$db->exec($query);
$query = "select #entier;";
$stmt = $db->query($query);
$rows = $stmt->fetchAll();
print_r($rows);
}
catch (PDOException $e) {
print ($e->getMessage());
}
catch (Exception $e) {
print ($e->getMessage());
}
?>
This code neither doesn't work :
try {
$db = new PDO('dblib:host=myhost;dbname=master','user','password');
$query = "declare #entier int = 1; select #entier;";
$stmt = $db->query($query);
$rows = $stmt->fetchAll();
print_r($rows);
}
catch (PDOException $e) {
print ($e->getMessage());
}
catch (Exception $e) {
print ($e->getMessage());
}
?>
But this code works :
<?php
try {
$db = new PDO('dblib:host=myhost;dbname=master','user','password');
$query = "select 1;";
$stmt = $db->query($query);
$rows = $stmt->fetchAll();
print_r($rows);
}
catch (PDOException $e) {
print ($e->getMessage());
}
catch (Exception $e) {
print ($e->getMessage());
}
?>
Thanks for your help
I know this is old, but for other people finding this from Google: you need to use PDOStatement::nextRowset to iterate over the result sets from your multiple queries.
However, it seems there are memory issues when using nextRowset with dblib in some versions (it tried to allocate 94Tb in my case...), so I ended up re-engineering to avoid multiple SQL queries altogether (instead duplicating the value of the DECLARE where it was being used).
PDO::query docs (http://php.net/manual/it/pdo.query.php) say
PDO::query() executes an SQL statement in a single function call, returning the result set (if any) returned by the statement as a PDOStatement object.
This could mean that you can execute with query() both queries with and without result
What is the best way to validate if a record was inserted successfully?
I'm using PDO Statements.
This:
/*******************
Update user picture
********************/
function updateuserpicture($userid, $filename) {
include ("./businesslogic/dbconnection/cfg.php");
try {
$db = new PDO('mysql:host='.$server.';dbname='.$db,$db_user,$db_password);
$sql = $db->prepare("Update usersdata set userpicture=:filename where userid=:userid");
$sql->bindParam(':filename',$filename);
$sql->bindParam(':userid',$userid);
$sql->execute();
$sqlresult = $sql->rowCount();
$db = null;
return $sqlresult; //Then validate if result is greater than 0.
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
}
}
or this:
/*******************
Update user picture
********************/
function updateuserpicture($userid, $filename) {
include ("./businesslogic/dbconnection/cfg.php");
try {
$db = new PDO('mysql:host='.$server.';dbname='.$db,$db_user,$db_password);
$sql = $db->prepare("Update usersdata set userpicture=:filename where userid=:userid");
$sql->bindParam(':filename',$filename);
$sql->bindParam(':userid',$userid);
if ($sql->execute()) {
$db = null;
return TRUE;
} else {
$db = null;
return FALSE;
} //Then validate if result is TRUE or FALSE.
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
}
}
Both ways works fine but im not sure what is the best, can you please help me?
PDO won't actually throw exceptions unless you tell it to. So your try..catch is entirely superfluous and will never do anything.
If the statement was executed without error, that means the data was inserted/updated successfully. No need to count rows, unless you are interested in the specific details of how many rows were altered (which is a different topic than "is the data in my database now?").
Given this, I'd recommend to set PDO to throw exceptions in case of errors and not do any further explicit checking:
$db = new PDO("mysql:host=$server;dbname=$db", $db_user, $db_password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = $db->prepare('UPDATE users SET userpicture = :filename WHERE userid = :userid');
$sql->bindParam(':filename', $filename);
$sql->bindParam(':userid', $userid);
$sql->execute();
This may still mean that the statement did nothing if the user id didn't exist. This would point to a deeper bug in your app, it's questionable if the PDO code should care about it specifically.
I'm converting my mysql_query() calls to PDO but don't understand how to get a false result on failure. This is my code:
$STH = $DBH->query("SELECT * FROM articles ORDER BY category");
$STH->setFetchMode(PDO::FETCH_ASSOC);
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
This is what I'm trying to do but does not work:
if($STH==false) {
foreach($dbh->errorInfo() as $error) {
echo $error.'<br />';
}
}
When using PDO the nature of querying usually goes down like so:
try
{
$STH = $DBH->prepare("SELECT * FROM articles ORDER BY category"); //Notice the prepare
$STH->setFetchMode(PDO::FETCH_ASSOC);
//No need to silent as the errors are catched.
if($STH === false) //Notice the explicit check with !==
{
//Do not run a foreach as its not multi-dimensional array
$Error = $DBH->errorInfo();
throw new Exception($Error[2]); //Driver Specific Error
}
}catch(Exception $e)
{
//An error accured of some nature, use $e->getMessage();
}
you should read errorInfo very carefully and study the examples.