]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Upgrade PEAR to 1.9.2
authorEvan Prodromou <evan@status.net>
Sat, 26 Mar 2011 18:37:42 +0000 (14:37 -0400)
committerEvan Prodromou <evan@status.net>
Sat, 26 Mar 2011 18:37:42 +0000 (14:37 -0400)
extlib/PEAR.php
extlib/PEAR/ErrorStack.php [new file with mode: 0644]
extlib/PEAR/Exception.php
extlib/PEAR5.php [new file with mode: 0644]
extlib/System.php [new file with mode: 0644]

index 4c24c6006a398f8f8ade714a87e67db58b9c7619..fec8de45cc1e788091f1fb117bb2e1f20576c722 100644 (file)
@@ -6,21 +6,15 @@
  *
  * PHP versions 4 and 5
  *
- * LICENSE: This source file is subject to version 3.0 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
  * @category   pear
  * @package    PEAR
  * @author     Sterling Hughes <sterling@php.net>
  * @author     Stig Bakken <ssb@php.net>
  * @author     Tomas V.V.Cox <cox@idecnet.com>
  * @author     Greg Beaver <cellog@php.net>
- * @copyright  1997-2008 The PHP Group
- * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
- * @version    CVS: $Id: PEAR.php,v 1.104 2008/01/03 20:26:34 cellog Exp $
+ * @copyright  1997-2010 The Authors
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    CVS: $Id: PEAR.php 307683 2011-01-23 21:56:12Z dufuz $
  * @link       http://pear.php.net/package/PEAR
  * @since      File available since Release 0.1
  */
@@ -52,15 +46,6 @@ if (substr(PHP_OS, 0, 3) == 'WIN') {
     define('PEAR_OS',    'Unix'); // blatant assumption
 }
 
-// instant backwards compatibility
-if (!defined('PATH_SEPARATOR')) {
-    if (OS_WINDOWS) {
-        define('PATH_SEPARATOR', ';');
-    } else {
-        define('PATH_SEPARATOR', ':');
-    }
-}
-
 $GLOBALS['_PEAR_default_error_mode']     = PEAR_ERROR_RETURN;
 $GLOBALS['_PEAR_default_error_options']  = E_USER_NOTICE;
 $GLOBALS['_PEAR_destructor_object_list'] = array();
@@ -92,8 +77,8 @@ $GLOBALS['_PEAR_error_handler_stack']    = array();
  * @author     Tomas V.V. Cox <cox@idecnet.com>
  * @author     Greg Beaver <cellog@php.net>
  * @copyright  1997-2006 The PHP Group
- * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
- * @version    Release: 1.7.2
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    Release: 1.9.2
  * @link       http://pear.php.net/package/PEAR
  * @see        PEAR_Error
  * @since      Class available since PHP 4.0.2
@@ -101,8 +86,6 @@ $GLOBALS['_PEAR_error_handler_stack']    = array();
  */
 class PEAR
 {
-    // {{{ properties
-
     /**
      * Whether to enable internal debug messages.
      *
@@ -153,10 +136,6 @@ class PEAR
      */
     var $_expected_errors = array();
 
-    // }}}
-
-    // {{{ constructor
-
     /**
      * Constructor.  Registers this object in
      * $_PEAR_destructor_object_list for destructor emulation if a
@@ -173,9 +152,11 @@ class PEAR
         if ($this->_debug) {
             print "PEAR constructor called, class=$classname\n";
         }
+
         if ($error_class !== null) {
             $this->_error_class = $error_class;
         }
+
         while ($classname && strcasecmp($classname, "pear")) {
             $destructor = "_$classname";
             if (method_exists($this, $destructor)) {
@@ -192,9 +173,6 @@ class PEAR
         }
     }
 
-    // }}}
-    // {{{ destructor
-
     /**
      * Destructor (the emulated type of...).  Does nothing right now,
      * but is included for forward compatibility, so subclass
@@ -212,9 +190,6 @@ class PEAR
         }
     }
 
-    // }}}
-    // {{{ getStaticProperty()
-
     /**
     * If you have a class that's mostly/entirely static, and you need static
     * properties, you can use this method to simulate them. Eg. in your method(s)
@@ -233,15 +208,14 @@ class PEAR
         if (!isset($properties[$class])) {
             $properties[$class] = array();
         }
+
         if (!array_key_exists($var, $properties[$class])) {
             $properties[$class][$var] = null;
         }
+
         return $properties[$class][$var];
     }
 
-    // }}}
-    // {{{ registerShutdownFunc()
-
     /**
     * Use this function to register a shutdown method for static
     * classes.
@@ -262,9 +236,6 @@ class PEAR
         $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
     }
 
-    // }}}
-    // {{{ isError()
-
     /**
      * Tell whether a value is a PEAR error.
      *
@@ -278,20 +249,18 @@ class PEAR
      */
     function isError($data, $code = null)
     {
-        if (is_a($data, 'PEAR_Error')) {
-            if (is_null($code)) {
-                return true;
-            } elseif (is_string($code)) {
-                return $data->getMessage() == $code;
-            } else {
-                return $data->getCode() == $code;
-            }
+        if (!is_a($data, 'PEAR_Error')) {
+            return false;
         }
-        return false;
-    }
 
-    // }}}
-    // {{{ setErrorHandling()
+        if (is_null($code)) {
+            return true;
+        } elseif (is_string($code)) {
+            return $data->getMessage() == $code;
+        }
+
+        return $data->getCode() == $code;
+    }
 
     /**
      * Sets how errors generated by this object should be handled.
@@ -331,7 +300,6 @@ class PEAR
      *
      * @since PHP 4.0.5
      */
-
     function setErrorHandling($mode = null, $options = null)
     {
         if (isset($this) && is_a($this, 'PEAR')) {
@@ -369,9 +337,6 @@ class PEAR
         }
     }
 
-    // }}}
-    // {{{ expectError()
-
     /**
      * This method is used to tell which errors you expect to get.
      * Expected errors are always returned with error mode
@@ -394,12 +359,9 @@ class PEAR
         } else {
             array_push($this->_expected_errors, array($code));
         }
-        return sizeof($this->_expected_errors);
+        return count($this->_expected_errors);
     }
 
-    // }}}
-    // {{{ popExpect()
-
     /**
      * This method pops one element off the expected error codes
      * stack.
@@ -411,9 +373,6 @@ class PEAR
         return array_pop($this->_expected_errors);
     }
 
-    // }}}
-    // {{{ _checkDelExpect()
-
     /**
      * This method checks unsets an error code if available
      *
@@ -425,8 +384,7 @@ class PEAR
     function _checkDelExpect($error_code)
     {
         $deleted = false;
-
-        foreach ($this->_expected_errors AS $key => $error_array) {
+        foreach ($this->_expected_errors as $key => $error_array) {
             if (in_array($error_code, $error_array)) {
                 unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
                 $deleted = true;
@@ -437,12 +395,10 @@ class PEAR
                 unset($this->_expected_errors[$key]);
             }
         }
+
         return $deleted;
     }
 
-    // }}}
-    // {{{ delExpect()
-
     /**
      * This method deletes all occurences of the specified element from
      * the expected error codes stack.
@@ -455,34 +411,26 @@ class PEAR
     function delExpect($error_code)
     {
         $deleted = false;
-
         if ((is_array($error_code) && (0 != count($error_code)))) {
-            // $error_code is a non-empty array here;
-            // we walk through it trying to unset all
-            // values
-            foreach($error_code as $key => $error) {
-                if ($this->_checkDelExpect($error)) {
-                    $deleted =  true;
-                } else {
-                    $deleted = false;
-                }
+            // $error_code is a non-empty array here; we walk through it trying
+            // to unset all values
+            foreach ($error_code as $key => $error) {
+                $deleted =  $this->_checkDelExpect($error) ? true : false;
             }
+
             return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
         } elseif (!empty($error_code)) {
             // $error_code comes alone, trying to unset it
             if ($this->_checkDelExpect($error_code)) {
                 return true;
-            } else {
-                return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
             }
-        } else {
-            // $error_code is empty
-            return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
+
+            return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
         }
-    }
 
-    // }}}
-    // {{{ raiseError()
+        // $error_code is empty
+        return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
+    }
 
     /**
      * This method is a wrapper that returns an instance of the
@@ -538,13 +486,20 @@ class PEAR
             $message     = $message->getMessage();
         }
 
-        if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) {
+        if (
+            isset($this) &&
+            isset($this->_expected_errors) &&
+            count($this->_expected_errors) > 0 &&
+            count($exp = end($this->_expected_errors))
+        ) {
             if ($exp[0] == "*" ||
                 (is_int(reset($exp)) && in_array($code, $exp)) ||
-                (is_string(reset($exp)) && in_array($message, $exp))) {
+                (is_string(reset($exp)) && in_array($message, $exp))
+            ) {
                 $mode = PEAR_ERROR_RETURN;
             }
         }
+
         // No mode given, try global ones
         if ($mode === null) {
             // Class error handler
@@ -565,46 +520,52 @@ class PEAR
         } else {
             $ec = 'PEAR_Error';
         }
+
         if (intval(PHP_VERSION) < 5) {
             // little non-eval hack to fix bug #12147
             include 'PEAR/FixPHP5PEARWarnings.php';
             return $a;
         }
+
         if ($skipmsg) {
             $a = new $ec($code, $mode, $options, $userinfo);
         } else {
             $a = new $ec($message, $code, $mode, $options, $userinfo);
         }
+
         return $a;
     }
 
-    // }}}
-    // {{{ throwError()
-
     /**
      * Simpler form of raiseError with fewer options.  In most cases
      * message, code and userinfo are enough.
      *
-     * @param string $message
+     * @param mixed $message a text error message or a PEAR error object
      *
+     * @param int $code      a numeric error code (it is up to your class
+     *                  to define these if you want to use codes)
+     *
+     * @param string $userinfo If you need to pass along for example debug
+     *                  information, this parameter is meant for that.
+     *
+     * @access public
+     * @return object   a PEAR error object
+     * @see PEAR::raiseError
      */
-    function &throwError($message = null,
-                         $code = null,
-                         $userinfo = null)
+    function &throwError($message = null, $code = null, $userinfo = null)
     {
         if (isset($this) && is_a($this, 'PEAR')) {
             $a = &$this->raiseError($message, $code, null, null, $userinfo);
             return $a;
-        } else {
-            $a = &PEAR::raiseError($message, $code, null, null, $userinfo);
-            return $a;
         }
+
+        $a = &PEAR::raiseError($message, $code, null, null, $userinfo);
+        return $a;
     }
 
-    // }}}
     function staticPushErrorHandling($mode, $options = null)
     {
-        $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+        $stack       = &$GLOBALS['_PEAR_error_handler_stack'];
         $def_mode    = &$GLOBALS['_PEAR_default_error_mode'];
         $def_options = &$GLOBALS['_PEAR_default_error_options'];
         $stack[] = array($def_mode, $def_options);
@@ -673,8 +634,6 @@ class PEAR
         return true;
     }
 
-    // {{{ pushErrorHandling()
-
     /**
      * Push a new error handler on top of the error handler options stack. With this
      * you can easily override the actual error handler for some code and restore
@@ -708,9 +667,6 @@ class PEAR
         return true;
     }
 
-    // }}}
-    // {{{ popErrorHandling()
-
     /**
     * Pop the last error handler used
     *
@@ -732,9 +688,6 @@ class PEAR
         return true;
     }
 
-    // }}}
-    // {{{ loadExtension()
-
     /**
     * OS independant PHP extension load. Remember to take care
     * on the correct extension name for case sensitive OSes.
@@ -744,31 +697,38 @@ class PEAR
     */
     function loadExtension($ext)
     {
-        if (!extension_loaded($ext)) {
-            // if either returns true dl() will produce a FATAL error, stop that
-            if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
-                return false;
-            }
-            if (OS_WINDOWS) {
-                $suffix = '.dll';
-            } elseif (PHP_OS == 'HP-UX') {
-                $suffix = '.sl';
-            } elseif (PHP_OS == 'AIX') {
-                $suffix = '.a';
-            } elseif (PHP_OS == 'OSX') {
-                $suffix = '.bundle';
-            } else {
-                $suffix = '.so';
-            }
-            return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
+        if (extension_loaded($ext)) {
+            return true;
+        }
+
+        // if either returns true dl() will produce a FATAL error, stop that
+        if (
+            function_exists('dl') === false ||
+            ini_get('enable_dl') != 1 ||
+            ini_get('safe_mode') == 1
+        ) {
+            return false;
         }
-        return true;
-    }
 
-    // }}}
+        if (OS_WINDOWS) {
+            $suffix = '.dll';
+        } elseif (PHP_OS == 'HP-UX') {
+            $suffix = '.sl';
+        } elseif (PHP_OS == 'AIX') {
+            $suffix = '.a';
+        } elseif (PHP_OS == 'OSX') {
+            $suffix = '.bundle';
+        } else {
+            $suffix = '.so';
+        }
+
+        return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
+    }
 }
 
