home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / tmp / PEAR-1.7.1 / PEAR / ErrorStack.php < prev    next >
Encoding:
PHP Script  |  2008-02-15  |  33.2 KB  |  986 lines

  1. <?php
  2. /**
  3.  * Error Stack Implementation
  4.  * 
  5.  * This is an incredibly simple implementation of a very complex error handling
  6.  * facility.  It contains the ability
  7.  * to track multiple errors from multiple packages simultaneously.  In addition,
  8.  * it can track errors of many levels, save data along with the error, context
  9.  * information such as the exact file, line number, class and function that
  10.  * generated the error, and if necessary, it can raise a traditional PEAR_Error.
  11.  * It has built-in support for PEAR::Log, to log errors as they occur
  12.  * 
  13.  * Since version 0.2alpha, it is also possible to selectively ignore errors,
  14.  * through the use of an error callback, see {@link pushCallback()}
  15.  * 
  16.  * Since version 0.3alpha, it is possible to specify the exception class
  17.  * returned from {@link push()}
  18.  *
  19.  * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class.  This can
  20.  * still be done quite handily in an error callback or by manipulating the returned array
  21.  * @category   Debugging
  22.  * @package    PEAR_ErrorStack
  23.  * @author     Greg Beaver <cellog@php.net>
  24.  * @copyright  2004-2008 Greg Beaver
  25.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  26.  * @version    CVS: $Id: ErrorStack.php,v 1.28 2008/01/03 20:26:35 cellog Exp $
  27.  * @link       http://pear.php.net/package/PEAR_ErrorStack
  28.  */
  29.  
  30. /**
  31.  * Singleton storage
  32.  * 
  33.  * Format:
  34.  * <pre>
  35.  * array(
  36.  *  'package1' => PEAR_ErrorStack object,
  37.  *  'package2' => PEAR_ErrorStack object,
  38.  *  ...
  39.  * )
  40.  * </pre>
  41.  * @access private
  42.  * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
  43.  */
  44. $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
  45.  
  46. /**
  47.  * Global error callback (default)
  48.  * 
  49.  * This is only used if set to non-false.  * is the default callback for
  50.  * all packages, whereas specific packages may set a default callback
  51.  * for all instances, regardless of whether they are a singleton or not.
  52.  *
  53.  * To exclude non-singletons, only set the local callback for the singleton
  54.  * @see PEAR_ErrorStack::setDefaultCallback()
  55.  * @access private
  56.  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
  57.  */
  58. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
  59.     '*' => false,
  60. );
  61.  
  62. /**
  63.  * Global Log object (default)
  64.  * 
  65.  * This is only used if set to non-false.  Use to set a default log object for
  66.  * all stacks, regardless of instantiation order or location
  67.  * @see PEAR_ErrorStack::setDefaultLogger()
  68.  * @access private
  69.  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
  70.  */
  71. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
  72.  
  73. /**
  74.  * Global Overriding Callback
  75.  * 
  76.  * This callback will override any error callbacks that specific loggers have set.
  77.  * Use with EXTREME caution
  78.  * @see PEAR_ErrorStack::staticPushCallback()
  79.  * @access private
  80.  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
  81.  */
  82. $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
  83.  
  84. /**#@+
  85.  * One of four possible return values from the error Callback
  86.  * @see PEAR_ErrorStack::_errorCallback()
  87.  */
  88. /**
  89.  * If this is returned, then the error will be both pushed onto the stack
  90.  * and logged.
  91.  */
  92. define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
  93. /**
  94.  * If this is returned, then the error will only be pushed onto the stack,
  95.  * and not logged.
  96.  */
  97. define('PEAR_ERRORSTACK_PUSH', 2);
  98. /**
  99.  * If this is returned, then the error will only be logged, but not pushed
  100.  * onto the error stack.
  101.  */
  102. define('PEAR_ERRORSTACK_LOG', 3);
  103. /**
  104.  * If this is returned, then the error is completely ignored.
  105.  */
  106. define('PEAR_ERRORSTACK_IGNORE', 4);
  107. /**
  108.  * If this is returned, then the error is logged and die() is called.
  109.  */
  110. define('PEAR_ERRORSTACK_DIE', 5);
  111. /**#@-*/
  112.  
  113. /**
  114.  * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
  115.  * the singleton method.
  116.  */
  117. define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
  118.  
  119. /**
  120.  * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
  121.  * that has no __toString() method
  122.  */
  123. define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
  124. /**
  125.  * Error Stack Implementation
  126.  *
  127.  * Usage:
  128.  * <code>
  129.  * // global error stack
  130.  * $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
  131.  * // local error stack
  132.  * $local_stack = new PEAR_ErrorStack('MyPackage');
  133.  * </code>
  134.  * @author     Greg Beaver <cellog@php.net>
  135.  * @version    1.7.1
  136.  * @package    PEAR_ErrorStack
  137.  * @category   Debugging
  138.  * @copyright  2004-2008 Greg Beaver
  139.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  140.  * @version    CVS: $Id: ErrorStack.php,v 1.28 2008/01/03 20:26:35 cellog Exp $
  141.  * @link       http://pear.php.net/package/PEAR_ErrorStack
  142.  */
  143. class PEAR_ErrorStack {
  144.     /**
  145.      * Errors are stored in the order that they are pushed on the stack.
  146.      * @since 0.4alpha Errors are no longer organized by error level.
  147.      * This renders pop() nearly unusable, and levels could be more easily
  148.      * handled in a callback anyway
  149.      * @var array
  150.      * @access private
  151.      */
  152.     var $_errors = array();
  153.  
  154.     /**
  155.      * Storage of errors by level.
  156.      *
  157.      * Allows easy retrieval and deletion of only errors from a particular level
  158.      * @since PEAR 1.4.0dev
  159.      * @var array
  160.      * @access private
  161.      */
  162.     var $_errorsByLevel = array();
  163.  
  164.     /**
  165.      * Package name this error stack represents
  166.      * @var string
  167.      * @access protected
  168.      */
  169.     var $_package;
  170.     
  171.     /**
  172.      * Determines whether a PEAR_Error is thrown upon every error addition
  173.      * @var boolean
  174.      * @access private
  175.      */
  176.     var $_compat = false;
  177.     
  178.     /**
  179.      * If set to a valid callback, this will be used to generate the error
  180.      * message from the error code, otherwise the message passed in will be
  181.      * used
  182.      * @var false|string|array
  183.      * @access private
  184.      */
  185.     var $_msgCallback = false;
  186.     
  187.     /**
  188.      * If set to a valid callback, this will be used to generate the error
  189.      * context for an error.  For PHP-related errors, this will be a file
  190.      * and line number as retrieved from debug_backtrace(), but can be
  191.      * customized for other purposes.  The error might actually be in a separate
  192.      * configuration file, or in a database query.
  193.      * @var false|string|array
  194.      * @access protected
  195.      */
  196.     var $_contextCallback = false;
  197.     
  198.     /**
  199.      * If set to a valid callback, this will be called every time an error
  200.      * is pushed onto the stack.  The return value will be used to determine
  201.      * whether to allow an error to be pushed or logged.
  202.      * 
  203.      * The return value must be one an PEAR_ERRORSTACK_* constant
  204.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  205.      * @var false|string|array
  206.      * @access protected
  207.      */
  208.     var $_errorCallback = array();
  209.     
  210.     /**
  211.      * PEAR::Log object for logging errors
  212.      * @var false|Log
  213.      * @access protected
  214.      */
  215.     var $_logger = false;
  216.     
  217.     /**
  218.      * Error messages - designed to be overridden
  219.      * @var array
  220.      * @abstract
  221.      */
  222.     var $_errorMsgs = array();
  223.     
  224.     /**
  225.      * Set up a new error stack
  226.      * 
  227.      * @param string   $package name of the package this error stack represents
  228.      * @param callback $msgCallback callback used for error message generation
  229.      * @param callback $contextCallback callback used for context generation,
  230.      *                 defaults to {@link getFileLine()}
  231.      * @param boolean  $throwPEAR_Error
  232.      */
  233.     function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false,
  234.                          $throwPEAR_Error = false)
  235.     {
  236.         $this->_package = $package;
  237.         $this->setMessageCallback($msgCallback);
  238.         $this->setContextCallback($contextCallback);
  239.         $this->_compat = $throwPEAR_Error;
  240.     }
  241.     
  242.     /**
  243.      * Return a single error stack for this package.
  244.      * 
  245.      * Note that all parameters are ignored if the stack for package $package
  246.      * has already been instantiated
  247.      * @param string   $package name of the package this error stack represents
  248.      * @param callback $msgCallback callback used for error message generation
  249.      * @param callback $contextCallback callback used for context generation,
  250.      *                 defaults to {@link getFileLine()}
  251.      * @param boolean  $throwPEAR_Error
  252.      * @param string   $stackClass class to instantiate
  253.      * @static
  254.      * @return PEAR_ErrorStack
  255.      */
  256.     function &singleton($package, $msgCallback = false, $contextCallback = false,
  257.                          $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack')
  258.     {
  259.         if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  260.             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
  261.         }
  262.         if (!class_exists($stackClass)) {
  263.             if (function_exists('debug_backtrace')) {
  264.                 $trace = debug_backtrace();
  265.             }
  266.             PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
  267.                 'exception', array('stackclass' => $stackClass),
  268.                 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
  269.                 false, $trace);
  270.         }
  271.         $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
  272.             new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
  273.  
  274.         return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
  275.     }
  276.  
  277.     /**
  278.      * Internal error handler for PEAR_ErrorStack class
  279.      * 
  280.      * Dies if the error is an exception (and would have died anyway)
  281.      * @access private
  282.      */
  283.     function _handleError($err)
  284.     {
  285.         if ($err['level'] == 'exception') {
  286.             $message = $err['message'];
  287.             if (isset($_SERVER['REQUEST_URI'])) {
  288.                 echo '<br />';
  289.             } else {
  290.                 echo "\n";
  291.             }
  292.             var_dump($err['context']);
  293.             die($message);
  294.         }
  295.     }
  296.     
  297.     /**
  298.      * Set up a PEAR::Log object for all error stacks that don't have one
  299.      * @param Log $log 
  300.      * @static
  301.      */
  302.     function setDefaultLogger(&$log)
  303.     {
  304.         if (is_object($log) && method_exists($log, 'log') ) {
  305.             $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
  306.         } elseif (is_callable($log)) {
  307.             $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
  308.     }
  309.     }
  310.     
  311.     /**
  312.      * Set up a PEAR::Log object for this error stack
  313.      * @param Log $log 
  314.      */
  315.     function setLogger(&$log)
  316.     {
  317.         if (is_object($log) && method_exists($log, 'log') ) {
  318.             $this->_logger = &$log;
  319.         } elseif (is_callable($log)) {
  320.             $this->_logger = &$log;
  321.         }
  322.     }
  323.     
  324.     /**
  325.      * Set an error code => error message mapping callback
  326.      * 
  327.      * This method sets the callback that can be used to generate error
  328.      * messages for any instance
  329.      * @param array|string Callback function/method
  330.      */
  331.     function setMessageCallback($msgCallback)
  332.     {
  333.         if (!$msgCallback) {
  334.             $this->_msgCallback = array(&$this, 'getErrorMessage');
  335.         } else {
  336.             if (is_callable($msgCallback)) {
  337.                 $this->_msgCallback = $msgCallback;
  338.             }
  339.         }
  340.     }
  341.     
  342.     /**
  343.      * Get an error code => error message mapping callback
  344.      * 
  345.      * This method returns the current callback that can be used to generate error
  346.      * messages
  347.      * @return array|string|false Callback function/method or false if none
  348.      */
  349.     function getMessageCallback()
  350.     {
  351.         return $this->_msgCallback;
  352.     }
  353.     
  354.     /**
  355.      * Sets a default callback to be used by all error stacks
  356.      * 
  357.      * This method sets the callback that can be used to generate error
  358.      * messages for a singleton
  359.      * @param array|string Callback function/method
  360.      * @param string Package name, or false for all packages
  361.      * @static
  362.      */
  363.     function setDefaultCallback($callback = false, $package = false)
  364.     {
  365.         if (!is_callable($callback)) {
  366.             $callback = false;
  367.         }
  368.         $package = $package ? $package : '*';
  369.         $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback;
  370.     }
  371.     
  372.     /**
  373.      * Set a callback that generates context information (location of error) for an error stack
  374.      * 
  375.      * This method sets the callback that can be used to generate context
  376.      * information for an error.  Passing in NULL will disable context generation
  377.      * and remove the expensive call to debug_backtrace()
  378.      * @param array|string|null Callback function/method
  379.      */
  380.     function setContextCallback($contextCallback)
  381.     {
  382.         if ($contextCallback === null) {
  383.             return $this->_contextCallback = false;
  384.         }
  385.         if (!$contextCallback) {
  386.             $this->_contextCallback = array(&$this, 'getFileLine');
  387.         } else {
  388.             if (is_callable($contextCallback)) {
  389.                 $this->_contextCallback = $contextCallback;
  390.             }
  391.         }
  392.     }
  393.     
  394.     /**
  395.      * Set an error Callback
  396.      * If set to a valid callback, this will be called every time an error
  397.      * is pushed onto the stack.  The return value will be used to determine
  398.      * whether to allow an error to be pushed or logged.
  399.      * 
  400.      * The return value must be one of the ERRORSTACK_* constants.
  401.      * 
  402.      * This functionality can be used to emulate PEAR's pushErrorHandling, and
  403.      * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
  404.      * the error stack or logging
  405.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  406.      * @see popCallback()
  407.      * @param string|array $cb
  408.      */
  409.     function pushCallback($cb)
  410.     {
  411.         array_push($this->_errorCallback, $cb);
  412.     }
  413.     
  414.     /**
  415.      * Remove a callback from the error callback stack
  416.      * @see pushCallback()
  417.      * @return array|string|false
  418.      */
  419.     function popCallback()
  420.     {
  421.         if (!count($this->_errorCallback)) {
  422.             return false;
  423.         }
  424.         return array_pop($this->_errorCallback);
  425.     }
  426.     
  427.     /**
  428.      * Set a temporary overriding error callback for every package error stack
  429.      *
  430.      * Use this to temporarily disable all existing callbacks (can be used
  431.      * to emulate the @ operator, for instance)
  432.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  433.      * @see staticPopCallback(), pushCallback()
  434.      * @param string|array $cb
  435.      * @static
  436.      */
  437.     function staticPushCallback($cb)
  438.     {
  439.         array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
  440.     }
  441.     
  442.     /**
  443.      * Remove a temporary overriding error callback
  444.      * @see staticPushCallback()
  445.      * @return array|string|false
  446.      * @static
  447.      */
  448.     function staticPopCallback()
  449.     {
  450.         $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']);
  451.         if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) {
  452.             $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
  453.         }
  454.         return $ret;
  455.     }
  456.     
  457.     /**
  458.      * Add an error to the stack
  459.      * 
  460.      * If the message generator exists, it is called with 2 parameters.
  461.      *  - the current Error Stack object
  462.      *  - an array that is in the same format as an error.  Available indices
  463.      *    are 'code', 'package', 'time', 'params', 'level', and 'context'
  464.      * 
  465.      * Next, if the error should contain context information, this is
  466.      * handled by the context grabbing method.
  467.      * Finally, the error is pushed onto the proper error stack
  468.      * @param int    $code      Package-specific error code
  469.      * @param string $level     Error level.  This is NOT spell-checked
  470.      * @param array  $params    associative array of error parameters
  471.      * @param string $msg       Error message, or a portion of it if the message
  472.      *                          is to be generated
  473.      * @param array  $repackage If this error re-packages an error pushed by
  474.      *                          another package, place the array returned from
  475.      *                          {@link pop()} in this parameter
  476.      * @param array  $backtrace Protected parameter: use this to pass in the
  477.      *                          {@link debug_backtrace()} that should be used
  478.      *                          to find error context
  479.      * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
  480.      * thrown.  If a PEAR_Error is returned, the userinfo
  481.      * property is set to the following array:
  482.      * 
  483.      * <code>
  484.      * array(
  485.      *    'code' => $code,
  486.      *    'params' => $params,
  487.      *    'package' => $this->_package,
  488.      *    'level' => $level,
  489.      *    'time' => time(),
  490.      *    'context' => $context,
  491.      *    'message' => $msg,
  492.      * //['repackage' => $err] repackaged error array/Exception class
  493.      * );
  494.      * </code>
  495.      * 
  496.      * Normally, the previous array is returned.
  497.      */
  498.     function push($code, $level = 'error', $params = array(), $msg = false,
  499.                   $repackage = false, $backtrace = false)
  500.     {
  501.         $context = false;
  502.         // grab error context
  503.         if ($this->_contextCallback) {
  504.             if (!$backtrace) {
  505.                 $backtrace = debug_backtrace();
  506.             }
  507.             $context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
  508.         }
  509.         
  510.         // save error
  511.         $time = explode(' ', microtime());
  512.         $time = $time[1] + $time[0];
  513.         $err = array(
  514.                 'code' => $code,
  515.                 'params' => $params,
  516.                 'package' => $this->_package,
  517.                 'level' => $level,
  518.                 'time' => $time,
  519.                 'context' => $context,
  520.                 'message' => $msg,
  521.                );
  522.  
  523.         if ($repackage) {
  524.             $err['repackage'] = $repackage;
  525.         }
  526.  
  527.         // set up the error message, if necessary
  528.         if ($this->_msgCallback) {
  529.             $msg = call_user_func_array($this->_msgCallback,
  530.                                         array(&$this, $err));
  531.             $err['message'] = $msg;
  532.         }        
  533.         $push = $log = true;
  534.         $die = false;
  535.         // try the overriding callback first
  536.         $callback = $this->staticPopCallback();
  537.         if ($callback) {
  538.             $this->staticPushCallback($callback);
  539.         }
  540.         if (!is_callable($callback)) {
  541.             // try the local callback next
  542.             $callback = $this->popCallback();
  543.             if (is_callable($callback)) {
  544.                 $this->pushCallback($callback);
  545.             } else {
  546.                 // try the default callback
  547.                 $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ?
  548.                     $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] :
  549.                     $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*'];
  550.             }
  551.         }
  552.         if (is_callable($callback)) {
  553.             switch(call_user_func($callback, $err)){
  554.                 case PEAR_ERRORSTACK_IGNORE: 
  555.                     return $err;
  556.                 break;
  557.                 case PEAR_ERRORSTACK_PUSH: 
  558.                     $log = false;
  559.                 break;
  560.                 case PEAR_ERRORSTACK_LOG: 
  561.                     $push = false;
  562.                 break;
  563.                 case PEAR_ERRORSTACK_DIE: 
  564.                     $die = true;
  565.                 break;
  566.                 // anything else returned has the same effect as pushandlog
  567.             }
  568.         }
  569.         if ($push) {
  570.             array_unshift($this->_errors, $err);
  571.             if (!isset($this->_errorsByLevel[$err['level']])) {
  572.                 $this->_errorsByLevel[$err['level']] = array();
  573.             }
  574.             $this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
  575.         }
  576.         if ($log) {
  577.             if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
  578.                 $this->_log($err);
  579.             }
  580.         }
  581.         if ($die) {
  582.             die();
  583.         }
  584.         if ($this->_compat && $push) {
  585.             return $this->raiseError($msg, $code, null, null, $err);
  586.         }
  587.         return $err;
  588.     }
  589.     
  590.     /**
  591.      * Static version of {@link push()}
  592.      * 
  593.      * @param string $package   Package name this error belongs to
  594.      * @param int    $code      Package-specific error code
  595.      * @param string $level     Error level.  This is NOT spell-checked
  596.      * @param array  $params    associative array of error parameters
  597.      * @param string $msg       Error message, or a portion of it if the message
  598.      *                          is to be generated
  599.      * @param array  $repackage If this error re-packages an error pushed by
  600.      *                          another package, place the array returned from
  601.      *                          {@link pop()} in this parameter
  602.      * @param array  $backtrace Protected parameter: use this to pass in the
  603.      *                          {@link debug_backtrace()} that should be used
  604.      *                          to find error context
  605.      * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
  606.      *                          thrown.  see docs for {@link push()}
  607.      * @static
  608.      */
  609.     function staticPush($package, $code, $level = 'error', $params = array(),
  610.                         $msg = false, $repackage = false, $backtrace = false)
  611.     {
  612.         $s = &PEAR_ErrorStack::singleton($package);
  613.         if ($s->_contextCallback) {
  614.             if (!$backtrace) {
  615.                 if (function_exists('debug_backtrace')) {
  616.                     $backtrace = debug_backtrace();
  617.                 }
  618.             }
  619.         }
  620.         return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
  621.     }
  622.     
  623.     /**
  624.      * Log an error using PEAR::Log
  625.      * @param array $err Error array
  626.      * @param array $levels Error level => Log constant map
  627.      * @access protected
  628.      */
  629.     function _log($err)
  630.     {
  631.         if ($this->_logger) {
  632.             $logger = &$this->_logger;
  633.         } else {
  634.             $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
  635.         }
  636.         if (is_a($logger, 'Log')) {
  637.             $levels = array(
  638.                 'exception' => PEAR_LOG_CRIT,
  639.                 'alert' => PEAR_LOG_ALERT,
  640.                 'critical' => PEAR_LOG_CRIT,
  641.                 'error' => PEAR_LOG_ERR,
  642.                 'warning' => PEAR_LOG_WARNING,
  643.                 'notice' => PEAR_LOG_NOTICE,
  644.                 'info' => PEAR_LOG_INFO,
  645.                 'debug' => PEAR_LOG_DEBUG);
  646.             if (isset($levels[$err['level']])) {
  647.                 $level = $levels[$err['level']];
  648.             } else {
  649.                 $level = PEAR_LOG_INFO;
  650.             }
  651.             $logger->log($err['message'], $level, $err);
  652.         } else { // support non-standard logs
  653.             call_user_func($logger, $err);
  654.         }
  655.     }
  656.  
  657.     
  658.     /**
  659.      * Pop an error off of the error stack
  660.      * 
  661.      * @return false|array
  662.      * @since 0.4alpha it is no longer possible to specify a specific error
  663.      * level to return - the last error pushed will be returned, instead
  664.      */
  665.     function pop()
  666.     {
  667.         $err = @array_shift($this->_errors);
  668.         if (!is_null($err)) {
  669.             @array_pop($this->_errorsByLevel[$err['level']]);
  670.             if (!count($this->_errorsByLevel[$err['level']])) {
  671.                 unset($this->_errorsByLevel[$err['level']]);
  672.             }
  673.         }
  674.         return $err;
  675.     }
  676.  
  677.     /**
  678.      * Pop an error off of the error stack, static method
  679.      *
  680.      * @param string package name
  681.      * @return boolean
  682.      * @since PEAR1.5.0a1
  683.      */
  684.     function staticPop($package)
  685.     {
  686.         if ($package) {
  687.             if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  688.                 return false;
  689.             }
  690.             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
  691.         }
  692.     }
  693.  
  694.     /**
  695.      * Determine whether there are any errors on the stack
  696.      * @param string|array Level name.  Use to determine if any errors
  697.      * of level (string), or levels (array) have been pushed
  698.      * @return boolean
  699.      */
  700.     function hasErrors($level = false)
  701.     {
  702.         if ($level) {
  703.             return isset($this->_errorsByLevel[$level]);
  704.         }
  705.         return count($this->_errors);
  706.     }
  707.     
  708.     /**
  709.      * Retrieve all errors since last purge
  710.      * 
  711.      * @param boolean set in order to empty the error stack
  712.      * @param string level name, to return only errors of a particular severity
  713.      * @return array
  714.      */
  715.     function getErrors($purge = false, $level = false)
  716.     {
  717.         if (!$purge) {
  718.             if ($level) {
  719.                 if (!isset($this->_errorsByLevel[$level])) {
  720.                     return array();
  721.                 } else {
  722.                     return $this->_errorsByLevel[$level];
  723.                 }
  724.             } else {
  725.                 return $this->_errors;
  726.             }
  727.         }
  728.         if ($level) {
  729.             $ret = $this->_errorsByLevel[$level];
  730.             foreach ($this->_errorsByLevel[$level] as $i => $unused) {
  731.                 // entries are references to the $_errors array
  732.                 $this->_errorsByLevel[$level][$i] = false;
  733.             }
  734.             // array_filter removes all entries === false
  735.             $this->_errors = array_filter($this->_errors);
  736.             unset($this->_errorsByLevel[$level]);
  737.             return $ret;
  738.         }
  739.         $ret = $this->_errors;
  740.         $this->_errors = array();
  741.         $this->_errorsByLevel = array();
  742.         return $ret;
  743.     }
  744.     
  745.     /**
  746.      * Determine whether there are any errors on a single error stack, or on any error stack
  747.      *
  748.      * The optional parameter can be used to test the existence of any errors without the need of
  749.      * singleton instantiation
  750.      * @param string|false Package name to check for errors
  751.      * @param string Level name to check for a particular severity
  752.      * @return boolean
  753.      * @static
  754.      */
  755.     function staticHasErrors($package = false, $level = false)
  756.     {
  757.         if ($package) {
  758.             if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  759.                 return false;
  760.             }
  761.             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level);
  762.         }
  763.         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  764.             if ($obj->hasErrors($level)) {
  765.                 return true;
  766.             }
  767.         }
  768.         return false;
  769.     }
  770.     
  771.     /**
  772.      * Get a list of all errors since last purge, organized by package
  773.      * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
  774.      * @param boolean $purge Set to purge the error stack of existing errors
  775.      * @param string  $level Set to a level name in order to retrieve only errors of a particular level
  776.      * @param boolean $merge Set to return a flat array, not organized by package
  777.      * @param array   $sortfunc Function used to sort a merged array - default
  778.      *        sorts by time, and should be good for most cases
  779.      * @static
  780.      * @return array 
  781.      */
  782.     function staticGetErrors($purge = false, $level = false, $merge = false,
  783.                              $sortfunc = array('PEAR_ErrorStack', '_sortErrors'))
  784.     {
  785.         $ret = array();
  786.         if (!is_callable($sortfunc)) {
  787.             $sortfunc = array('PEAR_ErrorStack', '_sortErrors');
  788.         }
  789.         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  790.             $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level);
  791.             if ($test) {
  792.                 if ($merge) {
  793.                     $ret = array_merge($ret, $test);
  794.                 } else {
  795.                     $ret[$package] = $test;
  796.                 }
  797.             }
  798.         }
  799.         if ($merge) {
  800.             usort($ret, $sortfunc);
  801.         }
  802.         return $ret;
  803.     }
  804.     
  805.     /**
  806.      * Error sorting function, sorts by time
  807.      * @access private
  808.      */
  809.     function _sortErrors($a, $b)
  810.     {
  811.         if ($a['time'] == $b['time']) {
  812.             return 0;
  813.         }
  814.         if ($a['time'] < $b['time']) {
  815.             return 1;
  816.         }
  817.         return -1;
  818.     }
  819.  
  820.     /**
  821.      * Standard file/line number/function/class context callback
  822.      *
  823.      * This function uses a backtrace generated from {@link debug_backtrace()}
  824.      * and so will not work at all in PHP < 4.3.0.  The frame should
  825.      * reference the frame that contains the source of the error.
  826.      * @return array|false either array('file' => file, 'line' => line,
  827.      *         'function' => function name, 'class' => class name) or
  828.      *         if this doesn't work, then false
  829.      * @param unused
  830.      * @param integer backtrace frame.
  831.      * @param array Results of debug_backtrace()
  832.      * @static
  833.      */
  834.     function getFileLine($code, $params, $backtrace = null)
  835.     {
  836.         if ($backtrace === null) {
  837.             return false;
  838.         }
  839.         $frame = 0;
  840.         $functionframe = 1;
  841.         if (!isset($backtrace[1])) {
  842.             $functionframe = 0;
  843.         } else {
  844.             while (isset($backtrace[$functionframe]['function']) &&
  845.                   $backtrace[$functionframe]['function'] == 'eval' &&
  846.                   isset($backtrace[$functionframe + 1])) {
  847.                 $functionframe++;
  848.             }
  849.         }
  850.         if (isset($backtrace[$frame])) {
  851.             if (!isset($backtrace[$frame]['file'])) {
  852.                 $frame++;
  853.             }
  854.             $funcbacktrace = $backtrace[$functionframe];
  855.             $filebacktrace = $backtrace[$frame];
  856.             $ret = array('file' => $filebacktrace['file'],
  857.                          'line' => $filebacktrace['line']);
  858.             // rearrange for eval'd code or create function errors
  859.             if (strpos($filebacktrace['file'], '(') && 
  860.                   preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
  861.                   $matches)) {
  862.                 $ret['file'] = $matches[1];
  863.                 $ret['line'] = $matches[2] + 0;
  864.             }
  865.             if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
  866.                 if ($funcbacktrace['function'] != 'eval') {
  867.                     if ($funcbacktrace['function'] == '__lambda_func') {
  868.                         $ret['function'] = 'create_function() code';
  869.                     } else {
  870.                         $ret['function'] = $funcbacktrace['function'];
  871.                     }
  872.                 }
  873.             }
  874.             if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
  875.                 $ret['class'] = $funcbacktrace['class'];
  876.             }
  877.             return $ret;
  878.         }
  879.         return false;
  880.     }
  881.     
  882.     /**
  883.      * Standard error message generation callback
  884.      * 
  885.      * This method may also be called by a custom error message generator
  886.      * to fill in template values from the params array, simply
  887.      * set the third parameter to the error message template string to use
  888.      * 
  889.      * The special variable %__msg% is reserved: use it only to specify
  890.      * where a message passed in by the user should be placed in the template,
  891.      * like so:
  892.      * 
  893.      * Error message: %msg% - internal error
  894.      * 
  895.      * If the message passed like so:
  896.      * 
  897.      * <code>
  898.      * $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
  899.      * </code>
  900.      * 
  901.      * The returned error message will be "Error message: server error 500 -
  902.      * internal error"
  903.      * @param PEAR_ErrorStack
  904.      * @param array
  905.      * @param string|false Pre-generated error message template
  906.      * @static
  907.      * @return string
  908.      */
  909.     function getErrorMessage(&$stack, $err, $template = false)
  910.     {
  911.         if ($template) {
  912.             $mainmsg = $template;
  913.         } else {
  914.             $mainmsg = $stack->getErrorMessageTemplate($err['code']);
  915.         }
  916.         $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
  917.         if (is_array($err['params']) && count($err['params'])) {
  918.             foreach ($err['params'] as $name => $val) {
  919.                 if (is_array($val)) {
  920.                     // @ is needed in case $val is a multi-dimensional array
  921.                     $val = @implode(', ', $val);
  922.                 }
  923.                 if (is_object($val)) {
  924.                     if (method_exists($val, '__toString')) {
  925.                         $val = $val->__toString();
  926.                     } else {
  927.                         PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
  928.                             'warning', array('obj' => get_class($val)),
  929.                             'object %obj% passed into getErrorMessage, but has no __toString() method');
  930.                         $val = 'Object';
  931.                     }
  932.                 }
  933.                 $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg);
  934.             }
  935.         }
  936.         return $mainmsg;
  937.     }
  938.     
  939.     /**
  940.      * Standard Error Message Template generator from code
  941.      * @return string
  942.      */
  943.     function getErrorMessageTemplate($code)
  944.     {
  945.         if (!isset($this->_errorMsgs[$code])) {
  946.             return '%__msg%';
  947.         }
  948.         return $this->_errorMsgs[$code];
  949.     }
  950.     
  951.     /**
  952.      * Set the Error Message Template array
  953.      * 
  954.      * The array format must be:
  955.      * <pre>
  956.      * array(error code => 'message template',...)
  957.      * </pre>
  958.      * 
  959.      * Error message parameters passed into {@link push()} will be used as input
  960.      * for the error message.  If the template is 'message %foo% was %bar%', and the
  961.      * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
  962.      * be 'message one was six'
  963.      * @return string
  964.      */
  965.     function setErrorMessageTemplate($template)
  966.     {
  967.         $this->_errorMsgs = $template;
  968.     }
  969.     
  970.     
  971.     /**
  972.      * emulate PEAR::raiseError()
  973.      * 
  974.      * @return PEAR_Error
  975.      */
  976.     function raiseError()
  977.     {
  978.         require_once 'PEAR.php';
  979.         $args = func_get_args();
  980.         return call_user_func_array(array('PEAR', 'raiseError'), $args);
  981.     }
  982. }
  983. $stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
  984. $stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
  985. ?>
  986.