986 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
		
		
			
		
	
	
			986 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
|   | <?php | ||
|  | /** | ||
|  |  * Error Stack Implementation | ||
|  |  *  | ||
|  |  * This is an incredibly simple implementation of a very complex error handling | ||
|  |  * facility.  It contains the ability | ||
|  |  * to track multiple errors from multiple packages simultaneously.  In addition, | ||
|  |  * it can track errors of many levels, save data along with the error, context | ||
|  |  * information such as the exact file, line number, class and function that | ||
|  |  * generated the error, and if necessary, it can raise a traditional PEAR_Error. | ||
|  |  * It has built-in support for PEAR::Log, to log errors as they occur | ||
|  |  *  | ||
|  |  * Since version 0.2alpha, it is also possible to selectively ignore errors, | ||
|  |  * through the use of an error callback, see {@link pushCallback()} | ||
|  |  *  | ||
|  |  * Since version 0.3alpha, it is possible to specify the exception class | ||
|  |  * returned from {@link push()} | ||
|  |  * | ||
|  |  * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class.  This can | ||
|  |  * still be done quite handily in an error callback or by manipulating the returned array | ||
|  |  * @category   Debugging | ||
|  |  * @package    PEAR_ErrorStack | ||
|  |  * @author     Greg Beaver <cellog@php.net> | ||
|  |  * @copyright  2004-2008 Greg Beaver | ||
|  |  * @license    http://opensource.org/licenses/bsd-license.php New BSD License | ||
|  |  * @version    CVS: $Id: ErrorStack.php 307683 2011-01-23 21:56:12Z dufuz $ | ||
|  |  * @link       http://pear.php.net/package/PEAR_ErrorStack | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Singleton storage | ||
|  |  *  | ||
|  |  * Format: | ||
|  |  * <pre> | ||
|  |  * array( | ||
|  |  *  'package1' => PEAR_ErrorStack object, | ||
|  |  *  'package2' => PEAR_ErrorStack object, | ||
|  |  *  ... | ||
|  |  * ) | ||
|  |  * </pre> | ||
|  |  * @access private | ||
|  |  * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] | ||
|  |  */ | ||
|  | $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); | ||
|  | 
 | ||
|  | /** | ||
|  |  * Global error callback (default) | ||
|  |  *  | ||
|  |  * This is only used if set to non-false.  * is the default callback for | ||
|  |  * all packages, whereas specific packages may set a default callback | ||
|  |  * for all instances, regardless of whether they are a singleton or not. | ||
|  |  * | ||
|  |  * To exclude non-singletons, only set the local callback for the singleton | ||
|  |  * @see PEAR_ErrorStack::setDefaultCallback() | ||
|  |  * @access private | ||
|  |  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] | ||
|  |  */ | ||
|  | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( | ||
|  |     '*' => false, | ||
|  | ); | ||
|  | 
 | ||
|  | /** | ||
|  |  * Global Log object (default) | ||
|  |  *  | ||
|  |  * This is only used if set to non-false.  Use to set a default log object for | ||
|  |  * all stacks, regardless of instantiation order or location | ||
|  |  * @see PEAR_ErrorStack::setDefaultLogger() | ||
|  |  * @access private | ||
|  |  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] | ||
|  |  */ | ||
|  | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Global Overriding Callback | ||
|  |  *  | ||
|  |  * This callback will override any error callbacks that specific loggers have set. | ||
|  |  * Use with EXTREME caution | ||
|  |  * @see PEAR_ErrorStack::staticPushCallback() | ||
|  |  * @access private | ||
|  |  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] | ||
|  |  */ | ||
|  | $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); | ||
|  | 
 | ||
|  | /**#@+
 | ||
|  |  * One of four possible return values from the error Callback | ||
|  |  * @see PEAR_ErrorStack::_errorCallback() | ||
|  |  */ | ||
|  | /** | ||
|  |  * If this is returned, then the error will be both pushed onto the stack | ||
|  |  * and logged. | ||
|  |  */ | ||
|  | define('PEAR_ERRORSTACK_PUSHANDLOG', 1); | ||
|  | /** | ||
|  |  * If this is returned, then the error will only be pushed onto the stack, | ||
|  |  * and not logged. | ||
|  |  */ | ||
|  | define('PEAR_ERRORSTACK_PUSH', 2); | ||
|  | /** | ||
|  |  * If this is returned, then the error will only be logged, but not pushed | ||
|  |  * onto the error stack. | ||
|  |  */ | ||
|  | define('PEAR_ERRORSTACK_LOG', 3); | ||
|  | /** | ||
|  |  * If this is returned, then the error is completely ignored. | ||
|  |  */ | ||
|  | define('PEAR_ERRORSTACK_IGNORE', 4); | ||
|  | /** | ||
|  |  * If this is returned, then the error is logged and die() is called. | ||
|  |  */ | ||
|  | define('PEAR_ERRORSTACK_DIE', 5); | ||
|  | /**#@-*/ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in | ||
|  |  * the singleton method. | ||
|  |  */ | ||
|  | define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); | ||
|  | 
 | ||
