upload
[pear] / PEAR.php
1 <?php
2 /**
3  * PEAR, the PHP Extension and Application Repository
4  *
5  * PEAR class and PEAR_Error class
6  *
7  * PHP versions 4 and 5
8  *
9  * @category   pear
10  * @package    PEAR
11  * @author     Sterling Hughes <sterling@php.net>
12  * @author     Stig Bakken <ssb@php.net>
13  * @author     Tomas V.V.Cox <cox@idecnet.com>
14  * @author     Greg Beaver <cellog@php.net>
15  * @copyright  1997-2009 The Authors
16  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
17  * @version    CVS: $Id: PEAR.php 286670 2009-08-02 14:16:06Z dufuz $
18  * @link       http://pear.php.net/package/PEAR
19  * @since      File available since Release 0.1
20  */
21
22 /**#@+
23  * ERROR constants
24  */
25 define('PEAR_ERROR_RETURN',     1);
26 define('PEAR_ERROR_PRINT',      2);
27 define('PEAR_ERROR_TRIGGER',    4);
28 define('PEAR_ERROR_DIE',        8);
29 define('PEAR_ERROR_CALLBACK',  16);
30 /**
31  * WARNING: obsolete
32  * @deprecated
33  */
34 define('PEAR_ERROR_EXCEPTION', 32);
35 /**#@-*/
36 define('PEAR_ZE2', (function_exists('version_compare') &&
37                     version_compare(zend_version(), "2-dev", "ge")));
38
39 if (substr(PHP_OS, 0, 3) == 'WIN') {
40     define('OS_WINDOWS', true);
41     define('OS_UNIX',    false);
42     define('PEAR_OS',    'Windows');
43 } else {
44     define('OS_WINDOWS', false);
45     define('OS_UNIX',    true);
46     define('PEAR_OS',    'Unix'); // blatant assumption
47 }
48
49 $GLOBALS['_PEAR_default_error_mode']     = PEAR_ERROR_RETURN;
50 $GLOBALS['_PEAR_default_error_options']  = E_USER_NOTICE;
51 $GLOBALS['_PEAR_destructor_object_list'] = array();
52 $GLOBALS['_PEAR_shutdown_funcs']         = array();
53 $GLOBALS['_PEAR_error_handler_stack']    = array();
54
55 @ini_set('track_errors', true);
56
57 /**
58  * Base class for other PEAR classes.  Provides rudimentary
59  * emulation of destructors.
60  *
61  * If you want a destructor in your class, inherit PEAR and make a
62  * destructor method called _yourclassname (same name as the
63  * constructor, but with a "_" prefix).  Also, in your constructor you
64  * have to call the PEAR constructor: $this->PEAR();.
65  * The destructor method will be called without parameters.  Note that
66  * at in some SAPI implementations (such as Apache), any output during
67  * the request shutdown (in which destructors are called) seems to be
68  * discarded.  If you need to get any debug information from your
69  * destructor, use error_log(), syslog() or something similar.
70  *
71  * IMPORTANT! To use the emulated destructors you need to create the
72  * objects by reference: $obj =& new PEAR_child;
73  *
74  * @category   pear
75  * @package    PEAR
76  * @author     Stig Bakken <ssb@php.net>
77  * @author     Tomas V.V. Cox <cox@idecnet.com>
78  * @author     Greg Beaver <cellog@php.net>
79  * @copyright  1997-2006 The PHP Group
80  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
81  * @version    Release: 1.9.0
82  * @link       http://pear.php.net/package/PEAR
83  * @see        PEAR_Error
84  * @since      Class available since PHP 4.0.2
85  * @link        http://pear.php.net/manual/en/core.pear.php#core.pear.pear
86  */
87 class PEAR
88 {
89     // {{{ properties
90
91     /**
92      * Whether to enable internal debug messages.
93      *
94      * @var     bool
95      * @access  private
96      */
97     var $_debug = false;
98
99     /**
100      * Default error mode for this object.
101      *
102      * @var     int
103      * @access  private
104      */
105     var $_default_error_mode = null;
106
107     /**
108      * Default error options used for this object when error mode
109      * is PEAR_ERROR_TRIGGER.
110      *
111      * @var     int
112      * @access  private
113      */
114     var $_default_error_options = null;
115
116     /**
117      * Default error handler (callback) for this object, if error mode is
118      * PEAR_ERROR_CALLBACK.
119      *
120      * @var     string
121      * @access  private
122      */
123     var $_default_error_handler = '';
124
125     /**
126      * Which class to use for error objects.
127      *
128      * @var     string
129      * @access  private
130      */
131     var $_error_class = 'PEAR_Error';
132
133     /**
134      * An array of expected errors.
135      *
136      * @var     array
137      * @access  private
138      */
139     var $_expected_errors = array();
140
141     // }}}
142
143     // {{{ constructor
144
145     /**
146      * Constructor.  Registers this object in
147      * $_PEAR_destructor_object_list for destructor emulation if a
148      * destructor object exists.
149      *
150      * @param string $error_class  (optional) which class to use for
151      *        error objects, defaults to PEAR_Error.
152      * @access public
153      * @return void
154      */
155     function PEAR($error_class = null)
156     {
157         $classname = strtolower(get_class($this));
158         if ($this->_debug) {
159             print "PEAR constructor called, class=$classname\n";
160         }
161         if ($error_class !== null) {
162             $this->_error_class = $error_class;
163         }
164         while ($classname && strcasecmp($classname, "pear")) {
165             $destructor = "_$classname";
166             if (method_exists($this, $destructor)) {
167                 global $_PEAR_destructor_object_list;
168                 $_PEAR_destructor_object_list[] = &$this;
169                 if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
170                     register_shutdown_function("_PEAR_call_destructors");
171                     $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
172                 }
173                 break;
174             } else {
175                 $classname = get_parent_class($classname);
176             }
177         }
178     }
179
180     // }}}
181     // {{{ destructor
182
183     /**
184      * Destructor (the emulated type of...).  Does nothing right now,
185      * but is included for forward compatibility, so subclass
186      * destructors should always call it.
187      *
188      * See the note in the class desciption about output from
189      * destructors.
190      *
191      * @access public
192      * @return void
193      */
194     function _PEAR() {
195         if ($this->_debug) {
196             printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
197         }
198     }
199
200     // }}}
201     // {{{ getStaticProperty()
202
203     /**
204     * If you have a class that's mostly/entirely static, and you need static
205     * properties, you can use this method to simulate them. Eg. in your method(s)
206     * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
207     * You MUST use a reference, or they will not persist!
208     *
209     * @access public
210     * @param  string $class  The calling classname, to prevent clashes
211     * @param  string $var    The variable to retrieve.
212     * @return mixed   A reference to the variable. If not set it will be
213     *                 auto initialised to NULL.
214     */
215     function &getStaticProperty($class, $var)
216     {
217         static $properties;
218         if (!isset($properties[$class])) {
219             $properties[$class] = array();
220         }
221
222         if (!array_key_exists($var, $properties[$class])) {
223             $properties[$class][$var] = null;
224         }
225
226         return $properties[$class][$var];
227     }
228
229     // }}}
230     // {{{ registerShutdownFunc()
231
232     /**
233     * Use this function to register a shutdown method for static
234     * classes.
235     *
236     * @access public
237     * @param  mixed $func  The function name (or array of class/method) to call
238     * @param  mixed $args  The arguments to pass to the function
239     * @return void
240     */
241     function registerShutdownFunc($func, $args = array())
242     {
243         // if we are called statically, there is a potential
244         // that no shutdown func is registered.  Bug #6445
245         if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
246             register_shutdown_function("_PEAR_call_destructors");
247             $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
248         }
249         $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
250     }
251
252     // }}}
253     // {{{ isError()
254
255     /**
256      * Tell whether a value is a PEAR error.
257      *
258      * @param   mixed $data   the value to test
259      * @param   int   $code   if $data is an error object, return true
260      *                        only if $code is a string and
261      *                        $obj->getMessage() == $code or
262      *                        $code is an integer and $obj->getCode() == $code
263      * @access  public
264      * @return  bool    true if parameter is an error
265      */
266     function isError($data, $code = null)
267     {
268         if (!is_a($data, 'PEAR_Error')) {
269             return false;
270         }
271
272         if (is_null($code)) {
273             return true;
274         } elseif (is_string($code)) {
275             return $data->getMessage() == $code;
276         }
277
278         return $data->getCode() == $code;
279     }
280
281     // }}}
282     // {{{ setErrorHandling()
283
284     /**
285      * Sets how errors generated by this object should be handled.
286      * Can be invoked both in objects and statically.  If called
287      * statically, setErrorHandling sets the default behaviour for all
288      * PEAR objects.  If called in an object, setErrorHandling sets
289      * the default behaviour for that object.
290      *
291      * @param int $mode
292      *        One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
293      *        PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
294      *        PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
295      *
296      * @param mixed $options
297      *        When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
298      *        of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
299      *
300      *        When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
301      *        to be the callback function or method.  A callback
302      *        function is a string with the name of the function, a
303      *        callback method is an array of two elements: the element
304      *        at index 0 is the object, and the element at index 1 is
305      *        the name of the method to call in the object.
306      *
307      *        When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
308      *        a printf format string used when printing the error
309      *        message.
310      *
311      * @access public
312      * @return void
313      * @see PEAR_ERROR_RETURN
314      * @see PEAR_ERROR_PRINT
315      * @see PEAR_ERROR_TRIGGER
316      * @see PEAR_ERROR_DIE
317      * @see PEAR_ERROR_CALLBACK
318      * @see PEAR_ERROR_EXCEPTION
319      *
320      * @since PHP 4.0.5
321      */
322
323     function setErrorHandling($mode = null, $options = null)
324     {
325         if (isset($this) && is_a($this, 'PEAR')) {
326             $setmode     = &$this->_default_error_mode;
327             $setoptions  = &$this->_default_error_options;
328         } else {
329             $setmode     = &$GLOBALS['_PEAR_default_error_mode'];
330             $setoptions  = &$GLOBALS['_PEAR_default_error_options'];
331         }
332
333         switch ($mode) {
334             case PEAR_ERROR_EXCEPTION:
335             case PEAR_ERROR_RETURN:
336             case PEAR_ERROR_PRINT:
337             case PEAR_ERROR_TRIGGER:
338             case PEAR_ERROR_DIE:
339             case null:
340                 $setmode = $mode;
341                 $setoptions = $options;
342                 break;
343
344             case PEAR_ERROR_CALLBACK:
345                 $setmode = $mode;
346                 // class/object method callback
347                 if (is_callable($options)) {
348                     $setoptions = $options;
349                 } else {
350                     trigger_error("invalid error callback", E_USER_WARNING);
351                 }
352                 break;
353
354             default:
355                 trigger_error("invalid error mode", E_USER_WARNING);
356                 break;
357         }
358     }
359
360     // }}}
361     // {{{ expectError()
362
363     /**
364      * This method is used to tell which errors you expect to get.
365      * Expected errors are always returned with error mode
366      * PEAR_ERROR_RETURN.  Expected error codes are stored in a stack,
367      * and this method pushes a new element onto it.  The list of
368      * expected errors are in effect until they are popped off the
369      * stack with the popExpect() method.
370      *
371      * Note that this method can not be called statically
372      *
373      * @param mixed $code a single error code or an array of error codes to expect
374      *
375      * @return int     the new depth of the "expected errors" stack
376      * @access public
377      */
378     function expectError($code = '*')
379     {
380         if (is_array($code)) {
381             array_push($this->_expected_errors, $code);
382         } else {
383             array_push($this->_expected_errors, array($code));
384         }
385         return sizeof($this->_expected_errors);
386     }
387
388     // }}}
389     // {{{ popExpect()
390
391     /**
392      * This method pops one element off the expected error codes
393      * stack.
394      *
395      * @return array   the list of error codes that were popped
396      */
397     function popExpect()
398     {
399         return array_pop($this->_expected_errors);
400     }
401
402     // }}}
403     // {{{ _checkDelExpect()
404
405     /**
406      * This method checks unsets an error code if available
407      *
408      * @param mixed error code
409      * @return bool true if the error code was unset, false otherwise
410      * @access private
411      * @since PHP 4.3.0
412      */
413     function _checkDelExpect($error_code)
414     {
415         $deleted = false;
416
417         foreach ($this->_expected_errors AS $key => $error_array) {
418             if (in_array($error_code, $error_array)) {
419                 unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
420                 $deleted = true;
421             }
422
423             // clean up empty arrays
424             if (0 == count($this->_expected_errors[$key])) {
425                 unset($this->_expected_errors[$key]);
426             }
427         }
428         return $deleted;
429     }
430
431     // }}}
432     // {{{ delExpect()
433
434     /**
435      * This method deletes all occurences of the specified element from
436      * the expected error codes stack.
437      *
438      * @param  mixed $error_code error code that should be deleted
439      * @return mixed list of error codes that were deleted or error
440      * @access public
441      * @since PHP 4.3.0
442      */
443     function delExpect($error_code)
444     {
445         $deleted = false;
446         if ((is_array($error_code) && (0 != count($error_code)))) {
447             // $error_code is a non-empty array here;
448             // we walk through it trying to unset all
449             // values
450             foreach($error_code as $key => $error) {
451                 if ($this->_checkDelExpect($error)) {
452                     $deleted =  true;
453                 } else {
454                     $deleted = false;
455                 }
456             }
457             return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
458         } elseif (!empty($error_code)) {
459             // $error_code comes alone, trying to unset it
460             if ($this->_checkDelExpect($error_code)) {
461                 return true;
462             } else {
463                 return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
464             }
465         }
466
467         // $error_code is empty
468         return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
469     }
470
471     // }}}
472     // {{{ raiseError()
473
474     /**
475      * This method is a wrapper that returns an instance of the
476      * configured error class with this object's default error
477      * handling applied.  If the $mode and $options parameters are not
478      * specified, the object's defaults are used.
479      *
480      * @param mixed $message a text error message or a PEAR error object
481      *
482      * @param int $code      a numeric error code (it is up to your class
483      *                  to define these if you want to use codes)
484      *
485      * @param int $mode      One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
486      *                  PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
487      *                  PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
488      *
489      * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter
490      *                  specifies the PHP-internal error level (one of
491      *                  E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
492      *                  If $mode is PEAR_ERROR_CALLBACK, this
493      *                  parameter specifies the callback function or
494      *                  method.  In other error modes this parameter
495      *                  is ignored.
496      *
497      * @param string $userinfo If you need to pass along for example debug
498      *                  information, this parameter is meant for that.
499      *
500      * @param string $error_class The returned error object will be
501      *                  instantiated from this class, if specified.
502      *
503      * @param bool $skipmsg If true, raiseError will only pass error codes,
504      *                  the error message parameter will be dropped.
505      *
506      * @access public
507      * @return object   a PEAR error object
508      * @see PEAR::setErrorHandling
509      * @since PHP 4.0.5
510      */
511     function &raiseError($message = null,
512                          $code = null,
513                          $mode = null,
514                          $options = null,
515                          $userinfo = null,
516                          $error_class = null,
517                          $skipmsg = false)
518     {
519         // The error is yet a PEAR error object
520         if (is_object($message)) {
521             $code        = $message->getCode();
522             $userinfo    = $message->getUserInfo();
523             $error_class = $message->getType();
524             $message->error_message_prefix = '';
525             $message     = $message->getMessage();
526         }
527
528         if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) {
529             if ($exp[0] == "*" ||
530                 (is_int(reset($exp)) && in_array($code, $exp)) ||
531                 (is_string(reset($exp)) && in_array($message, $exp))) {
532                 $mode = PEAR_ERROR_RETURN;
533             }
534         }
535
536         // No mode given, try global ones
537         if ($mode === null) {
538             // Class error handler
539             if (isset($this) && isset($this->_default_error_mode)) {
540                 $mode    = $this->_default_error_mode;
541                 $options = $this->_default_error_options;
542             // Global error handler
543             } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
544                 $mode    = $GLOBALS['_PEAR_default_error_mode'];
545                 $options = $GLOBALS['_PEAR_default_error_options'];
546             }
547         }
548
549         if ($error_class !== null) {
550             $ec = $error_class;
551         } elseif (isset($this) && isset($this->_error_class)) {
552             $ec = $this->_error_class;
553         } else {
554             $ec = 'PEAR_Error';
555         }
556
557         if (intval(PHP_VERSION) < 5) {
558             // little non-eval hack to fix bug #12147
559             include 'PEAR/FixPHP5PEARWarnings.php';
560             return $a;
561         }
562
563         if ($skipmsg) {
564             $a = new $ec($code, $mode, $options, $userinfo);
565         } else {
566             $a = new $ec($message, $code, $mode, $options, $userinfo);
567         }
568
569         return $a;
570     }
571
572     // }}}
573     // {{{ throwError()
574
575     /**
576      * Simpler form of raiseError with fewer options.  In most cases
577      * message, code and userinfo are enough.
578      *
579      * @param string $message
580      *
581      */
582     function &throwError($message = null,
583                          $code = null,
584                          $userinfo = null)
585     {
586         if (isset($this) && is_a($this, 'PEAR')) {
587             $a = &$this->raiseError($message, $code, null, null, $userinfo);
588             return $a;
589         }
590
591         $a = &PEAR::raiseError($message, $code, null, null, $userinfo);
592         return $a;
593     }
594
595     // }}}
596     function staticPushErrorHandling($mode, $options = null)
597     {
598         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
599         $def_mode    = &$GLOBALS['_PEAR_default_error_mode'];
600         $def_options = &$GLOBALS['_PEAR_default_error_options'];
601         $stack[] = array($def_mode, $def_options);
602         switch ($mode) {
603             case PEAR_ERROR_EXCEPTION:
604             case PEAR_ERROR_RETURN:
605             case PEAR_ERROR_PRINT:
606             case PEAR_ERROR_TRIGGER:
607             case PEAR_ERROR_DIE:
608             case null:
609                 $def_mode = $mode;
610                 $def_options = $options;
611                 break;
612
613             case PEAR_ERROR_CALLBACK:
614                 $def_mode = $mode;
615                 // class/object method callback
616                 if (is_callable($options)) {
617                     $def_options = $options;
618                 } else {
619                     trigger_error("invalid error callback", E_USER_WARNING);
620                 }
621                 break;
622
623             default:
624                 trigger_error("invalid error mode", E_USER_WARNING);
625                 break;
626         }
627         $stack[] = array($mode, $options);
628         return true;
629     }
630
631     function staticPopErrorHandling()
632     {
633         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
634         $setmode     = &$GLOBALS['_PEAR_default_error_mode'];
635         $setoptions  = &$GLOBALS['_PEAR_default_error_options'];
636         array_pop($stack);
637         list($mode, $options) = $stack[sizeof($stack) - 1];
638         array_pop($stack);
639         switch ($mode) {
640             case PEAR_ERROR_EXCEPTION:
641             case PEAR_ERROR_RETURN:
642             case PEAR_ERROR_PRINT:
643             case PEAR_ERROR_TRIGGER:
644             case PEAR_ERROR_DIE:
645             case null:
646                 $setmode = $mode;
647                 $setoptions = $options;
648                 break;
649
650             case PEAR_ERROR_CALLBACK:
651                 $setmode = $mode;
652                 // class/object method callback
653                 if (is_callable($options)) {
654                     $setoptions = $options;
655                 } else {
656                     trigger_error("invalid error callback", E_USER_WARNING);
657                 }
658                 break;
659
660             default:
661                 trigger_error("invalid error mode", E_USER_WARNING);
662                 break;
663         }
664         return true;
665     }
666
667     // {{{ pushErrorHandling()
668
669     /**
670      * Push a new error handler on top of the error handler options stack. With this
671      * you can easily override the actual error handler for some code and restore
672      * it later with popErrorHandling.
673      *
674      * @param mixed $mode (same as setErrorHandling)
675      * @param mixed $options (same as setErrorHandling)
676      *
677      * @return bool Always true
678      *
679      * @see PEAR::setErrorHandling
680      */
681     function pushErrorHandling($mode, $options = null)
682     {
683         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
684         if (isset($this) && is_a($this, 'PEAR')) {
685             $def_mode    = &$this->_default_error_mode;
686             $def_options = &$this->_default_error_options;
687         } else {
688             $def_mode    = &$GLOBALS['_PEAR_default_error_mode'];
689             $def_options = &$GLOBALS['_PEAR_default_error_options'];
690         }
691         $stack[] = array($def_mode, $def_options);
692
693         if (isset($this) && is_a($this, 'PEAR')) {
694             $this->setErrorHandling($mode, $options);
695         } else {
696             PEAR::setErrorHandling($mode, $options);
697         }
698         $stack[] = array($mode, $options);
699         return true;
700     }
701
702     // }}}
703     // {{{ popErrorHandling()
704
705     /**
706     * Pop the last error handler used
707     *
708     * @return bool Always true
709     *
710     * @see PEAR::pushErrorHandling
711     */
712     function popErrorHandling()
713     {
714         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
715         array_pop($stack);
716         list($mode, $options) = $stack[sizeof($stack) - 1];
717         array_pop($stack);
718         if (isset($this) && is_a($this, 'PEAR')) {
719             $this->setErrorHandling($mode, $options);
720         } else {
721             PEAR::setErrorHandling($mode, $options);
722         }
723         return true;
724     }
725
726     // }}}
727     // {{{ loadExtension()
728
729     /**
730     * OS independant PHP extension load. Remember to take care
731     * on the correct extension name for case sensitive OSes.
732     *
733     * @param string $ext The extension name
734     * @return bool Success or not on the dl() call
735     */
736     function loadExtension($ext)
737     {
738         if (!extension_loaded($ext)) {
739             // if either returns true dl() will produce a FATAL error, stop that
740             if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
741                 return false;
742             }
743
744             if (OS_WINDOWS) {
745                 $suffix = '.dll';
746             } elseif (PHP_OS == 'HP-UX') {
747                 $suffix = '.sl';
748             } elseif (PHP_OS == 'AIX') {
749                 $suffix = '.a';
750             } elseif (PHP_OS == 'OSX') {
751                 $suffix = '.bundle';
752             } else {
753                 $suffix = '.so';
754             }
755
756             return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
757         }
758
759         return true;
760     }
761
762     // }}}
763 }
764
765 if (PEAR_ZE2) {
766     include_once 'PEAR5.php';
767 }
768
769 // {{{ _PEAR_call_destructors()
770
771 function _PEAR_call_destructors()
772 {
773     global $_PEAR_destructor_object_list;
774     if (is_array($_PEAR_destructor_object_list) &&
775         sizeof($_PEAR_destructor_object_list))
776     {
777         reset($_PEAR_destructor_object_list);
778         if (PEAR_ZE2) {
779             $destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo');
780         } else {
781             $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo');
782         }
783
784         if ($destructLifoExists) {
785             $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
786         }
787
788         while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
789             $classname = get_class($objref);
790             while ($classname) {
791                 $destructor = "_$classname";
792                 if (method_exists($objref, $destructor)) {
793                     $objref->$destructor();
794                     break;
795                 } else {
796                     $classname = get_parent_class($classname);
797                 }
798             }
799         }
800         // Empty the object list to ensure that destructors are
801         // not called more than once.
802         $_PEAR_destructor_object_list = array();
803     }
804
805     // Now call the shutdown functions
806     if (isset($GLOBALS['_PEAR_shutdown_funcs']) AND is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) {
807         foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
808             call_user_func_array($value[0], $value[1]);
809         }
810     }
811 }
812
813 // }}}
814 /**
815  * Standard PEAR error class for PHP 4
816  *
817  * This class is supserseded by {@link PEAR_Exception} in PHP 5
818  *
819  * @category   pear
820  * @package    PEAR
821  * @author     Stig Bakken <ssb@php.net>
822  * @author     Tomas V.V. Cox <cox@idecnet.com>
823  * @author     Gregory Beaver <cellog@php.net>
824  * @copyright  1997-2006 The PHP Group
825  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
826  * @version    Release: 1.9.0
827  * @link       http://pear.php.net/manual/en/core.pear.pear-error.php
828  * @see        PEAR::raiseError(), PEAR::throwError()
829  * @since      Class available since PHP 4.0.2
830  */
831 class PEAR_Error
832 {
833     // {{{ properties
834
835     var $error_message_prefix = '';
836     var $mode                 = PEAR_ERROR_RETURN;
837     var $level                = E_USER_NOTICE;
838     var $code                 = -1;
839     var $message              = '';
840     var $userinfo             = '';
841     var $backtrace            = null;
842
843     // }}}
844     // {{{ constructor
845
846     /**
847      * PEAR_Error constructor
848      *
849      * @param string $message  message
850      *
851      * @param int $code     (optional) error code
852      *
853      * @param int $mode     (optional) error mode, one of: PEAR_ERROR_RETURN,
854      * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
855      * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
856      *
857      * @param mixed $options   (optional) error level, _OR_ in the case of
858      * PEAR_ERROR_CALLBACK, the callback function or object/method
859      * tuple.
860      *
861      * @param string $userinfo (optional) additional user/debug info
862      *
863      * @access public
864      *
865      */
866     function PEAR_Error($message = 'unknown error', $code = null,
867                         $mode = null, $options = null, $userinfo = null)
868     {
869         if ($mode === null) {
870             $mode = PEAR_ERROR_RETURN;
871         }
872         $this->message   = $message;
873         $this->code      = $code;
874         $this->mode      = $mode;
875         $this->userinfo  = $userinfo;
876
877         if (PEAR_ZE2) {
878             $skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace');
879         } else {
880             $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace');
881         }
882
883         if (!$skiptrace) {
884             $this->backtrace = debug_backtrace();
885             if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
886                 unset($this->backtrace[0]['object']);
887             }
888         }
889
890         if ($mode & PEAR_ERROR_CALLBACK) {
891             $this->level = E_USER_NOTICE;
892             $this->callback = $options;
893         } else {
894             if ($options === null) {
895                 $options = E_USER_NOTICE;
896             }
897
898             $this->level = $options;
899             $this->callback = null;
900         }
901
902         if ($this->mode & PEAR_ERROR_PRINT) {
903             if (is_null($options) || is_int($options)) {
904                 $format = "%s";
905             } else {
906                 $format = $options;
907             }
908
909             printf($format, $this->getMessage());
910         }
911
912         if ($this->mode & PEAR_ERROR_TRIGGER) {
913             trigger_error($this->getMessage(), $this->level);
914         }
915
916         if ($this->mode & PEAR_ERROR_DIE) {
917             $msg = $this->getMessage();
918             if (is_null($options) || is_int($options)) {
919                 $format = "%s";
920                 if (substr($msg, -1) != "\n") {
921                     $msg .= "\n";
922                 }
923             } else {
924                 $format = $options;
925             }
926             die(sprintf($format, $msg));
927         }
928
929         if ($this->mode & PEAR_ERROR_CALLBACK) {
930             if (is_callable($this->callback)) {
931                 call_user_func($this->callback, $this);
932             }
933         }
934
935         if ($this->mode & PEAR_ERROR_EXCEPTION) {
936             trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
937             eval('$e = new Exception($this->message, $this->code);throw($e);');
938         }
939     }
940
941     // }}}
942     // {{{ getMode()
943
944     /**
945      * Get the error mode from an error object.
946      *
947      * @return int error mode
948      * @access public
949      */
950     function getMode() {
951         return $this->mode;
952     }
953
954     // }}}
955     // {{{ getCallback()
956
957     /**
958      * Get the callback function/method from an error object.
959      *
960      * @return mixed callback function or object/method array
961      * @access public
962      */
963     function getCallback() {
964         return $this->callback;
965     }
966
967     // }}}
968     // {{{ getMessage()
969
970
971     /**
972      * Get the error message from an error object.
973      *
974      * @return  string  full error message
975      * @access public
976      */
977     function getMessage()
978     {
979         return ($this->error_message_prefix . $this->message);
980     }
981
982
983     // }}}
984     // {{{ getCode()
985
986     /**
987      * Get error code from an error object
988      *
989      * @return int error code
990      * @access public
991      */
992      function getCode()
993      {
994         return $this->code;
995      }
996
997     // }}}
998     // {{{ getType()
999
1000     /**
1001      * Get the name of this error/exception.
1002      *
1003      * @return string error/exception name (type)
1004      * @access public
1005      */
1006     function getType()
1007     {
1008         return get_class($this);
1009     }
1010
1011     // }}}
1012     // {{{ getUserInfo()
1013
1014     /**
1015      * Get additional user-supplied information.
1016      *
1017      * @return string user-supplied information
1018      * @access public
1019      */
1020     function getUserInfo()
1021     {
1022         return $this->userinfo;
1023     }
1024
1025     // }}}
1026     // {{{ getDebugInfo()
1027
1028     /**
1029      * Get additional debug information supplied by the application.
1030      *
1031      * @return string debug information
1032      * @access public
1033      */
1034     function getDebugInfo()
1035     {
1036         return $this->getUserInfo();
1037     }
1038
1039     // }}}
1040     // {{{ getBacktrace()
1041
1042     /**
1043      * Get the call backtrace from where the error was generated.
1044      * Supported with PHP 4.3.0 or newer.
1045      *
1046      * @param int $frame (optional) what frame to fetch
1047      * @return array Backtrace, or NULL if not available.
1048      * @access public
1049      */
1050     function getBacktrace($frame = null)
1051     {
1052         if (defined('PEAR_IGNORE_BACKTRACE')) {
1053             return null;
1054         }
1055         if ($frame === null) {
1056             return $this->backtrace;
1057         }
1058         return $this->backtrace[$frame];
1059     }
1060
1061     // }}}
1062     // {{{ addUserInfo()
1063
1064     function addUserInfo($info)
1065     {
1066         if (empty($this->userinfo)) {
1067             $this->userinfo = $info;
1068         } else {
1069             $this->userinfo .= " ** $info";
1070         }
1071     }
1072
1073     // }}}
1074     // {{{ toString()
1075     function __toString()
1076     {
1077         return $this->getMessage();
1078     }
1079     // }}}
1080     // {{{ toString()
1081
1082     /**
1083      * Make a string representation of this object.
1084      *
1085      * @return string a string with an object summary
1086      * @access public
1087      */
1088     function toString() {
1089         $modes = array();
1090         $levels = array(E_USER_NOTICE  => 'notice',
1091                         E_USER_WARNING => 'warning',
1092                         E_USER_ERROR   => 'error');
1093         if ($this->mode & PEAR_ERROR_CALLBACK) {
1094             if (is_array($this->callback)) {
1095                 $callback = (is_object($this->callback[0]) ?
1096                     strtolower(get_class($this->callback[0])) :
1097                     $this->callback[0]) . '::' .
1098                     $this->callback[1];
1099             } else {
1100                 $callback = $this->callback;
1101             }
1102             return sprintf('[%s: message="%s" code=%d mode=callback '.
1103                            'callback=%s prefix="%s" info="%s"]',
1104                            strtolower(get_class($this)), $this->message, $this->code,
1105                            $callback, $this->error_message_prefix,
1106                            $this->userinfo);
1107         }
1108         if ($this->mode & PEAR_ERROR_PRINT) {
1109             $modes[] = 'print';
1110         }
1111         if ($this->mode & PEAR_ERROR_TRIGGER) {
1112             $modes[] = 'trigger';
1113         }
1114         if ($this->mode & PEAR_ERROR_DIE) {
1115             $modes[] = 'die';
1116         }
1117         if ($this->mode & PEAR_ERROR_RETURN) {
1118             $modes[] = 'return';
1119         }
1120         return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.
1121                        'prefix="%s" info="%s"]',
1122                        strtolower(get_class($this)), $this->message, $this->code,
1123                        implode("|", $modes), $levels[$this->level],
1124                        $this->error_message_prefix,
1125                        $this->userinfo);
1126     }
1127
1128     // }}}
1129 }
1130
1131 /*
1132  * Local Variables:
1133  * mode: php
1134  * tab-width: 4
1135  * c-basic-offset: 4
1136  * End:
1137  */