die() or try/catch when interacting with MySql database in PHP? - php

A lot of tutorials and books I have been over and read have used the die() method to catch an exception when interacting with a local MySQL database
For example:
mysql_connect($dbhost, $dbuser, $dbpass)or die(mysql_error());
Would a try/catch block be more beneficial over the die() method or is that just the standard way that exception handling works with db connections?

or die() is an extremely primitive way to "handle" errors and only for examples or debugging at best. In practice, it depends on how you handle your errors. You may want to return false from a function call or you may want to throw your own exception instead; e.g.:
if (!$con = mysql_connect(..)) {
throw new DatabaseConnectionError(mysql_error());
}
try..catch will do exactly nothing with mysql, since mysql never throws any exceptions. It only ever returns false on failure.
You will have to have your own error handling strategy. You'll probably want to log errors and display a user friendly error page instead of cryptic error messages. mysql is not concerned with that part. It only gives you a way to check whether an operation was successful or not (check if it returns false); what you do with this information is up to you. die kills the entire application and at least doesn't allow the problem to propagate further; but it certainly does not display any user friendly error pages.
Having said all this, mysql is old and deprecated. If you'd use something newer like PDO instead, it can properly throw exceptions itself.

The mysql_connect method does not throw exceptions and thus die() is used by many applications to terminate when there is no connection available.
You can use the solution mentioned here: how to use throw exception in mysql database connect
Included for completeness:
try
{
if ($db = mysqli_connect($hostname_db, $username_db, $password_db))
{
//do something
}
else
{
throw new Exception('Unable to connect');
}
}
catch(Exception $e)
{
echo $e->getMessage();
}
Alternatively use the new and more OOP styled database access: http://php.net/manual/en/book.pdo.php
The reason a lot of applications uses die is from the fact that they are so reliant on the database that continuing without a connection is utterly fruitless.
Edit As mentioned in the comments, the code example above is for illustrational purposes. Catching right after throwing is pointless.

Related

How to handle PDO connection errors properly?

I try to handle or catch possible errors with PHP/MySQL for security reasons and would like to know if I'm doing it right.
The first case: I use it as a function and call it always when I need a database connection.
The second case: I am not sure how to handle it. I put all prepared statements in if conditions but that's pretty awkward.
And what about $stmt->execute? This could also fail and to handle this also in an if condition can really get confusing.
I hope there is a better way to go.
First:
function pdo () {
try {
$pdo = new PDO('mysql:host=localhost;dbname=dbname', 'user', 'pw');
}
catch(PDOException $e) {
header("Location: handle_error.php");
exit;
}
return ($pdo);
}
Second:
if ($stmt = $pdo->prepare("SELECT a FROM b WHERE c = :c")) {
$stmt->execute(array(':c' => $c));
$result = $stmt->fetch();
echo 'All fine.';
}
else {
echo 'Now we have a problem.';
}
Your current code has some flaws. Let me give you few pointers.
You do not need the function you have created, at least not in the current form. Every time you call this function it creates a new PDO object, which can hinder your script's performance. Ideally you would want to have only one connection throughout the execution of your whole script.
When creating new PDO connection you need to remember 3 things: to set proper connection charset, enable error reporting, and disable emulated prepares.
Proper charset is important. Without it your data could get corrupted or even leave you vulnerable to SQL injection. The recommended charset is utf8mb4.
Enabling error reporting saves you the trouble of manually checking every single function call for failures. You just need to tell PHP to trigger exceptions when an error occurs and find a suitable way of logging the errors on your server (read more: My PDO Statement doesn't work)
Emulated prepares are enabled by default, but the truth is you are better off without them. If your database supports native prepared statements, and most do, then use them instead.
The full code should look something like this:
$options = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new \PDO('mysql:host=localhost;dbname=dbname;charset=utf8mb4', 'user', 'pw', $options);
Don't catch the exceptions unless you know what to do with them and are positively sure you need to do so. Exceptions are best left be; let PHP handle them together with the other exceptions/errors/warnings. After all why make an exception just for PHP exceptions? All PHP errors should be handled the same. Whatever you do never print (including die, exit, echo, var_dump) the error message manually on the screen. This is a huge security issue if such code ever makes its way into production.
If your PDO connection is set to throw exceptions on errors, you never need to use if statements to check return code of prepare() or execute().

Can PDO methods fail and not throw PDOException?

I'm tweaking a legacy database class written for PHP/5.2 that was designed to connect to MySQL and hide all errors. I've configured the PDO instance to throw exceptions:
new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION))
Now I need to adjust my code accordingly to handle the case where functions can throw an exception where they wouldn't before so I head to the manual.
In some cases the manual is explicit, e.g. PDO::prepare:
If the database server successfully prepares the statement,
PDO::prepare() returns a PDOStatement object. If the database server
cannot successfully prepare the statement, PDO::prepare() returns
FALSE or emits PDOException (depending on error handling).
In other cases it's kind of vague, e.g. PDO::commit:
Returns TRUE on success or FALSE on failure. Throws a PDOException
if there is no active transaction.
(Can it fail for some other reason and simply return false?)
And there're cases when exceptions are not even mentioned, e.g. PDO::bindValue:
Returns TRUE on success or FALSE on failure.
... even though it's clear to verify that it does throw PDOException on error (at least, on certain errors).
Do I still need to check the return value of methods that return false on error when the manual doesn't say otherwise?
No, when you set PDO::ERRMODE_EXCEPTION there will be always exception for any errors
When you have exceptions enabled and there is an error happening in your code, the code directly stops executing from that function, so it wont return anything.
So to be blund, you don't need to check the return values but if you don't you cannot error anything specific and you would rely fully on PDO to error correctly.
When I created my database system, I take advantage of both if I see an error upcoming, I throw it myself instead. For example $pdo->prepare('') is very much valid but will error upon binding.
Then there are other functions such as fetch that wont error if there are no results in the database, not checking the results from that would be silly.
Now for committing to fail, I believe there is 1 scenario that would cause it to return false without throwing an exception and that is when the connection to the server drops after connecting to the database and before calling PDO::commit, quite good to know if you have a remote database server.
So to answer your question, yes it can fail without throwing an exception, but its timing has to be very specific even more so if you have a local database.
Try this one
try {
$db = new PDO("mysql:host=localhost;dbname=dbname", "username", "password");
}catch( PDOException $Exception ) { $Exception->getMessage( ) ; }

