Best practice for error handling using PDO
Problem:
Finding best practice for error handling using PDO. The options I have found on websites, SO, books, etc.
- A great number of websites say you should echo your error messages in your
catch
block. - A large number of users on SO say that you should never echo error messages due to security risks.
- Others are recommending logging it to a log file outside the document root.
- Some use error handling to log it to a SQL table.
With a multitude of options, it gets quite easy to drown into what option you should be using. Of course you could use a MVC framework and let it handle error logging for you, but how would it look like if you are not using MVC.
As I have understood it error handling should like the following in development environment:
display_errors = On
display_startup_errors = On
error_reporting = -1
log_errors = On
Or if no access is available to the php.ini file:
error_reporting(-1);
ini_set("display_errors", 1);
And in production environment:
display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
log_errors = On
Or if no access is available to the php.ini file:
error_reporting(0);
To take an example of a database connection in production environment.
Code:
<?php
// Error handling
error_reporting(0);
// Get credentials from outside document root
require_once('../settings.php');
// Tests connection to database
try {
$dbh = new PDO(
sprintf(
'mysql:host=%s;dbname=%s;port=%s;charset=%s',
$settings['host'],
$settings['name'],
$settings['port'],
$settings['charset']
),
$settings['username'],
$settings['password']
);
// Prevents emulated prepares and activates error handling
// PDO::ERRMODE_EXCEPTION
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
// Catches errors raised by PDO
catch (PDOException $e) {
// Prints error messages to file
file_put_contents('/home/ubuntu/errors.log', 'Error: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
// Shows generic error message to user
header('Location: 404.php');
exit;
}
?>
Question:
- What is the best practice for handling errors in general in PHP?
- What is the best practice for handling errors in the catch-block?
That's a very good question, but there is one wrong premise at the very beginning: you are taking error reporting for PDO separated from site-wide error reporting. Which makes very little sense: PDO errors in every way are the same as other errors - filesystem errors, HTTP errors, and so on. Thus, there is no reason in establishing PDO-only error reporting. All you need is to properly set site-wide error reporting.
There is also one wrong assumption regarding php.ini inaccessibility: you can always set any configuration directive using ini_set() function. Thus, here is not a single reason in setting error_reporting to disastrous level of 0.
To answer the rest of your questions all you need is a little common sense.
A great number of websites say you should echo your error messages in your catch block. A large number of users on SO say that you should never echo error messages due to security risks.
What you think yourself? Does it any good showing system error messages to user? Does it any good showing system internals to a malicious user?
Others are recommending logging it to a log file outside the document root.
Do you have any objections for this?
Some use error handling to log it to a SQL table.
Don't you think it's quite contradicting idea - to log database errors into database?
What is the best practice for handling errors in general in PHP?
You have shown it already: display in dev and log in prod. All is controlled site-wide through few simple configuration options.
What is the best practice for handling errors in the catch-block?
NOT to use try-catch block for error reporting at all. You aren't going to write a catch block with a friendly error message for the every query in your app, as it's suggested in the other answer, are you?
Thus your code have to be
<?php
// Error handling
error_reporting(-1);
ini_set('display_errors',0);
ini_set('log_errors',1);
// Get credentials from outside document root
require_once('../settings.php');
// Tests connection to database
$dbh = new PDO(
sprintf(
'mysql:host=%s;dbname=%s;port=%s;charset=%s',
$settings['host'],
$settings['name'],
$settings['port'],
$settings['charset']
),
$settings['username'],
$settings['password']
);
// Prevents emulated prepares and activates error handling
// PDO::ERRMODE_EXCEPTION
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Now to the question you voiced in the comment.
A custom error screen is a very different matter and your code is especially bad with it. Neither it should be a 404 error nor an HTTP redirect have to be used (thats very bad for SEO).
To create a custom error page you have to use either your web-server features (preferred) or an error handler in PHP script.
When encountering a fatal error (and uncaught exception is one), PHP responds not with 200 OK HTTP status but with 5xx status. And every web-server can catch this status and show an according error page. E.g. for Apache it would be
ErrorDocument 503 server_error.html
where you can write whatever excuses you want.
Or you can set up a custom error handler in PHP which would handle all PHP errors as well, an example can be seen in the article I wrote on the matter: The (im)proper use of try..catch.