Upgrade PEAR to 1.9.2

This commit is contained in:
Evan Prodromou 2011-03-26 14:37:42 -04:00
parent d1d5d234f8
commit 75baffc970
5 changed files with 1782 additions and 206 deletions

View File

@ -6,21 +6,15 @@
* *
* PHP versions 4 and 5 * 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 * @category pear
* @package PEAR * @package PEAR
* @author Sterling Hughes <sterling@php.net> * @author Sterling Hughes <sterling@php.net>
* @author Stig Bakken <ssb@php.net> * @author Stig Bakken <ssb@php.net>
* @author Tomas V.V.Cox <cox@idecnet.com> * @author Tomas V.V.Cox <cox@idecnet.com>
* @author Greg Beaver <cellog@php.net> * @author Greg Beaver <cellog@php.net>
* @copyright 1997-2008 The PHP Group * @copyright 1997-2010 The Authors
* @license http://www.php.net/license/3_0.txt PHP License 3.0 * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: PEAR.php,v 1.104 2008/01/03 20:26:34 cellog Exp $ * @version CVS: $Id: PEAR.php 307683 2011-01-23 21:56:12Z dufuz $
* @link http://pear.php.net/package/PEAR * @link http://pear.php.net/package/PEAR
* @since File available since Release 0.1 * @since File available since Release 0.1
*/ */
@ -52,15 +46,6 @@ if (substr(PHP_OS, 0, 3) == 'WIN') {
define('PEAR_OS', 'Unix'); // blatant assumption 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_mode'] = PEAR_ERROR_RETURN;
$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; $GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE;
$GLOBALS['_PEAR_destructor_object_list'] = array(); $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 Tomas V.V. Cox <cox@idecnet.com>
* @author Greg Beaver <cellog@php.net> * @author Greg Beaver <cellog@php.net>
* @copyright 1997-2006 The PHP Group * @copyright 1997-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0 * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 1.7.2 * @version Release: 1.9.2
* @link http://pear.php.net/package/PEAR * @link http://pear.php.net/package/PEAR
* @see PEAR_Error * @see PEAR_Error
* @since Class available since PHP 4.0.2 * @since Class available since PHP 4.0.2
@ -101,8 +86,6 @@ $GLOBALS['_PEAR_error_handler_stack'] = array();
*/ */
class PEAR class PEAR
{ {
// {{{ properties
/** /**
* Whether to enable internal debug messages. * Whether to enable internal debug messages.
* *
@ -153,10 +136,6 @@ class PEAR
*/ */
var $_expected_errors = array(); var $_expected_errors = array();
// }}}
// {{{ constructor
/** /**
* Constructor. Registers this object in * Constructor. Registers this object in
* $_PEAR_destructor_object_list for destructor emulation if a * $_PEAR_destructor_object_list for destructor emulation if a
@ -173,9 +152,11 @@ class PEAR
if ($this->_debug) { if ($this->_debug) {
print "PEAR constructor called, class=$classname\n"; print "PEAR constructor called, class=$classname\n";
} }
if ($error_class !== null) { if ($error_class !== null) {
$this->_error_class = $error_class; $this->_error_class = $error_class;
} }
while ($classname && strcasecmp($classname, "pear")) { while ($classname && strcasecmp($classname, "pear")) {
$destructor = "_$classname"; $destructor = "_$classname";
if (method_exists($this, $destructor)) { if (method_exists($this, $destructor)) {
@ -192,9 +173,6 @@ class PEAR
} }
} }
// }}}
// {{{ destructor
/** /**
* Destructor (the emulated type of...). Does nothing right now, * Destructor (the emulated type of...). Does nothing right now,
* but is included for forward compatibility, so subclass * 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 * 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) * properties, you can use this method to simulate them. Eg. in your method(s)
@ -233,15 +208,14 @@ class PEAR
if (!isset($properties[$class])) { if (!isset($properties[$class])) {
$properties[$class] = array(); $properties[$class] = array();
} }
if (!array_key_exists($var, $properties[$class])) { if (!array_key_exists($var, $properties[$class])) {
$properties[$class][$var] = null; $properties[$class][$var] = null;
} }
return $properties[$class][$var]; return $properties[$class][$var];
} }
// }}}
// {{{ registerShutdownFunc()
/** /**
* Use this function to register a shutdown method for static * Use this function to register a shutdown method for static
* classes. * classes.
@ -262,9 +236,6 @@ class PEAR
$GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
} }
// }}}
// {{{ isError()
/** /**
* Tell whether a value is a PEAR error. * Tell whether a value is a PEAR error.
* *
@ -278,20 +249,18 @@ class PEAR
*/ */
function isError($data, $code = null) function isError($data, $code = null)
{ {
if (is_a($data, 'PEAR_Error')) { if (!is_a($data, 'PEAR_Error')) {
if (is_null($code)) { return false;
return true;
} elseif (is_string($code)) {
return $data->getMessage() == $code;
} else {
return $data->getCode() == $code;
}
} }
return false;
}
// }}} if (is_null($code)) {
// {{{ setErrorHandling() return true;
} elseif (is_string($code)) {
return $data->getMessage() == $code;
}
return $data->getCode() == $code;
}
/** /**
* Sets how errors generated by this object should be handled. * Sets how errors generated by this object should be handled.
@ -331,7 +300,6 @@ class PEAR
* *
* @since PHP 4.0.5 * @since PHP 4.0.5
*/ */
function setErrorHandling($mode = null, $options = null) function setErrorHandling($mode = null, $options = null)
{ {
if (isset($this) && is_a($this, 'PEAR')) { 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. * This method is used to tell which errors you expect to get.
* Expected errors are always returned with error mode * Expected errors are always returned with error mode
@ -394,12 +359,9 @@ class PEAR
} else { } else {
array_push($this->_expected_errors, array($code)); 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 * This method pops one element off the expected error codes
* stack. * stack.
@ -411,9 +373,6 @@ class PEAR
return array_pop($this->_expected_errors); return array_pop($this->_expected_errors);
} }
// }}}
// {{{ _checkDelExpect()
/** /**
* This method checks unsets an error code if available * This method checks unsets an error code if available
* *
@ -425,8 +384,7 @@ class PEAR
function _checkDelExpect($error_code) function _checkDelExpect($error_code)
{ {
$deleted = false; $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)) { if (in_array($error_code, $error_array)) {
unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
$deleted = true; $deleted = true;
@ -437,12 +395,10 @@ class PEAR
unset($this->_expected_errors[$key]); unset($this->_expected_errors[$key]);
} }
} }
return $deleted; return $deleted;
} }
// }}}
// {{{ delExpect()
/** /**
* This method deletes all occurences of the specified element from * This method deletes all occurences of the specified element from
* the expected error codes stack. * the expected error codes stack.
@ -455,34 +411,26 @@ class PEAR
function delExpect($error_code) function delExpect($error_code)
{ {
$deleted = false; $deleted = false;
if ((is_array($error_code) && (0 != count($error_code)))) { if ((is_array($error_code) && (0 != count($error_code)))) {
// $error_code is a non-empty array here; // $error_code is a non-empty array here; we walk through it trying
// we walk through it trying to unset all // to unset all values
// values foreach ($error_code as $key => $error) {
foreach($error_code as $key => $error) { $deleted = $this->_checkDelExpect($error) ? true : false;
if ($this->_checkDelExpect($error)) {
$deleted = true;
} else {
$deleted = false;
}
} }
return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
} elseif (!empty($error_code)) { } elseif (!empty($error_code)) {
// $error_code comes alone, trying to unset it // $error_code comes alone, trying to unset it
if ($this->_checkDelExpect($error_code)) { if ($this->_checkDelExpect($error_code)) {
return true; 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 * This method is a wrapper that returns an instance of the
@ -538,13 +486,20 @@ class PEAR
$message = $message->getMessage(); $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] == "*" || if ($exp[0] == "*" ||
(is_int(reset($exp)) && in_array($code, $exp)) || (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; $mode = PEAR_ERROR_RETURN;
} }
} }
// No mode given, try global ones // No mode given, try global ones
if ($mode === null) { if ($mode === null) {
// Class error handler // Class error handler
@ -565,46 +520,52 @@ class PEAR
} else { } else {
$ec = 'PEAR_Error'; $ec = 'PEAR_Error';
} }
if (intval(PHP_VERSION) < 5) { if (intval(PHP_VERSION) < 5) {
// little non-eval hack to fix bug #12147 // little non-eval hack to fix bug #12147
include 'PEAR/FixPHP5PEARWarnings.php'; include 'PEAR/FixPHP5PEARWarnings.php';
return $a; return $a;
} }
if ($skipmsg) { if ($skipmsg) {
$a = new $ec($code, $mode, $options, $userinfo); $a = new $ec($code, $mode, $options, $userinfo);
} else { } else {
$a = new $ec($message, $code, $mode, $options, $userinfo); $a = new $ec($message, $code, $mode, $options, $userinfo);
} }
return $a; return $a;
} }
// }}}
// {{{ throwError()
/** /**
* Simpler form of raiseError with fewer options. In most cases * Simpler form of raiseError with fewer options. In most cases
* message, code and userinfo are enough. * 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, function &throwError($message = null, $code = null, $userinfo = null)
$code = null,
$userinfo = null)
{ {
if (isset($this) && is_a($this, 'PEAR')) { if (isset($this) && is_a($this, 'PEAR')) {
$a = &$this->raiseError($message, $code, null, null, $userinfo); $a = &$this->raiseError($message, $code, null, null, $userinfo);
return $a; 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) 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_mode = &$GLOBALS['_PEAR_default_error_mode'];
$def_options = &$GLOBALS['_PEAR_default_error_options']; $def_options = &$GLOBALS['_PEAR_default_error_options'];
$stack[] = array($def_mode, $def_options); $stack[] = array($def_mode, $def_options);
@ -673,8 +634,6 @@ class PEAR
return true; return true;
} }
// {{{ pushErrorHandling()
/** /**
* Push a new error handler on top of the error handler options stack. With this * 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 * you can easily override the actual error handler for some code and restore
@ -708,9 +667,6 @@ class PEAR
return true; return true;
} }
// }}}
// {{{ popErrorHandling()
/** /**
* Pop the last error handler used * Pop the last error handler used
* *
@ -732,9 +688,6 @@ class PEAR
return true; return true;
} }
// }}}
// {{{ loadExtension()
/** /**
* OS independant PHP extension load. Remember to take care * OS independant PHP extension load. Remember to take care
* on the correct extension name for case sensitive OSes. * on the correct extension name for case sensitive OSes.
@ -744,31 +697,38 @@ class PEAR
*/ */
function loadExtension($ext) function loadExtension($ext)
{ {
if (!extension_loaded($ext)) { if (extension_loaded($ext)) {
// if either returns true dl() will produce a FATAL error, stop that return true;
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);
} }
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;
}
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() function _PEAR_call_destructors()
{ {
@ -777,9 +737,16 @@ function _PEAR_call_destructors()
sizeof($_PEAR_destructor_object_list)) sizeof($_PEAR_destructor_object_list))
{ {
reset($_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); $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
} }
while (list($k, $objref) = each($_PEAR_destructor_object_list)) { while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
$classname = get_class($objref); $classname = get_class($objref);
while ($classname) { while ($classname) {
@ -798,14 +765,17 @@ function _PEAR_call_destructors()
} }
// Now call the shutdown functions // 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) { foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
call_user_func_array($value[0], $value[1]); call_user_func_array($value[0], $value[1]);
} }
} }
} }
// }}}
/** /**
* Standard PEAR error class for PHP 4 * Standard PEAR error class for PHP 4
* *
@ -817,16 +787,14 @@ function _PEAR_call_destructors()
* @author Tomas V.V. Cox <cox@idecnet.com> * @author Tomas V.V. Cox <cox@idecnet.com>
* @author Gregory Beaver <cellog@php.net> * @author Gregory Beaver <cellog@php.net>
* @copyright 1997-2006 The PHP Group * @copyright 1997-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0 * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 1.7.2 * @version Release: 1.9.2
* @link http://pear.php.net/manual/en/core.pear.pear-error.php * @link http://pear.php.net/manual/en/core.pear.pear-error.php
* @see PEAR::raiseError(), PEAR::throwError() * @see PEAR::raiseError(), PEAR::throwError()
* @since Class available since PHP 4.0.2 * @since Class available since PHP 4.0.2
*/ */
class PEAR_Error class PEAR_Error
{ {
// {{{ properties
var $error_message_prefix = ''; var $error_message_prefix = '';
var $mode = PEAR_ERROR_RETURN; var $mode = PEAR_ERROR_RETURN;
var $level = E_USER_NOTICE; var $level = E_USER_NOTICE;
@ -835,9 +803,6 @@ class PEAR_Error
var $userinfo = ''; var $userinfo = '';
var $backtrace = null; var $backtrace = null;
// }}}
// {{{ constructor
/** /**
* PEAR_Error constructor * PEAR_Error constructor
* *
@ -868,12 +833,20 @@ class PEAR_Error
$this->code = $code; $this->code = $code;
$this->mode = $mode; $this->mode = $mode;
$this->userinfo = $userinfo; $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(); $this->backtrace = debug_backtrace();
if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
unset($this->backtrace[0]['object']); unset($this->backtrace[0]['object']);
} }
} }
if ($mode & PEAR_ERROR_CALLBACK) { if ($mode & PEAR_ERROR_CALLBACK) {
$this->level = E_USER_NOTICE; $this->level = E_USER_NOTICE;
$this->callback = $options; $this->callback = $options;
@ -881,20 +854,25 @@ class PEAR_Error
if ($options === null) { if ($options === null) {
$options = E_USER_NOTICE; $options = E_USER_NOTICE;
} }
$this->level = $options; $this->level = $options;
$this->callback = null; $this->callback = null;
} }
if ($this->mode & PEAR_ERROR_PRINT) { if ($this->mode & PEAR_ERROR_PRINT) {
if (is_null($options) || is_int($options)) { if (is_null($options) || is_int($options)) {
$format = "%s"; $format = "%s";
} else { } else {
$format = $options; $format = $options;
} }
printf($format, $this->getMessage()); printf($format, $this->getMessage());
} }
if ($this->mode & PEAR_ERROR_TRIGGER) { if ($this->mode & PEAR_ERROR_TRIGGER) {
trigger_error($this->getMessage(), $this->level); trigger_error($this->getMessage(), $this->level);
} }
if ($this->mode & PEAR_ERROR_DIE) { if ($this->mode & PEAR_ERROR_DIE) {
$msg = $this->getMessage(); $msg = $this->getMessage();
if (is_null($options) || is_int($options)) { if (is_null($options) || is_int($options)) {
@ -907,47 +885,39 @@ class PEAR_Error
} }
die(sprintf($format, $msg)); die(sprintf($format, $msg));
} }
if ($this->mode & PEAR_ERROR_CALLBACK) {
if (is_callable($this->callback)) { if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) {
call_user_func($this->callback, $this); call_user_func($this->callback, $this);
}
} }
if ($this->mode & PEAR_ERROR_EXCEPTION) { if ($this->mode & PEAR_ERROR_EXCEPTION) {
trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); 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);'); eval('$e = new Exception($this->message, $this->code);throw($e);');
} }
} }
// }}}
// {{{ getMode()
/** /**
* Get the error mode from an error object. * Get the error mode from an error object.
* *
* @return int error mode * @return int error mode
* @access public * @access public
*/ */
function getMode() { function getMode()
{
return $this->mode; return $this->mode;
} }
// }}}
// {{{ getCallback()
/** /**
* Get the callback function/method from an error object. * Get the callback function/method from an error object.
* *
* @return mixed callback function or object/method array * @return mixed callback function or object/method array
* @access public * @access public
*/ */
function getCallback() { function getCallback()
{
return $this->callback; return $this->callback;
} }
// }}}
// {{{ getMessage()
/** /**
* Get the error message from an error object. * Get the error message from an error object.
* *
@ -959,10 +929,6 @@ class PEAR_Error
return ($this->error_message_prefix . $this->message); return ($this->error_message_prefix . $this->message);
} }
// }}}
// {{{ getCode()
/** /**
* Get error code from an error object * Get error code from an error object
* *
@ -974,9 +940,6 @@ class PEAR_Error
return $this->code; return $this->code;
} }
// }}}
// {{{ getType()
/** /**
* Get the name of this error/exception. * Get the name of this error/exception.
* *
@ -988,9 +951,6 @@ class PEAR_Error
return get_class($this); return get_class($this);
} }
// }}}
// {{{ getUserInfo()
/** /**
* Get additional user-supplied information. * Get additional user-supplied information.
* *
@ -1002,9 +962,6 @@ class PEAR_Error
return $this->userinfo; return $this->userinfo;
} }
// }}}
// {{{ getDebugInfo()
/** /**
* Get additional debug information supplied by the application. * Get additional debug information supplied by the application.
* *
@ -1016,9 +973,6 @@ class PEAR_Error
return $this->getUserInfo(); return $this->getUserInfo();
} }
// }}}
// {{{ getBacktrace()
/** /**
* Get the call backtrace from where the error was generated. * Get the call backtrace from where the error was generated.
* Supported with PHP 4.3.0 or newer. * Supported with PHP 4.3.0 or newer.
@ -1038,9 +992,6 @@ class PEAR_Error
return $this->backtrace[$frame]; return $this->backtrace[$frame];
} }
// }}}
// {{{ addUserInfo()
function addUserInfo($info) function addUserInfo($info)
{ {
if (empty($this->userinfo)) { if (empty($this->userinfo)) {
@ -1050,14 +1001,10 @@ class PEAR_Error
} }
} }
// }}}
// {{{ toString()
function __toString() function __toString()
{ {
return $this->getMessage(); return $this->getMessage();
} }
// }}}
// {{{ toString()
/** /**
* Make a string representation of this object. * Make a string representation of this object.
@ -1065,7 +1012,8 @@ class PEAR_Error
* @return string a string with an object summary * @return string a string with an object summary
* @access public * @access public
*/ */
function toString() { function toString()
{
$modes = array(); $modes = array();
$levels = array(E_USER_NOTICE => 'notice', $levels = array(E_USER_NOTICE => 'notice',
E_USER_WARNING => 'warning', E_USER_WARNING => 'warning',
@ -1104,8 +1052,6 @@ class PEAR_Error
$this->error_message_prefix, $this->error_message_prefix,
$this->userinfo); $this->userinfo);
} }
// }}}
} }
/* /*
@ -1115,4 +1061,3 @@ class PEAR_Error
* c-basic-offset: 4 * c-basic-offset: 4
* End: * End:
*/ */
?>

