No error is thrown on inexistant table - php

I must miss something but I have a very strange behaviour with PDO (MySQL).
$req = null;
try {
$sql = 'INSERT INTO inexistant_table (idmember) VALUES(:idmember)';
$req = $db->prepare($sql);
$req->bindParam(':idmembre', $_SESSION['ID']);
$req->execute();
}
catch (PDOException $e) {
echo 'exception';
}
if( !$req ) {
echo 'false';
}
echo 'success';
Then I don't get any error, it only prints 'success'. Any idea?
EDIT: $db->errorCode() returns 00000.

The outcome is explained as such,
Exceptions are not enabled - no "exception"
To enable exceptions, as per Fred -ii-'s comment, thanks! ;-)
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
(Also see Reference - frequently asked questions about PDO)
The wrong value is being checked - no "false"
The $req variable represents the prepared statement object, not the result of such executing such a statement. Compare with the following that checks the result.
$result = $req->execute();
// ..
if (!$result) { /* fail! */ }

Related

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.

var_dump and print_r show nothing, can't check it item exists in Database

I have a PDO that is querying a non-existant user in the database to handle user registration. The problem is, var_dump and print_r both do not print anything if the user is not found.
try {
$stmt->execute();
while($row = $stmt->fetch()) {
var_dump($row);
print_r($row);
if($row = null) { // Not working
# if(!isset($row)) { // Not working
# if(empty($row)) { // Also not working
echo "User not found";
} else {
echo $row['realname']."<br>";
}
}
} catch(PDOException $e) {
echo "FATAL ERROR OCCURED:".$e->getMessage();
}
What is happening here? The page is just blank.
php -l index.php repors no syntax errors and the page is not throwing error 500.
Nothing in view source either.
Here is connection details:
try {
$dbh = new PDO('mysql:host=127.0.0.1;dbname=PHP_PDO', "root", "root", array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
));
} catch(PDOException $e) {
die("FATAL ERROR OCCURED");
}
$stmt = $dbh->prepare("SELECT realname FROM users WHERE name = :name" );
$stmt->bindParam(":name", $name);
$name = "mivuckovaca"; // NOT IN DATA BASE
The reason why it's not working, is that you are "assigning" in if($row = null) using 1 equal sign, rather than "comparing" if($row == null) with 2 equal signs (or 3 "if identical", depending on what you want to check for).
Consult: The 3 different equals here on Stack about this.
References:
http://php.net/manual/en/language.operators.assignment.php
http://php.net/manual/en/language.operators.comparison.php
PHP sees the "assignment" as being valid syntax and that is why you are not receiving any errors.
Turns out i had to reorganize the code a bit.
I took the $row = $stmt->fetch(); out of the while loop, and checked the $row seperately. Like this:
$stmt = $dbh->prepare("SELECT realname FROM users WHERE name = :name" );
$stmt->bindParam(":name", $name);
$name = "mivuckovaca"; // NOT IN DATABSE ON PURPOSE
try {
$stmt->execute();
} catch(PDOException $e) {
echo "FATAL ERROR OCCURED:".$e->getMessage();
}
$res = $stmt->fetchAll(); # Replaced fetch() with fetchAll()
if(empty($res)) {
echo "User not found";
} else {
foreach($res as $row) { # replaced while() with foreach()
echo $row['realname'];
}
}

What is the best way to validate if a record was inserted successfully?

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.

Non-Object Errors using PHP PDO with MySQL

