Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php//// +----------------------------------------------------------------------+// | PEAR, the PHP Extension and Application Repository |// +----------------------------------------------------------------------+// | Copyright (c) 1997-2004 The PHP Group |// +----------------------------------------------------------------------+// | This source file is subject to version 2.0 of the PHP license, |// | that is bundled with this package in the file LICENSE, and is |// | available through the world-wide-web at the following url: |// | 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 world-wide-web, please send a note to |// | license@php.net so we can mail you a copy immediately. |// +----------------------------------------------------------------------+// | Authors: Sterling Hughes <sterling@php.net> |// | Stig Bakken <ssb@php.net> |// | Tomas V.V.Cox <cox@idecnet.com> |// +----------------------------------------------------------------------+//// $Id$//define('PEAR_ERROR_RETURN', 1);define('PEAR_ERROR_PRINT', 2);define('PEAR_ERROR_TRIGGER', 4);define('PEAR_ERROR_DIE', 8);define('PEAR_ERROR_CALLBACK', 16);define('PEAR_ERROR_EXCEPTION', 32);define('PEAR_ZE2', (function_exists('version_compare') &&version_compare(zend_version(), "2-dev", "ge")));if (substr(PHP_OS, 0, 3) == 'WIN') {define('OS_WINDOWS', true);define('OS_UNIX', false);define('PEAR_OS', 'Windows');} else {define('OS_WINDOWS', false);define('OS_UNIX', true);define('PEAR_OS', 'Unix'); // blatant assumption}// instant backwards compatibilityif (!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();$GLOBALS['_PEAR_shutdown_funcs'] = array();$GLOBALS['_PEAR_error_handler_stack'] = array();ini_set('track_errors', true);/*** Base class for other PEAR classes. Provides rudimentary* emulation of destructors.** If you want a destructor in your class, inherit PEAR and make a* destructor method called _yourclassname (same name as the* constructor, but with a "_" prefix). Also, in your constructor you* have to call the PEAR constructor: $this->PEAR();.* The destructor method will be called without parameters. Note that* at in some SAPI implementations (such as Apache), any output during* the request shutdown (in which destructors are called) seems to be* discarded. If you need to get any debug information from your* destructor, use error_log(), syslog() or something similar.** IMPORTANT! To use the emulated destructors you need to create the* objects by reference: $obj =& new PEAR_child;** @since PHP 4.0.2* @author Stig Bakken <ssb@php.net>* @see http://pear.php.net/manual/*/class PEAR{// {{{ properties/*** Whether to enable internal debug messages.** @var bool* @access private*/var $_debug = false;/*** Default error mode for this object.** @var int* @access private*/var $_default_error_mode = null;/*** Default error options used for this object when error mode* is PEAR_ERROR_TRIGGER.** @var int* @access private*/var $_default_error_options = null;/*** Default error handler (callback) for this object, if error mode is* PEAR_ERROR_CALLBACK.** @var string* @access private*/var $_default_error_handler = '';/*** Which class to use for error objects.** @var string* @access private*/var $_error_class = 'PEAR_Error';/*** An array of expected errors.** @var array* @access private*/var $_expected_errors = array();// }}}// {{{ constructor/*** Constructor. Registers this object in* $_PEAR_destructor_object_list for destructor emulation if a* destructor object exists.** @param string $error_class (optional) which class to use for* error objects, defaults to PEAR_Error.* @access public* @return void*/function PEAR($error_class = null){$classname = get_class($this);if ($this->_debug) {print "PEAR constructor called, class=$classname\n";}if ($error_class !== null) {$this->_error_class = $error_class;}while ($classname) {$destructor = "_$classname";if (method_exists($this, $destructor)) {global $_PEAR_destructor_object_list;$_PEAR_destructor_object_list[] = &$this;break;} else {$classname = get_parent_class($classname);}}}// }}}// {{{ destructor/*** Destructor (the emulated type of...). Does nothing right now,* but is included for forward compatibility, so subclass* destructors should always call it.** See the note in the class desciption about output from* destructors.** @access public* @return void*/function _PEAR() {if ($this->_debug) {printf("PEAR destructor called, class=%s\n", get_class($this));}}// }}}// {{{ 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)* do this: $myVar = &PEAR::getStaticProperty('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.*/function &getStaticProperty($class, $var){static $properties;return $properties[$class][$var];}// }}}// {{{ registerShutdownFunc()/*** Use this function to register a shutdown method for static* classes.** @access public* @param mixed $func The function name (or array of class/method) to call* @param mixed $args The arguments to pass to the function* @return void*/function registerShutdownFunc($func, $args = array()){$GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);}// }}}// {{{ isError()/*** Tell whether a value is a PEAR error.** @param mixed $data the value to test* @param int $code if $data is an error object, return true* only if $code is a string and* $obj->getMessage() == $code or* $code is an integer and $obj->getCode() == $code* @access public* @return bool true if parameter is an 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;}}return false;}// }}}// {{{ setErrorHandling()/*** Sets how errors generated by this object should be handled.* Can be invoked both in objects and statically. If called* statically, setErrorHandling sets the default behaviour for all* PEAR objects. If called in an object, setErrorHandling sets* the default behaviour for that object.** @param int $mode* One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,* PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,* PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.** @param mixed $options* When $mode is PEAR_ERROR_TRIGGER, this is the error level (one* of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).** When $mode is PEAR_ERROR_CALLBACK, this parameter is expected* to be the callback function or method. A callback* function is a string with the name of the function, a* callback method is an array of two elements: the element* at index 0 is the object, and the element at index 1 is* the name of the method to call in the object.** When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is* a printf format string used when printing the error* message.** @access public* @return void* @see PEAR_ERROR_RETURN* @see PEAR_ERROR_PRINT* @see PEAR_ERROR_TRIGGER* @see PEAR_ERROR_DIE* @see PEAR_ERROR_CALLBACK* @see PEAR_ERROR_EXCEPTION** @since PHP 4.0.5*/function setErrorHandling($mode = null, $options = null){if (isset($this) && is_a($this, 'PEAR')) {$setmode = &$this->_default_error_mode;$setoptions = &$this->_default_error_options;} else {$setmode = &$GLOBALS['_PEAR_default_error_mode'];$setoptions = &$GLOBALS['_PEAR_default_error_options'];}switch ($mode) {case PEAR_ERROR_RETURN:case PEAR_ERROR_PRINT:case PEAR_ERROR_TRIGGER:case PEAR_ERROR_DIE:case PEAR_ERROR_EXCEPTION:case null:$setmode = $mode;$setoptions = $options;break;case PEAR_ERROR_CALLBACK:$setmode = $mode;// class/object method callbackif (is_callable($options)) {$setoptions = $options;} else {trigger_error("invalid error callback", E_USER_WARNING);}break;default:trigger_error("invalid error mode", E_USER_WARNING);break;}}// }}}// {{{ expectError()/*** This method is used to tell which errors you expect to get.* Expected errors are always returned with error mode* PEAR_ERROR_RETURN. Expected error codes are stored in a stack,* and this method pushes a new element onto it. The list of* expected errors are in effect until they are popped off the* stack with the popExpect() method.** Note that this method can not be called statically** @param mixed $code a single error code or an array of error codes to expect** @return int the new depth of the "expected errors" stack* @access public*/function expectError($code = '*'){if (is_array($code)) {array_push($this->_expected_errors, $code);} else {array_push($this->_expected_errors, array($code));}return sizeof($this->_expected_errors);}// }}}// {{{ popExpect()/*** This method pops one element off the expected error codes* stack.** @return array the list of error codes that were popped*/function popExpect(){return array_pop($this->_expected_errors);}// }}}// {{{ _checkDelExpect()/*** This method checks unsets an error code if available** @param mixed error code* @return bool true if the error code was unset, false otherwise* @access private* @since PHP 4.3.0*/function _checkDelExpect($error_code){$deleted = false;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;}// clean up empty arraysif (0 == count($this->_expected_errors[$key])) {unset($this->_expected_errors[$key]);}}return $deleted;}// }}}// {{{ delExpect()/*** This method deletes all occurences of the specified element from* the expected error codes stack.** @param mixed $error_code error code that should be deleted* @return mixed list of error codes that were deleted or error* @access public* @since PHP 4.3.0*/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// valuesforeach($error_code as $key => $error) {if ($this->_checkDelExpect($error)) {$deleted = true;} else {$deleted = 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 itif ($this->_checkDelExpect($error_code)) {return true;} else {return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME}} else {// $error_code is emptyreturn PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME}}// }}}// {{{ raiseError()/*** This method is a wrapper that returns an instance of the* configured error class with this object's default error* handling applied. If the $mode and $options parameters are not* specified, the object's defaults are used.** @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 int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,* PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,* PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.** @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter* specifies the PHP-internal error level (one of* E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).* If $mode is PEAR_ERROR_CALLBACK, this* parameter specifies the callback function or* method. In other error modes this parameter* is ignored.** @param string $userinfo If you need to pass along for example debug* information, this parameter is meant for that.** @param string $error_class The returned error object will be* instantiated from this class, if specified.** @param bool $skipmsg If true, raiseError will only pass error codes,* the error message parameter will be dropped.** @access public* @return object a PEAR error object* @see PEAR::setErrorHandling* @since PHP 4.0.5*/function raiseError($message = null,$code = null,$mode = null,$options = null,$userinfo = null,$error_class = null,$skipmsg = false){// The error is yet a PEAR error objectif (is_object($message)) {$code = $message->getCode();$userinfo = $message->getUserInfo();$error_class = $message->getType();$message->error_message_prefix = '';$message = $message->getMessage();}if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) {if ($exp[0] == "*" ||(is_int(reset($exp)) && in_array($code, $exp)) ||(is_string(reset($exp)) && in_array($message, $exp))) {$mode = PEAR_ERROR_RETURN;}}// No mode given, try global onesif ($mode === null) {// Class error handlerif (isset($this) && isset($this->_default_error_mode)) {$mode = $this->_default_error_mode;$options = $this->_default_error_options;// Global error handler} elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {$mode = $GLOBALS['_PEAR_default_error_mode'];$options = $GLOBALS['_PEAR_default_error_options'];}}if ($error_class !== null) {$ec = $error_class;} elseif (isset($this) && isset($this->_error_class)) {$ec = $this->_error_class;} else {$ec = 'PEAR_Error';}if ($skipmsg) {return new $ec($code, $mode, $options, $userinfo);} else {return new $ec($message, $code, $mode, $options, $userinfo);}}// }}}// {{{ throwError()/*** Simpler form of raiseError with fewer options. In most cases* message, code and userinfo are enough.** @param string $message**/function throwError($message = null,$code = null,$userinfo = null){if (isset($this) && is_subclass_of($this, 'PEAR_Error')) {return $this->raiseError($message, $code, null, null, $userinfo);} else {return PEAR::raiseError($message, $code, null, null, $userinfo);}}// }}}// {{{ 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* it later with popErrorHandling.** @param mixed $mode (same as setErrorHandling)* @param mixed $options (same as setErrorHandling)** @return bool Always true** @see PEAR::setErrorHandling*/function pushErrorHandling($mode, $options = null){$stack = &$GLOBALS['_PEAR_error_handler_stack'];if (isset($this) && is_a($this, 'PEAR')) {$def_mode = &$this->_default_error_mode;$def_options = &$this->_default_error_options;} else {$def_mode = &$GLOBALS['_PEAR_default_error_mode'];$def_options = &$GLOBALS['_PEAR_default_error_options'];}$stack[] = array($def_mode, $def_options);if (isset($this) && is_a($this, 'PEAR')) {$this->setErrorHandling($mode, $options);} else {PEAR::setErrorHandling($mode, $options);}$stack[] = array($mode, $options);return true;}// }}}// {{{ popErrorHandling()/*** Pop the last error handler used** @return bool Always true** @see PEAR::pushErrorHandling*/function popErrorHandling(){$stack = &$GLOBALS['_PEAR_error_handler_stack'];array_pop($stack);list($mode, $options) = $stack[sizeof($stack) - 1];array_pop($stack);if (isset($this) && is_a($this, 'PEAR')) {$this->setErrorHandling($mode, $options);} else {PEAR::setErrorHandling($mode, $options);}return true;}// }}}// {{{ loadExtension()/*** OS independant PHP extension load. Remember to take care* on the correct extension name for case sensitive OSes.** @param string $ext The extension name* @return bool Success or not on the dl() call*/function loadExtension($ext){if (!extension_loaded($ext)) {// if either returns true dl() will produce a FATAL error, stop thatif ((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;}// }}}}// {{{ _PEAR_call_destructors()function _PEAR_call_destructors(){global $_PEAR_destructor_object_list;if (is_array($_PEAR_destructor_object_list) &&sizeof($_PEAR_destructor_object_list)){reset($_PEAR_destructor_object_list);while (list($k, $objref) = each($_PEAR_destructor_object_list)) {$classname = get_class($objref);while ($classname) {$destructor = "_$classname";if (method_exists($objref, $destructor)) {$objref->$destructor();break;} else {$classname = get_parent_class($classname);}}}// Empty the object list to ensure that destructors are// not called more than once.$_PEAR_destructor_object_list = array();}// Now call the shutdown functionsif (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) {foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {call_user_func_array($value[0], $value[1]);}}}// }}}class PEAR_Error{// {{{ propertiesvar $error_message_prefix = '';var $mode = PEAR_ERROR_RETURN;var $level = E_USER_NOTICE;var $code = -1;var $message = '';var $userinfo = '';var $backtrace = null;// }}}// {{{ constructor/*** PEAR_Error constructor** @param string $message message** @param int $code (optional) error code** @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN,* PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,* PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION** @param mixed $options (optional) error level, _OR_ in the case of* PEAR_ERROR_CALLBACK, the callback function or object/method* tuple.** @param string $userinfo (optional) additional user/debug info** @access public**/function PEAR_Error($message = 'unknown error', $code = null,$mode = null, $options = null, $userinfo = null){if ($mode === null) {$mode = PEAR_ERROR_RETURN;}$this->message = $message;$this->code = $code;$this->mode = $mode;$this->userinfo = $userinfo;if (function_exists("debug_backtrace")) {$this->backtrace = debug_backtrace();}if ($mode & PEAR_ERROR_CALLBACK) {$this->level = E_USER_NOTICE;$this->callback = $options;} else {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)) {$format = "%s";if (substr($msg, -1) != "\n") {$msg .= "\n";}} else {$format = $options;}die(sprintf($format, $msg));}if ($this->mode & PEAR_ERROR_CALLBACK) {if (is_callable($this->callback)) {call_user_func($this->callback, $this);}}if (PEAR_ZE2 && $this->mode & PEAR_ERROR_EXCEPTION) {eval('throw $this;');}}// }}}// {{{ getMode()/*** Get the error mode from an error object.** @return int error mode* @access public*/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() {return $this->callback;}// }}}// {{{ getMessage()/*** Get the error message from an error object.** @return string full error message* @access public*/function getMessage(){return ($this->error_message_prefix . $this->message);}// }}}// {{{ getCode()/*** Get error code from an error object** @return int error code* @access public*/function getCode(){return $this->code;}// }}}// {{{ getType()/*** Get the name of this error/exception.** @return string error/exception name (type)* @access public*/function getType(){return get_class($this);}// }}}// {{{ getUserInfo()/*** Get additional user-supplied information.** @return string user-supplied information* @access public*/function getUserInfo(){return $this->userinfo;}// }}}// {{{ getDebugInfo()/*** Get additional debug information supplied by the application.** @return string debug information* @access public*/function getDebugInfo(){return $this->getUserInfo();}// }}}// {{{ getBacktrace()/*** Get the call backtrace from where the error was generated.* Supported with PHP 4.3.0 or newer.** @param int $frame (optional) what frame to fetch* @return array Backtrace, or NULL if not available.* @access public*/function getBacktrace($frame = null){if ($frame === null) {return $this->backtrace;}return $this->backtrace[$frame];}// }}}// {{{ addUserInfo()function addUserInfo($info){if (empty($this->userinfo)) {$this->userinfo = $info;} else {$this->userinfo .= " ** $info";}}// }}}// {{{ toString()/*** Make a string representation of this object.** @return string a string with an object summary* @access public*/function toString() {$modes = array();$levels = array(E_USER_NOTICE => 'notice',E_USER_WARNING => 'warning',E_USER_ERROR => 'error');if ($this->mode & PEAR_ERROR_CALLBACK) {if (is_array($this->callback)) {$callback = get_class($this->callback[0]) . '::' .$this->callback[1];} else {$callback = $this->callback;}return sprintf('[%s: message="%s" code=%d mode=callback '.'callback=%s prefix="%s" info="%s"]',get_class($this), $this->message, $this->code,$callback, $this->error_message_prefix,$this->userinfo);}if ($this->mode & PEAR_ERROR_PRINT) {$modes[] = 'print';}if ($this->mode & PEAR_ERROR_TRIGGER) {$modes[] = 'trigger';}if ($this->mode & PEAR_ERROR_DIE) {$modes[] = 'die';}if ($this->mode & PEAR_ERROR_RETURN) {$modes[] = 'return';}return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.'prefix="%s" info="%s"]',get_class($this), $this->message, $this->code,implode("|", $modes), $levels[$this->level],$this->error_message_prefix,$this->userinfo);}// }}}}register_shutdown_function("_PEAR_call_destructors");/** Local Variables:* mode: php* tab-width: 4* c-basic-offset: 4* End:*/?>