-// {{{ _PEAR_call_destructors()
+if (PEAR_ZE2) {
+    include_once 'PEAR5.php';
+}
 
 function _PEAR_call_destructors()
 {
@@ -777,9 +737,16 @@ function _PEAR_call_destructors()
         sizeof($_PEAR_destructor_object_list))
     {
         reset($_PEAR_destructor_object_list);
-        if (PEAR::getStaticProperty('PEAR', 'destructlifo')) {
+        if (PEAR_ZE2) {
+            $destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo');
+        } else {
+            $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo');
+        }
+
+        if ($destructLifoExists) {
             $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
         }
+
         while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
             $classname = get_class($objref);
             while ($classname) {
@@ -798,14 +765,17 @@ function _PEAR_call_destructors()
     }
 
     // Now call the shutdown functions
-    if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) {
+    if (
+        isset($GLOBALS['_PEAR_shutdown_funcs']) &&
+        is_array($GLOBALS['_PEAR_shutdown_funcs']) &&
+        !empty($GLOBALS['_PEAR_shutdown_funcs'])
+    ) {
         foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
             call_user_func_array($value[0], $value[1]);
         }
     }
 }
 
-// }}}
 /**
  * Standard PEAR error class for PHP 4
  *
@@ -817,16 +787,14 @@ function _PEAR_call_destructors()
  * @author     Tomas V.V. Cox <cox@idecnet.com>
  * @author     Gregory Beaver <cellog@php.net>
  * @copyright  1997-2006 The PHP Group
- * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
- * @version    Release: 1.7.2
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    Release: 1.9.2
  * @link       http://pear.php.net/manual/en/core.pear.pear-error.php
  * @see        PEAR::raiseError(), PEAR::throwError()
  * @since      Class available since PHP 4.0.2
  */
 class PEAR_Error
 {
-    // {{{ properties
-
     var $error_message_prefix = '';
     var $mode                 = PEAR_ERROR_RETURN;
     var $level                = E_USER_NOTICE;
@@ -835,9 +803,6 @@ class PEAR_Error
     var $userinfo             = '';
     var $backtrace            = null;
 
-    // }}}
-    // {{{ constructor
-
     /**
      * PEAR_Error constructor
      *
@@ -868,12 +833,20 @@ class PEAR_Error
         $this->code      = $code;
         $this->mode      = $mode;
         $this->userinfo  = $userinfo;
-        if (!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) {
+
+        if (PEAR_ZE2) {
+            $skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace');
+        } else {
+            $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace');
+        }
+
+        if (!$skiptrace) {
             $this->backtrace = debug_backtrace();
             if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
                 unset($this->backtrace[0]['object']);
             }
         }
+
         if ($mode & PEAR_ERROR_CALLBACK) {
             $this->level = E_USER_NOTICE;
             $this->callback = $options;
@@ -881,20 +854,25 @@ class PEAR_Error
             if ($options === null) {
                 $options = E_USER_NOTICE;
             }
+
             $this->level = $options;
             $this->callback = null;
         }
+
         if ($this->mode & PEAR_ERROR_PRINT) {
             if (is_null($options) || is_int($options)) {
                 $format = "%s";
             } else {
                 $format = $options;
             }
+
             printf($format, $this->getMessage());
         }
+
         if ($this->mode & PEAR_ERROR_TRIGGER) {
             trigger_error($this->getMessage(), $this->level);
         }
+
         if ($this->mode & PEAR_ERROR_DIE) {
             $msg = $this->getMessage();
             if (is_null($options) || is_int($options)) {
@@ -907,47 +885,39 @@ class PEAR_Error
             }
             die(sprintf($format, $msg));
         }
-        if ($this->mode & PEAR_ERROR_CALLBACK) {
-            if (is_callable($this->callback)) {
-                call_user_func($this->callback, $this);
-            }
+
+        if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) {
+            call_user_func($this->callback, $this);
         }
+
         if ($this->mode & PEAR_ERROR_EXCEPTION) {
             trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
             eval('$e = new Exception($this->message, $this->code);throw($e);');
         }
     }
 
-    // }}}
-    // {{{ getMode()
-
     /**
      * Get the error mode from an error object.
      *
      * @return int error mode
      * @access public
      */
-    function getMode() {
+    function getMode()
+    {
         return $this->mode;
     }
 
-    // }}}
-    // {{{ getCallback()
-
     /**
      * Get the callback function/method from an error object.
      *
      * @return mixed callback function or object/method array
      * @access public
      */
-    function getCallback() {
+    function getCallback()
+    {
         return $this->callback;
     }
 
-    // }}}
-    // {{{ getMessage()
-
-
     /**
      * Get the error message from an error object.
      *
@@ -959,10 +929,6 @@ class PEAR_Error
         return ($this->error_message_prefix . $this->message);
     }
 
-
-    // }}}
-    // {{{ getCode()
-
     /**
      * Get error code from an error object
      *
@@ -974,9 +940,6 @@ class PEAR_Error
         return $this->code;
      }
 
-    // }}}
-    // {{{ getType()
-
     /**
      * Get the name of this error/exception.
      *
@@ -988,9 +951,6 @@ class PEAR_Error
         return get_class($this);
     }
 
-    // }}}
-    // {{{ getUserInfo()
-
     /**
      * Get additional user-supplied information.
      *
@@ -1002,9 +962,6 @@ class PEAR_Error
         return $this->userinfo;
     }
 
-    // }}}
-    // {{{ getDebugInfo()
-
     /**
      * Get additional debug information supplied by the application.
      *
@@ -1016,9 +973,6 @@ class PEAR_Error
         return $this->getUserInfo();
     }
 
-    // }}}
-    // {{{ getBacktrace()
-
     /**
      * Get the call backtrace from where the error was generated.
      * Supported with PHP 4.3.0 or newer.
@@ -1038,9 +992,6 @@ class PEAR_Error
         return $this->backtrace[$frame];
     }
 
-    // }}}
-    // {{{ addUserInfo()
-
     function addUserInfo($info)
     {
         if (empty($this->userinfo)) {
@@ -1050,14 +1001,10 @@ class PEAR_Error
         }
     }
 
-    // }}}
-    // {{{ toString()
     function __toString()
     {
         return $this->getMessage();
     }
-    // }}}
-    // {{{ toString()
 
     /**
      * Make a string representation of this object.
@@ -1065,7 +1012,8 @@ class PEAR_Error
      * @return string a string with an object summary
      * @access public
      */
-    function toString() {
+    function toString()
+    {
         $modes = array();
         $levels = array(E_USER_NOTICE  => 'notice',
                         E_USER_WARNING => 'warning',
@@ -1104,8 +1052,6 @@ class PEAR_Error
                        $this->error_message_prefix,
                        $this->userinfo);
     }
-
-    // }}}
 }
 
 /*
@@ -1115,4 +1061,3 @@ class PEAR_Error
  * c-basic-offset: 4
  * End:
  */
-?>
diff --git a/extlib/PEAR/ErrorStack.php b/extlib/PEAR/ErrorStack.php
new file mode 100644 (file)
index 0000000..3229fba
--- /dev/null
@@ -0,0 +1,985 @@
+<?php
+/**
+ * Error Stack Implementation
+ * 
+ * This is an incredibly simple implementation of a very complex error handling
+ * facility.  It contains the ability
+ * to track multiple errors from multiple packages simultaneously.  In addition,
+ * it can track errors of many levels, save data along with the error, context
+ * information such as the exact file, line number, class and function that
+ * generated the error, and if necessary, it can raise a traditional PEAR_Error.
+ * It has built-in support for PEAR::Log, to log errors as they occur
+ * 
+ * Since version 0.2alpha, it is also possible to selectively ignore errors,
+ * through the use of an error callback, see {@link pushCallback()}
+ * 
+ * Since version 0.3alpha, it is possible to specify the exception class
+ * returned from {@link push()}
+ *
+ * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class.  This can
+ * still be done quite handily in an error callback or by manipulating the returned array
+ * @category   Debugging
+ * @package    PEAR_ErrorStack
+ * @author     Greg Beaver <cellog@php.net>
+ * @copyright  2004-2008 Greg Beaver
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    CVS: $Id: ErrorStack.php 307683 2011-01-23 21:56:12Z dufuz $
+ * @link       http://pear.php.net/package/PEAR_ErrorStack
+ */
+
+/**
+ * Singleton storage
+ * 
+ * Format:
+ * <pre>
+ * array(
+ *  'package1' => PEAR_ErrorStack object,
+ *  'package2' => PEAR_ErrorStack object,
+ *  ...
+ * )
+ * </pre>
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
+
+/**
+ * Global error callback (default)
+ * 
+ * This is only used if set to non-false.  * is the default callback for
+ * all packages, whereas specific packages may set a default callback
+ * for all instances, regardless of whether they are a singleton or not.
+ *
+ * To exclude non-singletons, only set the local callback for the singleton
+ * @see PEAR_ErrorStack::setDefaultCallback()
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
+    '*' => false,
+);
+
+/**
+ * Global Log object (default)
+ * 
+ * This is only used if set to non-false.  Use to set a default log object for
+ * all stacks, regardless of instantiation order or location
+ * @see PEAR_ErrorStack::setDefaultLogger()
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
+
+/**
+ * Global Overriding Callback
+ * 
+ * This callback will override any error callbacks that specific loggers have set.
+ * Use with EXTREME caution
+ * @see PEAR_ErrorStack::staticPushCallback()
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
+
+/**#@+
+ * One of four possible return values from the error Callback
+ * @see PEAR_ErrorStack::_errorCallback()
+ */
+/**
+ * If this is returned, then the error will be both pushed onto the stack
+ * and logged.
+ */
+define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
+/**
+ * If this is returned, then the error will only be pushed onto the stack,
+ * and not logged.
+ */
+define('PEAR_ERRORSTACK_PUSH', 2);
+/**
+ * If this is returned, then the error will only be logged, but not pushed
+ * onto the error stack.
+ */
+define('PEAR_ERRORSTACK_LOG', 3);
+/**
+ * If this is returned, then the error is completely ignored.
+ */
+define('PEAR_ERRORSTACK_IGNORE', 4);
+/**
+ * If this is returned, then the error is logged and die() is called.
+ */
+define('PEAR_ERRORSTACK_DIE', 5);
+/**#@-*/
+
+/**
+ * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
+ * the singleton method.
+ */
+define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
+
+/**
+ * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
+ * that has no __toString() method
+ */
+define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
+/**
+ * Error Stack Implementation
+ *
+ * Usage:
+ * <code>
+ * // global error stack
+ * $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
+ * // local error stack
+ * $local_stack = new PEAR_ErrorStack('MyPackage');
+ * </code>
+ * @author     Greg Beaver <cellog@php.net>
+ * @version    1.9.2
+ * @package    PEAR_ErrorStack
+ * @category   Debugging
+ * @copyright  2004-2008 Greg Beaver
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    CVS: $Id: ErrorStack.php 307683 2011-01-23 21:56:12Z dufuz $
+ * @link       http://pear.php.net/package/PEAR_ErrorStack
+ */
+class PEAR_ErrorStack {
+    /**
+     * Errors are stored in the order that they are pushed on the stack.
+     * @since 0.4alpha Errors are no longer organized by error level.
+     * This renders pop() nearly unusable, and levels could be more easily
+     * handled in a callback anyway
+     * @var array
+     * @access private
+     */
+    var $_errors = array();
+
+    /**
+     * Storage of errors by level.
+     *
+     * Allows easy retrieval and deletion of only errors from a particular level
+     * @since PEAR 1.4.0dev
+     * @var array
+     * @access private
+     */
+    var $_errorsByLevel = array();
+
+    /**
+     * Package name this error stack represents
+     * @var string
+     * @access protected
+     */
+    var $_package;
+    
+    /**
+     * Determines whether a PEAR_Error is thrown upon every error addition
+     * @var boolean
+     * @access private
+     */
+    var $_compat = false;
+    
+    /**
+     * If set to a valid callback, this will be used to generate the error
+     * message from the error code, otherwise the message passed in will be
+     * used
+     * @var false|string|array
+     * @access private
+     */
+    var $_msgCallback = false;
+    
+    /**
+     * If set to a valid callback, this will be used to generate the error
+     * context for an error.  For PHP-related errors, this will be a file
+     * and line number as retrieved from debug_backtrace(), but can be
+     * customized for other purposes.  The error might actually be in a separate
+     * configuration file, or in a database query.
+     * @var false|string|array
+     * @access protected
+     */
+    var $_contextCallback = false;
+    
+    /**
+     * If set to a valid callback, this will be called every time an error
+     * is pushed onto the stack.  The return value will be used to determine
+     * whether to allow an error to be pushed or logged.
+     * 
+     * The return value must be one an PEAR_ERRORSTACK_* constant
+     * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
+     * @var false|string|array
+     * @access protected
+     */
+    var $_errorCallback = array();
+    
+    /**
+     * PEAR::Log object for logging errors
+     * @var false|Log
+     * @access protected
+     */
+    var $_logger = false;
+    
+    /**
+     * Error messages - designed to be overridden
+     * @var array
+     * @abstract
+     */
+    var $_errorMsgs = array();
+    
+    /**
+     * Set up a new error stack
+     * 
+     * @param string   $package name of the package this error stack represents
+     * @param callback $msgCallback callback used for error message generation
+     * @param callback $contextCallback callback used for context generation,
+     *                 defaults to {@link getFileLine()}
+     * @param boolean  $throwPEAR_Error
+     */
+    function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false,
+                         $throwPEAR_Error = false)
+    {
+        $this->_package = $package;
+        $this->setMessageCallback($msgCallback);
+        $this->setContextCallback($contextCallback);
+        $this->_compat = $throwPEAR_Error;
+    }
+    
+    /**
+     * Return a single error stack for this package.
+     * 
+     * Note that all parameters are ignored if the stack for package $package
+     * has already been instantiated
+     * @param string   $package name of the package this error stack represents
+     * @param callback $msgCallback callback used for error message generation
+     * @param callback $contextCallback callback used for context generation,
+     *                 defaults to {@link getFileLine()}
+     * @param boolean  $throwPEAR_Error
+     * @param string   $stackClass class to instantiate
+     * @static
+     * @return PEAR_ErrorStack
+     */
+    function &singleton($package, $msgCallback = false, $contextCallback = false,
+                         $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack')
+    {
+        if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
+            return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
+        }
+        if (!class_exists($stackClass)) {
+            if (function_exists('debug_backtrace')) {
+                $trace = debug_backtrace();
+            }
+            PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
+                'exception', array('stackclass' => $stackClass),
+                'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
+                false, $trace);
+        }
+        $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
+            new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
+
+        return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
+    }
+
+    /**
+     * Internal error handler for PEAR_ErrorStack class
+     * 
+     * Dies if the error is an exception (and would have died anyway)
+     * @access private
+     */
+    function _handleError($err)
+    {
+        if ($err['level'] == 'exception') {
+            $message = $err['message'];
+            if (isset($_SERVER['REQUEST_URI'])) {
+                echo '<br />';
+            } else {
+                echo "\n";
+            }
+            var_dump($err['context']);
+            die($message);
+        }
+    }
+    
+    /**
+     * Set up a PEAR::Log object for all error stacks that don't have one
+     * @param Log $log 
+     * @static
+     */
+    function setDefaultLogger(&$log)
+    {
+        if (is_object($log) && method_exists($log, 'log') ) {
+            $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
+        } elseif (is_callable($log)) {
+            $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
+       }
+    }
+    
+    /**
+     * Set up a PEAR::Log object for this error stack
+     * @param Log $log 
+     */
+    function setLogger(&$log)
+    {
+        if (is_object($log) && method_exists($log, 'log') ) {
+            $this->_logger = &$log;
+        } elseif (is_callable($log)) {
+            $this->_logger = &$log;
+        }
+    }
+    
+    /**
+     * Set an error code => error message mapping callback
+     * 
+     * This method sets the callback that can be used to generate error
+     * messages for any instance
+     * @param array|string Callback function/method
+     */
+    function setMessageCallback($msgCallback)
+    {
+        if (!$msgCallback) {
+            $this->_msgCallback = array(&$this, 'getErrorMessage');
+        } else {
+            if (is_callable($msgCallback)) {
+                $this->_msgCallback = $msgCallback;
+            }
+        }
+    }
+    
+    /**
+     * Get an error code => error message mapping callback
+     * 
+     * This method returns the current callback that can be used to generate error
+     * messages
+     * @return array|string|false Callback function/method or false if none
+     */
+    function getMessageCallback()
+    {
+        return $this->_msgCallback;
+    }
+    
+    /**
+     * Sets a default callback to be used by all error stacks
+     * 
+     * This method sets the callback that can be used to generate error
+     * messages for a singleton
+     * @param array|string Callback function/method
+     * @param string Package name, or false for all packages
+     * @static
+     */
+    function setDefaultCallback($callback = false, $package = false)
+    {
+        if (!is_callable($callback)) {
+            $callback = false;
+        }
+        $package = $package ? $package : '*';
+        $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback;
+    }
+    
+    /**
+     * Set a callback that generates context information (location of error) for an error stack
+     * 
+     * This method sets the callback that can be used to generate context
+     * information for an error.  Passing in NULL will disable context generation
+     * and remove the expensive call to debug_backtrace()
+     * @param array|string|null Callback function/method
+     */
+    function setContextCallback($contextCallback)
+    {
+        if ($contextCallback === null) {
+            return $this->_contextCallback = false;
+        }
+        if (!$contextCallback) {
+            $this->_contextCallback = array(&$this, 'getFileLine');
+        } else {
+            if (is_callable($contextCallback)) {
+                $this->_contextCallback = $contextCallback;
+            }
+        }
+    }
+    
+    /**
+     * Set an error Callback
+     * If set to a valid callback, this will be called every time an error
+     * is pushed onto the stack.  The return value will be used to determine
+     * whether to allow an error to be pushed or logged.
+     * 
+     * The return value must be one of the ERRORSTACK_* constants.
+     * 
+     * This functionality can be used to emulate PEAR's pushErrorHandling, and
+     * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
+     * the error stack or logging
+     * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
+     * @see popCallback()
+     * @param string|array $cb
+     */
+    function pushCallback($cb)
+    {
+        array_push($this->_errorCallback, $cb);
+    }
+    
+    /**
+     * Remove a callback from the error callback stack
+     * @see pushCallback()
+     * @return array|string|false
+     */
+    function popCallback()
+    {
+        if (!count($this->_errorCallback)) {
+            return false;
+        }
+        return array_pop($this->_errorCallback);
+    }
+    
+    /**
+     * Set a temporary overriding error callback for every package error stack
+     *
+     * Use this to temporarily disable all existing callbacks (can be used
+     * to emulate the @ operator, for instance)
+     * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
+     * @see staticPopCallback(), pushCallback()
+     * @param string|array $cb
+     * @static
+     */
+    function staticPushCallback($cb)
+    {
+        array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
+    }
+    
+    /**
+     * Remove a temporary overriding error callback
+     * @see staticPushCallback()
+     * @return array|string|false
+     * @static
+     */
+    function staticPopCallback()
+    {
+        $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']);
+        if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) {
+            $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
+        }
+        return $ret;
+    }
+    
+    /**
+     * Add an error to the stack
+     * 
+     * If the message generator exists, it is called with 2 parameters.
+     *  - the current Error Stack object
+     *  - an array that is in the same format as an error.  Available indices
+     *    are 'code', 'package', 'time', 'params', 'level', and 'context'
+     * 
+     * Next, if the error should contain context information, this is
+     * handled by the context grabbing method.
+     * Finally, the error is pushed onto the proper error stack
+     * @param int    $code      Package-specific error code
+     * @param string $level     Error level.  This is NOT spell-checked
+     * @param array  $params    associative array of error parameters
+     * @param string $msg       Error message, or a portion of it if the message
+     *                          is to be generated
+     * @param array  $repackage If this error re-packages an error pushed by
+     *                          another package, place the array returned from
+     *                          {@link pop()} in this parameter
+     * @param array  $backtrace Protected parameter: use this to pass in the
+     *                          {@link debug_backtrace()} that should be used
+     *                          to find error context
+     * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
+     * thrown.  If a PEAR_Error is returned, the userinfo
+     * property is set to the following array:
+     * 
+     * <code>
+     * array(
+     *    'code' => $code,
+     *    'params' => $params,
+     *    'package' => $this->_package,
+     *    'level' => $level,
+     *    'time' => time(),
+     *    'context' => $context,
+     *    'message' => $msg,
+     * //['repackage' => $err] repackaged error array/Exception class
+     * );
+     * </code>
+     * 
+     * Normally, the previous array is returned.
+     */
+    function push($code, $level = 'error', $params = array(), $msg = false,
+                  $repackage = false, $backtrace = false)
+    {
+        $context = false;
+        // grab error context
+        if ($this->_contextCallback) {
+            if (!$backtrace) {
+                $backtrace = debug_backtrace();
+            }
+            $context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
+        }
+        
+        // save error
+        $time = explode(' ', microtime());
+        $time = $time[1] + $time[0];
+        $err = array(
+                'code' => $code,
+                'params' => $params,
+                'package' => $this->_package,
+                'level' => $level,
+                'time' => $time,
+                'context' => $context,
+                'message' => $msg,
+               );
+
+        if ($repackage) {
+            $err['repackage'] = $repackage;
+        }
+
+        // set up the error message, if necessary
+        if ($this->_msgCallback) {
+            $msg = call_user_func_array($this->_msgCallback,
+                                        array(&$this, $err));
+            $err['message'] = $msg;
+        }        
+        $push = $log = true;
+        $die = false;
+        // try the overriding callback first
+        $callback = $this->staticPopCallback();
+        if ($callback) {
+            $this->staticPushCallback($callback);
+        }
+        if (!is_callable($callback)) {
+            // try the local callback next
+            $callback = $this->popCallback();
+            if (is_callable($callback)) {
+                $this->pushCallback($callback);
+            } else {
+                // try the default callback
+                $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ?
+                    $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] :
+                    $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*'];
+            }
+        }
+        if (is_callable($callback)) {
+            switch(call_user_func($callback, $err)){
+               case PEAR_ERRORSTACK_IGNORE: 
+                       return $err;
+                       break;
+               case PEAR_ERRORSTACK_PUSH: 
+                       $log = false;
+                       break;
+               case PEAR_ERRORSTACK_LOG: 
+                       $push = false;
+                       break;
+               case PEAR_ERRORSTACK_DIE: 
+                       $die = true;
+                       break;
+                // anything else returned has the same effect as pushandlog
+            }
+        }
+        if ($push) {
+            array_unshift($this->_errors, $err);
+            if (!isset($this->_errorsByLevel[$err['level']])) {
+                $this->_errorsByLevel[$err['level']] = array();
+            }
+            $this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
+        }
+        if ($log) {
+            if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
+                $this->_log($err);
+            }
+        }
+        if ($die) {
+            die();
+        }
+        if ($this->_compat && $push) {
+            return $this->raiseError($msg, $code, null, null, $err);
+        }
+        return $err;
+    }
+    
+    /**
+     * Static version of {@link push()}
+     * 
+     * @param string $package   Package name this error belongs to
+     * @param int    $code      Package-specific error code
+     * @param string $level     Error level.  This is NOT spell-checked
+     * @param array  $params    associative array of error parameters
+     * @param string $msg       Error message, or a portion of it if the message
+     *                          is to be generated
+     * @param array  $repackage If this error re-packages an error pushed by
+     *                          another package, place the array returned from
+     *                          {@link pop()} in this parameter
+     * @param array  $backtrace Protected parameter: use this to pass in the
+     *                          {@link debug_backtrace()} that should be used
+     *                          to find error context
+     * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
+     *                          thrown.  see docs for {@link push()}
+     * @static
+     */
+    function staticPush($package, $code, $level = 'error', $params = array(),
+                        $msg = false, $repackage = false, $backtrace = false)
+    {
+        $s = &PEAR_ErrorStack::singleton($package);
+        if ($s->_contextCallback) {
+            if (!$backtrace) {
+                if (function_exists('debug_backtrace')) {
+                    $backtrace = debug_backtrace();
+                }
+            }
+        }
+        return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
+    }
+    
+    /**
+     * Log an error using PEAR::Log
+     * @param array $err Error array
+     * @param array $levels Error level => Log constant map
+     * @access protected
+     */
+    function _log($err)
+    {
+        if ($this->_logger) {
+            $logger = &$this->_logger;
+        } else {
+            $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
+        }
+        if (is_a($logger, 'Log')) {
+            $levels = array(
+                'exception' => PEAR_LOG_CRIT,
+                'alert' => PEAR_LOG_ALERT,
+                'critical' => PEAR_LOG_CRIT,
+                'error' => PEAR_LOG_ERR,
+                'warning' => PEAR_LOG_WARNING,
+                'notice' => PEAR_LOG_NOTICE,
+                'info' => PEAR_LOG_INFO,
+                'debug' => PEAR_LOG_DEBUG);
+            if (isset($levels[$err['level']])) {
+                $level = $levels[$err['level']];
+            } else {
+                $level = PEAR_LOG_INFO;
+            }
+            $logger->log($err['message'], $level, $err);
+        } else { // support non-standard logs
+            call_user_func($logger, $err);
+        }
+    }
+
+    
+    /**
+     * Pop an error off of the error stack
+     * 
+     * @return false|array
+     * @since 0.4alpha it is no longer possible to specify a specific error
+     * level to return - the last error pushed will be returned, instead
+     */
+    function pop()
+    {
+        $err = @array_shift($this->_errors);
+        if (!is_null($err)) {
+            @array_pop($this->_errorsByLevel[$err['level']]);
+            if (!count($this->_errorsByLevel[$err['level']])) {
+                unset($this->_errorsByLevel[$err['level']]);
+            }
+        }
+        return $err;
+    }
+
+    /**
+     * Pop an error off of the error stack, static method
+     *
+     * @param string package name
+     * @return boolean
+     * @since PEAR1.5.0a1
+     */
+    function staticPop($package)
+    {
+        if ($package) {
+            if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
+                return false;
+            }
+            return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
+        }
+    }
+
+    /**
+     * Determine whether there are any errors on the stack
+     * @param string|array Level name.  Use to determine if any errors
+     * of level (string), or levels (array) have been pushed
+     * @return boolean
+     */
+    function hasErrors($level = false)
+    {
+        if ($level) {
+            return isset($this->_errorsByLevel[$level]);
+        }
+        return count($this->_errors);
+    }
+    
+    /**
+     * Retrieve all errors since last purge
+     * 
+     * @param boolean set in order to empty the error stack
+     * @param string level name, to return only errors of a particular severity
+     * @return array
+     */
+    function getErrors($purge = false, $level = false)
+    {
+        if (!$purge) {
+            if ($level) {
+                if (!isset($this->_errorsByLevel[$level])) {
+                    return array();
+                } else {
+                    return $this->_errorsByLevel[$level];
+                }
+            } else {
+                return $this->_errors;
+            }
+        }
+        if ($level) {
+            $ret = $this->_errorsByLevel[$level];
+            foreach ($this->_errorsByLevel[$level] as $i => $unused) {
+                // entries are references to the $_errors array
+                $this->_errorsByLevel[$level][$i] = false;
+            }
+            // array_filter removes all entries === false
+            $this->_errors = array_filter($this->_errors);
+            unset($this->_errorsByLevel[$level]);
+            return $ret;
+        }
+        $ret = $this->_errors;
+        $this->_errors = array();
+        $this->_errorsByLevel = array();
+        return $ret;
+    }
+    
+    /**
+     * Determine whether there are any errors on a single error stack, or on any error stack
+     *
+     * The optional parameter can be used to test the existence of any errors without the need of
+     * singleton instantiation
+     * @param string|false Package name to check for errors
+     * @param string Level name to check for a particular severity
+     * @return boolean
+     * @static
+     */
+    function staticHasErrors($package = false, $level = false)
+    {
+        if ($package) {
+            if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
+                return false;
+            }
+            return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level);
+        }
+        foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
+            if ($obj->hasErrors($level)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Get a list of all errors since last purge, organized by package
+     * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
+     * @param boolean $purge Set to purge the error stack of existing errors
+     * @param string  $level Set to a level name in order to retrieve only errors of a particular level
+     * @param boolean $merge Set to return a flat array, not organized by package
+     * @param array   $sortfunc Function used to sort a merged array - default
+     *        sorts by time, and should be good for most cases
+     * @static
+     * @return array 
+     */
+    function staticGetErrors($purge = false, $level = false, $merge = false,
+                             $sortfunc = array('PEAR_ErrorStack', '_sortErrors'))
+    {
+        $ret = array();
+        if (!is_callable($sortfunc)) {
+            $sortfunc = array('PEAR_ErrorStack', '_sortErrors');
+        }
+        foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
+            $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level);
+            if ($test) {
+                if ($merge) {
+                    $ret = array_merge($ret, $test);
+                } else {
+                    $ret[$package] = $test;
+                }
+            }
+        }
+        if ($merge) {
+            usort($ret, $sortfunc);
+        }
+        return $ret;
+    }
+    
+    /**
+     * Error sorting function, sorts by time
+     * @access private
+     */
+    function _sortErrors($a, $b)
+    {
+        if ($a['time'] == $b['time']) {
+            return 0;
+        }
+        if ($a['time'] < $b['time']) {
+            return 1;
+        }
+        return -1;
+    }
+
+    /**
+     * Standard file/line number/function/class context callback
+     *
+     * This function uses a backtrace generated from {@link debug_backtrace()}
+     * and so will not work at all in PHP < 4.3.0.  The frame should
+     * reference the frame that contains the source of the error.
+     * @return array|false either array('file' => file, 'line' => line,
+     *         'function' => function name, 'class' => class name) or
+     *         if this doesn't work, then false
+     * @param unused
+     * @param integer backtrace frame.
+     * @param array Results of debug_backtrace()
+     * @static
+     */
+    function getFileLine($code, $params, $backtrace = null)
+    {
+        if ($backtrace === null) {
+            return false;
+        }
+        $frame = 0;
+        $functionframe = 1;
+        if (!isset($backtrace[1])) {
+            $functionframe = 0;
+        } else {
+            while (isset($backtrace[$functionframe]['function']) &&
+                  $backtrace[$functionframe]['function'] == 'eval' &&
+                  isset($backtrace[$functionframe + 1])) {
+                $functionframe++;
+            }
+        }
+        if (isset($backtrace[$frame])) {
+            if (!isset($backtrace[$frame]['file'])) {
+                $frame++;
+            }
+            $funcbacktrace = $backtrace[$functionframe];
+            $filebacktrace = $backtrace[$frame];
+            $ret = array('file' => $filebacktrace['file'],
+                         'line' => $filebacktrace['line']);
+            // rearrange for eval'd code or create function errors
+            if (strpos($filebacktrace['file'], '(') && 
+                 preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
+                  $matches)) {
+                $ret['file'] = $matches[1];
+                $ret['line'] = $matches[2] + 0;
+            }
+            if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
+                if ($funcbacktrace['function'] != 'eval') {
+                    if ($funcbacktrace['function'] == '__lambda_func') {
+                        $ret['function'] = 'create_function() code';
+                    } else {
+                        $ret['function'] = $funcbacktrace['function'];
+                    }
+                }
+            }
+            if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
+                $ret['class'] = $funcbacktrace['class'];
+            }
+            return $ret;
+        }
+        return false;
+    }
+    
+    /**
+     * Standard error message generation callback
+     * 
+     * This method may also be called by a custom error message generator
+     * to fill in template values from the params array, simply
+     * set the third parameter to the error message template string to use
+     * 
+     * The special variable %__msg% is reserved: use it only to specify
+     * where a message passed in by the user should be placed in the template,
+     * like so:
+     * 
+     * Error message: %msg% - internal error
+     * 
+     * If the message passed like so:
+     * 
+     * <code>
+     * $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
+     * </code>
+     * 
+     * The returned error message will be "Error message: server error 500 -
+     * internal error"
+     * @param PEAR_ErrorStack
+     * @param array
+     * @param string|false Pre-generated error message template
+     * @static
+     * @return string
+     */
+    function getErrorMessage(&$stack, $err, $template = false)
+    {
+        if ($template) {
+            $mainmsg = $template;
+        } else {
+            $mainmsg = $stack->getErrorMessageTemplate($err['code']);
+        }
+        $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
+        if (is_array($err['params']) && count($err['params'])) {
+            foreach ($err['params'] as $name => $val) {
+                if (is_array($val)) {
+                    // @ is needed in case $val is a multi-dimensional array
+                    $val = @implode(', ', $val);
+                }
+                if (is_object($val)) {
+                    if (method_exists($val, '__toString')) {
+                        $val = $val->__toString();
+                    } else {
+                        PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
+                            'warning', array('obj' => get_class($val)),
+                            'object %obj% passed into getErrorMessage, but has no __toString() method');
+                        $val = 'Object';
+                    }
+                }
+                $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg);
+            }
+        }
+        return $mainmsg;
+    }
+    
+    /**
+     * Standard Error Message Template generator from code
+     * @return string
+     */
+    function getErrorMessageTemplate($code)
+    {
+        if (!isset($this->_errorMsgs[$code])) {
+            return '%__msg%';
+        }
+        return $this->_errorMsgs[$code];
+    }
+    
+    /**
+     * Set the Error Message Template array
+     * 
+     * The array format must be:
+     * <pre>
+     * array(error code => 'message template',...)
+     * </pre>
+     * 
+     * Error message parameters passed into {@link push()} will be used as input
+     * for the error message.  If the template is 'message %foo% was %bar%', and the
+     * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
+     * be 'message one was six'
+     * @return string
+     */
+    function setErrorMessageTemplate($template)
+    {
+        $this->_errorMsgs = $template;
+    }
+    
+    
+    /**
+     * emulate PEAR::raiseError()
+     * 
+     * @return PEAR_Error
+     */
+    function raiseError()
+    {
+        require_once 'PEAR.php';
+        $args = func_get_args();
+        return call_user_func_array(array('PEAR', 'raiseError'), $args);
+    }
+}
+$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
+$stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
+?>
index b3d75b20c9cfe886530994469f0275d059ab665a..d0327b141b432daea538dfdac9b06c6f9899ab3d 100644 (file)
@@ -5,21 +5,15 @@
  *
  * PHP versions 4 and 5
  *
