I have to pull data from at least 3 databases, is there anything wrong with reusing my PDO objects?
$dbh = new PDO('mysql:host=' . $host . ';dbname=' . $db_name, $user, $password);
$sth = $dbh->prepare($query1);
// do something
$dbh = new PDO('mysql:host=' . $host2 . ';dbname=' . $db_name2, $user2, $password2);
$sth = $dbh->prepare($query2);
//do something else
Sorry for the edit but here's another consideration. With each of these I obviously should check whether or not the connection was successful and throw an exception if it wasn't:
if (!$dbh) {
$err=$dbh->errorInfo();
throw new Exception('Could not connect: ' . $err[2]);
}
I don't suppose there's a way to avoid this, unless I create all the connections at the same time and do if (!dbh1|!dbh2) { ... }. Just something else to consider.
When you assign $dbh to a new PDO() you are not technically reusing your pdo object. You are creating a new PDO instance and assigning it to a variable that you have previously used. There is nothing wrong with doing this as long as you understand what is occurring in your program.
EDIT:
I'm editing my answer to address the new question you've added to your previous question.
With each of these I obviously should check whether or not the connection was successful and throw an exception if it wasn't:
You can surround your connection attempt in a try catch which is a typical strategy for dealing with connection errors:
<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=databaseName', $userName, $password);
foreach($dbh->query('SELECT * from TableName') as $row) {
print_r($row);
}
$dbh = null;
} catch (PDOException $ex) {
print "Error!: " . $ex->getMessage() . "<br />";
die();
}
?>
You can do that, but ... don't. Use another variable name (they are cheap) it will make your code much easier to understand. Heck you can (should) even use variable names that will clue you in on what database your object is connecting to, ie:
// connection to data warehouse
$dbh_dataWH = new PDO('mysql:host=' . $host . ';dbname=' . $db_name, $user, $password);
// connection to crm
$dbh_crm = new PDO('mysql:host=' . $host2 . ';dbname=' . $db_name2, $user2, $password2);
This way you will be able to re-use your connection objects, and the code in my very humble opinion will be much clearer for you or anyone else that has to maintain it.
Related
Forgive me, as I've not worked in php for years. I'm picking up some old code to get working again and I'm having a strange issue.
I'm writing in php with wordpress. As I am editing the code, I've noticed the php tag is closing after the following:
<?php
$databaseHost = "Localhost";
$databaseName = "testDB";
$databaseUser = "TESTUSER";
$databasePassword = "TESTPASS";
$coin_id = (isset($_POST['coin_id'])) ? $_POST['coin_id'] : '';
try {
$db = new PDO('mysql:host=' . $databaseHost . ';dbname=' . $databaseName . ';charset=utf8', $databaseUser, $databasePassword);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$request = "SELECT
_7UR_participants_database.city,
_7UR_participants_database.state,
_7UR_participants_database.country,
_7UR_participants_database.zip,
_7UR_participants_database.coin_id,
FROM _7UR_participants_database GROUP BY _7UR_participants_database.coin_id ASC";
$stmt = $db->query($request);
$item_info = $stmt->fetchAll();
} catch (PDOException $e) {
echo "Exception: " . $e->getMessage();
exit;
} // Try / catch end
?>
Everything after that > following $db- is not included in the php. The php tag is closing with that last >. Do I need to escape the character or something of that nature?
since your formatting is hard to undertand i rewrite it on my liking that it "migth" actually works
$dsn = "mysql:host=localhost;dbname=testDB;charset=utf8mb4"; // most cool kids use charset=utf8mb4
$options = [
PDO::ATTR_EMULATE_PREPARES => false, // turn off emulation mode for "real" prepared statements
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, //turn on errors in the form of exceptions
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, //make the default fetch be an associative array
];
try {
$dbh = new PDO($dsn, "TESTUSER", "TESTPASS", $options);
} catch (Exception $e) {
error_log($e->getMessage());
echo ("Error Code: " . $e->getCode() . "<br>"); // never use echo on public release build it would leak your database credential this is optional great for troubleshooting
echo ("Error Message: " . $e->getMessage() . "<br>");
exit('Something weird happened');//
}
$request = $dbh->prepare("SELECT
_7UR_participants_database.city,
_7UR_participants_database.state,
_7UR_participants_database.country,
_7UR_participants_database.zip,
_7UR_participants_database.coin_id,
FROM _7UR_participants_database GROUP BY _7UR_participants_database.coin_id ASC";
$request->execute([]); // you do not have something like this also i never put value since i don't know what your doing
$item_info = $request->fetchAll(); // store the fetched on $item_info also you need to indicate what data type you fetching by default it always PDO::FETCH_ASSOC
I know this question has been there many times, but no answer works for me.
My PDO just doesn't throw any error... or something catch the error before me.
I'm quite new to php, and I hate to not understand simple things.
Here's my initialization code
$pdo = new PDO("mysql:host=" . $db['host'] . ";dbname=" . $db['dbname'], $db['user'], $db['pass']);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
and an example where I'm, for example, inserting a duplicate row with an unicity constraint (but same problem for unknown row, or any pdo exception...)
$columnString = "....";
$valueString = "....";
$sql = "INSERT INTO " . $table . " (" . $columnString . ") VALUES (" . $valueString . ")";
try {
$stmt = $this->pdo->prepare($sql);
foreach($request_data as $key => $value){
$stmt->bindValue(':' . $key,$request_data[$key]);
}
$stmt->execute();
} catch (PDOException $e) {
return null;
}
Of course, this code works well when no database problem occurs.
I'm using Slim 3 framework, and php7. Same problem with php5.
Does it have something to do with the framework? Is there other configurations ? Why the hell exceptions are not caugh?
First, I do not see any use clause in your code snippet when you create PDO class instance or when you catch exception PDOException. If you miss them, it may give you error as PHP can not find where they are. You need to make sure you add
use PDO;
use PDOException;
in code that refer those classes.
Second, you suppress any exception related to PDO operation by using this code.
try {
//your code
} (PDOException $e) {
return null;
}
To be able to identify the cause of any database-related error, you need to handle exception properly. You need to replace return null; to do more meaningful action to handle the error.
I'm making a register script and using PDO for the first time, but I get this error when trying to use it. The defines works fine when use MySQLi.
My code gives me this error:
Array ( [0] => SQLSTATE[3D000]: Invalid catalog name: 1046 No database selected )
This is the code: (/register.php)
try{
$input_password_hash = password_hash($input_password, PASSWORD_DEFAULT);
$stmt = $PDO_new->prepare("SELECT user_name FROM users WHERE user_name = :username");
$stmt->bindParam(":username",$input_username);
$stmt->execute();
echo "code after exec";
//checks if user already exist in database.
if($stmt->rowCount()>0){
$error[] = "Username already exist";
echo "user is there";
}
else{
echo "user not there";
$insert = "INSERT INTO users(user_name, user_password_hash, user_email) VALUES($input_username,$input_password_hash, $input_email)";
}
} catch(PDOException $e){
$error[] = $e->getMessage();
}
This is the file for connecting to the databse: ((config/db_connect.php)
<?php
require_once($_SERVER['DOCUMENT_ROOT']."/config/db.php");
$PDO_new = new PDO("mysql:host=" . DB_HOST . ";DBName=" . DB_NAME, DB_USER, DB_PASS);
$PDO_new->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
And this is the file where I define the info for the database: (/config/db.php)
define("DB_HOST", "localhost");
define("DB_NAME", "username_databasename");
define("DB_USER", "username_admin");
define("DB_PASS", "password");
A quick test reveals that a PDO connection is case-sensitive in how it parses attributes. You use DBName when you should be using the lowercase dbname. This is not explicitly stated in the PDO::__construct() docs, as far as I can tell, but I was able to verify it testing in my own environment.
$PDO_new = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASS);
//--------------------------------------------^^^^^^^^^^
It is unclear why you are also establishing a connection via MySQLi, as MySQLi and PDO are comparable but incompatible APIs. You generally need one or the other, not both (unless you are combining code from 2 sources that use opposite APIs).
It is recommended to wrap the new PDO() in a try/catch to catch connection errors before setting ERRMODE_EXCEPTION on it.
try {
$PDO_new = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASS);
} catch (PDOException $e) {
// handle a connection error error
}
Finally, I would be remiss if I did not point out that you have plain variables in the INSERT statement rather than bound parameters. You should be binding values with placeholders here as you did in the first SELECT statement.
// Use placeholders please!
$insert = "INSERT INTO users(user_name, user_password_hash, user_email) VALUES(:input_username,:input_password_hash, :input_email)";
// prepare() then execute()...
I'm trying to display a server status, based upon whether the database can be connected to or not. With the old school mysql_connect() and mysqli_connect() it was easy. I'm trying to stay modern, so I'm using PDO, but I can't figure out how-to suppress the default warning. From what I can tell, you need to use the getMessage() function for it to print the PDO warning, but I'm not using it.
Here's my code:
8 $dbstatus = 1;
9 try {
10 $db = new PDO($dbms . ':host=' . $dbhost . ';port=' . $dbport . ';dbname=' . $dbname, $dbuser, $dbpasswd);
11 $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
12 } catch(PDOException $e) {
13 $dbstatus = 0;
14 }
15 if($dbstatus == 1) {
16 echo '<span style="color: green">DB Up</span>';
17 } else {
18 echo '<span style="color: red">DB Down</span>';
19 exit;
20 }
All the connection variables are supplied and correct, except the $dbhost, which is intentionally broken to test this. Now, it produces the desired results, but is also prints a warning message too:
Warning: PDO::__construct(): php_network_getaddresses: getaddrinfo failed: No such host is known. in C:\xampp\htdocs\cd\includes\dbconnect.php on line 10
If I correct the $dbhost variable, it works fine, so I know the issue isn't with the PDO statement being usable.
Any ideas on what I'm missing?
Solution
I used a variation of what was supplied by jeroen:
if(filter_var(gethostbyname($dbhost), FILTER_VALIDATE_IP)) {
$dbstatus = 1;
try {
$db = new PDO($dbms . ':host=' . $dbhost . ';port=' . $dbport . ';dbname=' . $dbname, $dbuser, $dbpasswd, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
} catch(PDOException $e) {
$dbstatus = 0;
}
} else {
$dbstatus = 0;
}
if($dbstatus == 1) {
echo '<span style="color: green">DB Up</span>';
} else {
echo '<span style="color: red">DB Down</span>';
exit;
}
Thank you for the help and I hope this helps someone else! ^^
The only thing I can see here, is that you tell PDO to throw exceptions after you have tried to open the connection. That is most likely too late.
What you could do instead, is send that option to the constructor directly using the 4th parameter:
try {
$opts = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
$db = new PDO($dbms . ':host=' . $dbhost . ';port=' . $dbport . ';dbname=' . $dbname,
$dbuser, $dbpasswd, $opts);
} catch(PDOException $e) {
...
That will probably solve your problem.
Edit: If the host name is provided by the user, you could validate it before sending it to the PDO constructor.
For example using:
if (filter_var(gethostbyname($user_provided_host_name), FILTER_VALIDATE_IP)) {
// valid hostname / ip address
}
That will work for domain names, localhost and ip addresses.
I'm trying to display a server status, based upon whether the database can be connected to or not. With the old school mysql_connect() and mysqli_connect() it was easy. I'm trying to stay modern, so I'm using PDO, but I can't figure out how-to suppress the default warning. From what I can tell, you need to use the getMessage() function for it to print the PDO warning, but I'm not using it.
Here's my code:
8 $dbstatus = 1;
9 try {
10 $db = new PDO($dbms . ':host=' . $dbhost . ';port=' . $dbport . ';dbname=' . $dbname, $dbuser, $dbpasswd);
11 $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
12 } catch(PDOException $e) {
13 $dbstatus = 0;
14 }
15 if($dbstatus == 1) {
16 echo '<span style="color: green">DB Up</span>';
17 } else {
18 echo '<span style="color: red">DB Down</span>';
19 exit;
20 }
All the connection variables are supplied and correct, except the $dbhost, which is intentionally broken to test this. Now, it produces the desired results, but is also prints a warning message too:
Warning: PDO::__construct(): php_network_getaddresses: getaddrinfo failed: No such host is known. in C:\xampp\htdocs\cd\includes\dbconnect.php on line 10
If I correct the $dbhost variable, it works fine, so I know the issue isn't with the PDO statement being usable.
Any ideas on what I'm missing?
Solution
I used a variation of what was supplied by jeroen:
if(filter_var(gethostbyname($dbhost), FILTER_VALIDATE_IP)) {
$dbstatus = 1;
try {
$db = new PDO($dbms . ':host=' . $dbhost . ';port=' . $dbport . ';dbname=' . $dbname, $dbuser, $dbpasswd, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
} catch(PDOException $e) {
$dbstatus = 0;
}
} else {
$dbstatus = 0;
}
if($dbstatus == 1) {
echo '<span style="color: green">DB Up</span>';
} else {
echo '<span style="color: red">DB Down</span>';
exit;
}
Thank you for the help and I hope this helps someone else! ^^
The only thing I can see here, is that you tell PDO to throw exceptions after you have tried to open the connection. That is most likely too late.
What you could do instead, is send that option to the constructor directly using the 4th parameter:
try {
$opts = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
$db = new PDO($dbms . ':host=' . $dbhost . ';port=' . $dbport . ';dbname=' . $dbname,
$dbuser, $dbpasswd, $opts);
} catch(PDOException $e) {
...
That will probably solve your problem.
Edit: If the host name is provided by the user, you could validate it before sending it to the PDO constructor.
For example using:
if (filter_var(gethostbyname($user_provided_host_name), FILTER_VALIDATE_IP)) {
// valid hostname / ip address
}
That will work for domain names, localhost and ip addresses.