diff options
| author | lsces <lester@lsces.co.uk> | 2012-08-04 20:35:13 +0100 |
|---|---|---|
| committer | lsces <lester@lsces.co.uk> | 2012-08-04 20:35:13 +0100 |
| commit | 7ca5d15d5cde559d645f9eda3e2cb09fa63d03db (patch) | |
| tree | ad6057cb4c547e17a4b9913d4c4f0d3619f7bf89 | |
| parent | 04a507483586d593e89598466b12c99708db3e27 (diff) | |
| download | util-7ca5d15d5cde559d645f9eda3e2cb09fa63d03db.tar.gz util-7ca5d15d5cde559d645f9eda3e2cb09fa63d03db.tar.bz2 util-7ca5d15d5cde559d645f9eda3e2cb09fa63d03db.zip | |
PEAR does not currently work with E_STRICT so we need to manually convert
This is only being stored here as it will then be used correctly when installed
These updates need re-porting to PEAR project.
| m--------- | adodb | 0 | ||||
| -rw-r--r-- | pear/Auth.php | 1365 | ||||
| -rw-r--r-- | pear/HTTP.php | 548 | ||||
| -rw-r--r-- | pear/PEAR.php | 1037 | ||||
| -rw-r--r-- | pear/PEAR5.php | 33 | ||||
| -rw-r--r-- | pear/System.php | 607 | ||||
| m--------- | smarty | 0 | ||||
| m--------- | uniform | 0 |
8 files changed, 3590 insertions, 0 deletions
diff --git a/adodb b/adodb deleted file mode 160000 -Subproject 9fb77bd6d89521bf61bf0d4495fd611e02e86e3 diff --git a/pear/Auth.php b/pear/Auth.php new file mode 100644 index 0000000..52fe7ae --- /dev/null +++ b/pear/Auth.php @@ -0,0 +1,1365 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */ + +/** + * The main include file for Auth package + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.01 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_01.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 Authentication + * @package Auth + * @author Martin Jansen <mj@php.net> + * @author Adam Ashley <aashley@php.net> + * @copyright 2001-2006 The PHP Group + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @version CVS: $Id: Auth.php 289651 2009-10-15 04:39:07Z aashley $ + * @link http://pear.php.net/package/Auth + */ + +/** + * Returned if session exceeds idle time + */ +define('AUTH_IDLED', -1); +/** + * Returned if session has expired + */ +define('AUTH_EXPIRED', -2); +/** + * Returned if container is unable to authenticate user/password pair + */ +define('AUTH_WRONG_LOGIN', -3); +/** + * Returned if a container method is not supported. + */ +define('AUTH_METHOD_NOT_SUPPORTED', -4); +/** + * Returned if new Advanced security system detects a breach + */ +define('AUTH_SECURITY_BREACH', -5); +/** + * Returned if checkAuthCallback says session should not continue. + */ +define('AUTH_CALLBACK_ABORT', -6); + +/** + * Auth Log level - INFO + */ +define('AUTH_LOG_INFO', 6); +/** + * Auth Log level - DEBUG + */ +define('AUTH_LOG_DEBUG', 7); + +/** + * Auth Advanced Security - IP Checks + */ +define('AUTH_ADV_IPCHECK', 1); +/** + * Auth Advanced Security - User Agent Checks + */ +define('AUTH_ADV_USERAGENT', 2); +/** + * Auth Advanced Security - Challenge Response + */ +define('AUTH_ADV_CHALLENGE', 3); + + +/** + * PEAR::Auth + * + * The PEAR::Auth class provides methods for creating an + * authentication system using PHP. + * + * @category Authentication + * @package Auth + * @author Martin Jansen <mj@php.net> + * @author Adam Ashley <aashley@php.net> + * @copyright 2001-2006 The PHP Group + * @license http://www.php.net/license/3_01.txt PHP License 3.01 + * @version Release: @package_version@ File: $Revision: 289651 $ + * @link http://pear.php.net/package/Auth + */ +class Auth { + + // {{{ properties + + /** + * Auth lifetime in seconds + * + * If this variable is set to 0, auth never expires + * + * @var integer + * @see setExpire(), checkAuth() + */ + var $expire = 0; + + /** + * Has the auth session expired? + * + * @var bool + * @see checkAuth() + */ + var $expired = false; + + /** + * Maximum idletime in seconds + * + * The difference to $expire is, that the idletime gets + * refreshed each time checkAuth() is called. If this + * variable is set to 0, idletime is never checked. + * + * @var integer + * @see setIdle(), checkAuth() + */ + var $idle = 0; + + /** + * Is the maximum idletime over? + * + * @var boolean + * @see checkAuth() + */ + var $idled = false; + + /** + * Storage object + * + * @var object + * @see Auth(), validateLogin() + */ + var $storage = ''; + + /** + * User-defined function that creates the login screen + * + * @var string + */ + var $loginFunction = ''; + + /** + * Should the login form be displayed + * + * @var bool + * @see setShowlogin() + */ + var $showLogin = true; + + /** + * Is Login Allowed from this page + * + * @var bool + * @see setAllowLogin + */ + var $allowLogin = true; + + /** + * Current authentication status + * + * @var string + */ + var $status = ''; + + /** + * Username + * + * @var string + */ + var $username = ''; + + /** + * Password + * + * @var string + */ + var $password = ''; + + /** + * checkAuth callback function name + * + * @var string + * @see setCheckAuthCallback() + */ + var $checkAuthCallback = ''; + + /** + * Login callback function name + * + * @var string + * @see setLoginCallback() + */ + var $loginCallback = ''; + + /** + * Failed Login callback function name + * + * @var string + * @see setFailedLoginCallback() + */ + var $loginFailedCallback = ''; + + /** + * Logout callback function name + * + * @var string + * @see setLogoutCallback() + */ + var $logoutCallback = ''; + + /** + * Auth session-array name + * + * @var string + */ + var $_sessionName = '_authsession'; + + /** + * Package Version + * + * @var string + */ + var $version = "@version@"; + + /** + * Flag to use advanced security + * When set extra checks will be made to see if the + * user's IP or useragent have changed across requests. + * Turned off by default to preserve BC. + * + * @var mixed Boolean to turn all advanced security options on or off + * Array containing named values turning specific advanced + * security features on or off individually + * array( + * AUTH_ADV_IPCHECK => true, + * AUTH_ADV_USERAGENT => true, + * AUTH_ADV_CHALLENGE => true, + * ); + */ + var $advancedsecurity = false; + + /** + * Username key in POST array + * + * @var string + */ + var $_postUsername = 'username'; + + /** + * Password key in POST array + * + * @var string + */ + var $_postPassword = 'password'; + + /** + * Holds a reference to the session auth variable + * @var array + */ + var $session; + + /** + * Holds a reference to the global server variable + * @var array + */ + var $server; + + /** + * Holds a reference to the global post variable + * @var array + */ + var $post; + + /** + * Holds a reference to the global cookie variable + * @var array + */ + var $cookie; + + /** + * A hash to hold various superglobals as reference + * @var array + */ + var $authdata; + + /** + * How many times has checkAuth been called + * @var int + */ + var $authChecks = 0; + + /** + * PEAR::Log object + * + * @var object Log + */ + var $logger = null; + + /** + * Whether to enable logging of behaviour + * + * @var boolean + */ + var $enableLogging = false; + + /** + * Whether to regenerate session id everytime start is called + * + * @var boolean + */ + var $regenerateSessionId = false; + + // }}} + // {{{ Auth() [constructor] + + /** + * Constructor + * + * Set up the storage driver. + * + * @param string Type of the storage driver + * @param mixed Additional options for the storage driver + * (example: if you are using DB as the storage + * driver, you have to pass the dsn string here) + * + * @param string Name of the function that creates the login form + * @param boolean Should the login form be displayed if necessary? + * @return void + */ + function Auth($storageDriver, $options = '', $loginFunction = '', $showLogin = true) + { + $this->applyAuthOptions($options); + + // Start the session suppress error if already started + if(!session_id()){ + @session_start(); + if(!session_id()) { + // Throw error + include_once 'PEAR.php'; + PEAR::throwError('Session could not be started by Auth, ' + .'possibly headers are already sent, try putting ' + .'ob_start in the beginning of your script'); + } + } + + // Make Sure Auth session variable is there + if(!isset($_SESSION[$this->_sessionName])) { + $_SESSION[$this->_sessionName] = array(); + } + + // Assign Some globals to internal references, this will replace _importGlobalVariable + $this->session =& $_SESSION[$this->_sessionName]; + $this->server =& $_SERVER; + $this->post =& $_POST; + $this->cookie =& $_COOKIE; + + if ($loginFunction != '' && is_callable($loginFunction)) { + $this->loginFunction = $loginFunction; + } + + if (is_bool($showLogin)) { + $this->showLogin = $showLogin; + } + + if (is_object($storageDriver)) { + $this->storage =& $storageDriver; + // Pass a reference to auth to the container, ugly but works + // this is used by the DB container to use method setAuthData not staticaly. + $this->storage->_auth_obj =& $this; + } else { + // $this->storage = $this->_factory($storageDriver, $options); + // + $this->storage_driver = $storageDriver; + $this->storage_options =& $options; + } + } + + // }}} + // {{{ applyAuthOptions() + + /** + * Set the Auth options + * + * Some options which are Auth specific will be applied + * the rest will be left for usage by the container + * + * @param array An array of Auth options + * @return array The options which were not applied + * @access private + */ + function &applyAuthOptions(&$options) + { + if(is_array($options)){ + if (!empty($options['sessionName'])) { + $this->_sessionName = $options['sessionName']; + unset($options['sessionName']); + } + if (isset($options['allowLogin'])) { + $this->allowLogin = $options['allowLogin']; + unset($options['allowLogin']); + } + if (!empty($options['postUsername'])) { + $this->_postUsername = $options['postUsername']; + unset($options['postUsername']); + } + if (!empty($options['postPassword'])) { + $this->_postPassword = $options['postPassword']; + unset($options['postPassword']); + } + if (isset($options['advancedsecurity'])) { + $this->advancedsecurity = $options['advancedsecurity']; + unset($options['advancedsecurity']); + } + if (isset($options['enableLogging'])) { + $this->enableLogging = $options['enableLogging']; + unset($options['enableLogging']); + } + if (isset($options['regenerateSessionId']) && is_bool($options['regenerateSessionId'])) { + $this->regenerateSessionId = $options['regenerateSessionId']; + } + } + return($options); + } + + // }}} + // {{{ _loadStorage() + + /** + * Load Storage Driver if not already loaded + * + * Suspend storage instantiation to make Auth lighter to use + * for calls which do not require login + * + * @return bool True if the conainer is loaded, false if the container + * is already loaded + * @access private + */ + function _loadStorage() + { + if(!is_object($this->storage)) { + $this->storage =& $this->_factory($this->storage_driver, + $this->storage_options); + $this->storage->_auth_obj =& $this; + $this->log('Loaded storage container ('.$this->storage_driver.')', AUTH_LOG_DEBUG); + return(true); + } + return(false); + } + + // }}} + // {{{ _factory() + + /** + * Return a storage driver based on $driver and $options + * + * @static + * @param string $driver Type of storage class to return + * @param string $options Optional parameters for the storage class + * @return object Object Storage object + * @access private + */ + function &_factory($driver, $options = '') + { + $storage_class = 'Auth_Container_' . $driver; + include_once 'Auth/Container/' . $driver . '.php'; + $obj = new $storage_class($options); + return $obj; + } + + // }}} + // {{{ assignData() + + /** + * Assign data from login form to internal values + * + * This function takes the values for username and password + * from $HTTP_POST_VARS/$_POST and assigns them to internal variables. + * If you wish to use another source apart from $HTTP_POST_VARS/$_POST, + * you have to derive this function. + * + * @global $HTTP_POST_VARS, $_POST + * @see Auth + * @return void + * @access private + */ + function assignData() + { + $this->log('Auth::assignData() called.', AUTH_LOG_DEBUG); + + if ( isset($this->post[$this->_postUsername]) + && $this->post[$this->_postUsername] != '') { + $this->username = (get_magic_quotes_gpc() == 1 + ? stripslashes($this->post[$this->_postUsername]) + : $this->post[$this->_postUsername]); + } + if ( isset($this->post[$this->_postPassword]) + && $this->post[$this->_postPassword] != '') { + $this->password = (get_magic_quotes_gpc() == 1 + ? stripslashes($this->post[$this->_postPassword]) + : $this->post[$this->_postPassword] ); + } + } + + // }}} + // {{{ start() + + /** + * Start new auth session + * + * @return void + * @access public + */ + function start() + { + $this->log('Auth::start() called.', AUTH_LOG_DEBUG); + + // #10729 - Regenerate session id here if we are generating it on every + // page load. + if ($this->regenerateSessionId) { + session_regenerate_id(true); + } + + $this->assignData(); + if (!$this->checkAuth() && $this->allowLogin) { + $this->login(); + } + } + + // }}} + // {{{ login() + + /** + * Login function + * + * @return void + * @access private + */ + function login() + { + $this->log('Auth::login() called.', AUTH_LOG_DEBUG); + + $login_ok = false; + $this->_loadStorage(); + + // Check if using challenge response + (isset($this->post['authsecret']) && $this->post['authsecret'] == 1) + ? $usingChap = true + : $usingChap = false; + + + // When the user has already entered a username, we have to validate it. + if (!empty($this->username)) { + if (true === $this->storage->fetchData($this->username, $this->password, $usingChap)) { + $this->session['challengekey'] = md5($this->username.$this->password); + $login_ok = true; + $this->log('Successful login.', AUTH_LOG_INFO); + } + } + + if (!empty($this->username) && $login_ok) { + $this->setAuth($this->username); + if (is_callable($this->loginCallback)) { + $this->log('Calling loginCallback ('.$this->loginCallback.').', AUTH_LOG_DEBUG); + call_user_func_array($this->loginCallback, array($this->username, &$this)); + } + } + + // If the login failed or the user entered no username, + // output the login screen again. + if (!empty($this->username) && !$login_ok) { + $this->log('Incorrect login.', AUTH_LOG_INFO); + $this->status = AUTH_WRONG_LOGIN; + if (is_callable($this->loginFailedCallback)) { + $this->log('Calling loginFailedCallback ('.$this->loginFailedCallback.').', AUTH_LOG_DEBUG); + call_user_func_array($this->loginFailedCallback, array($this->username, &$this)); + } + } + + if ((empty($this->username) || !$login_ok) && $this->showLogin) { + $this->log('Rendering Login Form.', AUTH_LOG_INFO); + if (is_callable($this->loginFunction)) { + $this->log('Calling loginFunction ('.$this->loginFunction.').', AUTH_LOG_DEBUG); + call_user_func_array($this->loginFunction, array($this->username, $this->status, &$this)); + } else { + // BC fix Auth used to use drawLogin for this + // call is sub classes implement this + if (is_callable(array($this, 'drawLogin'))) { + $this->log('Calling Auth::drawLogin()', AUTH_LOG_DEBUG); + return $this->drawLogin($this->username, $this); + } + + $this->log('Using default Auth_Frontend_Html', AUTH_LOG_DEBUG); + + // New Login form + include_once 'Auth/Frontend/Html.php'; + return Auth_Frontend_Html::render($this, $this->username); + } + } else { + return; + } + } + + // }}} + // {{{ setExpire() + + /** + * Set the maximum expire time + * + * @param integer time in seconds + * @param bool add time to current expire time or not + * @return void + * @access public + */ + function setExpire($time, $add = false) + { + $add ? $this->expire += $time : $this->expire = $time; + } + + // }}} + // {{{ setIdle() + + /** + * Set the maximum idle time + * + * @param integer time in seconds + * @param bool add time to current maximum idle time or not + * @return void + * @access public + */ + function setIdle($time, $add = false) + { + $add ? $this->idle += $time : $this->idle = $time; + } + + // }}} + // {{{ setSessionName() + + /** + * Set name of the session to a customized value. + * + * If you are using multiple instances of PEAR::Auth + * on the same domain, you can change the name of + * session per application via this function. + * This will chnage the name of the session variable + * auth uses to store it's data in the session + * + * @param string New name for the session + * @return void + * @access public + */ + function setSessionName($name = 'session') + { + $this->_sessionName = '_auth_'.$name; + // Make Sure Auth session variable is there + if(!isset($_SESSION[$this->_sessionName])) { + $_SESSION[$this->_sessionName] = array(); + } + $this->session =& $_SESSION[$this->_sessionName]; + } + + // }}} + // {{{ setShowLogin() + + /** + * Should the login form be displayed if necessary? + * + * @param bool show login form or not + * @return void + * @access public + */ + function setShowLogin($showLogin = true) + { + $this->showLogin = $showLogin; + } + + // }}} + // {{{ setAllowLogin() + + /** + * Is Login Allowed from this page? + * + * @param bool allow login from this page or not + * @return void + * @access public + */ + function setAllowLogin($allowLogin = true) + { + $this->allowLogin = $allowLogin; + } + + // }}} + // {{{ setCheckAuthCallback() + + /** + * Register a callback function to be called whenever the validity of the login is checked + * The function will receive two parameters, the username and a reference to the auth object. + * + * @param string callback function name + * @return void + * @access public + * @since Method available since Release 1.4.3 + */ + function setCheckAuthCallback($checkAuthCallback) + { + $this->checkAuthCallback = $checkAuthCallback; + } + + // }}} + // {{{ setLoginCallback() + + /** + * Register a callback function to be called on user login. + * The function will receive two parameters, the username and a reference to the auth object. + * + * @param string callback function name + * @return void + * @see setLogoutCallback() + * @access public + */ + function setLoginCallback($loginCallback) + { + $this->loginCallback = $loginCallback; + } + + // }}} + // {{{ setFailedLoginCallback() + + /** + * Register a callback function to be called on failed user login. + * The function will receive two parameters, the username and a reference to the auth object. + * + * @param string callback function name + * @return void + * @access public + */ + function setFailedLoginCallback($loginFailedCallback) + { + $this->loginFailedCallback = $loginFailedCallback; + } + + // }}} + // {{{ setLogoutCallback() + + /** + * Register a callback function to be called on user logout. + * The function will receive three parameters, the username and a reference to the auth object. + * + * @param string callback function name + * @return void + * @see setLoginCallback() + * @access public + */ + function setLogoutCallback($logoutCallback) + { + $this->logoutCallback = $logoutCallback; + } + + // }}} + // {{{ setAuthData() + + /** + * Register additional information that is to be stored + * in the session. + * + * @param string Name of the data field + * @param mixed Value of the data field + * @param boolean Should existing data be overwritten? (default + * is true) + * @return void + * @access public + */ + function setAuthData($name, $value, $overwrite = true) + { + if (!empty($this->session['data'][$name]) && $overwrite == false) { + return; + } + $this->session['data'][$name] = $value; + } + + // }}} + // {{{ getAuthData() + + /** + * Get additional information that is stored in the session. + * + * If no value for the first parameter is passed, the method will + * return all data that is currently stored. + * + * @param string Name of the data field + * @return mixed Value of the data field. + * @access public + */ + function getAuthData($name = null) + { + if (!isset($this->session['data'])) { + return null; + } + if(!isset($name)) { + return $this->session['data']; + } + if (isset($name) && isset($this->session['data'][$name])) { + return $this->session['data'][$name]; + } + return null; + } + + // }}} + // {{{ setAuth() + + /** + * Register variable in a session telling that the user + * has logged in successfully + * + * @param string Username + * @return void + * @access public + */ + function setAuth($username) + { + $this->log('Auth::setAuth() called.', AUTH_LOG_DEBUG); + + // #10729 - Regenerate session id here only if generating at login only + // Don't do it if we are regenerating on every request so we don't + // regenerate it twice in one request. + if (!$this->regenerateSessionId) { + // #2021 - Change the session id to avoid session fixation attacks php 4.3.3 > + session_regenerate_id(true); + } + + if (!isset($this->session) || !is_array($this->session)) { + $this->session = array(); + } + + if (!isset($this->session['data'])) { + $this->session['data'] = array(); + } + + $this->session['sessionip'] = isset($this->server['REMOTE_ADDR']) + ? $this->server['REMOTE_ADDR'] + : ''; + $this->session['sessionuseragent'] = isset($this->server['HTTP_USER_AGENT']) + ? $this->server['HTTP_USER_AGENT'] + : ''; + $this->session['sessionforwardedfor'] = isset($this->server['HTTP_X_FORWARDED_FOR']) + ? $this->server['HTTP_X_FORWARDED_FOR'] + : ''; + + // This should be set by the container to something more safe + // Like md5(passwd.microtime) + if(empty($this->session['challengekey'])) { + $this->session['challengekey'] = md5($username.microtime()); + } + + $this->session['challengecookie'] = md5($this->session['challengekey'].microtime()); + setcookie('authchallenge', $this->session['challengecookie'], 0, '/'); + + $this->session['registered'] = true; + $this->session['username'] = $username; + $this->session['timestamp'] = time(); + $this->session['idle'] = time(); + } + + // }}} + // {{{ setAdvancedSecurity() + + /** + * Enables advanced security checks + * + * Currently only ip change and useragent change + * are detected + * @todo Add challenge cookies - Create a cookie which changes every time + * and contains some challenge key which the server can verify with + * a session var cookie might need to be crypted (user pass) + * @param bool Enable or disable + * @return void + * @access public + */ + function setAdvancedSecurity($flag=true) + { + $this->advancedsecurity = $flag; + } + + // }}} + // {{{ checkAuth() + + /** + * Checks if there is a session with valid auth information. + * + * @access public + * @return boolean Whether or not the user is authenticated. + */ + function checkAuth() + { + $this->log('Auth::checkAuth() called.', AUTH_LOG_DEBUG); + $this->authChecks++; + if (isset($this->session)) { + // Check if authentication session is expired + if ( $this->expire > 0 + && isset($this->session['timestamp']) + && ($this->session['timestamp'] + $this->expire) < time()) { + $this->log('Session Expired', AUTH_LOG_INFO); + $this->expired = true; + $this->status = AUTH_EXPIRED; + $this->logout(); + return false; + } + + // Check if maximum idle time is reached + if ( $this->idle > 0 + && isset($this->session['idle']) + && ($this->session['idle'] + $this->idle) < time()) { + $this->log('Session Idle Time Reached', AUTH_LOG_INFO); + $this->idled = true; + $this->status = AUTH_IDLED; + $this->logout(); + return false; + } + + if ( isset($this->session['registered']) + && isset($this->session['username']) + && $this->session['registered'] == true + && $this->session['username'] != '') { + Auth::updateIdle(); + + if ($this->_isAdvancedSecurityEnabled()) { + $this->log('Advanced Security Mode Enabled.', AUTH_LOG_DEBUG); + + // Only Generate the challenge once + if ( $this->authChecks == 1 + && $this->_isAdvancedSecurityEnabled(AUTH_ADV_CHALLENGE)) { + $this->log('Generating new Challenge Cookie.', AUTH_LOG_DEBUG); + $this->session['challengecookieold'] = $this->session['challengecookie']; + $this->session['challengecookie'] = md5($this->session['challengekey'].microtime()); + setcookie('authchallenge', $this->session['challengecookie'], 0, '/'); + } + + // Check for ip change + if ( $this->_isAdvancedSecurityEnabled(AUTH_ADV_IPCHECK) + && isset($this->server['REMOTE_ADDR']) + && $this->session['sessionip'] != $this->server['REMOTE_ADDR']) { + $this->log('Security Breach. Remote IP Address changed.', AUTH_LOG_INFO); + // Check if the IP of the user has changed, if so we + // assume a man in the middle attack and log him out + $this->expired = true; + $this->status = AUTH_SECURITY_BREACH; + $this->logout(); + return false; + } + + // Check for ip change (if connected via proxy) + if ( $this->_isAdvancedSecurityEnabled(AUTH_ADV_IPCHECK) + && isset($this->server['HTTP_X_FORWARDED_FOR']) + && $this->session['sessionforwardedfor'] != $this->server['HTTP_X_FORWARDED_FOR']) { + $this->log('Security Breach. Forwarded For IP Address changed.', AUTH_LOG_INFO); + // Check if the IP of the user connecting via proxy has + // changed, if so we assume a man in the middle attack + // and log him out. + $this->expired = true; + $this->status = AUTH_SECURITY_BREACH; + $this->logout(); + return false; + } + + // Check for useragent change + if ( $this->_isAdvancedSecurityEnabled(AUTH_ADV_USERAGENT) + && isset($this->server['HTTP_USER_AGENT']) + && $this->session['sessionuseragent'] != $this->server['HTTP_USER_AGENT']) { + $this->log('Security Breach. User Agent changed.', AUTH_LOG_INFO); + // Check if the User-Agent of the user has changed, if + // so we assume a man in the middle attack and log him out + $this->expired = true; + $this->status = AUTH_SECURITY_BREACH; + $this->logout(); + return false; + } + + // Check challenge cookie here, if challengecookieold is not set + // this is the first time and check is skipped + // TODO when user open two pages similtaneuly (open in new window,open + // in tab) auth breach is caused find out a way around that if possible + if ( $this->_isAdvancedSecurityEnabled(AUTH_ADV_CHALLENGE) + && isset($this->session['challengecookieold']) + && $this->session['challengecookieold'] != $this->cookie['authchallenge']) { + $this->log('Security Breach. Challenge Cookie mismatch.', AUTH_LOG_INFO); + $this->expired = true; + $this->status = AUTH_SECURITY_BREACH; + $this->logout(); + $this->login(); + return false; + } + } + + if (is_callable($this->checkAuthCallback)) { + $this->log('Calling checkAuthCallback ('.$this->checkAuthCallback.').', AUTH_LOG_DEBUG); + $checkCallback = call_user_func_array($this->checkAuthCallback, array($this->username, &$this)); + if ($checkCallback == false) { + $this->log('checkAuthCallback failed.', AUTH_LOG_INFO); + $this->expired = true; + $this->status = AUTH_CALLBACK_ABORT; + $this->logout(); + return false; + } + } + + $this->log('Session OK.', AUTH_LOG_INFO); + return true; + } + } else { + $this->log('Unable to locate session storage.', AUTH_LOG_DEBUG); + return false; + } + $this->log('No login session.', AUTH_LOG_DEBUG); + return false; + } + + // }}} + // {{{ staticCheckAuth() [static] + + /** + * Statically checks if there is a session with valid auth information. + * + * @access public + * @see checkAuth + * @return boolean Whether or not the user is authenticated. + * @static + */ + function staticCheckAuth($options = null) + { + static $staticAuth; + if(!isset($staticAuth)) { + $staticAuth = new Auth('null', $options); + } + $staticAuth->log('Auth::staticCheckAuth() called', AUTH_LOG_DEBUG); + return $staticAuth->checkAuth(); + } + + // }}} + // {{{ getAuth() + + /** + * Has the user been authenticated? + * + * Is there a valid login session. Previously this was different from + * checkAuth() but now it is just an alias. + * + * @access public + * @return bool True if the user is logged in, otherwise false. + */ + function getAuth() + { + $this->log('Auth::getAuth() called.', AUTH_LOG_DEBUG); + return $this->checkAuth(); + } + + // }}} + // {{{ logout() + + /** + * Logout function + * + * This function clears any auth tokens in the currently + * active session and executes the logout callback function, + * if any + * + * @access public + * @return void + */ + function logout() + { + $this->log('Auth::logout() called.', AUTH_LOG_DEBUG); + + if (is_callable($this->logoutCallback) && isset($this->session['username'])) { + $this->log('Calling logoutCallback ('.$this->logoutCallback.').', AUTH_LOG_DEBUG); + call_user_func_array($this->logoutCallback, array($this->session['username'], &$this)); + } + + $this->username = ''; + $this->password = ''; + + $this->session = null; + } + + // }}} + // {{{ updateIdle() + + /** + * Update the idletime + * + * @access private + * @return void + */ + function updateIdle() + { + $this->session['idle'] = time(); + } + + // }}} + // {{{ getUsername() + + /** + * Get the username + * + * @return string + * @access public + */ + function getUsername() + { + if (isset($this->session['username'])) { + return($this->session['username']); + } + return(''); + } + + // }}} + // {{{ getStatus() + + /** + * Get the current status + * + * @return string + * @access public + */ + function getStatus() + { + return $this->status; + } + + // }}} + // {{{ getPostUsernameField() + + /** + * Gets the post varible used for the username + * + * @return string + * @access public + */ + function getPostUsernameField() + { + return($this->_postUsername); + } + + // }}} + // {{{ getPostPasswordField() + + /** + * Gets the post varible used for the username + * + * @return string + * @access public + */ + function getPostPasswordField() + { + return($this->_postPassword); + } + + // }}} + // {{{ sessionValidThru() + + /** + * Returns the time up to the session is valid + * + * @access public + * @return integer + */ + function sessionValidThru() + { + if (!isset($this->session['idle'])) { + return 0; + } + if ($this->idle == 0) { + return 0; + } + return ($this->session['idle'] + $this->idle); + } + + // }}} + // {{{ listUsers() + + /** + * List all users that are currently available in the storage + * container + * + * @access public + * @return array + */ + function listUsers() + { + $this->log('Auth::listUsers() called.', AUTH_LOG_DEBUG); + $this->_loadStorage(); + return $this->storage->listUsers(); + } + + // }}} + // {{{ addUser() + + /** + * Add user to the storage container + * + * @access public + * @param string Username + * @param string Password + * @param mixed Additional parameters + * @return mixed True on success, PEAR error object on error + * and AUTH_METHOD_NOT_SUPPORTED otherwise. + */ + function addUser($username, $password, $additional = '') + { + $this->log('Auth::addUser() called.', AUTH_LOG_DEBUG); + $this->_loadStorage(); + return $this->storage->addUser($username, $password, $additional); + } + + // }}} + // {{{ removeUser() + + /** + * Remove user from the storage container + * + * @access public + * @param string Username + * @return mixed True on success, PEAR error object on error + * and AUTH_METHOD_NOT_SUPPORTED otherwise. + */ + function removeUser($username) + { + $this->log('Auth::removeUser() called.', AUTH_LOG_DEBUG); + $this->_loadStorage(); + return $this->storage->removeUser($username); + } + + // }}} + // {{{ changePassword() + + /** + * Change password for user in the storage container + * + * @access public + * @param string Username + * @param string The new password + * @return mixed True on success, PEAR error object on error + * and AUTH_METHOD_NOT_SUPPORTED otherwise. + */ + function changePassword($username, $password) + { + $this->log('Auth::changePassword() called', AUTH_LOG_DEBUG); + $this->_loadStorage(); + return $this->storage->changePassword($username, $password); + } + + // }}} + // {{{ log() + + /** + * Log a message from the Auth system + * + * @access public + * @param string The message to log + * @param string The log level to log the message under. See the Log documentation for more info. + * @return boolean + */ + function log($message, $level = AUTH_LOG_DEBUG) + { + if (!$this->enableLogging) return false; + + $this->_loadLogger(); + + $this->logger->log('AUTH: '.$message, $level); + } + + // }}} + // {{{ _loadLogger() + + /** + * Load Log object if not already loaded + * + * Suspend logger instantiation to make Auth lighter to use + * for calls which do not require logging + * + * @return bool True if the logger is loaded, false if the logger + * is already loaded + * @access private + */ + function _loadLogger() + { + if(is_null($this->logger)) { + if (!class_exists('Log')) { + include_once 'Log.php'; + } + $this->logger =& Log::singleton('null', + null, + 'auth['.getmypid().']', + array(), + AUTH_LOG_DEBUG); + return(true); + } + return(false); + } + + // }}} + // {{{ attachLogObserver() + + /** + * Attach an Observer to the Auth Log Source + * + * @param object Log_Observer A Log Observer instance + * @return boolean + */ + function attachLogObserver(&$observer) { + + $this->_loadLogger(); + + return $this->logger->attach($observer); + + } + + // }}} + // {{{ _isAdvancedSecurityEnabled() + + /** + * Is advanced security enabled? + * + * Pass one of the Advanced Security constants as the first parameter + * to check if that advanced security check is enabled. + * + * @param integer + * @return boolean + */ + function _isAdvancedSecurityEnabled($feature = null) { + + if (is_null($feature)) { + + if ($this->advancedsecurity === true) + return true; + + if ( is_array($this->advancedsecurity) + && in_array(true, $this->advancedsecurity, true)) + return true; + + return false; + + } else { + + if (is_array($this->advancedsecurity)) { + + if ( isset($this->advancedsecurity[$feature]) + && $this->advancedsecurity[$feature] == true) + return true; + + return false; + + } + + return (bool)$this->advancedsecurity; + + } + + } + + // }}} + +} +?> diff --git a/pear/HTTP.php b/pear/HTTP.php new file mode 100644 index 0000000..6ebd6db --- /dev/null +++ b/pear/HTTP.php @@ -0,0 +1,548 @@ +<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * HTTP
+ *
+ * PHP versions 4 and 5
+ *
+ * @category HTTP
+ * @package HTTP
+ * @author Stig Bakken <ssb@fast.no>
+ * @author Sterling Hughes <sterling@php.net>
+ * @author Tomas V.V.Cox <cox@idecnet.com>
+ * @author Richard Heyes <richard@php.net>
+ * @author Philippe Jausions <jausions@php.net>
+ * @author Michael Wallner <mike@php.net>
+ * @copyright 2002-2008 The Authors
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @version CVS: $Id: HTTP.php,v 1.56 2008/08/31 20:15:43 jausions Exp $
+ * @link http://pear.php.net/package/HTTP
+ */
+
+/**
+ * Miscellaneous HTTP Utilities
+ *
+ * PEAR::HTTP provides static shorthand methods for generating HTTP dates,
+ * issueing HTTP HEAD requests, building absolute URIs, firing redirects and
+ * negotiating user preferred language.
+ *
+ * @category HTTP
+ * @package HTTP
+ * @author Stig Bakken <ssb@fast.no>
+ * @author Sterling Hughes <sterling@php.net>
+ * @author Tomas V.V.Cox <cox@idecnet.com>
+ * @author Richard Heyes <richard@php.net>
+ * @author Philippe Jausions <jausions@php.net>
+ * @author Michael Wallner <mike@php.net>
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @abstract
+ * @version Release: $Revision: 1.56 $
+ * @link http://pear.php.net/package/HTTP
+ */
+class HTTP
+{
+ /**
+ * Formats a RFC compliant GMT date HTTP header. This function honors the
+ * "y2k_compliance" php.ini directive and formats the GMT date corresponding
+ * to either RFC850 or RFC822.
+ *
+ * @param mixed $time unix timestamp or date (default = current time)
+ *
+ * @return mixed GMT date string, or false for an invalid $time parameter
+ * @access public
+ * @static
+ */
+ function Date($time = null)
+ {
+ if (!isset($time)) {
+ $time = time();
+ } elseif (!is_numeric($time) && (-1 === $time = strtotime($time))) {
+ return false;
+ }
+
+ // RFC822 or RFC850
+ $format = ini_get('y2k_compliance') ? 'D, d M Y' : 'l, d-M-y';
+
+ return gmdate($format .' H:i:s \G\M\T', $time);
+ }
+
+ /**
+ * Negotiates language with the user's browser through the Accept-Language
+ * HTTP header or the user's host address. Language codes are generally in
+ * the form "ll" for a language spoken in only one country, or "ll-CC" for a
+ * language spoken in a particular country. For example, U.S. English is
+ * "en-US", while British English is "en-UK". Portugese as spoken in
+ * Portugal is "pt-PT", while Brazilian Portugese is "pt-BR".
+ *
+ * Quality factors in the Accept-Language: header are supported, e.g.:
+ * Accept-Language: en-UK;q=0.7, en-US;q=0.6, no, dk;q=0.8
+ *
+ * <code>
+ * require_once 'HTTP.php';
+ * $langs = array(
+ * 'en' => 'locales/en',
+ * 'en-US' => 'locales/en',
+ * 'en-UK' => 'locales/en',
+ * 'de' => 'locales/de',
+ * 'de-DE' => 'locales/de',
+ * 'de-AT' => 'locales/de',
+ * );
+ * $neg = HTTP::negotiateLanguage($langs);
+ * $dir = $langs[$neg];
+ * </code>
+ *
+ * @param array $supported An associative array of supported languages,
+ * whose values must evaluate to true.
+ * @param string $default The default language to use if none is found.
+ *
+ * @return string The negotiated language result or the supplied default.
+ * @static
+ * @access public
+ */
+ function negotiateLanguage($supported, $default = 'en-US')
+ {
+ $supp = array();
+ foreach ($supported as $lang => $isSupported) {
+ if ($isSupported) {
+ $supp[strtolower($lang)] = $lang;
+ }
+ }
+
+ if (!count($supp)) {
+ return $default;
+ }
+
+ if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+ $match = HTTP::_matchAccept($_SERVER['HTTP_ACCEPT_LANGUAGE'],
+ $supp);
+ if (!is_null($match)) {
+ return $match;
+ }
+ }
+
+ if (isset($_SERVER['REMOTE_HOST'])) {
+ $lang = strtolower(end($h = explode('.', $_SERVER['REMOTE_HOST'])));
+ if (isset($supp[$lang])) {
+ return $supp[$lang];
+ }
+ }
+
+ return $default;
+ }
+
+ /**
+ * Negotiates charset with the user's browser through the Accept-Charset
+ * HTTP header.
+ *
+ * Quality factors in the Accept-Charset: header are supported, e.g.:
+ * Accept-Language: en-UK;q=0.7, en-US;q=0.6, no, dk;q=0.8
+ *
+ * <code>
+ * require_once 'HTTP.php';
+ * $charsets = array(
+ * 'UTF-8',
+ * 'ISO-8859-1',
+ * );
+ * $charset = HTTP::negotiateCharset($charsets);
+ * </code>
+ *
+ * @param array $supported An array of supported charsets
+ * @param string $default The default charset to use if none is found.
+ *
+ * @return string The negotiated language result or the supplied default.
+ * @static
+ * @author Philippe Jausions <jausions@php.net>
+ * @access public
+ * @since 1.4.1
+ */
+ function negotiateCharset($supported, $default = 'ISO-8859-1')
+ {
+ $supp = array();
+ foreach ($supported as $charset) {
+ $supp[strtolower($charset)] = $charset;
+ }
+
+ if (!count($supp)) {
+ return $default;
+ }
+
+ if (isset($_SERVER['HTTP_ACCEPT_CHARSET'])) {
+ $match = HTTP::_matchAccept($_SERVER['HTTP_ACCEPT_CHARSET'],
+ $supp);
+ if (!is_null($match)) {
+ return $match;
+ }
+ }
+
+ return $default;
+ }
+
+ /**
+ * Negotiates content type with the user's browser through the Accept
+ * HTTP header.
+ *
+ * Quality factors in the Accept: header are supported, e.g.:
+ * Accept: application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8
+ *
+ * <code>
+ * require_once 'HTTP.php';
+ * $contentType = array(
+ * 'application/xhtml+xml',
+ * 'application/xml',
+ * 'text/html',
+ * 'text/plain',
+ * );
+ * $mime = HTTP::negotiateContentType($contentType);
+ * </code>
+ *
+ * @param array $supported An associative array of supported MIME types.
+ * @param string $default The default type to use if none match.
+ *
+ * @return string The negotiated MIME type result or the supplied default.
+ * @static
+ * @author Philippe Jausions <jausions@php.net>
+ * @access public
+ * @since 1.4.1
+ */
+ function negotiateMimeType($supported, $default)
+ {
+ $supp = array();
+ foreach ($supported as $type) {
+ $supp[strtolower($type)] = $type;
+ }
+
+ if (!count($supp)) {
+ return $default;
+ }
+
+ if (isset($_SERVER['HTTP_ACCEPT'])) {
+ $accepts = HTTP::_sortAccept($_SERVER['HTTP_ACCEPT']);
+
+ foreach ($accepts as $type => $q) {
+ if (substr($type, -2) != '/*') {
+ if (isset($supp[$type])) {
+ return $supp[$type];
+ }
+ continue;
+ }
+ if ($type == '*/*') {
+ return array_shift($supp);
+ }
+ list($general, $specific) = explode('/', $type);
+ $general .= '/';
+ $len = strlen($general);
+ foreach ($supp as $mime => $t) {
+ if (strncasecmp($general, $mime, $len) == 0) {
+ return $t;
+ }
+ }
+ }
+ }
+
+ return $default;
+ }
+
+ /**
+ * Parses a weighed "Accept" HTTP header and matches it against a list
+ * of supported options
+ *
+ * @param string $header The HTTP "Accept" header to parse
+ * @param array $supported A list of supported values
+ *
+ * @return string|NULL a matched option, or NULL if no match
+ * @access private
+ * @static
+ */
+ function _matchAccept($header, $supported)
+ {
+ $matches = HTTP::_sortAccept($header);
+ foreach ($matches as $key => $q) {
+ if (isset($supported[$key])) {
+ return $supported[$key];
+ }
+ }
+ // If any (i.e. "*") is acceptable, return the first supported format
+ if (isset($matches['*'])) {
+ return array_shift($supported);
+ }
+ return null;
+ }
+
+ /**
+ * Parses and sorts a weighed "Accept" HTTP header
+ *
+ * @param string $header The HTTP "Accept" header to parse
+ *
+ * @return array a sorted list of "accept" options
+ * @access private
+ * @static
+ */
+ function _sortAccept($header)
+ {
+ $matches = array();
+ foreach (explode(',', $header) as $option) {
+ $option = array_map('trim', explode(';', $option));
+
+ $l = strtolower($option[0]);
+ if (isset($option[1])) {
+ $q = (float) str_replace('q=', '', $option[1]);
+ } else {
+ $q = null;
+ // Assign default low weight for generic values
+ if ($l == '*/*') {
+ $q = 0.01;
+ } elseif (substr($l, -1) == '*') {
+ $q = 0.02;
+ }
+ }
+ // Unweighted values, get high weight by their position in the
+ // list
+ $matches[$l] = isset($q) ? $q : 1000 - count($matches);
+ }
+ arsort($matches, SORT_NUMERIC);
+ return $matches;
+ }
+
+ /**
+ * Sends a "HEAD" HTTP command to a server and returns the headers
+ * as an associative array.
+ *
+ * Example output could be:
+ * <code>
+ * Array
+ * (
+ * [response_code] => 200 // The HTTP response code
+ * [response] => HTTP/1.1 200 OK // The full HTTP response string
+ * [Date] => Fri, 11 Jan 2002 01:41:44 GMT
+ * [Server] => Apache/1.3.20 (Unix) PHP/4.1.1
+ * [X-Powered-By] => PHP/4.1.1
+ * [Connection] => close
+ * [Content-Type] => text/html
+ * )
+ * </code>
+ *
+ * @param string $url A valid URL, e.g.: http://pear.php.net/credits.php
+ * @param integer $timeout Timeout in seconds (default = 10)
+ *
+ * @return array Returns associative array of response headers on success
+ * or PEAR error on failure.
+ * @static
+ * @access public
+ * @see HTTP_Client::head()
+ * @see HTTP_Request
+ */
+ function head($url, $timeout = 10)
+ {
+ $p = parse_url($url);
+ if (!isset($p['scheme'])) {
+ $p = parse_url(HTTP::absoluteURI($url));
+ } elseif ($p['scheme'] != 'http') {
+ return HTTP::raiseError('Unsupported protocol: '. $p['scheme']);
+ }
+
+ $port = isset($p['port']) ? $p['port'] : 80;
+
+ if (!$fp = @fsockopen($p['host'], $port, $eno, $estr, $timeout)) {
+ return HTTP::raiseError("Connection error: $estr ($eno)");
+ }
+
+ $path = !empty($p['path']) ? $p['path'] : '/';
+ $path .= !empty($p['query']) ? '?' . $p['query'] : '';
+
+ fputs($fp, "HEAD $path HTTP/1.0\r\n");
+ fputs($fp, 'Host: ' . $p['host'] . ':' . $port . "\r\n");
+ fputs($fp, "Connection: close\r\n\r\n");
+
+ $response = rtrim(fgets($fp, 4096));
+ if (preg_match("|^HTTP/[^\s]*\s(.*?)\s|", $response, $status)) {
+ $headers['response_code'] = $status[1];
+ }
+ $headers['response'] = $response;
+
+ while ($line = fgets($fp, 4096)) {
+ if (!trim($line)) {
+ break;
+ }
+ if (($pos = strpos($line, ':')) !== false) {
+ $header = substr($line, 0, $pos);
+ $value = trim(substr($line, $pos + 1));
+
+ $headers[$header] = $value;
+ }
+ }
+ fclose($fp);
+ return $headers;
+ }
+
+ /**
+ * This function redirects the client. This is done by issuing
+ * a "Location" header and exiting if wanted. If you set $rfc2616 to true
+ * HTTP will output a hypertext note with the location of the redirect.
+ *
+ * @param string $url URL where the redirect should go to.
+ * @param bool $exit Whether to exit immediately after redirection.
+ * @param bool $rfc2616 Wheter to output a hypertext note where we're
+ * redirecting to (Redirecting to
+ * <a href="...">...</a>.)
+ *
+ * @return boolean Returns TRUE on succes (or exits) or FALSE if headers
+ * have already been sent.
+ * @static
+ * @access public
+ */
+ function redirect($url, $exit = true, $rfc2616 = false)
+ {
+ if (headers_sent()) {
+ return false;
+ }
+
+ $url = HTTP::absoluteURI($url);
+ header('Location: '. $url);
+
+ if ($rfc2616 && isset($_SERVER['REQUEST_METHOD'])
+ && $_SERVER['REQUEST_METHOD'] != 'HEAD') {
+ echo '
+<p>Redirecting to: <a href="'.str_replace('"', '%22', $url).'">'
+ .htmlspecialchars($url).'</a>.</p>
+<script type="text/javascript">
+//<![CDATA[
+if (location.replace == null) {
+ location.replace = location.assign;
+}
+location.replace("'.str_replace('"', '\\"', $url).'");
+// ]]>
+</script>';
+ }
+ if ($exit) {
+ exit;
+ }
+ return true;
+ }
+
+ /**
+ * This function returns the absolute URI for the partial URL passed.
+ * The current scheme (HTTP/HTTPS), host server, port, current script
+ * location are used if necessary to resolve any relative URLs.
+ *
+ * Offsets potentially created by PATH_INFO are taken care of to resolve
+ * relative URLs to the current script.
+ *
+ * You can choose a new protocol while resolving the URI. This is
+ * particularly useful when redirecting a web browser using relative URIs
+ * and to switch from HTTP to HTTPS, or vice-versa, at the same time.
+ *
+ * @param string $url Absolute or relative URI the redirect should
+ * go to.
+ * @param string $protocol Protocol to use when redirecting URIs.
+ * @param integer $port A new port number.
+ *
+ * @return string The absolute URI.
+ * @author Philippe Jausions <Philippe.Jausions@11abacus.com>
+ * @static
+ * @access public
+ */
+ function absoluteURI($url = null, $protocol = null, $port = null)
+ {
+ // filter CR/LF
+ $url = str_replace(array("\r", "\n"), ' ', $url);
+
+ // Mess around protocol and port with already absolute URIs
+ if (preg_match('!^([a-z0-9]+)://!i', $url)) {
+ if (empty($protocol) && empty($port)) {
+ return $url;
+ }
+ if (!empty($protocol)) {
+ $url = $protocol .':'. end($array = explode(':', $url, 2));
+ }
+ if (!empty($port)) {
+ $url = preg_replace('!^(([a-z0-9]+)://[^/:]+)(:[\d]+)?!i',
+ '\1:'. $port, $url);
+ }
+ return $url;
+ }
+
+ $host = 'localhost';
+ if (!empty($_SERVER['HTTP_HOST'])) {
+ list($host) = explode(':', $_SERVER['HTTP_HOST']);
+ } elseif (!empty($_SERVER['SERVER_NAME'])) {
+ list($host) = explode(':', $_SERVER['SERVER_NAME']);
+ }
+
+ if (empty($protocol)) {
+ if (isset($_SERVER['HTTPS']) && !strcasecmp($_SERVER['HTTPS'], 'on')) {
+ $protocol = 'https';
+ } else {
+ $protocol = 'http';
+ }
+ if (!isset($port) || $port != intval($port)) {
+ $port = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80;
+ }
+ }
+
+ if ($protocol == 'http' && $port == 80) {
+ unset($port);
+ }
+ if ($protocol == 'https' && $port == 443) {
+ unset($port);
+ }
+
+ $server = $protocol.'://'.$host.(isset($port) ? ':'.$port : '');
+
+ $uriAll = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI']
+ : $_SERVER['PHP_SELF'];
+ if (false !== ($q = strpos($uriAll, '?'))) {
+ $uriBase = substr($uriAll, 0, $q);
+ } else {
+ $uriBase = $uriAll;
+ }
+ if (!strlen($url) || $url{0} == '#') {
+ $url = $uriAll.$url;
+ } elseif ($url{0} == '?') {
+ $url = $uriBase.$url;
+ }
+ if ($url{0} == '/') {
+ return $server . $url;
+ }
+
+ // Adjust for PATH_INFO if needed
+ if (isset($_SERVER['PATH_INFO']) && strlen($_SERVER['PATH_INFO'])) {
+ $path = dirname(substr($uriBase, 0,
+ -strlen($_SERVER['PATH_INFO'])));
+ } else {
+ /**
+ * Fixes bug #12672 PHP_SELF ending on / causes incorrect redirects
+ *
+ * @link http://pear.php.net/bugs/12672
+ */
+ $path = dirname($uriBase.'-');
+ }
+
+ if (substr($path = strtr($path, '\\', '/'), -1) != '/') {
+ $path .= '/';
+ }
+
+ return $server . $path . $url;
+ }
+
+ /**
+ * Raise Error
+ *
+ * Lazy raising of PEAR_Errors.
+ *
+ * @param mixed $error Error
+ * @param integer $code Error code
+ *
+ * @return object PEAR_Error
+ * @static
+ * @access protected
+ */
+ function raiseError($error = null, $code = null)
+ {
+ include_once 'PEAR.php';
+ return PEAR::raiseError($error, $code);
+ }
+}
+
+?>
\ No newline at end of file diff --git a/pear/PEAR.php b/pear/PEAR.php new file mode 100644 index 0000000..362be5a --- /dev/null +++ b/pear/PEAR.php @@ -0,0 +1,1037 @@ +<?php +/** + * PEAR, the PHP Extension and Application Repository + * + * PEAR class and PEAR_Error class + * + * PHP versions 4 and 5 + * + * @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-2010 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: PEAR.php 313023 2011-07-06 19:17:11Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/**#@+ + * ERROR constants + */ +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); +/** + * WARNING: obsolete + * @deprecated + */ +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 +} + +$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; + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.4 + * @link http://pear.php.net/package/PEAR + * @see PEAR_Error + * @since Class available since PHP 4.0.2 + * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear + */ +class PEAR +{ + /** + * Whether to enable internal debug messages. + * + * @var bool + */ + private $_debug = false; + + /** + * Default error mode for this object. + * + * @var int + */ + private $_default_error_mode = null; + + /** + * Default error options used for this object when error mode + * is PEAR_ERROR_TRIGGER. + * + * @var int + */ + private $_default_error_options = null; + + /** + * Default error handler (callback) for this object, if error mode is + * PEAR_ERROR_CALLBACK. + * + * @var string + */ + private $_default_error_handler = ''; + + /** + * Which class to use for error objects. + * + * @var string + */ + private $_error_class = 'PEAR_Error'; + + /** + * An array of expected errors. + * + * @var array + */ + private $_expected_errors = array(); + + /** + * 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. + * @return void + */ + public function PEAR($error_class = null) + { + $classname = strtolower(get_class($this)); + 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)) { + global $_PEAR_destructor_object_list; + $_PEAR_destructor_object_list[] = &$this; + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + break; + } else { + $classname = get_parent_class($classname); + } + } + } + + /** + * 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. + * + * @return void + */ + public function _PEAR() { + if ($this->_debug) { + printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); + } + } + + /** + * 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('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. + */ + public 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]; + } + + /** + * 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 + */ + public static function registerShutdownFunc($func, $args = array()) + { + // if we are called statically, there is a potential + // that no shutdown func is registered. Bug #6445 + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + } + + /** + * 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 + * @return bool true if parameter is an error + */ + public static function isError($data, $code = null) + { + if (!is_a($data, 'PEAR_Error')) { + return false; + } + + 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. + * 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. + * + * @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 + */ + public 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_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (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; + } + } + + /** + * 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 + */ + public function expectError($code = '*') + { + if (is_array($code)) { + array_push($this->_expected_errors, $code); + } else { + array_push($this->_expected_errors, array($code)); + } + return count($this->_expected_errors); + } + + /** + * This method pops one element off the expected error codes + * stack. + * + * @return array the list of error codes that were popped + */ + public function popExpect() + { + return array_pop($this->_expected_errors); + } + + /** + * This method checks unsets an error code if available + * + * @param mixed error code + * @return bool true if the error code was unset, false otherwise + * @since PHP 4.3.0 + */ + private 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 arrays + if (0 == count($this->_expected_errors[$key])) { + unset($this->_expected_errors[$key]); + } + } + + return $deleted; + } + + /** + * 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 + * @since PHP 4.3.0 + */ + public 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) { + $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; + } + + return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } + + // $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 + * 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. + * + * @return object a PEAR error object + * @see PEAR::setErrorHandling + * @since PHP 4.0.5 + */ + public function &raiseError($message = null, + $code = null, + $mode = null, + $options = null, + $userinfo = null, + $error_class = null, + $skipmsg = false) + { + // The error is yet a PEAR error object + if (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) && + 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)) + ) { + $mode = PEAR_ERROR_RETURN; + } + } + + // No mode given, try global ones + if ($mode === null) { + // Class error handler + if (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 (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; + } + + /** + * Simpler form of raiseError with fewer options. In most cases + * message, code and userinfo are enough. + * + * @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. + * + * @return object a PEAR error object + * @see PEAR::raiseError + */ + public 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; + } + + $a = &PEAR::raiseError($message, $code, null, null, $userinfo); + return $a; + } + + public static function staticPushErrorHandling($mode, $options = null) + { + $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); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $def_mode = $mode; + $def_options = $options; + break; + + case PEAR_ERROR_CALLBACK: + $def_mode = $mode; + // class/object method callback + if (is_callable($options)) { + $def_options = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + $stack[] = array($mode, $options); + return true; + } + + public static function staticPopErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (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; + } + return true; + } + + /** + * 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 + */ + public 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; + } + + /** + * Pop the last error handler used + * + * @return bool Always true + * + * @see PEAR::pushErrorHandling + */ + public 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; + } + + /** + * 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 + */ + public function loadExtension($ext) + { + 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; + } + + 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 (PEAR_ZE2) { + include_once 'PEAR5.php'; +} + +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); + 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) { + $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 functions + 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 + * + * This class is supserseded by {@link PEAR_Exception} in PHP 5 + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Gregory Beaver <cellog@php.net> + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.4 + * @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 +{ + var $error_message_prefix = ''; + var $mode = PEAR_ERROR_RETURN; + var $level = E_USER_NOTICE; + var $code = -1; + var $message = ''; + var $userinfo = ''; + var $backtrace = null; + + /** + * 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 + * + */ + 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 (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; + } 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 && 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);'); + } + } + + /** + * Get the error mode from an error object. + * + * @return int error mode + */ + public function getMode() + { + return $this->mode; + } + + /** + * Get the callback function/method from an error object. + * + * @return mixed callback function or object/method array + */ + public function getCallback() + { + return $this->callback; + } + + /** + * Get the error message from an error object. + * + * @return string full error message + */ + public function getMessage() + { + return ($this->error_message_prefix . $this->message); + } + + /** + * Get error code from an error object + * + * @return int error code + */ + public function getCode() + { + return $this->code; + } + + /** + * Get the name of this error/exception. + * + * @return string error/exception name (type) + */ + public function getType() + { + return get_class($this); + } + + /** + * Get additional user-supplied information. + * + * @return string user-supplied information + */ + public function getUserInfo() + { + return $this->userinfo; + } + + /** + * Get additional debug information supplied by the application. + * + * @return string debug information + */ + public function getDebugInfo() + { + return $this->getUserInfo(); + } + + /** + * 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. + */ + public function getBacktrace($frame = null) + { + if (defined('PEAR_IGNORE_BACKTRACE')) { + return null; + } + if ($frame === null) { + return $this->backtrace; + } + return $this->backtrace[$frame]; + } + + public function addUserInfo($info) + { + if (empty($this->userinfo)) { + $this->userinfo = $info; + } else { + $this->userinfo .= " ** $info"; + } + } + + public function __toString() + { + return $this->getMessage(); + } + + /** + * Make a string representation of this object. + * + * @return string a string with an object summary + */ + 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 = (is_object($this->callback[0]) ? + strtolower(get_class($this->callback[0])) : + $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"]', + strtolower(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"]', + strtolower(get_class($this)), $this->message, $this->code, + implode("|", $modes), $levels[$this->level], + $this->error_message_prefix, + $this->userinfo); + } +} + +/* + * Local Variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/pear/PEAR5.php b/pear/PEAR5.php new file mode 100644 index 0000000..4286067 --- /dev/null +++ b/pear/PEAR5.php @@ -0,0 +1,33 @@ +<?php +/** + * This is only meant for PHP 5 to get rid of certain strict warning + * that doesn't get hidden since it's in the shutdown function + */ +class PEAR5 +{ + /** + * If you have a class that's mostly/entirely static, and you need static + * properties, you can use this method to simulate them. Eg. in your method(s) + * do this: $myVar = &PEAR5::getStaticProperty('myclass', 'myVar'); + * You MUST use a reference, or they will not persist! + * + * @access public + * @param string $class The calling classname, to prevent clashes + * @param string $var The variable to retrieve. + * @return mixed A reference to the variable. If not set it will be + * auto initialised to NULL. + */ + static function &getStaticProperty($class, $var) + { + static $properties; + if (!isset($properties[$class])) { + $properties[$class] = array(); + } + + if (!array_key_exists($var, $properties[$class])) { + $properties[$class][$var] = null; + } + + return $properties[$class][$var]; + } +}
\ No newline at end of file diff --git a/pear/System.php b/pear/System.php new file mode 100644 index 0000000..a1900e9 --- /dev/null +++ b/pear/System.php @@ -0,0 +1,607 @@ +<?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 313024 2011-07-06 19:51:24Z 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.4 +* @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 + */ + public static function _parseArgs($argv, $short_options, $long_options = null) + { + if (!is_array($argv) && $argv !== null) { + // Find all items, quoted or otherwise + preg_match_all("/(?:[\"'])(.*?)(?:['\"])|([^\s]+)/", $argv, $av); + $argv = $av[1]; + foreach ($av[2] as $k => $a) { + if (empty($a)) { + continue; + } + $argv[$k] = trim($a) ; + } + } + return Console_Getopt::getopt2($argv, $short_options, $long_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 + */ + public static 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 + */ + public static 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 + * @see System::_dirToStruct() + */ + public static 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 + */ + public static 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 + */ + public static 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 + */ + public static 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() + */ + public static 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 + */ + public static 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 + * + * @return string The temporary directory on the system + */ + public static 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 + * @author Stig Bakken <ssb@php.net> + */ + public static 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 + */ + public 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; + } +} diff --git a/smarty b/smarty deleted file mode 160000 -Subproject 241adf74a6cf0b171809ed07c2c191fcd374a27 diff --git a/uniform b/uniform deleted file mode 160000 -Subproject d0b0747f394dac8b97ceda6541674f792762a2a |