- * LICENSE: This source file is subject to version 3.0 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
  * @category   pear
  * @package    PEAR
  * @author     Tomas V. V. Cox <cox@idecnet.com>
  * @author     Hans Lellelid <hans@velum.net>
  * @author     Bertrand Mansion <bmansion@mamasam.com>
  * @author     Greg Beaver <cellog@php.net>
- * @copyright  1997-2008 The PHP Group
- * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
- * @version    CVS: $Id: Exception.php,v 1.29 2008/01/03 20:26:35 cellog Exp $
+ * @copyright  1997-2009 The Authors
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    CVS: $Id: Exception.php 307683 2011-01-23 21:56:12Z dufuz $
  * @link       http://pear.php.net/package/PEAR
  * @since      File available since Release 1.3.3
  */
@@ -93,9 +87,9 @@
  * @author     Hans Lellelid <hans@velum.net>
  * @author     Bertrand Mansion <bmansion@mamasam.com>
  * @author     Greg Beaver <cellog@php.net>
- * @copyright  1997-2008 The PHP Group
- * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
- * @version    Release: 1.7.2
+ * @copyright  1997-2009 The Authors
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    Release: 1.9.2
  * @link       http://pear.php.net/package/PEAR
  * @since      Class available since Release 1.3.3
  *
