*
* 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
*/
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();
* @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
*/
class PEAR
{
- // {{{ properties
-
/**
* Whether to enable internal debug messages.
*
*/
var $_expected_errors = array();
- // }}}
-
- // {{{ constructor
-
/**
* Constructor. Registers this object in
* $_PEAR_destructor_object_list for destructor emulation if a
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)) {
}
}
- // }}}
- // {{{ destructor
-
/**
* Destructor (the emulated type of...). Does nothing right now,
* but is included for forward compatibility, so subclass
}
}
- // }}}
- // {{{ 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)
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.
$GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
}
- // }}}
- // {{{ isError()
-
/**
* Tell whether a value is a PEAR error.
*
*/
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.
*
* @since PHP 4.0.5
*/
-
function setErrorHandling($mode = null, $options = null)
{
if (isset($this) && is_a($this, 'PEAR')) {
}
}
- // }}}
- // {{{ expectError()
-
/**
* This method is used to tell which errors you expect to get.
* Expected errors are always returned with error mode
} 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.
return array_pop($this->_expected_errors);
}
- // }}}
- // {{{ _checkDelExpect()
-
/**
* This method checks unsets an error code if available
*
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;
unset($this->_expected_errors[$key]);
}
}
+
return $deleted;
}
- // }}}
- // {{{ delExpect()
-
/**
* This method deletes all occurences of the specified element from
* the expected error codes stack.
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
$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
} 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);
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
return true;
}
- // }}}
- // {{{ popErrorHandling()
-
/**
* Pop the last error handler used
*
return true;
}
- // }}}
- // {{{ loadExtension()
-
/**
* OS independant PHP extension load. Remember to take care
* on the correct extension name for case sensitive OSes.
*/
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()
{
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) {
}
// 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
*
* @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;
var $userinfo = '';
var $backtrace = null;
- // }}}
- // {{{ constructor
-
/**
* PEAR_Error constructor
*
$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;
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)) {
}
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.
*
return ($this->error_message_prefix . $this->message);
}
-
- // }}}
- // {{{ getCode()
-
/**
* Get error code from an error object
*
return $this->code;
}
- // }}}
- // {{{ getType()
-
/**
* Get the name of this error/exception.
*
return get_class($this);
}
- // }}}
- // {{{ getUserInfo()
-
/**
* Get additional user-supplied information.
*
return $this->userinfo;
}
- // }}}
- // {{{ getDebugInfo()
-
/**
* Get additional debug information supplied by the application.
*
return $this->getUserInfo();
}
- // }}}
- // {{{ getBacktrace()
-
/**
* Get the call backtrace from where the error was generated.
* Supported with PHP 4.3.0 or newer.
return $this->backtrace[$frame];
}
- // }}}
- // {{{ addUserInfo()
-
function addUserInfo($info)
{
if (empty($this->userinfo)) {
}
}
- // }}}
- // {{{ toString()
function __toString()
{
return $this->getMessage();
}
- // }}}
- // {{{ toString()
/**
* Make a string representation of this object.
* @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',
$this->error_message_prefix,
$this->userinfo);
}
-
- // }}}
}
/*
* c-basic-offset: 4
* End:
*/
-?>
--- /dev/null
+<?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'));
+?>
*
* 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
*/
* @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
*
}
public function getTraceSafe()
- {
+ {
if (!isset($this->_trace)) {
$this->_trace = $this->getTrace();
if (empty($this->_trace)) {
$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'];
. ':' . (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> </td></tr>' . "\n"
. '</table>';
}
return $causeMsg . $this->getTraceAsString();
}
-}
-
-?>
\ No newline at end of file
+}
\ No newline at end of file
--- /dev/null
+<?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
--- /dev/null
+<?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