PageRenderTime 65ms CodeModel.GetById 15ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/php/PEAR/ErrorStack.php

https://bitbucket.org/adarshj/convenient_website
PHP | 985 lines | 455 code | 49 blank | 481 comment | 96 complexity | 3d1ee44f11a5c927f98149041cbba536 MD5 | raw file
  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://opensource.org/licenses/bsd-license.php New BSD License
 26 * @version    CVS: $Id: ErrorStack.php 313023 2011-07-06 19:17:11Z dufuz $
 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 */
 92define('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 */
 97define('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 */
102define('PEAR_ERRORSTACK_LOG', 3);
103/**
104 * If this is returned, then the error is completely ignored.
105 */
106define('PEAR_ERRORSTACK_IGNORE', 4);
107/**
108 * If this is returned, then the error is logged and die() is called.
109 */
110define('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 */
117define('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 */
123define('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.9.4
136 * @package    PEAR_ErrorStack
137 * @category   Debugging
138 * @copyright  2004-2008 Greg Beaver
139 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
140 * @version    CVS: $Id: ErrorStack.php 313023 2011-07-06 19:17:11Z dufuz $
141 * @link       http://pear.php.net/package/PEAR_ErrorStack
142 */
143class 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?>