|  | /** | ||
|  |  * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} | ||
|  |  * that has no __toString() method | ||
|  |  */ | ||
|  | define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); | ||
|  | /** | ||
|  |  * Error Stack Implementation | ||
|  |  * | ||
|  |  * Usage: | ||
|  |  * <code> | ||
|  |  * // global error stack
 | ||
|  |  * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); | ||
|  |  * // local error stack
 | ||
|  |  * $local_stack = new PEAR_ErrorStack('MyPackage'); | ||
|  |  * </code> | ||
|  |  * @author     Greg Beaver <cellog@php.net> | ||
|  |  * @version    1.9.2 | ||
|  |  * @package    PEAR_ErrorStack | ||
|  |  * @category   Debugging | ||
|  |  * @copyright  2004-2008 Greg Beaver | ||
|  |  * @license    http://opensource.org/licenses/bsd-license.php New BSD License | ||
|  |  * @version    CVS: $Id: ErrorStack.php 307683 2011-01-23 21:56:12Z dufuz $ | ||
|  |  * @link       http://pear.php.net/package/PEAR_ErrorStack | ||
|  |  */ | ||
|  | class PEAR_ErrorStack { | ||
|  |     /** | ||
|  |      * Errors are stored in the order that they are pushed on the stack. | ||
|  |      * @since 0.4alpha Errors are no longer organized by error level. | ||
|  |      * This renders pop() nearly unusable, and levels could be more easily | ||
|  |      * handled in a callback anyway | ||
|  |      * @var array | ||
|  |      * @access private | ||
|  |      */ | ||
|  |     var $_errors = array(); | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Storage of errors by level. | ||
|  |      * | ||
|  |      * Allows easy retrieval and deletion of only errors from a particular level | ||
|  |      * @since PEAR 1.4.0dev | ||
|  |      * @var array | ||
|  |      * @access private | ||
|  |      */ | ||
|  |     var $_errorsByLevel = array(); | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Package name this error stack represents | ||
|  |      * @var string | ||
|  |      * @access protected | ||
|  |      */ | ||
|  |     var $_package; | ||
|  |      | ||
|  |     /** | ||
|  |      * Determines whether a PEAR_Error is thrown upon every error addition | ||
|  |      * @var boolean | ||
|  |      * @access private | ||
|  |      */ | ||
|  |     var $_compat = false; | ||
|  |      | ||
|  |     /** | ||
|  |      * If set to a valid callback, this will be used to generate the error | ||
|  |      * message from the error code, otherwise the message passed in will be | ||
|  |      * used | ||
|  |      * @var false|string|array | ||
|  |      * @access private | ||
|  |      */ | ||
|  |     var $_msgCallback = false; | ||
|  |      | ||
|  |     /** | ||
|  |      * If set to a valid callback, this will be used to generate the error | ||
|  |      * context for an error.  For PHP-related errors, this will be a file | ||
|  |      * and line number as retrieved from debug_backtrace(), but can be | ||
|  |      * customized for other purposes.  The error might actually be in a separate | ||
|  |      * configuration file, or in a database query. | ||
|  |      * @var false|string|array | ||
|  |      * @access protected | ||
|  |      */ | ||
|  |     var $_contextCallback = false; | ||
|  |      | ||
|  |     /** | ||
|  |      * If set to a valid callback, this will be called every time an error | ||
|  |      * is pushed onto the stack.  The return value will be used to determine | ||
|  |      * whether to allow an error to be pushed or logged. | ||
|  |      *  | ||
|  |      * The return value must be one an PEAR_ERRORSTACK_* constant | ||
|  |      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG | ||
|  |      * @var false|string|array | ||
|  |      * @access protected | ||
|  |      */ | ||
|  |     var $_errorCallback = array(); | ||
|  |      | ||
|  |     /** | ||
|  |      * PEAR::Log object for logging errors | ||
|  |      * @var false|Log | ||
|  |      * @access protected | ||
|  |      */ | ||
|  |     var $_logger = false; | ||
|  |      | ||
|  |     /** | ||
|  |      * Error messages - designed to be overridden | ||
|  |      * @var array | ||
|  |      * @abstract | ||
|  |      */ | ||
|  |     var $_errorMsgs = array(); | ||
|  |      | ||
|  |     /** | ||
|  |      * Set up a new error stack | ||
|  |      *  | ||
|  |      * @param string   $package name of the package this error stack represents | ||
|  |      * @param callback $msgCallback callback used for error message generation | ||
|  |      * @param callback $contextCallback callback used for context generation, | ||
|  |      *                 defaults to {@link getFileLine()} | ||
|  |      * @param boolean  $throwPEAR_Error | ||
|  |      */ | ||
|  |     function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false, | ||
|  |                          $throwPEAR_Error = false) | ||
|  |     { | ||
|  |         $this->_package = $package; | ||
|  |         $this->setMessageCallback($msgCallback); | ||
|  |         $this->setContextCallback($contextCallback); | ||
|  |         $this->_compat = $throwPEAR_Error; | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Return a single error stack for this package. | ||
|  |      *  | ||
|  |      * Note that all parameters are ignored if the stack for package $package | ||
|  |      * has already been instantiated | ||
|  |      * @param string   $package name of the package this error stack represents | ||
|  |      * @param callback $msgCallback callback used for error message generation | ||
|  |      * @param callback $contextCallback callback used for context generation, | ||
|  |      *                 defaults to {@link getFileLine()} | ||
|  |      * @param boolean  $throwPEAR_Error | ||
|  |      * @param string   $stackClass class to instantiate | ||
|  |      * @static | ||
|  |      * @return PEAR_ErrorStack | ||
|  |      */ | ||
|  |     function &singleton($package, $msgCallback = false, $contextCallback = false, | ||
|  |                          $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack') | ||
|  |     { | ||
|  |         if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { | ||
|  |             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; | ||
|  |         } | ||
|  |         if (!class_exists($stackClass)) { | ||
|  |             if (function_exists('debug_backtrace')) { | ||
|  |                 $trace = debug_backtrace(); | ||
|  |             } | ||
|  |             PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, | ||
|  |                 'exception', array('stackclass' => $stackClass), | ||
|  |                 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', | ||
|  |                 false, $trace); | ||
|  |         } | ||
|  |         $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = | ||
|  |             new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); | ||
|  | 
 | ||
|  |         return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Internal error handler for PEAR_ErrorStack class | ||
|  |      *  | ||
|  |      * Dies if the error is an exception (and would have died anyway) | ||
|  |      * @access private | ||
|  |      */ | ||
|  |     function _handleError($err) | ||
|  |     { | ||
|  |         if ($err['level'] == 'exception') { | ||
|  |             $message = $err['message']; | ||
|  |             if (isset($_SERVER['REQUEST_URI'])) { | ||
|  |                 echo '<br />'; | ||
|  |             } else { | ||
|  |                 echo "\n"; | ||
|  |             } | ||
|  |             var_dump($err['context']); | ||
|  |             die($message); | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Set up a PEAR::Log object for all error stacks that don't have one | ||
|  |      * @param Log $log  | ||
|  |      * @static | ||
|  |      */ | ||
|  |     function setDefaultLogger(&$log) | ||
|  |     { | ||
|  |         if (is_object($log) && method_exists($log, 'log') ) { | ||
|  |             $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; | ||
|  |         } elseif (is_callable($log)) { | ||
|  |             $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; | ||
|  | 	} | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Set up a PEAR::Log object for this error stack | ||
|  |      * @param Log $log  | ||
|  |      */ | ||
|  |     function setLogger(&$log) | ||
|  |     { | ||
|  |         if (is_object($log) && method_exists($log, 'log') ) { | ||
|  |             $this->_logger = &$log; | ||
|  |         } elseif (is_callable($log)) { | ||
|  |             $this->_logger = &$log; | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Set an error code => error message mapping callback | ||
|  |      *  | ||
|  |      * This method sets the callback that can be used to generate error | ||
|  |      * messages for any instance | ||
|  |      * @param array|string Callback function/method | ||
|  |      */ | ||
|  |     function setMessageCallback($msgCallback) | ||
|  |     { | ||
|  |         if (!$msgCallback) { | ||
|  |             $this->_msgCallback = array(&$this, 'getErrorMessage'); | ||
|  |         } else { | ||
|  |             if (is_callable($msgCallback)) { | ||
|  |                 $this->_msgCallback = $msgCallback; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Get an error code => error message mapping callback | ||
|  |      *  | ||
|  |      * This method returns the current callback that can be used to generate error | ||
|  |      * messages | ||
|  |      * @return array|string|false Callback function/method or false if none | ||
|  |      */ | ||
|  |     function getMessageCallback() | ||
|  |     { | ||
|  |         return $this->_msgCallback; | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Sets a default callback to be used by all error stacks | ||
|  |      *  | ||
|  |      * This method sets the callback that can be used to generate error | ||
|  |      * messages for a singleton | ||
|  |      * @param array|string Callback function/method | ||
|  |      * @param string Package name, or false for all packages | ||
|  |      * @static | ||
|  |      */ | ||
|  |     function setDefaultCallback($callback = false, $package = false) | ||
|  |     { | ||
|  |         if (!is_callable($callback)) { | ||
|  |             $callback = false; | ||
|  |         } | ||
|  |         $package = $package ? $package : '*'; | ||
|  |         $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Set a callback that generates context information (location of error) for an error stack | ||
|  |      *  | ||
|  |      * This method sets the callback that can be used to generate context | ||
|  |      * information for an error.  Passing in NULL will disable context generation | ||
|  |      * and remove the expensive call to debug_backtrace() | ||
|  |      * @param array|string|null Callback function/method | ||
|  |      */ | ||
|  |     function setContextCallback($contextCallback) | ||
|  |     { | ||
|  |         if ($contextCallback === null) { | ||
|  |             return $this->_contextCallback = false; | ||
|  |         } | ||
|  |         if (!$contextCallback) { | ||
|  |             $this->_contextCallback = array(&$this, 'getFileLine'); | ||
|  |         } else { | ||
|  |             if (is_callable($contextCallback)) { | ||
|  |                 $this->_contextCallback = $contextCallback; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Set an error Callback | ||
|  |      * If set to a valid callback, this will be called every time an error | ||
|  |      * is pushed onto the stack.  The return value will be used to determine | ||
|  |      * whether to allow an error to be pushed or logged. | ||
|  |      *  | ||
|  |      * The return value must be one of the ERRORSTACK_* constants. | ||
|  |      *  | ||
|  |      * This functionality can be used to emulate PEAR's pushErrorHandling, and | ||
|  |      * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of | ||
|  |      * the error stack or logging | ||
|  |      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG | ||
|  |      * @see popCallback() | ||
|  |      * @param string|array $cb | ||
|  |      */ | ||
|  |     function pushCallback($cb) | ||
|  |     { | ||
|  |         array_push($this->_errorCallback, $cb); | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Remove a callback from the error callback stack | ||
|  |      * @see pushCallback() | ||
|  |      * @return array|string|false | ||
|  |      */ | ||
|  |     function popCallback() | ||
|  |     { | ||
|  |         if (!count($this->_errorCallback)) { | ||
|  |             return false; | ||
|  |         } | ||
|  |         return array_pop($this->_errorCallback); | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Set a temporary overriding error callback for every package error stack | ||
|  |      * | ||
|  |      * Use this to temporarily disable all existing callbacks (can be used | ||
|  |      * to emulate the @ operator, for instance) | ||
|  |      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG | ||
|  |      * @see staticPopCallback(), pushCallback() | ||
|  |      * @param string|array $cb | ||
|  |      * @static | ||
|  |      */ | ||
|  |     function staticPushCallback($cb) | ||
|  |     { | ||
|  |         array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Remove a temporary overriding error callback | ||
|  |      * @see staticPushCallback() | ||
|  |      * @return array|string|false | ||
|  |      * @static | ||
|  |      */ | ||
|  |     function staticPopCallback() | ||
|  |     { | ||
|  |         $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); | ||
|  |         if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { | ||
|  |             $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); | ||
|  |         } | ||
|  |         return $ret; | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Add an error to the stack | ||
|  |      *  | ||
|  |      * If the message generator exists, it is called with 2 parameters. | ||
|  |      *  - the current Error Stack object | ||
|  |      *  - an array that is in the same format as an error.  Available indices | ||
|  |      *    are 'code', 'package', 'time', 'params', 'level', and 'context' | ||
|  |      *  | ||
|  |      * Next, if the error should contain context information, this is | ||
|  |      * handled by the context grabbing method. | ||
|  |      * Finally, the error is pushed onto the proper error stack | ||
|  |      * @param int    $code      Package-specific error code | ||
|  |      * @param string $level     Error level.  This is NOT spell-checked | ||
|  |      * @param array  $params    associative array of error parameters | ||
|  |      * @param string $msg       Error message, or a portion of it if the message | ||
|  |      *                          is to be generated | ||
|  |      * @param array  $repackage If this error re-packages an error pushed by | ||
|  |      *                          another package, place the array returned from | ||
|  |      *                          {@link pop()} in this parameter | ||
|  |      * @param array  $backtrace Protected parameter: use this to pass in the | ||
|  |      *                          {@link debug_backtrace()} that should be used | ||
|  |      *                          to find error context | ||
|  |      * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also | ||
|  |      * thrown.  If a PEAR_Error is returned, the userinfo | ||
|  |      * property is set to the following array: | ||
|  |      *  | ||
|  |      * <code> | ||
|  |      * array( | ||
|  |      *    'code' => $code, | ||
|  |      *    'params' => $params, | ||
|  |      *    'package' => $this->_package, | ||
|  |      *    'level' => $level, | ||
|  |      *    'time' => time(), | ||
|  |      *    'context' => $context, | ||
|  |      *    'message' => $msg, | ||
|  |      * //['repackage' => $err] repackaged error array/Exception class
 | ||
|  |      * ); | ||
|  |      * </code> | ||
|  |      *  | ||
|  |      * Normally, the previous array is returned. | ||
|  |      */ | ||
|  |     function push($code, $level = 'error', $params = array(), $msg = false, | ||
|  |                   $repackage = false, $backtrace = false) | ||
|  |     { | ||
|  |         $context = false; | ||
|  |         // grab error context
 | ||
|  |         if ($this->_contextCallback) { | ||
|  |             if (!$backtrace) { | ||
|  |                 $backtrace = debug_backtrace(); | ||
|  |             } | ||
|  |             $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); | ||
|  |         } | ||
|  |          | ||
|  |         // save error
 | ||
|  |         $time = explode(' ', microtime()); | ||
|  |         $time = $time[1] + $time[0]; | ||
|  |         $err = array( | ||
|  |                 'code' => $code, | ||
|  |                 'params' => $params, | ||
|  |                 'package' => $this->_package, | ||
|  |                 'level' => $level, | ||
|  |                 'time' => $time, | ||
|  |                 'context' => $context, | ||
|  |                 'message' => $msg, | ||
|  |                ); | ||
|  | 
 | ||
|  |         if ($repackage) { | ||
|  |             $err['repackage'] = $repackage; | ||
|  |         } | ||
|  | 
 | ||
|  |         // set up the error message, if necessary
 | ||
|  |         if ($this->_msgCallback) { | ||
|  |             $msg = call_user_func_array($this->_msgCallback, | ||
|  |                                         array(&$this, $err)); | ||
|  |             $err['message'] = $msg; | ||
|  |         }         | ||
|  |         $push = $log = true; | ||
|  |         $die = false; | ||
|  |         // try the overriding callback first
 | ||
|  |         $callback = $this->staticPopCallback(); | ||
|  |         if ($callback) { | ||
|  |             $this->staticPushCallback($callback); | ||
|  |         } | ||
|  |         if (!is_callable($callback)) { | ||
|  |             // try the local callback next
 | ||
|  |             $callback = $this->popCallback(); | ||
|  |             if (is_callable($callback)) { | ||
|  |                 $this->pushCallback($callback); | ||
|  |             } else { | ||
|  |                 // try the default callback
 | ||
|  |                 $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? | ||
|  |                     $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : | ||
|  |                     $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; | ||
|  |             } | ||
|  |         } | ||
|  |         if (is_callable($callback)) { | ||
|  |             switch(call_user_func($callback, $err)){ | ||
|  |             	case PEAR_ERRORSTACK_IGNORE:  | ||
|  |             		return $err; | ||
|  |         		break; | ||
|  |             	case PEAR_ERRORSTACK_PUSH:  | ||
|  |             		$log = false; | ||
|  |         		break; | ||
|  |             	case PEAR_ERRORSTACK_LOG:  | ||
|  |             		$push = false; | ||
|  |         		break; | ||
|  |             	case PEAR_ERRORSTACK_DIE:  | ||
|  |             		$die = true; | ||
|  |         		break; | ||
|  |                 // anything else returned has the same effect as pushandlog
 | ||
|  |             } | ||
|  |         } | ||
|  |         if ($push) { | ||
|  |             array_unshift($this->_errors, $err); | ||
|  |             if (!isset($this->_errorsByLevel[$err['level']])) { | ||
|  |                 $this->_errorsByLevel[$err['level']] = array(); | ||
|  |             } | ||
|  |             $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; | ||
|  |         } | ||
|  |         if ($log) { | ||
|  |             if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { | ||
|  |                 $this->_log($err); | ||
|  |             } | ||
|  |         } | ||
|  |         if ($die) { | ||
|  |             die(); | ||
|  |         } | ||
|  |         if ($this->_compat && $push) { | ||
|  |             return $this->raiseError($msg, $code, null, null, $err); | ||
|  |         } | ||
|  |         return $err; | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Static version of {@link push()} | ||
|  |      *  | ||
|  |      * @param string $package   Package name this error belongs to | ||
|  |      * @param int    $code      Package-specific error code | ||
|  |      * @param string $level     Error level.  This is NOT spell-checked | ||
|  |      * @param array  $params    associative array of error parameters | ||
|  |      * @param string $msg       Error message, or a portion of it if the message | ||
|  |      *                          is to be generated | ||
|  |      * @param array  $repackage If this error re-packages an error pushed by | ||
|  |      *                          another package, place the array returned from | ||
|  |      *                          {@link pop()} in this parameter | ||
|  |      * @param array  $backtrace Protected parameter: use this to pass in the | ||
|  |      *                          {@link debug_backtrace()} that should be used | ||
|  |      *                          to find error context | ||
|  |      * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also | ||
|  |      *                          thrown.  see docs for {@link push()} | ||
|  |      * @static | ||
|  |      */ | ||
|  |     function staticPush($package, $code, $level = 'error', $params = array(), | ||
|  |                         $msg = false, $repackage = false, $backtrace = false) | ||
|  |     { | ||
|  |         $s = &PEAR_ErrorStack::singleton($package); | ||
|  |         if ($s->_contextCallback) { | ||
|  |             if (!$backtrace) { | ||
|  |                 if (function_exists('debug_backtrace')) { | ||
|  |                     $backtrace = debug_backtrace(); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |         return $s->push($code, $level, $params, $msg, $repackage, $backtrace); | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Log an error using PEAR::Log | ||
|  |      * @param array $err Error array | ||
|  |      * @param array $levels Error level => Log constant map | ||
|  |      * @access protected | ||
|  |      */ | ||
|  |     function _log($err) | ||
|  |     { | ||
|  |         if ($this->_logger) { | ||
|  |             $logger = &$this->_logger; | ||
|  |         } else { | ||
|  |             $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; | ||
|  |         } | ||
|  |         if (is_a($logger, 'Log')) { | ||
|  |             $levels = array( | ||
|  |                 'exception' => PEAR_LOG_CRIT, | ||
|  |                 'alert' => PEAR_LOG_ALERT, | ||
|  |                 'critical' => PEAR_LOG_CRIT, | ||
|  |                 'error' => PEAR_LOG_ERR, | ||
|  |                 'warning' => PEAR_LOG_WARNING, | ||
|  |                 'notice' => PEAR_LOG_NOTICE, | ||
|  |                 'info' => PEAR_LOG_INFO, | ||
|  |                 'debug' => PEAR_LOG_DEBUG); | ||
|  |             if (isset($levels[$err['level']])) { | ||
|  |                 $level = $levels[$err['level']]; | ||
|  |             } else { | ||
|  |                 $level = PEAR_LOG_INFO; | ||
|  |             } | ||
|  |             $logger->log($err['message'], $level, $err); | ||
|  |         } else { // support non-standard logs
 | ||
|  |             call_user_func($logger, $err); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |      | ||
|  |     /** | ||
|  |      * Pop an error off of the error stack | ||
|  |      *  | ||
|  |      * @return false|array | ||
|  |      * @since 0.4alpha it is no longer possible to specify a specific error | ||
|  |      * level to return - the last error pushed will be returned, instead | ||
|  |      */ | ||
|  |     function pop() | ||
|  |     { | ||
|  |         $err = @array_shift($this->_errors); | ||
|  |         if (!is_null($err)) { | ||
|  |             @array_pop($this->_errorsByLevel[$err['level']]); | ||
|  |             if (!count($this->_errorsByLevel[$err['level']])) { | ||
|  |                 unset($this->_errorsByLevel[$err['level']]); | ||
|  |             } | ||
|  |         } | ||
|  |         return $err; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Pop an error off of the error stack, static method | ||
|  |      * | ||
|  |      * @param string package name | ||
|  |      * @return boolean | ||
|  |      * @since PEAR1.5.0a1 | ||
|  |      */ | ||
|  |     function staticPop($package) | ||
|  |     { | ||
|  |         if ($package) { | ||
|  |             if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { | ||
|  |                 return false; | ||
|  |             } | ||
|  |             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Determine whether there are any errors on the stack | ||
|  |      * @param string|array Level name.  Use to determine if any errors | ||
|  |      * of level (string), or levels (array) have been pushed | ||
|  |      * @return boolean | ||
|  |      */ | ||
|  |     function hasErrors($level = false) | ||
|  |     { | ||
|  |         if ($level) { | ||
|  |             return isset($this->_errorsByLevel[$level]); | ||
|  |         } | ||
|  |         return count($this->_errors); | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Retrieve all errors since last purge | ||
|  |      *  | ||
|  |      * @param boolean set in order to empty the error stack | ||
|  |      * @param string level name, to return only errors of a particular severity | ||
|  |      * @return array | ||
|  |      */ | ||
|  |     function getErrors($purge = false, $level = false) | ||
|  |     { | ||
|  |         if (!$purge) { | ||
|  |             if ($level) { | ||
|  |                 if (!isset($this->_errorsByLevel[$level])) { | ||
|  |                     return array(); | ||
|  |                 } else { | ||
|  |                     return $this->_errorsByLevel[$level]; | ||
|  |                 } | ||
|  |             } else { | ||
|  |                 return $this->_errors; | ||
|  |             } | ||
|  |         } | ||
|  |         if ($level) { | ||
|  |             $ret = $this->_errorsByLevel[$level]; | ||
|  |             foreach ($this->_errorsByLevel[$level] as $i => $unused) { | ||
|  |                 // entries are references to the $_errors array
 | ||
|  |                 $this->_errorsByLevel[$level][$i] = false; | ||
|  |             } | ||
|  |             // array_filter removes all entries === false
 | ||
|  |             $this->_errors = array_filter($this->_errors); | ||
|  |             unset($this->_errorsByLevel[$level]); | ||
|  |             return $ret; | ||
|  |         } | ||
|  |         $ret = $this->_errors; | ||
|  |         $this->_errors = array(); | ||
|  |         $this->_errorsByLevel = array(); | ||
|  |         return $ret; | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Determine whether there are any errors on a single error stack, or on any error stack | ||
|  |      * | ||
|  |      * The optional parameter can be used to test the existence of any errors without the need of | ||
|  |      * singleton instantiation | ||
|  |      * @param string|false Package name to check for errors | ||
|  |      * @param string Level name to check for a particular severity | ||
|  |      * @return boolean | ||
|  |      * @static | ||
|  |      */ | ||
|  |     function staticHasErrors($package = false, $level = false) | ||
|  |     { | ||
|  |         if ($package) { | ||
|  |             if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { | ||
|  |                 return false; | ||
|  |             } | ||
|  |             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); | ||
|  |         } | ||
|  |         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { | ||
|  |             if ($obj->hasErrors($level)) { | ||
|  |                 return true; | ||
|  |             } | ||
|  |         } | ||
|  |         return false; | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Get a list of all errors since last purge, organized by package | ||
|  |      * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be | ||
|  |      * @param boolean $purge Set to purge the error stack of existing errors | ||
|  |      * @param string  $level Set to a level name in order to retrieve only errors of a particular level | ||
|  |      * @param boolean $merge Set to return a flat array, not organized by package | ||
|  |      * @param array   $sortfunc Function used to sort a merged array - default | ||
|  |      *        sorts by time, and should be good for most cases | ||
|  |      * @static | ||
|  |      * @return array  | ||
|  |      */ | ||
|  |     function staticGetErrors($purge = false, $level = false, $merge = false, | ||
|  |                              $sortfunc = array('PEAR_ErrorStack', '_sortErrors')) | ||
|  |     { | ||
|  |         $ret = array(); | ||
|  |         if (!is_callable($sortfunc)) { | ||
|  |             $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); | ||
|  |         } | ||
|  |         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { | ||
|  |             $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); | ||
|  |             if ($test) { | ||
|  |                 if ($merge) { | ||
|  |                     $ret = array_merge($ret, $test); | ||
|  |                 } else { | ||
|  |                     $ret[$package] = $test; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |         if ($merge) { | ||
|  |             usort($ret, $sortfunc); | ||
|  |         } | ||
|  |         return $ret; | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Error sorting function, sorts by time | ||
|  |      * @access private | ||
|  |      */ | ||
|  |     function _sortErrors($a, $b) | ||
|  |     { | ||
|  |         if ($a['time'] == $b['time']) { | ||
|  |             return 0; | ||
|  |         } | ||
|  |         if ($a['time'] < $b['time']) { | ||
|  |             return 1; | ||
|  |         } | ||
|  |         return -1; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Standard file/line number/function/class context callback | ||
|  |      * | ||
|  |      * This function uses a backtrace generated from {@link debug_backtrace()} | ||
|  |      * and so will not work at all in PHP < 4.3.0.  The frame should | ||
|  |      * reference the frame that contains the source of the error. | ||
|  |      * @return array|false either array('file' => file, 'line' => line, | ||
|  |      *         'function' => function name, 'class' => class name) or | ||
|  |      *         if this doesn't work, then false | ||
|  |      * @param unused | ||
|  |      * @param integer backtrace frame. | ||
|  |      * @param array Results of debug_backtrace() | ||
|  |      * @static | ||
|  |      */ | ||
|  |     function getFileLine($code, $params, $backtrace = null) | ||
|  |     { | ||
|  |         if ($backtrace === null) { | ||
|  |             return false; | ||
|  |         } | ||
|  |         $frame = 0; | ||
|  |         $functionframe = 1; | ||
|  |         if (!isset($backtrace[1])) { | ||
|  |             $functionframe = 0; | ||
|  |         } else { | ||
|  |             while (isset($backtrace[$functionframe]['function']) && | ||
|  |                   $backtrace[$functionframe]['function'] == 'eval' && | ||
|  |                   isset($backtrace[$functionframe + 1])) { | ||
|  |                 $functionframe++; | ||
|  |             } | ||
|  |         } | ||
|  |         if (isset($backtrace[$frame])) { | ||
|  |             if (!isset($backtrace[$frame]['file'])) { | ||
|  |                 $frame++; | ||
|  |             } | ||
|  |             $funcbacktrace = $backtrace[$functionframe]; | ||
|  |             $filebacktrace = $backtrace[$frame]; | ||
|  |             $ret = array('file' => $filebacktrace['file'], | ||
|  |                          'line' => $filebacktrace['line']); | ||
|  |             // rearrange for eval'd code or create function errors
 | ||
|  |             if (strpos($filebacktrace['file'], '(') &&  | ||
|  |             	  preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], | ||
|  |                   $matches)) { | ||
|  |                 $ret['file'] = $matches[1]; | ||
|  |                 $ret['line'] = $matches[2] + 0; | ||
|  |             } | ||
|  |             if (isset($funcbacktrace['function']) && isset($backtrace[1])) { | ||
|  |                 if ($funcbacktrace['function'] != 'eval') { | ||
|  |                     if ($funcbacktrace['function'] == '__lambda_func') { | ||
|  |                         $ret['function'] = 'create_function() code'; | ||
|  |                     } else { | ||
|  |                         $ret['function'] = $funcbacktrace['function']; | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             if (isset($funcbacktrace['class']) && isset($backtrace[1])) { | ||
|  |                 $ret['class'] = $funcbacktrace['class']; | ||
|  |             } | ||
|  |             return $ret; | ||
|  |         } | ||
|  |         return false; | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Standard error message generation callback | ||
|  |      *  | ||
|  |      * This method may also be called by a custom error message generator | ||
|  |      * to fill in template values from the params array, simply | ||
|  |      * set the third parameter to the error message template string to use | ||
|  |      *  | ||
|  |      * The special variable %__msg% is reserved: use it only to specify | ||
|  |      * where a message passed in by the user should be placed in the template, | ||
|  |      * like so: | ||
|  |      *  | ||
|  |      * Error message: %msg% - internal error | ||
|  |      *  | ||
|  |      * If the message passed like so: | ||
|  |      *  | ||
|  |      * <code> | ||
|  |      * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); | ||
|  |      * </code> | ||
|  |      *  | ||
|  |      * The returned error message will be "Error message: server error 500 -
 | ||
|  |      * internal error"
 | ||
|  |      * @param PEAR_ErrorStack | ||
|  |      * @param array | ||
|  |      * @param string|false Pre-generated error message template | ||
|  |      * @static | ||
|  |      * @return string | ||
|  |      */ | ||
|  |     function getErrorMessage(&$stack, $err, $template = false) | ||
|  |     { | ||
|  |         if ($template) { | ||
|  |             $mainmsg = $template; | ||
|  |         } else { | ||
|  |             $mainmsg = $stack->getErrorMessageTemplate($err['code']); | ||
|  |         } | ||
|  |         $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); | ||
|  |         if (is_array($err['params']) && count($err['params'])) { | ||
|  |             foreach ($err['params'] as $name => $val) { | ||
|  |                 if (is_array($val)) { | ||
|  |                     // @ is needed in case $val is a multi-dimensional array
 | ||
|  |                     $val = @implode(', ', $val); | ||
|  |                 } | ||
|  |                 if (is_object($val)) { | ||
|  |                     if (method_exists($val, '__toString')) { | ||
|  |                         $val = $val->__toString(); | ||
|  |                     } else { | ||
|  |                         PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, | ||
|  |                             'warning', array('obj' => get_class($val)), | ||
|  |                             'object %obj% passed into getErrorMessage, but has no __toString() method'); | ||
|  |                         $val = 'Object'; | ||
|  |                     } | ||
|  |                 } | ||
|  |                 $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); | ||
|  |             } | ||
|  |         } | ||
|  |         return $mainmsg; | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Standard Error Message Template generator from code | ||
|  |      * @return string | ||
|  |      */ | ||
|  |     function getErrorMessageTemplate($code) | ||
|  |     { | ||
|  |         if (!isset($this->_errorMsgs[$code])) { | ||
|  |             return '%__msg%'; | ||
|  |         } | ||
|  |         return $this->_errorMsgs[$code]; | ||
|  |     } | ||
|  |      | ||
|  |     /** | ||
|  |      * Set the Error Message Template array | ||
|  |      *  | ||
|  |      * The array format must be: | ||
|  |      * <pre> | ||
|  |      * array(error code => 'message template',...) | ||
|  |      * </pre> | ||
|  |      *  | ||
|  |      * Error message parameters passed into {@link push()} will be used as input | ||
|  |      * for the error message.  If the template is 'message %foo% was %bar%', and the | ||
|  |      * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will | ||
|  |      * be 'message one was six' | ||
|  |      * @return string | ||
|  |      */ | ||
|  |     function setErrorMessageTemplate($template) | ||
|  |     { | ||
|  |         $this->_errorMsgs = $template; | ||
|  |     } | ||
|  |      | ||
|  |      | ||
|  |     /** | ||
|  |      * emulate PEAR::raiseError() | ||
|  |      *  | ||
|  |      * @return PEAR_Error | ||
|  |      */ | ||
|  |     function raiseError() | ||
|  |     { | ||
|  |         require_once 'PEAR.php'; | ||
|  |         $args = func_get_args(); | ||
|  |         return call_user_func_array(array('PEAR', 'raiseError'), $args); | ||
|  |     } | ||
|  | } | ||
|  | $stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); | ||
|  | $stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); | ||
|  | ?>
 |