I can't find an answer to this anywhere. Maybe its really simple
I have my mysql PDO connection like this:
try{
$DBH = new PDO("mysql:host=$db_hostname;dbname=$db_database", $db_username, $db_password);
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
}
catch (PDOException $e){
echo $e->getMessage();
exit;
}
i want to just test if the connection worked, ie. if the password, username, databasename & hostname were spelled correctly.
the try, throw just seems to pick up fundamental errors, like if the driver is spelt wrong. it doesnt throw an error if say the password is wrong.
thanks
In a single click from this question, in the PDO tag wiki lies the exact how-to:
$dsn = "mysql:host=localhost;dbname=test;charset=utf8";
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
$pdo = new PDO($dsn,'root','', $opt);
As well as a warning
DO NOT use try..catch operator just to handle an error message.
Uncaught exception already excellent for this purpose, as it will treat PDO errors just the same way as other PHP errors - so, you can define the behavior using site-wide settings.
A custom exception handler could be added later, but not required. Especially for new users, it is recommended to use unhandled exceptions, as they are extremely informative, helpful and secure.
More info...
I use the following code to connect:
<?php
class dbConnection extends PDO{
public function __construct() {
switch(DB_TYPE){
case "mysql":
$dbconn = "mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=".DB_CHARSET;
break;
case "sqlite":
$dbconn = "sqlite:".DB_PATH.";charset=".DB_CHARSET;
break;
case "postgresql":
$dbconn = "pgsql:host=".DB_HOST." dbname=".DB_NAME.";charset=".DB_CHARSET;
break;
}
parent::__construct($dbconn,DB_USER,DB_PASS,array(PDO::ATTR_EMULATE_PREPARES => false,PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
}
}
?>
If I give wrong password, I get
Connection error, because: SQLSTATE[28000] [1045] Access denied for
user 'microaid_logger'#'localhost' (using password: YES)
As Your common sense pointed out, an exception is already thrown in case the connection is not succesful, which will also trigger if the password is wrong. If you want to format the text of the error message or handle it, just set a custom error handler as described here
Related
i try to implement a fallback solution for when my database is not available. Somhow i do not manage to catch the error.
Call to create connection:
if(!$this->connection = mysqli_connect(
$this->host,
$this->name,
$this->pass,
$this->db
)) { throw new Exception('Unable to connect to Database'); }
init.php to include dbClass
require_once __DIR__ . '/../classes/Database.php';
$db = new Database();
$connection = $db->getConnection();
actual usage with try catch wrap
try {
include __DIR__ . '/../out/script/content/config/init_direct.php';
... do stuff regulary
}catch (Exception $e) {
... do fallback stuff
}
i do not get into the catch block. for test purpose i just set the database offline.
there are several problems with your approach
First, your problem is insufficient debugging. You just assume that exception has been thrown, but in reality it weren't.
Second, this happened because mysqli_connect returns an object, not boolean you expect.
Third, as you've been told in the comments, errors aren't exceptions and you cannot catch them.
Anyway, with mysqli you don't need to throw exceptions manually - this extension can throw them by itself, so, all you need is to set the proper mode up - an exception will be thrown which will be caught all right.
In my connect script this works, but will be deprecated.
$dbLink = mysql_connect($dbHostname, $dbUsername, $dbPassword) or die("Unable to connect to MySQL");
$dbselected = mysql_select_db($dbDatabase,$dbLink) or die("Could not select database");
If I change it to use either a PDO or mysqli it fails with
"No database selected"
on my test pc, or
"Access denied for user 'xxxxxx'#'localhost' (using password: NO)"
on my live site.
$dbLink = mysqli_connect($dbHostname, $dbUsername, $dbPassword, $dbDatabase);
Read and tested the similar question with the ini_get("mysqli.default_port").. The new commands connect ok, but then nothing completes.
My PDO code is
$dbLink = new PDO('mysql:host=localhost;dbname=mass', $dbUsername, $dbPassword);
I'd say your main problem is relying on or die() to handle error conditions. This won't work as neither the PDO nor mysqli constructor will return a falsey value.
Instead, you should use the appropriate level of error handling.
Development environment
While developing, always work with the following properties in your php.ini file
display_errors = On
error_reporting = E_ALL
You may need to restart your web server (if you're using one) after making changes to this file.
mysqli
Check the connect_errno property for a connection error state
$mysqli = new mysqli('localhost', 'username', 'password', 'dbname');
if ($mysqli->connect_errno) {
throw new Exception($mysqli->connect_error, $mysqli->connect_errno);
}
$mysqli->set_charset('utf8');
PDO
The PDO constructor should throw an exception if it can't connect. Setting the error mode to exception means that any further errors will also throw an exception.
$pdo = new PDO('mysql:host=localhost;dbname=dbname;charset=utf8', 'username', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
I wouldn't bother with any try {...} catch statements while you're developing, at least not in this initial stage as you're likely to end up hiding any serious errors.
try {
self::$dbinstance = new PDO(
"mysql:host=$c[host];dbname=$c[dbname]", $c['user'], $c['password']
);
self::$dbinstance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
echo "Errors" . $e->getMessage();
}
In the above code, if PDO fails to connect to the host, a fatal error reveals the username and password.
Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [2003]
Can't connect to MySQL server on '172.25.102.65' (10060)' in
D:\xampp\htdocs\mytest\wh_client_2.1\classes\importmodule-class.php:33 Stack trace: #0
D:\xampp\htdocs\mytest\wh_client_2.1\classes\importmodule-class.php(33): PDO-
>__construct('mysql:host=172....', 'host', 'password') #1
One possible way is to turn the display_error=0 off in php.ini, but this way I won't able to know that when my host is not responding.
Is there a way I can modify the error message?
There is a difference between error handling and error reporting.
Error handling is the process of preventing your end users to see any stack trace, vital information or automatically generated error messages. It can also modify the way your script runs by using a try catch block.
Error reporting defines which information will be reported by a given script.
To handle errors properly, I think that ini_set('display_errors',0); is the better approach. You do not want any error message displaying on the screen.
However, I want to have all possible information on errors, so I use error_reporting(E_ALL);.
Errors are written in a file, error_log, which usually resides at the same level as your index.php (or any PHP file called directly). You can also access it from your cPanel.
Your error is probably uncaught because your code is in a namespace, whereas you want to catch the global namespace PDOException. Use a \ to indicate your script you're looking for the global PDOException. Once you catch your error, you can echo the content you want, using the normal methods of the PDOException class.
try {
$db = new PDO (/*connection infos*/);
}
catch (\PDOException $e) {
switch ($e->errorCode()) {
case 'HY000':
// Or whatever error you are looking for
// here it's the general error code
mail('your#email.com','connection problem',$e->getTraceAsString());
$db = new PDO (/*rollback connection infos of a local database*/);
break;
}
}
That would send you a mail, containing the trace of the error, preventing your user from seeing it while telling you something is wrong.
Here is the reference for the error codes returned by PDO statements.
When your host is not responding you will know all right - your host will stop responding. Then you have to peek into the error log and find the error message with the particular error.
So, just keep with display_errors=0 as it's a must-have in a production environment anyway.
No, don't try to throw the exception as it will spit out such critical information... Handle them with some appropriate custom error messages and handle those exceptions inside your custom logging functions...
You must be doing something similar to this...
<?php
try {
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'uname', 'pass');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->query('bla bla bla bla'); //<---- This will definitely fail!!!!
} catch(PDOException $ex) {
echo "An error occurred!";
file_put_contents('somefile.txt', $ex->getMessage(), FILE_APPEND);
}
As you can see, the above query is indeed going to fail. So the end user will be seeing just An error occurred! message, but the error will be logged to your somefile.txt file.
You can do something like this:
<?php
// connect
try
{
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
}
catch (PDOException $e)
{
$dbh = NULL;
}
// check if connected
if($dbh)
{
// run queries
}
else
{
die('Oops! Our server has encountered an error, please try again later');
}
?>
I've browsed the web quite a bit before asking here; I noticed that some people have the same problem as me, but none of the answers that were given to the others didn't solve my problem, so....
I have a basic PDO Update Statement inside a public function:
public function editRank($name, $rank){
$query = "UPDATE `chat_mod` SET `chat_mod_rank` = :rank WHERE `chat_mod_ign` = :username";
$prepare = $this->_db->prepare($query);
$array = array(
':rank' => $rank,
':username' => $name
);
try {
$prepare->execute($array);
} catch (PDOException $e){
echo 'Error: ' . $e->getMessage();
return false;
}
return true; // If no PDO Exception is thrown..
}
No exception is thrown, so the function always returns true; but the rows are not being updated. Yes, I've checked that the rows are named properly and the values are not nulls.
Thanks,
Tom.
P.S Other queries like Select, Add & Delete work fine.
You are catching PDO exceptions but did you tell PDO to throw them?
To make PDO throw exceptions you have to configure PDO errmode. Note that setting this mode as a connection option will let PDO throw exceptions on connection errors too, which is very important.
So, here is an example for creating a PDO connection right way:
$dsn = "mysql:host=$host;dbname=$db;charset=utf8";
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// other options
);
$pdo = new PDO($dsn, $user, $pass, $opt);
Connecting this way, you will be always notified of all database errors, occurred during query execution. Note that you have to be able to see PHP errors in general. On a live site you have to peek into error logs, so, settings have to be
error_reporting(E_ALL);
ini_set('display_errors',0);
ini_set('log_errors',1);
while on a local development server it's ok to make errors on screen:
error_reporting(E_ALL);
ini_set('display_errors',1);
and of course you should never ever use error suppression operator (#) in front of your PDO statements.
Also, due to many bad examples telling you to wrap every PDO statement into try..catch block, I have to make a distinct note:
DO NOT use try..catch operator just to echo an error message. Uncaught exception is already excellent for this purpose, as it will act just the same way as other PHP errors - so, you can define the behavior using site-wide settings - so, you will have your error message without this useless code. While unconditionally echoed error message may reveal some sensitive information to a potential attacker, yet confuse a honest visitor.
A custom exception handler could be added later, but not required. Especially for new users, it is recommended to use unhandled exceptions, as they are extremely informative, helpful and secure.
Use try..catch only if you are going to handle the error itself - say, to rollback a transaction.
I am writing an installer for one of my apps and I would like to be able to test some default database settings.
Is this possible using PDO to test valid and invalid database connections?
I have the following code:
try{
$dbh = new pdo('mysql:host=127.0.0.1:3308;dbname=axpdb','admin','1234');
die(json_encode(array('outcome' => true)));
}catch(PDOException $ex){
die(json_encode(array(
'outcome' => false,
'message' => 'Unable to connect'
)));
}
The problem I am having is that the script trys to connect until the script execution time of 60 seconds runs out instead of saying it cannot connect to the db.
Thanks
you need to set the error mode when connection to the database:
try{
$dbh = new pdo( 'mysql:host=127.0.0.1:3308;dbname=axpdb',
'admin',
'1234',
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
die(json_encode(array('outcome' => true)));
}
catch(PDOException $ex){
die(json_encode(array('outcome' => false, 'message' => 'Unable to connect')));
}
for more infos see the following links:
Using MySQL with PDO
Errors and error handling
As #Sascha Galley already mentioned you should set error mode to exception mode. However, you should also set up PDO::ATTR_TIMEOUT attribute to prevent a long time waiting for response in some cases.
Although documentation says that behavior of this attribute is driver-dependent in case of MySQL it's a connection timeout. You won't find anything about it documentation but here's a short snippet from driver's source code:
long connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
As seen e.g. in the comments at this answer (but hardly anywhere else, so I made it more visible here), the "classic" PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION solution does not always work.
The implementation of PDO::ERRMODE_EXCEPTION is broken, so it seems to be "leaking" in some cases.
For example:
Warning: PDO::__construct() [pdo.--construct]: [2002] No connection could be made because the target machine actively refused
it. (trying to connect via tcp://localhost:3306) in
[...] db.php on line 34
The code there:
try {
$this->pdo = new PDO($cfg['DB'], $cfg['DB_USER'], $cfg['DB_PASS'],
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
} catch {
echo("Can't open the database.");
}
The exception is thrown (and cought: I can see my message).
So, as a necessary workaround, you need to also put a # (let's call it a "diaper operator" in this case) before new pdo(...) to actually keep it clean.
There's a missing closing parenthese at the end of PDO::ERRMODE_EXCEPTION.
Should be:
$this->pdo = new PDO($cfg['DB'], $cfg['DB_USER'], $cfg['DB_PASS'],
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));