This tutorial is intended for the novice or
intermediate PHP programmer. Basic knowledge of creating and using
functions is assumed. All the functionality is there, you just have to
customise it to your specific requirements.
Customizing the PHP Error Handler
Intended Audience
This tutorial is intended for the novice or intermediate PHP
programmer. Basic knowledge of creating and using functions is assumed.
Introduction
One of the last areas that developers seem to deal with in their code
is error handling. I am not talking here about errors with user input
where it is a simple matter to display an error message and ask for new
input, I am taking about the kind of error over which the user has
absolutely no control and which may cause the current PHP script to
stop running. In this situation you as a developer need to know some
details about the error otherwise you will have a very difficult time
in locating the source of the error so that you can fix it.
Developers new to PHP often complain there there is no proper error
handling in the language. This is utter nonsense. All the functionality
is there, you just have to customise it to your specific requirements.
In this tutorial I will show to how to create an error handler that will:
- Trap all errors whether triggered by PHP or a specific function call.
- Filter all errors depending on their error level.
- Output a formatted error message to the user.
- Send an email to the system administrator.
- Write the error details to a separate log file.
Creating the Error Handler
This is done by using the set_error_handler() function. With this you
supply the name of the function you want to be called when any errors
are triggered. You then create a function of this name to deal with
these errors. In the following code snippets I shall use the name
errorHandler.
set_error_handler('errorHandler');
function errorHandler ($errno, $errstr, $errfile, $errline, $errcontext)
{
Here I am using the switch() statement to take action depending on the
value of $errno. Anything less than E_USER_ERROR will be ignored and
processing will continue.
Note that by defining your own error handler the standard PHP
error handler is completely bypassed and any settings for
error_reporting() are completely ignored. This is why we are checking
for all possible error levels, not just fatal errors.
switch ($errno)
{
case E_USER_WARNING:
case E_USER_NOTICE:
case E_WARNING:
case E_NOTICE:
case E_CORE_WARNING:
case E_COMPILE_WARNING:
break;
case E_USER_ERROR:
case E_ERROR:
case E_PARSE:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
Here I am picking up the last SQL query from a
global variable. I am them checking the contents of $errstr to see if
this error was triggered with the string 'SQL' so I know when to
include some additional information.
global $query;
if (eregi('^(sql)$', $errstr)) {
$MYSQL_ERRNO = mysql_errno();
$MYSQL_ERROR = mysql_error();
$errstr = "MySQL error: $MYSQL_ERRNO : $MYSQL_ERROR";
} else {
$query = NULL;
} // if
Now we can start constructing an error message. I personally like to start with the current date and time.
$errorstring = "
" .date('Y-m-d H:i:s') ."
\n";
Next we include the contents of $errno and $errstr.
$errorstring .= "
Fatal Error: $errstr (# $errno).
\n";
If the error was triggered by an SQL problem I have found it of
enormous benefit to include the actual query string in the error
message.
if ($query) $errorstring .= "
SQL query: $query
\n";
These next lines will identify the filename and line number where the
error was triggered, plus the name of the currently executing script.
$errorstring .= "
Error in line $errline of file '$errfile'.
\n";
$errorstring .= "
Script: '{$_SERVER['PHP_SELF']}'.
\n";
These next lines of code show you how it is possible to extract some
more information about the context of the current error. In this case
if the context is an object it will extract the name of the class and
the name of the parent class (if it is a derived class).
if (isset($errcontext['this'])) {
if (is_object($errcontext['this'])) {
$classname = get_class($errcontext['this']);
$parentclass = get_parent_class($errcontext['this']);
$errorstring .= "
Object/Class: '$classname', Parent Class: '$parentclass'.
\n";
} // if
} // if
This next group of lines will send the error message to the client's browser.
echo "
This system is temporarily unavailable
\n";
echo "
The following has been reported to the administrator:
\n";
echo "\n$errorstring\n";
This next line of code will send the error details to the system administrator by email.
error_log($errorstring, 1, $_SERVER['SERVER_ADMIN']);
Here I am appending the error details to a disk file with the extension
'.html' so that I can easily view its contents with my browser. This
means that I do not have to wait for the email to arrive to obtain the
details of the error.
$logfile = $_SERVER['DOCUMENT_ROOT'] .'/errorlog.html';
error_log($errorstring, 3, $logfile);
The final act is to terminate the current session then cease processing altogether.
session_start();
session_unset();
session_destroy();
die();
default:
break;
} // switch
} // errorHandler
Calling the error handler
Certain types of error, such as trying to access a variable which has not yet been defined, will be triggered automatically by PHP.
As these are at the E_NOTICE level they will fall through the error
handler and allow processing to continue. It would be possible to do
something with these errors, such as writing them out to a log file, if
you so desired.
It is also possible to trigger the error handler by using the
trigger_error() function. Here for example we are using the simple
error string 'SQL' to force the error handler to extract the contents
of mysql_errno() and mysql_error().
$result = mysql_query($query, $dbconnect) or trigger_error("SQL", E_USER_ERROR);
For non-sql errors a specific error string should be supplied.
if ($divisor == 0) {
trigger_error ("Cannot divide by zero", E_USER_ERROR);
} // if
if (!function_exists('xslt_create')) {
trigger_error('XSLT functions are not available.', E_USER_ERROR);
} // if
Summary
As you can see the steps required to create an error handler are quite
small, but whenever an error occurs you can now be supplied with all
the relevant details so you can track it down and fix it more easily.
|