@@ -295,7 +289,7 @@ class PEAR_Exception extends Exception
     }
 
     public function getTraceSafe()
-    {   
+    {
         if (!isset($this->_trace)) {
             $this->_trace = $this->getTrace();
             if (empty($this->_trace)) {
@@ -331,21 +325,21 @@ class PEAR_Exception extends Exception
         $trace = $this->getTraceSafe();
         $causes = array();
         $this->getCauseMessage($causes);
-        $html =  '<table border="1" cellspacing="0">' . "\n";
+        $html =  '<table style="border: 1px" cellspacing="0">' . "\n";
         foreach ($causes as $i => $cause) {
-            $html .= '<tr><td colspan="3" bgcolor="#ff9999">'
+            $html .= '<tr><td colspan="3" style="background: #ff9999">'
                . str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: '
                . htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> '
                . 'on line <b>' . $cause['line'] . '</b>'
                . "</td></tr>\n";
         }
-        $html .= '<tr><td colspan="3" bgcolor="#aaaaaa" align="center"><b>Exception trace</b></td></tr>' . "\n"
-               . '<tr><td align="center" bgcolor="#cccccc" width="20"><b>#</b></td>'
-               . '<td align="center" bgcolor="#cccccc"><b>Function</b></td>'
-               . '<td align="center" bgcolor="#cccccc"><b>Location</b></td></tr>' . "\n";
+        $html .= '<tr><td colspan="3" style="background-color: #aaaaaa; text-align: center; font-weight: bold;">Exception trace</td></tr>' . "\n"
+               . '<tr><td style="text-align: center; background: #cccccc; width:20px; font-weight: bold;">#</td>'
+               . '<td style="text-align: center; background: #cccccc; font-weight: bold;">Function</td>'
+               . '<td style="text-align: center; background: #cccccc; font-weight: bold;">Location</td></tr>' . "\n";
 
         foreach ($trace as $k => $v) {
-            $html .= '<tr><td align="center">' . $k . '</td>'
+            $html .= '<tr><td style="text-align: center;">' . $k . '</td>'
                    . '<td>';
             if (!empty($v['class'])) {
                 $html .= $v['class'] . $v['type'];
@@ -373,7 +367,7 @@ class PEAR_Exception extends Exception
                    . ':' . (isset($v['line']) ? $v['line'] : 'unknown')
                    . '</td></tr>' . "\n";
         }
-        $html .= '<tr><td align="center">' . ($k+1) . '</td>'
+        $html .= '<tr><td style="text-align: center;">' . ($k+1) . '</td>'
                . '<td>{main}</td>'
                . '<td>&nbsp;</td></tr>' . "\n"
                . '</table>';
@@ -392,6 +386,4 @@ class PEAR_Exception extends Exception
         }
         return $causeMsg . $this->getTraceAsString();
     }
-}
-
-?>
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/extlib/PEAR5.php b/extlib/PEAR5.php
new file mode 100644 (file)
index 0000000..4286067
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+/**
+ * This is only meant for PHP 5 to get rid of certain strict warning
+ * that doesn't get hidden since it's in the shutdown function
+ */
+class PEAR5
+{
+    /**
+    * If you have a class that's mostly/entirely static, and you need static
+    * properties, you can use this method to simulate them. Eg. in your method(s)
+    * do this: $myVar = &PEAR5::getStaticProperty('myclass', 'myVar');
+    * You MUST use a reference, or they will not persist!
+    *
+    * @access public
+    * @param  string $class  The calling classname, to prevent clashes
+    * @param  string $var    The variable to retrieve.
+    * @return mixed   A reference to the variable. If not set it will be
+    *                 auto initialised to NULL.
+    */
+    static function &getStaticProperty($class, $var)
+    {
+        static $properties;
+        if (!isset($properties[$class])) {
+            $properties[$class] = array();
+        }
+
+        if (!array_key_exists($var, $properties[$class])) {
+            $properties[$class][$var] = null;
+        }
+
+        return $properties[$class][$var];
+    }
+}
\ No newline at end of file
diff --git a/extlib/System.php b/extlib/System.php
new file mode 100644 (file)
index 0000000..db7c3a6
--- /dev/null
@@ -0,0 +1,621 @@
+<?php
+/**
+ * File/Directory manipulation
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   pear
+ * @package    System
+ * @author     Tomas V.V.Cox <cox@idecnet.com>
+ * @copyright  1997-2009 The Authors
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    CVS: $Id: System.php 307683 2011-01-23 21:56:12Z dufuz $
+ * @link       http://pear.php.net/package/PEAR
+ * @since      File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR.php';
+require_once 'Console/Getopt.php';
+
+$GLOBALS['_System_temp_files'] = array();
+
+/**
+* System offers cross plattform compatible system functions
+*
+* Static functions for different operations. Should work under
+* Unix and Windows. The names and usage has been taken from its respectively
+* GNU commands. The functions will return (bool) false on error and will
+* trigger the error with the PHP trigger_error() function (you can silence
+* the error by prefixing a '@' sign after the function call, but this
+* is not recommended practice.  Instead use an error handler with
+* {@link set_error_handler()}).
+*
+* Documentation on this class you can find in:
+* http://pear.php.net/manual/
+*
+* Example usage:
+* if (!@System::rm('-r file1 dir1')) {
+*    print "could not delete file1 or dir1";
+* }
+*
+* In case you need to to pass file names with spaces,
+* pass the params as an array:
+*
+* System::rm(array('-r', $file1, $dir1));
+*
+* @category   pear
+* @package    System
+* @author     Tomas V.V. Cox <cox@idecnet.com>
+* @copyright  1997-2006 The PHP Group
+* @license    http://opensource.org/licenses/bsd-license.php New BSD License
+* @version    Release: 1.9.2
+* @link       http://pear.php.net/package/PEAR
+* @since      Class available since Release 0.1
+* @static
+*/
+class System
+{
+    /**
+     * returns the commandline arguments of a function
+     *
+     * @param    string  $argv           the commandline
+     * @param    string  $short_options  the allowed option short-tags
+     * @param    string  $long_options   the allowed option long-tags
+     * @return   array   the given options and there values
+     * @static
+     * @access private
+     */
+    function _parseArgs($argv, $short_options, $long_options = null)
+    {
+        if (!is_array($argv) && $argv !== null) {
+            $argv = preg_split('/\s+/', $argv, -1, PREG_SPLIT_NO_EMPTY);
+        }
+        return Console_Getopt::getopt2($argv, $short_options);
+    }
+
+    /**
+     * Output errors with PHP trigger_error(). You can silence the errors
+     * with prefixing a "@" sign to the function call: @System::mkdir(..);
+     *
+     * @param mixed $error a PEAR error or a string with the error message
+     * @return bool false
+     * @static
+     * @access private
+     */
+    function raiseError($error)
+    {
+        if (PEAR::isError($error)) {
+            $error = $error->getMessage();
+        }
+        trigger_error($error, E_USER_WARNING);
+        return false;
+    }
+
+    /**
+     * Creates a nested array representing the structure of a directory
+     *
+     * System::_dirToStruct('dir1', 0) =>
+     *   Array
+     *    (
+     *    [dirs] => Array
+     *        (
+     *            [0] => dir1
+     *        )
+     *
+     *    [files] => Array
+     *        (
+     *            [0] => dir1/file2
+     *            [1] => dir1/file3
+     *        )
+     *    )
+     * @param    string  $sPath      Name of the directory
+     * @param    integer $maxinst    max. deep of the lookup
+     * @param    integer $aktinst    starting deep of the lookup
+     * @param    bool    $silent     if true, do not emit errors.
+     * @return   array   the structure of the dir
+     * @static
+     * @access   private
+     */
+    function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false)
+    {
+        $struct = array('dirs' => array(), 'files' => array());
+        if (($dir = @opendir($sPath)) === false) {
+            if (!$silent) {
+                System::raiseError("Could not open dir $sPath");
+            }
+            return $struct; // XXX could not open error
+        }
+
+        $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ?
+        $list = array();
+        while (false !== ($file = readdir($dir))) {
+            if ($file != '.' && $file != '..') {
+                $list[] = $file;
+            }
+        }
+
+        closedir($dir);
+        natsort($list);
+        if ($aktinst < $maxinst || $maxinst == 0) {
+            foreach ($list as $val) {
+                $path = $sPath . DIRECTORY_SEPARATOR . $val;
+                if (is_dir($path) && !is_link($path)) {
+                    $tmp    = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent);
+                    $struct = array_merge_recursive($struct, $tmp);
+                } else {
+                    $struct['files'][] = $path;
+                }
+            }
+        }
+
+        return $struct;
+    }
+
+    /**
+     * Creates a nested array representing the structure of a directory and files
+     *
+     * @param    array $files Array listing files and dirs
+     * @return   array
+     * @static
+     * @see System::_dirToStruct()
+     */
+    function _multipleToStruct($files)
+    {
+        $struct = array('dirs' => array(), 'files' => array());
+        settype($files, 'array');
+        foreach ($files as $file) {
+            if (is_dir($file) && !is_link($file)) {
+                $tmp    = System::_dirToStruct($file, 0);
+                $struct = array_merge_recursive($tmp, $struct);
+            } else {
+                if (!in_array($file, $struct['files'])) {
+                    $struct['files'][] = $file;
+                }
+            }
+        }
+        return $struct;
+    }
+
+    /**
+     * The rm command for removing files.
+     * Supports multiple files and dirs and also recursive deletes
+     *
+     * @param    string  $args   the arguments for rm
+     * @return   mixed   PEAR_Error or true for success
+     * @static
+     * @access   public
+     */
+    function rm($args)
+    {
+        $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-)
+        if (PEAR::isError($opts)) {
+            return System::raiseError($opts);
+        }
+        foreach ($opts[0] as $opt) {
+            if ($opt[0] == 'r') {
+                $do_recursive = true;
+            }
+        }
+        $ret = true;
+        if (isset($do_recursive)) {
+            $struct = System::_multipleToStruct($opts[1]);
+            foreach ($struct['files'] as $file) {
+                if (!@unlink($file)) {
+                    $ret = false;
+                }
+            }
+
+            rsort($struct['dirs']);
+            foreach ($struct['dirs'] as $dir) {
+                if (!@rmdir($dir)) {
+                    $ret = false;
+                }
+            }
+        } else {
+            foreach ($opts[1] as $file) {
+                $delete = (is_dir($file)) ? 'rmdir' : 'unlink';
+                if (!@$delete($file)) {
+                    $ret = false;
+                }
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * Make directories.
+     *
+     * The -p option will create parent directories
+     * @param    string  $args    the name of the director(y|ies) to create
+     * @return   bool    True for success
+     * @static
+     * @access   public
+     */
+    function mkDir($args)
+    {
+        $opts = System::_parseArgs($args, 'pm:');
+        if (PEAR::isError($opts)) {
+            return System::raiseError($opts);
+        }
+
+        $mode = 0777; // default mode
+        foreach ($opts[0] as $opt) {
+            if ($opt[0] == 'p') {
+                $create_parents = true;
+            } elseif ($opt[0] == 'm') {
+                // if the mode is clearly an octal number (starts with 0)
+                // convert it to decimal
+                if (strlen($opt[1]) && $opt[1]{0} == '0') {
+                    $opt[1] = octdec($opt[1]);
+                } else {
+                    // convert to int
+                    $opt[1] += 0;
+                }
+                $mode = $opt[1];
+            }
+        }
+
+        $ret = true;
+        if (isset($create_parents)) {
+            foreach ($opts[1] as $dir) {
+                $dirstack = array();
+                while ((!file_exists($dir) || !is_dir($dir)) &&
+                        $dir != DIRECTORY_SEPARATOR) {
+                    array_unshift($dirstack, $dir);
+                    $dir = dirname($dir);
+                }
+
+                while ($newdir = array_shift($dirstack)) {
+                    if (!is_writeable(dirname($newdir))) {
+                        $ret = false;
+                        break;
+                    }
+
+                    if (!mkdir($newdir, $mode)) {
+                        $ret = false;
+                    }
+                }
+            }
+        } else {
+            foreach($opts[1] as $dir) {
+                if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) {
+                    $ret = false;
+                }
+            }
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Concatenate files
+     *
+     * Usage:
+     * 1) $var = System::cat('sample.txt test.txt');
+     * 2) System::cat('sample.txt test.txt > final.txt');
+     * 3) System::cat('sample.txt test.txt >> final.txt');
+     *
+     * Note: as the class use fopen, urls should work also (test that)
+     *
+     * @param    string  $args   the arguments
+     * @return   boolean true on success
+     * @static
+     * @access   public
+     */
+    function &cat($args)
+    {
+        $ret = null;
+        $files = array();
+        if (!is_array($args)) {
+            $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
+        }
+
+        $count_args = count($args);
+        for ($i = 0; $i < $count_args; $i++) {
+            if ($args[$i] == '>') {
+                $mode = 'wb';
+                $outputfile = $args[$i+1];
+                break;
+            } elseif ($args[$i] == '>>') {
+                $mode = 'ab+';
+                $outputfile = $args[$i+1];
+                break;
+            } else {
+                $files[] = $args[$i];
+            }
+        }
+        $outputfd = false;
+        if (isset($mode)) {
+            if (!$outputfd = fopen($outputfile, $mode)) {
+                $err = System::raiseError("Could not open $outputfile");
+                return $err;
+            }
+            $ret = true;
+        }
+        foreach ($files as $file) {
+            if (!$fd = fopen($file, 'r')) {
+                System::raiseError("Could not open $file");
+                continue;
+            }
+            while ($cont = fread($fd, 2048)) {
+                if (is_resource($outputfd)) {
+                    fwrite($outputfd, $cont);
+                } else {
+                    $ret .= $cont;
+                }
+            }
+            fclose($fd);
+        }
+        if (is_resource($outputfd)) {
+            fclose($outputfd);
+        }
+        return $ret;
+    }
+
+    /**
+     * Creates temporary files or directories. This function will remove
+     * the created files when the scripts finish its execution.
+     *
+     * Usage:
+     *   1) $tempfile = System::mktemp("prefix");
+     *   2) $tempdir  = System::mktemp("-d prefix");
+     *   3) $tempfile = System::mktemp();
+     *   4) $tempfile = System::mktemp("-t /var/tmp prefix");
+     *
+     * prefix -> The string that will be prepended to the temp name
+     *           (defaults to "tmp").
+     * -d     -> A temporary dir will be created instead of a file.
+     * -t     -> The target dir where the temporary (file|dir) will be created. If
+     *           this param is missing by default the env vars TMP on Windows or
+     *           TMPDIR in Unix will be used. If these vars are also missing
+     *           c:\windows\temp or /tmp will be used.
+     *
+     * @param   string  $args  The arguments
+     * @return  mixed   the full path of the created (file|dir) or false
+     * @see System::tmpdir()
+     * @static
+     * @access  public
+     */
+    function mktemp($args = null)
+    {
+        static $first_time = true;
+        $opts = System::_parseArgs($args, 't:d');
+        if (PEAR::isError($opts)) {
+            return System::raiseError($opts);
+        }
+
+        foreach ($opts[0] as $opt) {
+            if ($opt[0] == 'd') {
+                $tmp_is_dir = true;
+            } elseif ($opt[0] == 't') {
+                $tmpdir = $opt[1];
+            }
+        }
+
+        $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp';
+        if (!isset($tmpdir)) {
+            $tmpdir = System::tmpdir();
+        }
+
+        if (!System::mkDir(array('-p', $tmpdir))) {
+            return false;
+        }
+
+        $tmp = tempnam($tmpdir, $prefix);
+        if (isset($tmp_is_dir)) {
+            unlink($tmp); // be careful possible race condition here
+            if (!mkdir($tmp, 0700)) {
+                return System::raiseError("Unable to create temporary directory $tmpdir");
+            }
+        }
+
+        $GLOBALS['_System_temp_files'][] = $tmp;
+        if (isset($tmp_is_dir)) {
+            //$GLOBALS['_System_temp_files'][] = dirname($tmp);
+        }
+
+        if ($first_time) {
+            PEAR::registerShutdownFunc(array('System', '_removeTmpFiles'));
+            $first_time = false;
+        }
+
+        return $tmp;
+    }
+
+    /**
+     * Remove temporary files created my mkTemp. This function is executed
+     * at script shutdown time
+     *
+     * @static
+     * @access private
+     */
+    function _removeTmpFiles()
+    {
+        if (count($GLOBALS['_System_temp_files'])) {
+            $delete = $GLOBALS['_System_temp_files'];
+            array_unshift($delete, '-r');
+            System::rm($delete);
+            $GLOBALS['_System_temp_files'] = array();
+        }
+    }
+
+    /**
+     * Get the path of the temporal directory set in the system
+     * by looking in its environments variables.
+     * Note: php.ini-recommended removes the "E" from the variables_order setting,
+     * making unavaible the $_ENV array, that s why we do tests with _ENV
+     *
+     * @static
+     * @return string The temporary directory on the system
+     */
+    function tmpdir()
+    {
+        if (OS_WINDOWS) {
+            if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {
+                return $var;
+            }
+            if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {
+                return $var;
+            }
+            if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) {
+                return $var;
+            }
+            if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {
+                return $var;
+            }
+            return getenv('SystemRoot') . '\temp';
+        }
+        if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {
+            return $var;
+        }
+        return realpath('/tmp');
+    }
+
+    /**
+     * The "which" command (show the full path of a command)
+     *
+     * @param string $program The command to search for
+     * @param mixed  $fallback Value to return if $program is not found
+     *
+     * @return mixed A string with the full path or false if not found
+     * @static
+     * @author Stig Bakken <ssb@php.net>
+     */
+    function which($program, $fallback = false)
+    {
+        // enforce API
+        if (!is_string($program) || '' == $program) {
+            return $fallback;
+        }
+
+        // full path given
+        if (basename($program) != $program) {
+            $path_elements[] = dirname($program);
+            $program = basename($program);
+        } else {
+            // Honor safe mode
+            if (!ini_get('safe_mode') || !$path = ini_get('safe_mode_exec_dir')) {
+                $path = getenv('PATH');
+                if (!$path) {
+                    $path = getenv('Path'); // some OSes are just stupid enough to do this
+                }
+            }
+            $path_elements = explode(PATH_SEPARATOR, $path);
+        }
+
+        if (OS_WINDOWS) {
+            $exe_suffixes = getenv('PATHEXT')
+                                ? explode(PATH_SEPARATOR, getenv('PATHEXT'))
+                                : array('.exe','.bat','.cmd','.com');
+            // allow passing a command.exe param
+            if (strpos($program, '.') !== false) {
+                array_unshift($exe_suffixes, '');
+            }
+            // is_executable() is not available on windows for PHP4
+            $pear_is_executable = (function_exists('is_executable')) ? 'is_executable' : 'is_file';
+        } else {
+            $exe_suffixes = array('');
+            $pear_is_executable = 'is_executable';
+        }
+
+        foreach ($exe_suffixes as $suff) {
+            foreach ($path_elements as $dir) {
+                $file = $dir . DIRECTORY_SEPARATOR . $program . $suff;
+                if (@$pear_is_executable($file)) {
+                    return $file;
+                }
+            }
+        }
+        return $fallback;
+    }
+
+    /**
+     * The "find" command
+     *
+     * Usage:
+     *
+     * System::find($dir);
+     * System::find("$dir -type d");
+     * System::find("$dir -type f");
+     * System::find("$dir -name *.php");
+     * System::find("$dir -name *.php -name *.htm*");
+     * System::find("$dir -maxdepth 1");
+     *
+     * Params implmented:
+     * $dir            -> Start the search at this directory
+     * -type d         -> return only directories
+     * -type f         -> return only files
+     * -maxdepth <n>   -> max depth of recursion
+     * -name <pattern> -> search pattern (bash style). Multiple -name param allowed
+     *
+     * @param  mixed Either array or string with the command line
+     * @return array Array of found files
+     * @static
+     *
+     */
+    function find($args)
+    {
+        if (!is_array($args)) {
+            $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
+        }
+        $dir = realpath(array_shift($args));
+        if (!$dir) {
+            return array();
+        }
+        $patterns = array();
+        $depth = 0;
+        $do_files = $do_dirs = true;
+        $args_count = count($args);
+        for ($i = 0; $i < $args_count; $i++) {
+            switch ($args[$i]) {
+                case '-type':
+                    if (in_array($args[$i+1], array('d', 'f'))) {
+                        if ($args[$i+1] == 'd') {
+                            $do_files = false;
+                        } else {
+                            $do_dirs = false;
+                        }
+                    }
+                    $i++;
+                    break;
+                case '-name':
+                    $name = preg_quote($args[$i+1], '#');
+                    // our magic characters ? and * have just been escaped,
+                    // so now we change the escaped versions to PCRE operators
+                    $name = strtr($name, array('\?' => '.', '\*' => '.*'));
+                    $patterns[] = '('.$name.')';
+                    $i++;
+                    break;
+                case '-maxdepth':
+                    $depth = $args[$i+1];
+                    break;
+            }
+        }
+        $path = System::_dirToStruct($dir, $depth, 0, true);
+        if ($do_files && $do_dirs) {
+            $files = array_merge($path['files'], $path['dirs']);
+        } elseif ($do_dirs) {
+            $files = $path['dirs'];
+        } else {
+            $files = $path['files'];
+        }
+        if (count($patterns)) {
+            $dsq = preg_quote(DIRECTORY_SEPARATOR, '#');
+            $pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#';
+            $ret = array();
+            $files_count = count($files);
+            for ($i = 0; $i < $files_count; $i++) {
+                // only search in the part of the file below the current directory
+                $filepart = basename($files[$i]);
+                if (preg_match($pattern, $filepart)) {
+                    $ret[] = $files[$i];
+                }
+            }
+            return $ret;
+        }
+        return $files;
+    }
+}
\ No newline at end of file