PDO Update Statement Not Working

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.

When is error checking too much?

During the process of my PHP learning I have been trying to read up on the best practices for error reporting and handling, but statements vary person to person and I have struggled to come up with a clear concise way of handling errors in my applications. I use exceptions on things that could go wrong, but for the most part it is hard for me to understand whether an exception should kill the application and display an error page or just be caught and silently dealt with.
Something that seems to elude me is, is there such thing as too much reporting? Every single time you call a function something could go horribly wrong meaning that if you were to confirm every single function call you would have to fill pages with if statements and work out what effect one failure may have on the rest. Is there a concise document or idea for error reporting that could clear this up for me? Are there best practices? What are the best examples of good error handling?
Currently I do the following:
Add important event results to an array to be logged and emailed to me if a fatal error was to occur
Display abstract/generic errors for fatal errors.
Use exceptions for cases that are likely to fail
Turn on error reporting in a development environment and off for live environment
Validate all user input data
Sanitizing invalid user input
Display concise, informative error messages to users without providing a platform for exploitation.
Exceptions are the only thing that you haven't understood IMHO: exceptions are meant to be out of your control, are meant to be caught be dealt with from outside the scope they are thrown in. The try block has a specific limit: it should contain related actions. For example take a database try catch block:
$array = array();
try {
// connect throws exception on fail
// query throws exception on fail
// fetch results into $array
} catch (...) {
$array[0]['default'] = 'me';
$array[0]['default2'] = ...;
...
}
as you can see I put every database related function inside the try block. If the connection fails the query and the fetching is not performed because they would have no sense without a connection. If the querying fails the fetching is skipped because there would be no sense in fetching no results. And if anything goes wrong, I have an empty $array to deal with: so I can, for example, populate it with default data.
Using exceptions like:
$array = array();
try {
if (!file_exists('file.php')) throw new Exception('file does not exists');
include('file.php');
} catch (Exception $e) {
trigger_error($e->getMessage());
}
makes no sense. It just a longer version of:
if (!file_exists('file.php')) trigger_error('file does not exists');
include('file.php');

Catch database exception in Kohana

I'm using Kohana 2. I would like to catch a database exception to prevent an error page when no connection to the server can be established.
The error displayed is
system/libraries/drivers/Database/Mysql.php [61]:
mysql_connect() [function.mysql-connect]: Lost connection to MySQL server at
'reading initial communication packet', system error: 110
The database server is not reachable at all at this point.
I'm doing this from a model. I tried both
public function __construct()
{
// load database library into $this->db
try
{
parent::__construct();
}
catch (Exception $e)
{
die('Database error occured');
}
}
as well as
try
{
$hoststatus = $this->db->query('SELECT x FROM y WHERE z;');
}
catch (Exception $e)
{
die('Database error occured');
}
...but none of them seemed to work. It seems as if no exception gets passed on from the main model. Is there another way to catch the database error and use my own error handling?
Kohana 2 does not convert errors into exceptions. You will either need to attach your own error handler, or use error_reporting() to turn off the error (temporarily) then do some kind of handling yourself.
You can catch the exception, but you are probably trying to catch it in the wrong place. The problem with trying to catch that low-level of an exception is that it can be spawned from many different sources.
For example, if you use the database driver for your sessions that exception will be thrown from instantiation of the database driver in the session library (which is instantiated in a call to session which will probably happen before you instantiate any models).
Catching that exception can happen from the model, but it is more likely to happen from another source - in which case you would probably have to extend a few libraries, or be sure you are wrapping a base model parent::__construct call and the session library in a try-catch block.
(I would personally extend the Model library to do that instead of putting it in a base model)
Hope that helps.
I don't know Kohana, but a try .. catch block will not catch normal errors, only Exceptions. Are you sure Kohana throws Exceptions where you expect to receive Exceptions?
Edit based on you comments:
Well, first of all, in a production environment (meaning your live application) you should always disable the displaying of PHP errors to the screen. Displaying of these errors to the screen should only be done in a development environment to inform you, the developer. Visitors of your live application however have no business in knowing/reading PHP errors, as it might disclose sensitive information about your environment. You should however log the errors to a log file.
Furthermore, I just took a quick peek at Kohana, and indeed see that here and there Exceptions are thrown, but it doesn't seem to do this in a consistent manner.
If you want php errors to be treated as Exceptions have a look example #1 in this documentation.

Categories