Error Handler - a powerful debugging and monitoring assistant

This is a short but descriptive manual and user's guide of ErrorHandler includes.
It also describes the basic principles and considerations of developing ErrorHandler includes (mainly in Background sections).
Please, take a look at the list of the most important informations and changes!

Copyright terms

As you can realize the copyright terms are slightly modified version of PostgreSQL's ones. I hope much copy of copyright terms are not prohibited by any law or authority and I didn't break any rule. If it does not hold where you apply this product or its pieces, you are kindly asked to remove the last two paragraph and the reference to them from the preceding paragraph.

Bruce Momjiam is one of the PostgreSQL core developers and currently also the vice president of Great Bridge, a PostgreSQL support company, he said:

"I personally find that the fewer restrictions, the easier things are to understand, the better. I think that a lot of people don't really understand the implications of, for example, the GPL license because it's a long document. It's very complicated, too, it really has a lot of things, it doesn't cover completely so you are left not understanding what's legal to do, or what's not legal to do. "
I think he is absolutely right. That is why I dare to use their copyright for my own purpose.

By the way, PostgreSQL is one of my favourite developing tool (not only among RDBMS'), you should try it if you have any spare time.

--COPYRIGHT----------------------------------------------------------------
 Error Handler Copyright by all of us 
 Permission to use, copy, modify, and distribute this software and 
 its documentation for any purpose, without fee, and without a written 
 agreement is hereby granted, provided that the above copyright notice 
 and this paragraph and the following two paragraphs appear in all copies. 
 
 IN NO EVENT SHALL i BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, 
 INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, 
 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
 EVEN IF i HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

 i SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS-IS" BASIS, 
 AND i HAS NO OBLIGATIONS TO PROVIDE MAINTAINANCE, SUPPORT, UPDATES, 
 ENHANCEMENTS, OR MODIFICATIONS.
 BUT i LIKE TO VERY MUCH.
--------------------------------------------------------------------------

Information and Changes

Current version: 1.2.0 last modified, 31st January 2002.
I've implemented several new features since the last release. All these features have been tested:

ErrorHandler distribution contains several files. The list of files in the current distribution is following:

$ls -1
readme.1st
ErrorHandler.inc
manual.html
reference.html
try.php

Although the file only needed is

All other files comes along with these ones are only for demonstrating ErrorHandler functionality.

Manual

Error Reporting Features

CONTEXT report

Description: prints variable context, that is, dumps the array that points to the active symbol table at the point the error occurred.
CONTEXT report has a special mode: strict. It means only those variables to be reported which appear in the code fragment extracted by SOURCE report. Beware, you get nothing in strict mode unless you use SOURCE report!

You can exclude arbitrary variable(s) from CONTEXT report either to save process time and space to the log file, or to hide sensitive data. For example, if you are using a template engine (ie. Smarty), you may make ErrorHandler skip the variable instance of object Smarty (e.g. $smarty), which has usually numerous large properties. The main goal is that reports and logmessages may be shorter with excluding unnecessary variables (less resource consumption, network traffic, etc).

The latter case is when you want to hide some sensitive information stored in variables, such as passwords, connection strings, or filepaths. If a variable is excluded, then neither its name nor its proper content will be displayed or logged, only the following message will introduce the report: Some variables may have been excluded. Noone can sniff your secrets from error reports or log mails, because ErrorHandler does not betray this kind of information.

ErrorHandler use its own mechanism to retrieve variable structure, similar to var_dump or print_r. You can specify 'level', that is, the maximum depth in a non-scalar variable to be traversed and displayed by ErrorHandler. It can be applied to arrays and objects only, obviously.

Background: In a hurry I often make silly mistakes, like changing the right order of arguments in a function call, not properly initialized variables in very divergent flow control. It can be very hard to discover which variable has not been set properly. CONTEXT report makes sense in such case.

Configuration directive values
flag value
(example)
description
'strict' n.a. switch 'strict' mode on
'level' number
5
specifies the maximum depth level be traversed
'exclude' array or string(s) containing variable names
array('password', 'connection') or simply
'password', 'connection'
excludes the specified variable from CONTEXT report

CUSTOM report

Description: appends an additional descriptive error string from a global array named by the CUSTOM report configuration variable, if error fired by user (trigger_error, user_error). The original error message supplied in the first argument of trigger_error (or user_error) treated as a key to this array.

Background: trigger_error is used intensively in order not to pollute the code unnecessarily with error handling code fragments. The common practice is that only a 'reference' is passed to the error-handling function. This reference is the name of the function which causes the error and it addresses the real descriptive error-string in the global named by this configuration directive.
It may be helpful to set up a poor man's multilanguage or per-directory error handling support.

Configuration directive value: the name of the global array ie.: 'USER_ERROR'

Note: A short example in 'error.message.inc', please have a look at it!

LOGGING

Descpription: ErrorHandler is able to log each error message to a specified location. This location can be a file, an e-mailbox or the system logger. It can be very helpful - especially via e-mail - to monitor a remote server in production state while users are not disturbed by frustrating error messages on their screens.

The log message contains the reports that is actually enabled. For example, if SOURCE report is actually disabled, then no source fragment will be added to the logmessage. It is only a copy of what may be sent to the browser.

See also SILENT report!

Configuration directive values
LOGGING TYPE
(predefined constant)
LOGGING TARGET
(example)
description
SYSTEM_LOG should be undefined
null
sends the log message to the system logger
MAIL_LOG comma separated list of email-addresses
jonnhy@i.am, happy@box.com
sends an email to the given recepient
FILE_LOG full path to logfile
'/var/log/php.log'
appends the log message to the given file
MULTI_LOG array enumerating the logging targets with the respective logging types as keys.
array(FILE_LOG =>'/var/log/php.log', 'MAIL_LOG' => 'johnny@i.am')
more than one logging destination can be specified

Automatic Log Target Detecting Logging (ATDLOG)

Descpription: You can specify any kind of logging type and destination to any included PHP file and the main script, of course. This operation is called registration. Thus, when error occurs in a previously registered PHP file the corresponding error report will be sent to the specified logging destination - additionally.

This logging mechanism is also affected by the other configuration directives. For example: if SOURCE report is actually disabled then no source fragment will be added to the logmessage.
See the LOGGING examples!

Background: This feature may ease the teamwork. Developers can be automatically notified on errors in a particular piece of code which they are involved in. You can easily group the related error messages when developing a fairly complex site with many includes.

SILENT report

Description: In silent mode neither error messages nor any report layouts appear in the current page, only a customized error page will be displayed. Some dynamically generated information can be shown within this page, if it contains PHP code. Prior to inclusion the previous content of output buffer will be swept out, so to get the expected result Output Buffering needs to be turned on. (It's done automatically when instantiating ErrorHandler.) Enabling SILENT report automatically activates silent mode and additonal report features (CUSTOM, SOURCE, CONTEXT report) can be accessed with the LOGGING report (can be read from the logging target).

Note: As mentioned, the file will be included, so you can access all variables from the symbol table of ErrorHandler() or ErrorHandler::HandleError() method.

Background: This feature is very useful in production sites. No error messages will be printed to the screen as part of the HTML output, so during an accidental misbehaviour noone can get to know any secure information of your site, such as: passwords, script names, database configuration, etc.

Configuration directive value: the name of the customized error page to be displayed.

Note: the file must be accessible via the server's filesystem. Remote files are not allowed.

SOURCE report

Description: prints the corresponding source code fragment where the error encountered. ErrorHandler highlights this fragment with the "colours for Syntax Highlighting mode" given in PHP.ini. SOURCE report is available only if SILENT report is disabled. (see SILENT report!).

Background: It may help you to concentrate on the error source and may save that a huge code flow distracts your attention.

Configuration directive value:

  1. 0 = only the line where the error encountered
  2. 1..n = how many lines to be printed surrounding that line
  3. 'block' - preserved for further development

REPORT level

Description: what kind of malfunction/misbehaviour set to be handled by the ErrorHandler. As of 1.1.0 you can specify REPORT levels for each report layout independently. The most important effect is that no matter what error rises up, the auxiliary reports may be used in the LOGGING, while SILENT report is activated only in case of FATAL errors. Beside this, you can switch on/off the reports depending on the severity of the error, for example, CONTEXT is enabled for warnings and errors only, but SOURCE for all.
Whatever misbehaviour rises up the appropiate PHP configuration directives will be set accordingly to the current report settings, specifically:

Note: This makes sense to use SILENT and LOGGING report together.
Several error-type (E_ERROR, E_CORE_ERROR) can not be handled by a custom function, only the built-in one. (Error-logging & and suppressing error-messages in silent report still can be used!)

Other Features

CONSOLE window

Description: There is a debugging console included with ErrorHandler. Each error and debugging output generated by ErrorHandler can appear in a separate, pop-up window. The main goal is not to break the original page design and to gather all related reports in a separate place. The CONSOLE window is achieved by using JavaScript, so you must enable JavaScript and pop ups in your browser.

If CONSOLE is enabled, ErrorHandler gathers its output in a history, and prints it at the end of the request. It means

When ErrorHandler is launched (by calling its constructor), it opens an output buffer with a callback handler. This callback injects the actual content into the output at the end of the request. You are warned not to manipulate the output buffer allocated by ErrorHandler anyhow (flush or clear its content). It is recommended that ErrorHandler allocates the very first output buffer, and just make sure that you call ob_end_flush() to close only your buffers. What you must ensure is that _console() private method will be called back to insert the source of the CONSOLE window at the end of the request.

Variable Debugging (DEBUG)

Description: You can easily dump out a variable with ErrorHandler. This is very similiar to using print_r() or var_dump(), but ErrorHandler provides some additional capabilities over these functions due to the high level integration with other features.

Error Trapping (TRAPPING)

Description: Sometimes you need to test a piece of code or validate any kind of submission. In this case you can initialize an error trap to a code block. Any error which occurs in this block will not be reported, but be assembled instead. While the actual error trap is active, you can query whether an error with a given level has been occurred. There can be only one trap activated at a time.

Usage

First, you must include the ErrorHandler.inc. Consider to use require_once(). Anyway, this file registers a new error handling function named Lookup_ErrorHandler(). When the first(!) error occurs Lookup_ErrorHandler() searches the first object instance of ErrorHandler and stores its name. In any further invocation Lookup_ErrorHandler() uses the stored object name and calls the respective HandleError() method. It means you should instantiate only one ErrorHandler object in the global scope and use it all over your scripts (in functions or class-methods). Lookup_ErrorHandler stores neither a copy nor a reference of this object, so unset the ErrorHandler variable is not allowed.

Note: Since class methods can not be passed to set_error_handler() function, these can not be used as an error handler directly.

Note: If one needs to retrieve the name of the previous error-handler function or to restore it, use OLD_ERROR_HANLDER constant or restore_error_handler() - respectively.

You can set configuration directives, first, when you create the object. CONSOLE window must be set via constructor, and can not be changed afterwards.

Note:You are allowed to modify default argument values of the constructor.

<?php
require_once('ErrorHandler.inc');

// make an instance of ErrorHandler class, 
// always use references (=&), do not simply copy the returned object!

$error =& new ErrorHandler(
		E_ALL,                               // the default error level for all report
		MAIL_LOG, 'gerzson17@freemail.hu',   // log type and log target
		'./error.html',                      // path to silent page, or FALSE to switch off
		'USER_ERROR',                        // name of the array containing custom error messages 
		1,                                   // source size, or FALSE to switch off 
		'strict', 10,                        // context mode flag and its value
		TRUE                                 // use CONSOLE window, FALSE otherwise
	);
...
?>

I must admit that initializing the ErrorHandler via constructor arguments has a very limited capabilities. Alternatively, you can change almost any settings at run-time by calling the general wrapper method report_layout() or the specific ones. report_layout() ensures a unified interface to manipulate the configuration directives. You can easily change the layouts and your script will be still readable. The first argument of report_layout() is one of the enumerated values for <report_name> (see below). The rest of the argument list is passed to the invoked method as its argument list.

Each report layout has its own configuring method. The methods' name match the following pattern:
set_<report_name>(), where
<report_name> stands for ALTDLOG, CONTEXT, CUSTOM, LOGGING, REPORT, SILENT, SOURCE.

Now change some settings!

// increase the SOURCE size around the error source
$error->report_layout('SOURCE', 2); // or $error->set_source(2);

// exclude $pwd from the CONTEXT report, because $pwd stores password to database
$error->set_context('exclude', 'pwd'); // or $error->report_layout('CONTEXT', 'exclude', 'pwd'); 

To disable a report layout, call the respective set_*() method with a single FALSE argument:

$error->report_layout('CONTEXT', FALSE); // or $error->set_context(FALSE);  
$error->report_layout('SOURCE', FALSE); // or $error->set_source(FALSE);
$error->report_layout('SILENT', FALSE); // or $error->set_silent(FALSE);

Using ErrorHandler inside a function: Lookup_ErrorHandler() calling without arguments returns the name of the ErrorHandler instance in the global scope. This variable name can be used to reference the original object in the following ways.

// 1. indexing the $GLOBALS array
function pg_start($role)
{
	// returns with the ErrorHandler's name in the global scope
	$error = Lookup_ErrorHandler();	

	$GLOBALS[$error]->set_context('exclude', 'pm', 'pw', 'user'); // not to show $pm $pw and $user variables

	$pm = '';
	if ( defined('DB_HOST') ){
		$pm .= 'host='.DB_HOST;
	if ( defined('DB_PORT') ){ 
		$pm .= ' port='.DB_PORT;
	}

	list($user, $pw) = get_dbuser($role);
	$pm .= ' dbname='.DB_NAME;
	$pm .= ' user='.$user;
	$pm .= ' password='.$pw;
	return pg_connect($pm);
}

// 2. using a reference in the local scope
function get_dbuser($role)
{
	$error =& $GLOBALS[Lookup_ErrorHandler()]; // reference assignment
	$error->set_source(FALSE);
	
	$shadows = file(SHADOW,'r') 
	foreach ( $shadows as $line ){
		$user = explode(':', $line);
		if ( $user[0] == $mapname ){
			return array($user[1],$user[2]);
		}
		trigger_error('get_passwd', E_USER_NOTICE);
		return false;
	}
	$error->set_source(TRUE); // restore previous settings for SOURCE report
}

Automatic Log Target Detecting examples: If more programmers work together, error logs can be grouped together based on the filenames. The authors can gather information about the misbehaviour of their scripts, from separate logfiles or mails.

// in db.inc - written by Joe
$error->set_altdlog(__FILE__, FILE_LOG, 'joe-db.log');

// in mail.inc - written by Ally
$error->set_altdlog(__FILE__, FILE_LOG, 'ally-mail.log');

// in template.inc script - written by Tom
$error->set_altdlog(__FILE__, MULI_LOG, array(MAIL_LOG => 'tom@example.com', FILE_LOG => 'template.log'));

Debugging Variables:

// the simplest usage
$error->debug($variable);

// the variable name can be provided
$error->debug($variable, 'variable');

// and filename and line number so as to find the corresponding debug output easier
$error->debug($variable, 'variable', __FILE__, __LINE__);

Error Trapping:

// all kinds of error be trapped
$error->set_error_trap(E_ALL);

// testing regular expession submitted by the user
preg_match("/$submitted_regexp/i", "");

if ( $error->is_trapped(E_WARNING) ){
	print "The regular expression compilation failed.\n";
	print "You must type a correct regular expression, once more.\n";
    
}
// disabling error trapping
$error->set_error_trap(); 

For detailed information about the exact argument list of each public method, see the ErrorHandler Reference!

Have a fun!