I'm updating a code base from mysql to pdo and this is the first time I've done a project like this so I've been doing research on best practices and would like some input. Here is the old code:
$link = #mysql_connect('localhost', "xxx", "xxx")
or die('Could not connect: ' . mysql_error());
mysql_select_db("xxx") or die('Could not select database');
In my code I'm putting all the login credentials into a separate file and using the ip address, username and password to connect as opposed to localhost.
try {
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e){
log_error("Failed to run query", $e->getMessage(), $e->getCode(), array('exception' => $e));
die('Could not connect!');
Two questions, is this a good alternative to using the die method deal with errors and log to the client and also is this the correct way to connect? Is there an advantage to connecting using localhost vs the server IP address? Thanks for the help!
Is this a good alternative to using the die method?
What you're doing is reasonable as part of a migration - it should behave the same way it did before. You might consider, however, not catching that PDOException and allowing it to be thrown all the way up to your global error handler. That's nicer because it's less code, and you're not catching an exception just to die. But before making that change, you should have an idea of the way it will behave in your production systems (will you see the error in your logs)?
Is this the correct way to connect?
Yes, it seems like you're using PDO correctly.
Is there an advantage to connecting using localhost vs the server IP address?
You mean in production? Best practice would be to run your database on a separate server - in which case localhost would obviously not work. If the load is light and you are running the database and PHP server on the same box for now, then it shouldn't matter either way.
Good questions, and I already have all the answers for you (and even answers to questions you didn't ask yet), just follow my article, How to connect to MySQL using PDO.
To answer your questions more directly:
is this a good alternative to using the die method deal with errors
By all means - no.
To be honest, your current approach is not much better than the old one. The code here is inflexible, you have to edit it manually to change the behavior. It would be much better if your code would only throw an error, whereas its processing would be defined elsewhere and easily configurable.
Let alone the die() is still there. Trust me, a site that tells you 'Could not connect!' on a white screen looks awfully unprofessional. You should never ever use die like that.
#mkasberg is right, generally, you don't catch an Exception but let it bubble up to where it will be appropriate to handle it. However, PDO connection is a special case as the stack trace in case of error would contain the db credentials which you likely don't want to show to anyone. To prevent this, I propose to throw a brand new exception that would contain the same error information but no stack trace.
is this the correct way to connect?
Apart from what was said above, without seeing the DSN we cannot tell for sure.
Is there an advantage to connecting using localhost vs the server IP address?
Generally, a hostname is preferred, like with any other service. the IP address could change but thanks to DNS system the domain name would always point at the correct address. However, localhost is a special case, and judging by many questions here on Stack Overflow I would rather recommend to use the IP address, as it could save you a headache or two, like a too big timeout when DNS is misconfigured.
Related
I connect to MySQL using PHP's PDO like this:
$driver_options[PDO::ATTR_PERSISTENT] = true;
$db = new PDO('mysql:host='.$host.';dbname='.$db_name, $user, $pass, $driver_options);
I have 2 databases (let's call them database_A and database_B) on this server and sometimes very strange thing happens. Even though, $db_name is 100% set to 'database_A', connection is made to 'database_B'.
It's happening completely random. I can run the same script 10 times over again and everything is fine. And 11th time this problem happens.
I would never expect this to happen. It gave me a lot of headache. Can anyone explain it ? And is the only solution not to use persistence ?
PDO::ATTR_PERSISTENT is partially supported and is dependent on the the PHP version and SQL server you're using.
I would recommend never setting this attribute to true in the drive options due to it's instability.
I was able to replicate your case and i found that the ODBC Connection Pooling layer was caching the connection and since your connection is being set to persistent, the cache was being reset each time i made a new connection.
$driver_options[PDO::ATTR_PERSISTENT] = true;
$db = new PDO('mysql:host='.$host.';dbname='.$db_name, $user, $pass, $driver_options);
When you do the above, the PDO connection is placed in the "persistent connection pool", but the pool purpose is not to cache the database, but rather the memory allocation, authentication and setup groundwork. That is what uses time (not so much, at that).
Whatever else you supply in the new PDO() call is LOST.
And if you have two databases with the same credentials, you can get them swapped at random -- as you experienced.
So, do not specify the DB in the new PDO statement, but use the USE databasename SQL statement as soon as the new PDO object is ready.
Or, as PankajKumar suggests, set up different credentials for the two DBs. Then the mistaken cache hit will not happen (but is wont to happen again as soon as someone reuses those same credentials - such as 'ubuntu/ubuntu' or 'root/').
I suppose you are running this in production, or a dev system which is reloaded not so often.
Therefore please restart all your php workers/instances/threads and check if the problem occurs again.
I believe one of these processes is holding your old configuration. And silently causes your errors, randomly when your webserver actually chooses to use the old thing.
I have database back-up kept in 3 different servers.
Whenever a database failure happens in the currently connected database server, I want my site to connect to the next specified database server automatically. Also the failure should be notified to the specified email.
Like that each database failure should be handled by connecting to the next available database server till the failure is handled. If all three servers fail, it can show Wordpress default message "Error establishing database connection".
Though I'd try to get to a more stable environment as well, you should be able to do this. Here's my idea:
$wpdb is set in require_wp_db() (wp-includes/load.php). If a file named "db.php" exists in WP_CONTENT_DIR (usually wp-content), it will be included before $wpdb is created.
Add a class in db.php that extends wpdb and override db_connect with custom code to change host, credentials etc depending on $this->reconnect_retries and then use parent::db_connect(). Instantiate $wpdb with your db-class.
I haven't tested this, but I don't see why it shouldn't work.
You can use many open source tools for failover, for MySQL automated failover I would recommend orchestrator
If you are trying to achieve from php side, then only thing I can tell is, implement something like load balance or kind of distributed system.
What that means ?
Assuming you have 3 database servers and they are all in sync. When you are establishing connection to database you can user different server on different user/request. This way, you can avoid database server being overloaded.
Implementation
You could maintain log of active user on each database server and according you open connection for new request/user.
This generally seems like an awkward solution, you should consider some sort of distributed system or cluster servers/databases.
But if you insist on implementing it programmatically in your codes, then you can include your connections in successive try/catch blocks.
e.g if you use PDO, you can
try {
$con = new PDO("mysql:host=$lang[dhost];dbname=$lang[db]", $lang['user'], $lang['pass']);
} catch(PDOException $e) {
try{second connection..........
......................
}
I think that this problem is bigger than you think.
I don't have any experience, but I can tell you that this kind of things affect the way your systems work currently, and a real investigation (of actual code and servers architecture) it's needed.
I don't think this is the kind of things StackOverflow should do for you.
Can I get data from three different servers on my php application? Actually I have my data on three different servers and I want to generate a report with having data from all three servers. Can you please suggest me a code for this?
function dbcon(ipaddress,servername,serverpassword,databasename)
{
$con = mysql_connect(ipaddress,servername,serverpassword);
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db(databasename) or die ("Cant find DB");
}
Certainly that is possible. I assume (though you are not very clear in this) that you are talking about three database servers? Then all you have to do is:
make sure the database servers are accessible via network (tcp)
create three database connections instead of only one
Since opening a connection to a database server returns a handle you have something you can use to address a specific connection. The syntax required for opening the connection is clearly explained in the manual pages. I suggest you read them and take a look at the provided examples...
First:
Welcome to Stack Overflow! Please, don't use mysql_* functions in new code. They are no longer maintained and the deprecation process has begun on it. See the red box? Learn about prepared statements instead, and use PDO or MySQLi - this article will help you decide which. If you choose PDO, here is a good tutorial.
In order to connect to three different databases, you'll need 3 connection objects, and query each separately. Make sure you have configured the receiving ends to correctly accept connections.
I am trying to understand this: If there are errors in the database like FK issues, Missing tables/columns, or even if the database is dead -> Will this crash the application? I have my website in php. What about application and network related errors? Can these cases be caught for and have a work around without users seeing a non functionaning site or site down message?
In general you must check every single bit of your application, from database connectivity to user input using php. That link helped me some time ago http://www.nyphp.org/PHundamentals/7_PHP-Error-Handling It introduces you to try/catch error handling.
There are several ways to detect errors and handle them in PHP.
Exceptions, and Try-Catch statements.
Here's examples of both.
How you catch database errors will depend on what kind of database it is. If you're using MySQL, then PHP lets you catch query errors like this. Here's the doc on die and mysql_error().
mysql_query( querystuff ) or die( mysql_error() );
Where is the most secure place to put MySQL database connection details when connecting via a PHP script?
$connection = mysql_connect($hostname, $username, $password);
if (!$connection) {die('Could not connect: ' . mysql_error());}
mysql_select_db($database, $connection);
I know it's not a good idea to put them directly in the script that is querying the database. However, some say that you should put the connection details in a separate PHP script and include that script to connect.
Is there a more secure place to put the connection details?
The usual practice is to put them into a separate file, and put that outside the web root. See this answer for details.
You may want to put it in a directory that is not in the webapp hierarchy, to prevent a browser from having any chance to access it.
Depending on your level of paranoia, you could write a webservice that is behind a firewall, and call for the credentials, but that may be overkill.
It would help if we understood your architecture, is it just php script goes to database, then the first suggestion would be best, if you have firewalls, for example, then you will have more options.
If your OS has reasonable security features, it doesn't matter so much where, as long as the file belongs to a group with the minimum possible rights.