985
extlib/PEAR/ErrorStack.php Normal file
View File

@ -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'));
?>

View File

@ -5,21 +5,15 @@
* *
* PHP versions 4 and 5 * 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 * @category pear
* @package PEAR * @package PEAR
* @author Tomas V. V. Cox <cox@idecnet.com> * @author Tomas V. V. Cox <cox@idecnet.com>
* @author Hans Lellelid <hans@velum.net> * @author Hans Lellelid <hans@velum.net>
* @author Bertrand Mansion <bmansion@mamasam.com> * @author Bertrand Mansion <bmansion@mamasam.com>
* @author Greg Beaver <cellog@php.net> * @author Greg Beaver <cellog@php.net>
* @copyright 1997-2008 The PHP Group * @copyright 1997-2009 The Authors
* @license http://www.php.net/license/3_0.txt PHP License 3.0 * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: Exception.php,v 1.29 2008/01/03 20:26:35 cellog Exp $ * @version CVS: $Id: Exception.php 307683 2011-01-23 21:56:12Z dufuz $
* @link http://pear.php.net/package/PEAR * @link http://pear.php.net/package/PEAR
* @since File available since Release 1.3.3 * @since File available since Release 1.3.3
*/ */
@ -93,9 +87,9 @@
* @author Hans Lellelid <hans@velum.net> * @author Hans Lellelid <hans@velum.net>
* @author Bertrand Mansion <bmansion@mamasam.com> * @author Bertrand Mansion <bmansion@mamasam.com>
* @author Greg Beaver <cellog@php.net> * @author Greg Beaver <cellog@php.net>
* @copyright 1997-2008 The PHP Group * @copyright 1997-2009 The Authors
* @license http://www.php.net/license/3_0.txt PHP License 3.0 * @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 1.7.2 * @version Release: 1.9.2
* @link http://pear.php.net/package/PEAR * @link http://pear.php.net/package/PEAR
* @since Class available since Release 1.3.3 * @since Class available since Release 1.3.3
* *
@ -331,21 +325,21 @@ class PEAR_Exception extends Exception
$trace = $this->getTraceSafe(); $trace = $this->getTraceSafe();
$causes = array(); $causes = array();
$this->getCauseMessage($causes); $this->getCauseMessage($causes);
$html = '<table border="1" cellspacing="0">' . "\n"; $html = '<table style="border: 1px" cellspacing="0">' . "\n";
foreach ($causes as $i => $cause) { 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>: ' . str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: '
. htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> ' . htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> '
. 'on line <b>' . $cause['line'] . '</b>' . 'on line <b>' . $cause['line'] . '</b>'
. "</td></tr>\n"; . "</td></tr>\n";
} }
$html .= '<tr><td colspan="3" bgcolor="#aaaaaa" align="center"><b>Exception trace</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 align="center" bgcolor="#cccccc" width="20"><b>#</b></td>' . '<tr><td style="text-align: center; background: #cccccc; width:20px; font-weight: bold;">#</td>'
. '<td align="center" bgcolor="#cccccc"><b>Function</b></td>' . '<td style="text-align: center; background: #cccccc; font-weight: bold;">Function</td>'
. '<td align="center" bgcolor="#cccccc"><b>Location</b></td></tr>' . "\n"; . '<td style="text-align: center; background: #cccccc; font-weight: bold;">Location</td></tr>' . "\n";
foreach ($trace as $k => $v) { foreach ($trace as $k => $v) {
$html .= '<tr><td align="center">' . $k . '</td>' $html .= '<tr><td style="text-align: center;">' . $k . '</td>'
. '<td>'; . '<td>';
if (!empty($v['class'])) { if (!empty($v['class'])) {
$html .= $v['class'] . $v['type']; $html .= $v['class'] . $v['type'];
@ -373,7 +367,7 @@ class PEAR_Exception extends Exception
. ':' . (isset($v['line']) ? $v['line'] : 'unknown') . ':' . (isset($v['line']) ? $v['line'] : 'unknown')
. '</td></tr>' . "\n"; . '</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>{main}</td>'
. '<td>&nbsp;</td></tr>' . "\n" . '<td>&nbsp;</td></tr>' . "\n"
. '</table>'; . '</table>';
@ -393,5 +387,3 @@ class PEAR_Exception extends Exception
return $causeMsg . $this->getTraceAsString(); return $causeMsg . $this->getTraceAsString();
} }
} }
?>

33
extlib/PEAR5.php Normal file
View File

@ -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];
}
}

621
extlib/System.php Normal file
View File

@ -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;
}
}