Automatic error reporting in PHP

I edited this page on the 21 March 2010 because a lot of people seem interested and the code as since improved !

PHP has a pretty interesting feature, you can define a callback method to “catch” any error “thrown” in your code. And I’m sure most of you don’t use it. It’s really usefull when you want to make sure to detect error before any user reports it (which can takes time). This is all about avoiding to demolish with some lame errors your “user experience”.

I now use it in each of my index.php pages (which generally loads every other pages), but to speed things up I make it load the actual method only when the error is “catched”.

This is the code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function lightErrorHandler($errno, $errstr, $errfile, $errline, $shutdown = false ) {
	// When called from the shutdown function, the relative path doesn't work anymore.
	// You have to load the errorHandler function from its absolute path
	// If you don't like that method, you can always preload this function.
	require_once('/home/website/mysite.com/dev-www/include/error/errorHandler.inc.php');
	return errorHandler($errno, $errstr, $errfile, $errline, $shutdown);
}
set_error_handler( 'lightErrorHandler', E_ALL ^ E_NOTICE);
 
function lightExceptionHandler( $exception ) {
	require_once('./include/error/exceptionHandler.inc.php');
	return exceptionHandler( $exception );
}
set_exception_handler( 'lightExceptionHandler' );
 
function shutdown_function() {
	if(is_null($e = error_get_last()) === false && $e['type'] & (E_ALL ^ E_NOTICE) ) {
		lightErrorHandler( $e['type'], $e['message'], $e['file'], $e['line'], true );
	}
}
register_shutdown_function('shutdown_function');

include/error/errorHandler.inc.php :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function errorHandler($errno, $errstr, $errfile, $errline, $shutdown) {
	global $engine;
 
	$tab = array(
	        'no'    => $errno,
	        'str'   => $errstr,
	        'file'  => $errfile,
	        'line'  => $errline
	);
 
	$message = 'An error happened :'."\n\n".'Error : '."\n".print_r( $tab, true )."\n\n".'StackTrace : '."\n\n".print_r( debug_backtrace(), true )."\r\n".'Memory state : '."\n".print_r( $GLOBALS, true )."\n";
 
	mail(
	        'email@company.com',
	        'MyProject : Error : '.$errfile.':'.$errline,
	        $message
	);
 
	$target = $errfile.':'.$errline;
 
	if ( ! $engine['bug'] && ! $shutdown ) {
		$engine['bug'] = true;
		Logger::log(array(
			'message'		=> 'Error : '.$errstr.' ('.$errno.')',
			'type'			=> 'error/codeError',
			'target'		=> substr( $target, 0-min(250, strlen( $target ))),
			'data'			=> serialize($GLOBALS),
			'level'			=> Logger::CRITICAL
		));
	}
 
	return false;
}

include/error/exceptionHandler.inc.php :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function exceptionHandler( $exception ) {
	global $engine;
 
 
	$_SESSION['lastException'] = $exception;
 
	$message = 'An error happened :'."\n\n".'Error : '."\n".$exception."\n\n".'StackTrace : '.debug_backtrace()."\r\n".'Informations diverses : '."\n".print_r( $GLOBALS, true )."\n";
 
	mail(
	        'email@company.com',
	        'MyProject : Error : '.$exception->getFile().':'.$exception->getLine(),
	        $message
	);
 
	$target = $exception->getFile().':'.$exception->getLine();
 
	if ( ! $engine['bug'] ) {
		$engine['bug'] = true;
		Logger::log(array(
			'message'		=> 'An exception was thrown',
			'type'			=> 'error/exception',
			'target'		=> substr( $target, 0-min(250, strlen( $target ))),
			'data'			=> serialize($GLOBALS),
			'level'			=> Logger::CRITICAL
		));
	}
 
	return false;
}

debug_backtrace requires PHP 4.3 and set_error_handler only supports error types since PHP 5.0. So, if you plan on using this on a PHP 4.X host, you have to make sure your code doesn’t throw E_NOTICE errors. My code is never E_NOTICE error safe.

2 thoughts on “Automatic error reporting in PHP”

  1. Very interesting code and benchmarking … my website is fully PHP driven, if I also cache it like in your example, will it load faster? i did a quick read trough all of the content you have here… its quite a lot, but good :)

  2. This post isn’t about caching but error reporting. You be speaking about the WordPress APC caching post.

    Anyway, caching in PHP is almost always a good choice because the language is very slow. Fetching is always better than generating. So, there’s a pretty big chance this also applies to your website.
    You can cache from database, from file, from memory (APC) and something a little bit between memory and database : memcached. The fastest (but not distributed) technique is APC caching.

Leave a Reply

Your email address will not be published. Required fields are marked *