PHP Error Handling on Production Sites
For those of you who are running production sites, switch off display_errors. Although these errors have become somewhat safer in terms of the content that it displays, they still pose a security risk to your site. To manage errors that occur during production, make use of PHP’s error-handling capabilities. To demonstrate these capabilities, we will create a custom error handler. Before we start developing our own error handler, I’d like to share the following things about PHP’s error reporting. PHP has three kinds of error levels:
- Warnings, which indicate a problem but don’t stop a script’s execution.
- Errors, which stop a script from continuing (including the ever-common parse error, which prevent scripts from running at all).
- Notices, which do not stop the execution of a script and may not necessarily be a problem.
This will sound familiar to you, since we already looked at each type in detail. The three error types each have reporting levels as listed below:
Number |
Constant |
Reporting on |
1 |
E_ERROR |
Fatal runtime errors (that stop execution of the script) |
2 |
E_WARNING |
Runtime warnings (non-fatal errors) |
4 |
E_PARSE |
Parse errors |
8 |
E_NOTICE |
Notices (things that may or may not be a problem) |
256 |
E_USER_ERROR |
User-generated error messages, generated by the trigger_error() function |
512 |
E_USER_WARNING |
User-generated warnings, generated by the |
1024 |
E_USER_NOTICE |
User-generated notices, generated by the trigger_error() function |
2048 |
E_STRICT |
Recommendations for compatibility and interoperability(available as from PHP6) |
8191 |
E_ALL |
All errors, warnings, and recommendations |
In our custom error handler, we will try to catch the type of error that PHP is reporting and then handle it appropriately. We can either send the error to an email address, or we can log the error to a file. Our error handler will be a class, which will get its information from a config file:
Config file:
<?php $app_name="Error Manager"; $filename = 'error_log.txt'; //filename to which the error will be logged $email ='[email protected]';//email address to which error messages are to be sent to $emailname = 'joe blogg'; //email recipient name $currdate=date("l, dS of F Y @ H:i:s A"); ?>
The config file contains the email address, logfile and current date information. We can easily include this information in the main class, but it is better security-wise to have it somewhere (even outside of the root) where you can make changes.
Errorhandler class:
<?php /* functions: handle error - Actual error handler vars are not echoed when the error is printed out. You can do this if you so wish TO DO: HTML Format error messages */ class errors { var $msg; function errors() { global $filename,$email,$currdate,$app_name; // Populate class variables $this->email = $email; $this->logfile =$filename; $this->currdate=$currdate; $this->appname="Error Manager"; // Take over from PHP error handling set_error_handler(array($this, 'handle_error')); } function handle_error($type, $string, $efile, $line, $vars) { // Decide which type of error it is, and handle appropriately switch ($type) { // Error type case E_ERROR: case E_USER_ERROR: //build the message $this->msg = '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line.'</b> <br>' ; //$this->msg .= print_r($vars); if(isset($this->appname)){ $this->msg .='Error generated by <b>'.$this->appname.'</b> on <b>'.$this->currdate.'</b><br>'; }else{ $this->msg .='Error generated on <b>'.$this->currdate.'</b><br>'; } echo '<br>'; /*//log the error to file error_log($this->msg,3,$this->logfile); //sent message to web administrator error_log($this->msg,1,$this->email); */ //print out message echo '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line. '</b><br>' ; echo 'Error generated on <b>'.$this->currdate.'</b><br>'; echo '<br>'; break; case E_WARNING: case E_USER_WARNING: //build the message $this->msg = '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line.'</b> <br>' ; // $this->msg .= print_r($vars); if(isset($this->appname)){ $this->msg .='Error generated by <b>'.$this->appname.'</b> on <b>'.$this->currdate.'</b><br>'; }else{ $this->msg .='Error generated on <b>'.$this->currdate.'</b><br>'; } echo '<br>'; /*//log the error to file error_log($this->msg,3,$this->logfile); //sent message to web administrator error_log($this->msg,1,$this->email); */ //print out message echo '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line. '</b><br>' ; echo 'Error generated on <b>'.$this->currdate.'</b><br>'; echo '<br>'; break; case E_PARSE: //build the message $this->msg = '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line.'</b> <br>' ; // $this->msg .= print_r($vars); if(isset($this->appname)){ $this->msg .='Error generated by <b>'.$this->appname.'</b> on <b>'.$this->currdate.'</b><br>'; }else{ $this->msg .='Error generated on <b>'.$this->currdate.'</b><br>'; } echo '<br>'; /*//log the error to file error_log($this->msg,3,$this->logfile); //sent message to web administrator error_log($this->msg,1,$this->email); */ //print out message echo '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line. '</b><br>' ; echo 'Error generated on <b>'.$this->currdate.'</b><br>'; echo '<br>'; break; case E_NOTICE: case E_USER_NOTICE: //build the message $this->msg = '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line.'</b> <br>' ; // $this->msg .= print_r($vars); if(isset($this->appname)){ $this->msg .='Error generated by <b>'.$this->appname.'</b> on <b>'.$this->currdate.'</b><br>'; }else{ $this->msg .='Error generated on <b>'.$this->currdate.'</b><br>'; } echo '<br>'; /*//log the error to file error_log($this->msg,3,$this->logfile); //sent message to web administrator error_log($this->msg,1,$this->email); */ //print out message echo '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line. '</b><br>' ; echo 'Error generated on <b>'.$this->currdate.'</b><br>'; echo '<br>'; break; } } } ?>
The errorhandler class uses a function called handle_error()
to list all the available error reporting levels and constructs a message using the reported error:
function handle_error($type, $string, $efile, $line, $vars) { // Decide which type of error it is, and handle appropriately switch ($type) { // Error type case E_ERROR: case E_USER_ERROR: //build the message $this->msg = '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line.'</b> <br>' ; //$this->msg .= print_r($vars); if(isset($this->appname)){ $this->msg .='Error generated by <b>'.$this->appname.'</b> on <b>'.$this->currdate.'</b><br>'; }else{ $this->msg .='Error generated on <b>'.$this->currdate.'</b><br>'; } echo '<br>';
Then it writes the error message to a file:
/*//log the error to file error_log($this->msg,3,$this->logfile);
And then sends the error to the email address that was defined in the config file:
//sent message to web administrator error_log($this->msg,1,$this->email); */ //print out message echo '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line. '</b><br>' ; echo 'Error generated on <b>'.$this->currdate.'</b><br>'; echo '<br>'; break;
To test the errorhandler class, you simply do the following:
<?php include "errorhandler.class.php"; include "config/errorhandler.conf.php"; //instantiate the class $errors = new errors(); //trigger some errors $row = mysql_fetch_array($result); 100/0; ?>
I’ve included the source code for download.
Conclusion
Handling errors this way keeps your site secure and enables you to deal with any errors in the background. The error handler can, of course, be expanded to include any new error reporting levels that might be introduced in the newer versions of PHP.