<?php
/**
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*/
/**
* Error behaviour constant, indicating:
* Continue the script.
*/
define('ZZOSS_ERROR_B_CONTINUE', 0);
/**
* Error behaviour constant, indicating:
* Stop script execution.
*/
define('ZZOSS_ERROR_B_EXIT', 1);
/**
* Error behaviour constant, indicating:
* Send error notification email.
*/
define('ZZOSS_ERROR_B_HANDLER', 2);
/**
* Error behaviour constant, indicating:
* Send error notification email.
*/
define('ZZOSS_ERROR_B_MAIL', 4);
/**
* Error behaviour constant, indicating:
* Display error message to client (e.g. browser).
*/
define('ZZOSS_ERROR_B_CLIENT', 8);
/**
* Error behaviour constant, indicating:
* Execute development callback function.
*/
define('ZZOSS_ERROR_B_DEV', 16);
/**
* Error behaviour constant, indicating:
* Write error message to log file.
*/
define('ZZOSS_ERROR_B_LOG', 32);
/**
* Do not rotate the error log file.
*/
define('ZZOSS_ERROR_ROTATE_NONE', 0);
/**
* Rotate error logfile daily.
*/
define('ZZOSS_ERROR_ROTATE_DAILY', 1);
/**
* Rotate error logfile monthly.
*/
define('ZZOSS_ERROR_ROTATE_MONTHLY', 2);
/**
* Rotate error logfile yearly.
*/
define('ZZOSS_ERROR_ROTATE_YEARLY', 3);
/**
* This is an error class that handles errors
* triggered by PHP.
*
* @package com.zzoss.error.lib
* @version $Id: Error.php,v 1.8 2004/01/29 14:07:06 ordnas Exp $
* @author Sandro Zic <hide@address.com>
* @copyright 2001-2003 ZZOSS GbR, http://www.zzoss.com
* @license LGPL
* @example tests/test.php Initial test script
*/
class ZZOSS_Error {
/**
* Mode of error capturing.
*
* @var bool
* @access private
* @see setMode()
*/
var $production = true;
/**
* Registry of behaviours of error capturing.
*
* @var array
* @access private
* @see setBehaviour()
*/
var $behaviours = array();
/**
* The behaviour of the current error.
*
* @var array
* @access private
* @see trigger()
*/
var $behaviour;
/**
* Recipients of error email.
*
* @var string
* @access private
* @see setRecipients()
*/
var $recipients = '';
/**
* Path of error log file.
*
* @var string
* @access private
* @see setLog()
*/
var $log = '';
/**
* Registry of callback functions for error
* notification output.
*
* @var array
* @access private
* @see setCallback()
*/
var $callback = array();
/**
* Decide if we capture errors in production or development mode.
*
* Use the following constants to set mode:
* ZZOSS_ERROR_MODE_PROD - We are in production mode.
* ZZOSS_ERROR_MODE_DEV - We are in development mode.
*/
function ZZOSS_Error($options = NULL)
{
if(isset($options['production'])){
$this->production = $options['production'];
}
// Turn on display_errors on development environment, turn it off
// on production environment
if($this->production){
// Suppress default PHP error output.
ini_set('display_errors', 0);
// Set behaviours.
$this->setBehaviour(E_WARNING, ZZOSS_ERROR_B_EXIT + ZZOSS_ERROR_B_HANDLER + ZZOSS_ERROR_B_MAIL + ZZOSS_ERROR_B_CLIENT + ZZOSS_ERROR_B_LOG);
$this->setBehaviour(E_NOTICE, ZZOSS_ERROR_B_CONTINUE);
$this->setBehaviour(E_USER_ERROR, ZZOSS_ERROR_B_EXIT + ZZOSS_ERROR_B_HANDLER + ZZOSS_ERROR_B_MAIL + ZZOSS_ERROR_B_CLIENT + ZZOSS_ERROR_B_LOG);
$this->setBehaviour(E_USER_WARNING, ZZOSS_ERROR_B_EXIT + ZZOSS_ERROR_B_HANDLER + ZZOSS_ERROR_B_MAIL + ZZOSS_ERROR_B_CLIENT + ZZOSS_ERROR_B_LOG);
$this->setBehaviour(E_USER_NOTICE, ZZOSS_ERROR_B_HANDLER + ZZOSS_ERROR_B_MAIL + ZZOSS_ERROR_B_LOG);
} else {
ini_set('display_errors', 1);
$this->setBehaviour(E_WARNING, ZZOSS_ERROR_B_DEV);
$this->setBehaviour(E_NOTICE, ZZOSS_ERROR_B_DEV);
$this->setBehaviour(E_USER_ERROR, ZZOSS_ERROR_B_DEV);
$this->setBehaviour(E_USER_WARNING, ZZOSS_ERROR_B_DEV);
$this->setBehaviour(E_USER_NOTICE, ZZOSS_ERROR_B_DEV);
}
// Set PHP error handler.
$handlerPhp = array(&$this, 'handlerPhp');
set_error_handler($handlerPhp);
// Set PEAR error handler.
if(is_callable(array('PEAR', 'setErrorHandling'))){
$handlerPear = array(&$this, 'handlerPear');
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, $handlerPear);
}
}
/**
* Capture PHP error handling and decide how to procede concerning
* the PHP error mapped to the ZZOSS_ERROR_B_* constants described
* below. Note that the error behaviour is set in a bitwise
* fashion, just like PHP error handling.
*
* Value | Constant | Meaning
* ----------------------------------------------------------------
* 0 | ZZOSS_ERROR_B_CONTINUE | Continue script execution.
* 1 | ZZOSS_ERROR_B_EXIT | Stop script execution.
* 2 | ZZOSS_ERROR_B_HANDLER | A handler that allows to do any PHP action..
* 4 | ZZOSS_ERROR_B_MAIL | Send error notification email.
* 8 | ZZOSS_ERROR_B_CLIENT | Display error message to client (e.g. browser).
* 16 | ZZOSS_ERROR_B_DEV | Specific for development mode, e.g. detailed
* | | error messages for client (e.g. browser).
* 32 | ZZOSS_ERROR_B_LOG | Write error message to log file.
*
* Behaviour depends on error mode, which decides if we are in a production
* or development environment. In a development environment, emails are
* not being sent, instead they will be displayed to the client. Also, log
* files will not be written.
*
* Please consult the PHP manual for further information:
* http://www.php.net/manual/en/ref.errorfunc.php#ini.error-log
*/
function setBehaviour($phperr, $behaviour)
{
$this->behaviours[$phperr] = $behaviour;
}
/**
* Set the identification string of this error object.
*/
function setIdent($ident)
{
$this->ident = $ident;
}
/**
* Send error notification per email to the specified address(es).
* Use comma to separate emails.
*/
function setRecipients($recipients)
{
$this->recipients = $recipients;
}
/**
* Set path of error log file and when to rotate.
*
* Choose from the following constants to set as the rotation
* parameter.
*
* ZZOSS_ERROR_ROTATE_NONE
* ZZOSS_ERROR_ROTATE_DAILY
* ZZOSS_ERROR_ROTATE_MONTHLY
* ZZOSS_ERROR_ROTATE_YEARLY
*/
function setLog($path, $rotate = ZZOSS_ERROR_ROTATE_MONTHLY)
{
$this->log_path = $path;
$this->log_rotate = $rotate;
}
/**
* Set the callback function for several error notification output
* types. If not defined, default output will be used.
*
* mail_subj - The name of the user defined function composing the email
* subject for error notification.
* mail_body - The name of the user defined function composing the email
* body for error notification.
* client - The name of the user defined function composing the
* client output for error notification in production mode.
* Client is for example a browser.
* dev - Output to client if in development mode.
* log - Function composing the string written to the error log file.
*/
function setCallback($type, $callback)
{
$this->callback[$type] = $callback;
}
/**
* Store the error status and trigger the error notification callbacks.
*
* @see status()
* @see _callback()
* @see setBehaviour()
*/
function trigger($type, $msg, $file, $line)
{
// Check, if this error type is supposed to trigger any action.
if($this->behaviours[$type]) {
$GLOBALS['ZZOSS_Error']['ident'] = $this->ident;
// The date time in ISO format.
$GLOBALS['ZZOSS_Error']['date'] = date('Y-m-d H:i:s');
$GLOBALS['ZZOSS_Error']['type'] = $type;
$GLOBALS['ZZOSS_Error']['behaviour'] = $this->behaviour = $this->behaviours[$type];
$GLOBALS['ZZOSS_Error']['message'] = $msg;
$GLOBALS['ZZOSS_Error']['file'] = $file;
$GLOBALS['ZZOSS_Error']['line'] = $line;
$GLOBALS['ZZOSS_Error']['parent'] = getenv('SCRIPT_FILENAME');
$GLOBALS['ZZOSS_Error']['request'] = $GLOBALS['ZZOSS_Error']['query'] = getenv('QUERY_STRING');
$GLOBALS['ZZOSS_Error']['host'] = getenv("HTTP_HOST");
$GLOBALS['ZZOSS_Error']['recipients'] = $this->recipients;
if(strlen($GLOBALS['ZZOSS_Error']['query'])){
$GLOBALS['ZZOSS_Error']['request'] .= '?'.$GLOBALS['ZZOSS_Error']['query'];
}
// Execute callbacks.
return $this->_callback();
}
}
/**
* Read the status of the error.
*
* 'ident' - The identifier of this error object.
* 'date' - The date and time when the error occured
* in ISO format YYYY-MM-DD hh:mm:ss.
* 'type' - The PHP error type (e.g. E_ERROR).
* 'behaviour' - The action taken for this error.
* 'message' - The error message.
* 'file' - The error file.
* 'line' - The error line.
* 'parent' - The parent script being executed while the error occured.
* This is different from the error file, which could be a
* file included in the parent script.
* 'request' - The URI of the client request.
* 'query' - The query string of the request, if available.
* 'host' - The host/domain.
*
* @see setBehaviour()
*/
function status($name, $val = NULL)
{
if(isset($GLOBALS['ZZOSS_Error'][$name])){
return $GLOBALS['ZZOSS_Error'][$name];
}
return false;
}
/**
* Translates an error status type to a human readable format.
*
* @see status()
*/
function statusTranslated($name)
{
if(isset($GLOBALS['ZZOSS_Error'][$name])){
switch($name){
case 'type':
$translated = array(
E_ERROR => 'E_ERROR',
E_WARNING => 'E_WARNING',
E_PARSE => 'E_PARSE',
E_NOTICE => 'E_NOTICE',
E_USER_ERROR => 'E_USER_ERROR',
E_USER_WARNING => 'E_USER_WARNING',
E_USER_NOTICE => 'E_USER_NOTICE'
);
return $translated[$GLOBALS['ZZOSS_Error']['type']];
break;
case 'behaviour':
$translated = array(
ZZOSS_ERROR_B_CONTINUE => 'ZZOSS_ERROR_B_CONTINUE',
ZZOSS_ERROR_B_EXIT => 'ZZOSS_ERROR_B_EXIT',
ZZOSS_ERROR_B_MAIL => 'ZZOSS_ERROR_B_MAIL',
ZZOSS_ERROR_B_CLIENT => 'ZZOSS_ERROR_B_CLIENT',
ZZOSS_ERROR_B_LOG => 'ZZOSS_ERROR_B_LOG',
ZZOSS_ERROR_B_DEV => 'ZZOSS_ERROR_B_DEV'
);
$behaviour = $GLOBALS['ZZOSS_Error']['behaviour'];
$output = '';
foreach($translated as $key => $val){
if($behaviour & $key){
$output .= $val.' & ';
}
}
return substr($output, 0, -3);
default:
return false;
break;
}
}
return false;
}
function _callback()
{
// Write error log file?
if($this->behaviour & ZZOSS_ERROR_B_LOG){
// Check if user defined callback has been specified, otherwise
// use default callback.
if(!isset($this->callback['log'])){
include_once 'callbacks.php';
$this->callback['log'] = 'zzoss_error_default_log';
} elseif(!function_exists($this->callback['log'])){
$this->_setError($this->callback['log'].' callback function does not exist.');
return false;
}
// Include PEAR::Log.
// Include PEAR::Log.
if(!@include_once('Log.php')){
echo 'Failed to include Log.php from PEAR::Log';
die();
}
$this->_callbackLog();
}
// Should we sent email error notification?
if($this->behaviour & ZZOSS_ERROR_B_MAIL){
// Check if user defined callback has been specified, otherwise
// use default callback.
if(!isset($this->callback['mail_subj'])){
include_once 'callbacks.php';
$this->callback['mail_subj'] = 'zzoss_error_default_mail_subj';
} elseif(!function_exists($this->callback['mail_subj'])){
$this->_setError($this->callback['mail_subj'].' callback function does not exist.');
return false;
}
if(!isset($this->callback['mail_body'])){
include_once 'callbacks.php';
$this->callback['mail_body'] = 'zzoss_error_default_mail_body';
} elseif(!function_exists($this->callback['mail_body'])){
$this->_setError($this->callback['mail_body'].' callback function does not exist.');
return false;
}
// Include PEAR::Log.
if(!@include_once('Log.php')){
echo 'Failed to include Log.php from PEAR::Log';
die();
}
$this->_callbackMail();
}
// Output error info to client/browser?
if($this->behaviour & ZZOSS_ERROR_B_CLIENT){
// Check if user defined callback has been specified, otherwise
// use default callback.
if(!isset($this->callback['client'])){
include_once 'callbacks.php';
$this->callback['client'] = 'zzoss_error_default_client';
} elseif(!function_exists($this->callback['client'])){
$this->_setError($this->callback['client'].' callback function does not exist.');
return false;
}
call_user_func($this->callback['client']);
}
// Output error info to client/browser?
if($this->behaviour & ZZOSS_ERROR_B_DEV){
// Check if user defined callback has been specified, otherwise
// use default callback.
if(!isset($this->callback['dev'])){
include_once 'callbacks.php';
$this->callback['dev'] = 'zzoss_error_default_dev';
} elseif(!function_exists($this->callback['dev'])){
$this->_setError($this->callback['dev'].' callback function does not exist.');
return false;
}
// Show development error notification.
call_user_func($this->callback['dev']);
}
// Are we supposed to stop the script from execution?
if($this->behaviour & ZZOSS_ERROR_B_EXIT){
exit;
}
return true;
}
function _callbackLog()
{
// If specified, write to the userdefined log file path.
if(strlen($this->log_path)){
switch($this->log_rotate){
case ZZOSS_ERROR_ROTATE_DAILY:
$log_postfix = '-'.date('Y-m-d');
break;
case ZZOSS_ERROR_ROTATE_MONTHLY:
$log_postfix = '-'.date('Y-m');
break;
case ZZOSS_ERROR_ROTATE_YEARLY:
$log_postfix = '-'.date('Y-m');
break;
}
$log_file = $this->log_path.$log_postfix;
$logger = &Log::singleton('file', $log_file, $this->ident);
} elseif(strlen(ini_get('error_log'))){
// No user defined path, hence we write to the PHP error log path.
$logger = &Log::singleton('error_log', PEAR_LOG_TYPE_SYSTEM, $this->ident);
}
$logger->log(call_user_func($this->callback['log']));
}
function _callbackMail()
{
$conf = array('subject' => call_user_func($this->callback['mail_subj']));
$logger = &Log::singleton('mail', $this->recipients, $this->ident, $conf);
$logger->log(call_user_func($this->callback['mail_body']));
}
/**
* Pass through function for PHP errors.
*
* @see ZZOSS_Error()
*/
function handlerPhp ($type, $message, $file, $line) {
$this->trigger($type, $message, $file, $line);
}
/**
* This method catches errors generated by Pear,
* transforms them to PHP errors and trigger them to the php_error_handler.
*
* @see ZZOSS_Error()
* @see handlerPhp()
*/
function handlerPear ( $error ) {
// add name of class
// add error information
$msg = $error->getMessage()."\n"
.$error->getDebugInfo()."\n\n"
.$error->toString();
trigger_error ($msg, E_USER_ERROR);
}
function _setError($error)
{
$this->errors = $error."\n";
}
function getErrors()
{
return $this->errors;
}
}
?>