try {
$db = new PDO("mysql:host=".HOST.";dbname=".DB, USER, PW);
$st = $db->prepare("SELECT * FROM c6ode");
}
catch (PDOException $e){
echo $e->getMessage();
}
How can I check the mysql error for the query in above case?
You need to set the error mode attribute PDO::ATTR_ERRMODE to PDO::ERRMODE_EXCEPTION.
And since you expect the exception to be thrown by the prepare() method you should disable the PDO::ATTR_EMULATE_PREPARES* feature. Otherwise the MySQL server doesn't "see" the statement until it's executed.
<?php
try {
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->prepare('INSERT INTO DoesNotExist (x) VALUES (?)');
}
catch(Exception $e) {
echo 'Exception -> ';
var_dump($e->getMessage());
}
prints (in my case)
Exception -> string(91) "SQLSTATE[42S02]: Base table or view not found:
1146 Table 'test.doesnotexist' doesn't exist"
see http://wezfurlong.org/blog/2006/apr/using-pdo-mysql/
EMULATE_PREPARES=true seems to be the default setting for the pdo_mysql driver right now.
The query cache thing has been fixed/change since then and with the mysqlnd driver I hadn't problems with EMULATE_PREPARES=false (though I'm only a php hobbyist, don't take my word on it...)
*) and then there's PDO::MYSQL_ATTR_DIRECT_QUERY - I must admit that I don't understand the interaction of those two attributes (yet?), so I set them both, like
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly', array(
PDO::ATTR_EMULATE_PREPARES=>false,
PDO::MYSQL_ATTR_DIRECT_QUERY=>false,
PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION
));
I'm using this without any additional settings:
if (!$st->execute()) {
print_r($st->errorInfo());
}
I'm guessing that your complaint is that the exception is not firing. PDO is most likely configured to not throw exceptions. Enable them with this:
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
a quick way to see your errors whilst testing:
$error= $st->errorInfo();
echo $error[2];
/* Provoke an error -- the BONES table does not exist */
$sth = $dbh->prepare('SELECT skull FROM bones');
$sth->execute();
echo "\nPDOStatement::errorInfo():\n";
$arr = $sth->errorInfo();
print_r($arr);
output
Array
(
[0] => 42S02
[1] => -204
[2] => [IBM][CLI Driver][DB2/LINUX] SQL0204N "DANIELS.BONES" is an undefined name. SQLSTATE=42704
)
Related
Hi I have the following code :
try {
$sth = $this->container->db->prepare("select x from table");
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_ASSOC);
return $result;
} catch (\PDOException $e) {
throw new ServerException("Could not get data");
} catch (\Exception $e) {
return false;
}
using slim 3 with wamp
the problem is when I point to the API(polling every 1 second) I got the following error:
Fatal error: Call to a member function prepare() on boolean in /
2 issues : it throws an error to the client
and it throws an error in php_error.log under wamp and the file becomes bigger
how can I prevent and catch those errors
PDO class:
public function getConnection($dsn, $username, $password) {
$conn = null;
try {
$conn = new PDO($dsn, $username, $password);
//Set common attributes
$conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
return $conn;
} catch (PDOException $e) {
return false;
//TODO: flag to disable errors?
throw $e;
}
catch(Exception $e) {
die();
//TODO: flag to disable errors?
throw $e;
}
}
Like many learners, you are taking this matter upside down
You should never actually catch an exception like this.
it throws an error to the client
Disable it for the whole site on the live server. There should be not a single PHP error message shown to the user, no matter if it's PHP exception or a filesystem error. Set display_errors to a negative value and forget this matter for all.
how can I prevent and catch those errors
Again, you should never do anything like this, bluntly catching every error and just dismissing it. It's like using the notorious # operator
it throws an error in php_error.log under wamp and the file becomes bigger
Ok, only this one makes sense. There are two possible solutions:
The best one: configure your mysql server properly so it wouldn't die under such a light load like 1 RPS.
Okay, what you actually want but I still don't recommend as it never pays to sweep the dirt under the rug: catch the exception, then verify if it's one you expect, then do something (i.e. try to reconnect after a short timeout), but re-throw the exception otherwise so you will have an idea when something else would go wrong. For this purpose you should add a condition in the try..catch block that should verify the error, handle it if it's one that you expect or just throw it again otherwise.
Of course, in order to catch a PDOException you have to enable it for PDO.
1) In Slim you should use the container (service factory) to build the PDO object. Example:
$container['db'] = function (Container $container) {
$settings = $container->get('settings');
$host = $settings['db']['host'];
$dbname = $settings['db']['database'];
$username = $settings['db']['username'];
$password = $settings['db']['password'];
$charset = $settings['db']['charset'];
$collate = $settings['db']['collate'];
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_PERSISTENT => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES $charset COLLATE $collate"
];
return new PDO($dsn, $username, $password, $options);
};
2) You must set the PDO options into the constructor to make it work. Example:
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
];
$pdo = new PDO($dsn, $username, $password, $options);
I have this code
try {
$dbh = new PDO('mysql:host=localhost;dbname=db_informations', 'root', '');
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo $e->getMessage();
}
And it gives me the exception message:
SQLSTATE[HY000] [1049] Unknown database 'db_informations'
Because the correct name of my database is db_information only.
My question is, even if I don't include the line:
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
I still get the same exception and I think it's not necessary to use it? Is it?
This is simply because that's the behaviour of PDO::__construct() as you can read in the manual:
PDO::__construct() throws a PDOException if the attempt to connect to the requested database fails.
But if you don't set the error mode to Exception and you do:
try {
$dbh = new PDO('mysql:host=localhost;dbname=db_informations', 'root', '');
$dbh->query("SELECT * FROM aTableWhichDoesNotExists");
} catch(PDOException $e) {
echo $e->getMessage();
}
You won't get any excpetion message or error, because you didn't set the error mode. So you need to do this:
try {
$dbh = new PDO('mysql:host=localhost;dbname=db_informations', 'root', '');
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->query("SELECT * FROM aTableWhichDoesNotExists");
} catch(PDOException $e) {
echo $e->getMessage();
}
To receive an exception, which you then can catch:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.atablewhichdoesnotexists' doesn't exist
Also if you just think logically:
setAttribute() needs to be used with ->, which means you need an instance of the class to call that method. So how would you be able to call that method, if the instance couldn't be created correctly?
(So that would mean setAttribute() would have to bee static, so that you can set something/call it before you take the instance of the class)
Goal: to simply fetch array from a MySQL database.
Issue: I am using the $dsn "string variable" as a parameter in the PDO Statement but there appears to be an uncaught exception and it has something to do with invoking the driver or the (PDO->__construct) -- I am not sure. Do you have any ideas on how to fix the $dsn string variable or other areas of this code that would cause it to fail? Thanks in advance.
// Define Database Parameters
$dbhost = "localhost";
$dbname = "x";
$dbuser = "y";
$dbpass = "z";
// Invoke Driver (as a variable string)
$dsn = "mysql:host=$dbhost;dbname=$dbname";
// Connect to newly created db object
$dbh = new PDO($dsn, $dbuser, $dbpass);
// Set the PDO error mode to enable exceptions
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
// Execute query to the database
$sql = "SELECT * FROM a_aif_remaining";
$sth = $dbh->prepare($sql);
$sth->execute();
// Present results from query
print("PDO::FETCH_ASSOC: ");
print("Return next row as an array indexed by column name");
$result = $sth->fetch(PDO::FETCH_ASSOC);
print_r($result);
print("");
return $results;
// Close db connection
$dbh = NULL;
?>
Put your code in a try catch block. And see the error message reported. An example of this below:
try
{
if ( !class_exists( 'PDO' ) )
throw new Exception( 'PHP without PDO' );
if ( array_search( PDO::getAvailableDrivers(), 'mysql' ) === false )
throw new Exception( 'PHP without PDO mysql driver' );
$dbh = new PDO( ... );
...
}
catch ( PDOException $e )
{
print $e->getMessage();
}
catch ( Exception $e )
{
print $e->getMessage();
}
There can't be any problem where you're looking for it. Substituting a string with a variable is okay and cannot cause any issues. So, it is somewhere else. Luckily PHP reported of it, but strangely, you paid not much attention to that report.
there appears to be an uncaught exception
Uncaught exceptions often contains the error message.
Most of PHP error messages are quite informative. One have to read them through to get the explanation of the problem. After all, it's the only your source of information. No one can tell you what is wrong on your server but server itself. If you have difficulties with interpreting the error message - it is essential to post it along with your question, to let people interpret it for you. So, every error message you get, should be posted in your question, whole and intact. Simple but very important rule.
I'm using the following script to use a database using PHP:
try{
$db = new PDO('mysql:host='.$host.';port='.$port.';dbname='.$db, $user, $pass, $options);
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Now, I want to use this database handle to do a request using this code:
try{
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Here is the problem:
When the connection to the DB is OK, everything works,
When the connection fails but I don't use the DB, I have the $GLOBALS['errors'][] array and the script is still running afterwards,
When the connection to the DB has failed, I get the following fatal error:
Notice: Undefined variable: db in C:\xampp\htdocs[...]\test.php on line 32
Fatal error: Call to a member function prepare() on a non-object in C:\xampp\htdocs[...]\test.php on line 32
Note: Line 32 is the $query = $db->prepare(...) instruction.
That is to say, the script crashes, and the try/catch seems to be useless. Do you know why this second try/catch don't works and how to solve it?
Thanks for the help!
EDIT: There are some really good replies. I've validated one which is not exactly what I wanted to do, but which is probably the best approach.
try/catch blocks only work for thrown exceptions (throw Exception or a subclass of Exception must be called). You cannot catch fatal errors using try/catch.
If your DB connection cannot be established, I would consider it fatal since you probably need your DB to do anything meaningful on the page.
PDO will throw an exception if the connection cannot be established. Your specific problem is that $db is not defined when you try to call a method with it so you get a null pointer (sort of) which is fatal. Rather than jump through if ($db == null) hoops as others are suggesting, you should just fix your code to make sure that $db is either always defined when you need it or have a less fragile way of making sure a DB connection is available in the code that uses it.
If you really want to "catch" fatal errors, use set_error_handler, but this still stops script execution on fatal errors.
In PHP7, we now can using try catch fatal error with simple work
try {
do some thing evil
} catch (Error $e) {
echo 'Now you can catch me!';
}
But usualy, we should avoid using catch Error, because it involve to miss code which is belong to programmer's reponsibility :-)
I will not report what has already been written about testing if $db is empty. Just add that a "clean" solution is to artificially create an exception if the connection to the database failed:
if ($db == NULL) throw new Exception('Connection failed.');
Insert the previous line in the try - catch as follow:
try{
// This line create an exception if $db is empty
if ($db == NULL) throw new Exception('Connection failed.');
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Hope this will help others!
If database connection fails, $db from your first try .. catch block will be null. That's why later you cannot use a member of non-object, in your case $db->prepare(...). Before using this add
if ($db) {
// other try catch statement
}
This will ensure that you have db instance to work with it.
Try adding the following if statement :
if ($db) {
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(....);
}
else die('Connection lost');
try{
if(!is_null($db))
{
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
try {
$db = new PDO("mysql:host=".HOST.";dbname=".DB, USER, PW);
$st = $db->prepare("SELECT * FROM c6ode");
}
catch (PDOException $e){
echo $e->getMessage();
}
How can I check the mysql error for the query in above case?
You need to set the error mode attribute PDO::ATTR_ERRMODE to PDO::ERRMODE_EXCEPTION.
And since you expect the exception to be thrown by the prepare() method you should disable the PDO::ATTR_EMULATE_PREPARES* feature. Otherwise the MySQL server doesn't "see" the statement until it's executed.
<?php
try {
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->prepare('INSERT INTO DoesNotExist (x) VALUES (?)');
}
catch(Exception $e) {
echo 'Exception -> ';
var_dump($e->getMessage());
}
prints (in my case)
Exception -> string(91) "SQLSTATE[42S02]: Base table or view not found:
1146 Table 'test.doesnotexist' doesn't exist"
see http://wezfurlong.org/blog/2006/apr/using-pdo-mysql/
EMULATE_PREPARES=true seems to be the default setting for the pdo_mysql driver right now.
The query cache thing has been fixed/change since then and with the mysqlnd driver I hadn't problems with EMULATE_PREPARES=false (though I'm only a php hobbyist, don't take my word on it...)
*) and then there's PDO::MYSQL_ATTR_DIRECT_QUERY - I must admit that I don't understand the interaction of those two attributes (yet?), so I set them both, like
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly', array(
PDO::ATTR_EMULATE_PREPARES=>false,
PDO::MYSQL_ATTR_DIRECT_QUERY=>false,
PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION
));
I'm using this without any additional settings:
if (!$st->execute()) {
print_r($st->errorInfo());
}
I'm guessing that your complaint is that the exception is not firing. PDO is most likely configured to not throw exceptions. Enable them with this:
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
a quick way to see your errors whilst testing:
$error= $st->errorInfo();
echo $error[2];
/* Provoke an error -- the BONES table does not exist */
$sth = $dbh->prepare('SELECT skull FROM bones');
$sth->execute();
echo "\nPDOStatement::errorInfo():\n";
$arr = $sth->errorInfo();
print_r($arr);
output
Array
(
[0] => 42S02
[1] => -204
[2] => [IBM][CLI Driver][DB2/LINUX] SQL0204N "DANIELS.BONES" is an undefined name. SQLSTATE=42704
)