I've been scratching my head over this for a few days now and I've still got nowhere.
I'm trying to pull a small set of values from a MySQL database via PHP PDO; I know PDO works as I am using it else where and I have based my code around te previously working code.
function custom_sub_cat_list($db_details, $cat_id) { //ln21
$subcat = NULL;
try {
$h = new PDO("mysql:host=".$db_details['host'].";dbase=".$db_details['db'],$db_details['user'],$db_details['pass']);
$h->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch(PDOException $ex) {
return false;
}
try {
$q = $h->prepare("SELECT category FROM :tbl WHERE parentid = :catid;");
$q->bindValue(":tbl", $db_details['tbl'], PDO::PARAM_STR);
$q->bindValue(':catid', $cat_id, PDO::PARAM_STR);
$q->execute();
while($row = $_query->fetch()) {
$subcat['id'][] = $row['categoryid'];
$subcat['name'][] = $row['category'];
};
return $subcat;
} catch(PDOException $ex) {
return false;
}
}//ln49
I am getting "Call to a member function bindValue() on a non-object" on the bindValue's and being called up like below.
$cat_id = 123;
$db_details = array(
"host" => $sql_host,
"db" => $sql_db,
"user" => $sql_user,
"pass" => $sql_password,
"tbl" => $sql_tbl['categories']
);
custom_sub_cat_list ($db_details, $cat_id)
I'm sure it's something glaringly obvious but I can't see the problem and would like a fresh pair of eyes.
WORKING VERSION BELOW
Thank You Very Very Much! to everyone who helped, I've learnt a few bits too :-) There was some silly mistakes in there that I had overlooked, I just blame looking at it for two days solid.
function custom_sub_cat_list($db_details, $cat_id) {
$subcat = NULL;
try {
$h = new PDO("mysql:host=".$db_details['host'].";dbname=".$db_details['db'].";charset=utf8",$db_details['user'],$db_details['pass']);
$h->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$h->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$q = $h->prepare("SELECT category, categoryid FROM ".$db_details['table']." WHERE parentid = :cid;");
$q->bindParam(':cid', $cat_id, PDO::PARAM_INT);
$q->execute();
while($row = $q->fetch()) {
$subcat['id'][] = $row['categoryid'];
$subcat['name'][] = $row['category'];
};
$h = NULL;
return $subcat;
} catch(PDOException $ex) {
print_r($ex->getMessage());
print_r($ex->getTrace());
//return false;
}
}
You don't need a fresh pair of eyes
You are not painter but a programmer (supposedly).
So, instead of watching your code you have to run it. And enable error reporting.
Oh, just spotted it
And of course, you shouldn't gag error messages!
} catch(PDOException $ex) {
return false;
}
a modern version of # operator.
Please get rid of ALL try..catch blocks in your code and start using them only after learning what are they for.
So, in order to solve this very problem as well as many other problems in the future
Get rid of all try..catch blocks in your code.
Enable error reporting for PDO as described in tag wiki I linked to in the comments.
Do not use placeholders for the identifiers but format them as described in the tag wiki I linked to
Turn off display_errors setting if you don't want errors to be displayed (the only reason for suppressing error messages I can think of).
Also, you shouldn't open separate connection in every function call.
Create one connection in the beginning of your script and then use if in the function, using
global $h;
$q = $h->prepare("SELECT category FROM :tbl WHERE parentid = :catid;");
You can't use a bound parameter for a table name in SQL.
When you try to prepare an invalid SQL statement like this, prepare() returns false, not a PDOStatement object.
$q->bindValue(":tbl", $db_details['tbl'], PDO::PARAM_STR);
Then you try to call a bindValue() method on $q, but the scalar value false has no methods, so it's a fatal error.
You're also trying to catch exceptions, but you didn't configure PDO to throw exceptions on error. So the PDO functions default to reporting errors simply by returning false.
As #Arkh shows, you need to tell PDO to throw exceptions:
$h->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
So, your error tells you that $q is not an object. Which means that the $h->prepare("SELECT category FROM :tbl WHERE parentid = :catid;"); failed.
When reading the PDO::prepare doc, you can read this:
Return Values
If the database server successfully prepares the statement, PDO::prepare() returns a PDOStatement object. If the database server cannot successfully prepare the statement, PDO::prepare() returns FALSE or emits PDOException (depending on error handling).
As you have not set PDO to throw exceptions, you should either do it to get a good error message or check the value of $q and get the last reported error.
First method:
function custom_sub_cat_list($db_details, $cat_id) { //ln21
$subcat = NULL;
try {
$h = new PDO("mysql:host=".$db_details['host'].";dbase=".$db_details['db'],$db_details['user'],$db_details['pass']);
$h->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$h->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$q = $h->prepare("SELECT category FROM :tbl WHERE parentid = :catid;");
$q->bindValue(":tbl", $db_details['tbl'], PDO::PARAM_STR);
$q->bindValue(':catid', $cat_id, PDO::PARAM_STR);
$q->execute();
while($row = $_query->fetch()) {
$subcat['id'][] = $row['categoryid'];
$subcat['name'][] = $row['category'];
};
return $subcat;
} catch(PDOException $ex) {
echo $ex->getMessage();
return false;
}
}//ln49
Which gives the error:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? WHERE parentid = ?' at line 1
Second method:
function custom_sub_cat_list($db_details, $cat_id) { //ln21
$subcat = NULL;
$h = new PDO("mysql:host=".$db_details['host'].";dbase=".$db_details['db'],$db_details['user'],$db_details['pass']);
$h->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$q = $h->prepare("SELECT category FROM :tbl WHERE parentid = :catid;");
if ($q === false) {
print_r($h->errorInfo());
return false;
}
$q->bindValue(":tbl", $db_details['tbl'], PDO::PARAM_STR);
$q->bindValue(':catid', $cat_id, PDO::PARAM_STR);
$q->execute();
while($row = $_query->fetch()) {
$subcat['id'][] = $row['categoryid'];
$subcat['name'][] = $row['category'];
};
return $subcat;
}//ln49
Result:
Array ( [0] => 42000 1 => 1064 [2] => You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? WHERE parentid = ?' at line 1 )
Your problem is that you cannot use a bound value for :tbl (or other non values parts of your SQL string).
So you have to do this:
$q = $h->prepare("SELECT category FROM ".$db_details['tbl']." WHERE parentid = :catid;");

How to retrieve PDO result==false?

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.

Categories