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));
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.
i'm in trouble. I'm trying to connect remote mysql server with pdo (php 5.4.12). With this code it's connect normally:
$dbh=new PDO('mysql:host=xxx.xxx.xxx.xxx;dbname=newdb', $user, $pass);
But, if i try set host with variable, like this:
$host='xxx.xxx.xxx.xxx';
$dbh=new PDO('mysql:host='.$host.';dbname=newdb', $user, $pass);
It's just thinks sometime, and tell me:
Fatal error: Uncaught exception 'PDOException' with message ' in
D:\wamp\www\test.php on line 21
21 it's line of creating new PDO object.
Ok, i'm try to catch exception (sorry, it's new for me), and now i have this:
Error!: SQLSTATE[HY000] [2002]
Can you help me, please?
Double quoting not helps
$dbh = new PDO("mysql:host=$host;dbname=newdb", $user, $pass);
Nothing changed.
var_dump('mysql:host='.$host.';dbname=newdb');
string 'mysql:host=xx.xx.xxx.xxx;dbname=newdb' (length=37)
Way with {} not helped for me.
Ok, the situation becomes clear. I'm try to connect another server on another IP, and it's normally connected. Can it be mysql server security options?
Try this way
$host = "xxx.xxx.xxx.xxx";
$dbh = new PDO("mysql:host={$host};dbname=newdb", $user, $pass);
The double quotes and the braces to include the var in the string as you can see here
http://www.php.net/manual/en/language.operators.string.php
I need to use silent PDO mode without any exceptions or errors so i do it like this:
$this->db = new PDO($db_config['dsn'], $db_config['username'], $db_config['password'],
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
PDO::ATTR_TIMEOUT => 5,
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
)
);
But it still throws exception that i cant connect to db.
I need to use silent PDO mode
Nope, you don't.
You are asking this question out of some false assumption. Instead of following it further, you have to rethink your premises, set PDO to Exception mode and then fix something else. Most likely - an error handler.
If you cannot connect to the database, PHP can't create a PDO object. You can't have a PDO object which is not connected to the database. You can't return anything but a valid object instance when using the new operator. Hence an exception is the only thing how the PDO constructor can fail here.
In other words, you can't silence an exception happening at construction time, that setting only applies to all later errors PDO may produce. You just have to catch it.
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