diff --git a/e107_handlers/e107_class.php b/e107_handlers/e107_class.php index 4730d1fe9..010de8036 100644 --- a/e107_handlers/e107_class.php +++ b/e107_handlers/e107_class.php @@ -49,7 +49,8 @@ class e107 public $_ip_cache; public $_host_name_cache; - public $site_theme; + public $site_theme; // class2 -> check valid theme + public $http_theme_dir; // class2 -> check valid theme /** * Contains reference to global $_E107 array @@ -144,6 +145,7 @@ class e107 'e107_user_extended' => '{e_HANDLER}user_extended_class.php', 'e107plugin' => '{e_HANDLER}plugin_class.php', 'eURL' => '{e_HANDLER}e107Url.php', + 'e_core_session' => '{e_HANDLER}session_handler.php', 'e_admin_controller' => '{e_HANDLER}admin_ui.php', 'e_admin_controller_ui' => '{e_HANDLER}admin_ui.php', 'e_admin_dispatcher' => '{e_HANDLER}admin_ui.php', @@ -162,6 +164,7 @@ class e107 'e_model' => '{e_HANDLER}model_class.php', 'e_news_item' => '{e_HANDLER}news_class.php', 'e_news_tree' => '{e_HANDLER}news_class.php', + 'e_object' => '{e_HANDLER}model_class.php', 'e_online' => '{e_HANDLER}online_class.php', 'e_parse' => '{e_HANDLER}e_parse_class.php', 'e_parse_shortcode' => '{e_HANDLER}shortcode_handler.php', @@ -174,7 +177,7 @@ class e107 'e_user_extended_structure_tree' => '{e_HANDLER}user_model.php', 'e_userperms' => '{e_HANDLER}user_handler.php', 'e_validator' => '{e_HANDLER}validator_class.php', - 'e_vars' => '{e_HANDLER}e_parse_class.php', + 'e_vars' => '{e_HANDLER}model_class.php', 'ecache' => '{e_HANDLER}cache_handler.php', 'news' => '{e_HANDLER}news_class.php', 'notify' => '{e_HANDLER}notify_class.php', @@ -247,7 +250,37 @@ class e107 */ public function initCore($e107_paths, $e107_root_path, $e107_config_mysql_info, $e107_config_override = array()) { - return $this->_init($e107_paths, $e107_root_path, $e107_config_mysql_info, $e107_config_override = array()); + return $this->_init($e107_paths, $e107_root_path, $e107_config_mysql_info, $e107_config_override); + } + + /** + * Initialize environment path constants while installing e107 + * + * @return e107 + */ + public function initInstall($e107_paths, $e107_root_path, $e107_config_override = array()) + { + // Do some security checks/cleanup, prepare the environment + $this->prepare_request(); + + // folder info + //$this->e107_dirs = $e107_paths; + $this->setDirs($e107_paths, $e107_config_override); + + // build all paths + $this->set_paths(); + $this->file_path = $this->fix_windows_paths($e107_root_path)."/"; + + // set base path, SSL is auto-detected + $this->set_base_path(); + + // cleanup QUERY_STRING and friends, set related constants + $this->set_request(); + + // set some core URLs (e_LOGIN/SIGNUP) + $this->set_urls(); + + return $this; } /** @@ -279,13 +312,11 @@ class e107 // set base path, SSL is auto-detected $this->set_base_path(); - // set some core URLs (e_LOGIN/SIGNUP) - $this->set_urls(); - // cleanup QUERY_STRING and friends, set related constants - $this->set_request(); + // set some core URLs (e_LOGIN/SIGNUP) + $this->set_urls(); } return $this; @@ -310,7 +341,9 @@ class e107 */ public function setDirs($e107_dirs, $e107_config_override = array()) { - $this->e107_dirs = array_merge($this->defaultDirs($e107_dirs), (array) $e107_dirs, (array) $e107_config_override); + $override = array_merge((array) $e107_dirs, (array) $e107_config_override); + // override all + $this->e107_dirs = array_merge($this->defaultDirs($override), $override); return $this; } @@ -336,7 +369,7 @@ class e107 'SYSTEM_DIRECTORY' => 'e107_system/', 'CORE_DIRECTORY' => 'e107_core/', 'WEB_DIRECTORY' => 'e107_web/', - ), $override_root); + ), (array) $override_root); if($return_root) return $ret; @@ -367,36 +400,6 @@ class e107 return $ret; } - /** - * Initialize environment path constants while installing e107 - * - * @return e107 - */ - public function initInstall($e107_paths, $e107_root_path, $e107_config_override = array()) - { - // Do some security checks/cleanup, prepare the environment - $this->prepare_request(); - - // folder info - //$this->e107_dirs = $e107_paths; - $this->setDirs($e107_paths, $e107_config_override); - - // build all paths - $this->set_paths(); - $this->file_path = $this->fix_windows_paths($e107_root_path)."/"; - - // set base path, SSL is auto-detected - $this->set_base_path(); - - // set some core URLs (e_LOGIN/SIGNUP) - $this->set_urls(); - - // cleanup QUERY_STRING and friends, set related constants - $this->set_request(); - - return $this; - } - /** * Set mysql data * @@ -484,7 +487,8 @@ class e107 function getFolder($for) { $key = strtoupper($for).'_DIRECTORY'; - return (isset($this->e107_dirs[$key]) ? $this->e107_dirs[$key] : ''); + $self = self::getInstance(); + return (isset($self->e107_dirs[$key]) ? $self->e107_dirs[$key] : ''); } /** @@ -744,12 +748,12 @@ class e107 * @param string $name core|core_backup|emote|menu|search|notify|ipool * @return e_core_pref */ - public static function getConfig($name = 'core') + public static function getConfig($name = 'core', $load = true) { if(!isset(self::$_core_config_arr[$name])) { e107_require_once(e_HANDLER.'pref_class.php'); - self::$_core_config_arr[$name] = new e_core_pref($name, true); + self::$_core_config_arr[$name] = new e_core_pref($name, $load); } return self::$_core_config_arr[$name]; @@ -949,11 +953,28 @@ class e107 * * @return UserHandler */ - public static function getSession() + public static function getUserSession() { return self::getSingleton('UserHandler', true); } + /** + * Retrieve core session singleton object(s) + * + * @return e_core_session + */ + public static function getSession($namespace = null) + { + $id = 'core/e107/session/'.(null === $namespace ? 'e107' : $namespace); + if(self::getRegistry($id)) + { + return self::getRegistry($id); + } + $session = self::getObject('e_core_session', array('namespace' => $namespace), true); + self::setRegistry($id, $session); + return $session; + } + /** * Retrieve redirection singleton object * @@ -967,7 +988,7 @@ class e107 /** * Retrieve sitelinks singleton object * - * @return user_class + * @return sitelinks */ public static function getSitelinks() { @@ -1095,7 +1116,7 @@ class e107 { return self::getSingleton('notify', true); } - + /** * Retrieve Language handler singleton object * @@ -1200,7 +1221,7 @@ class e107 /** * Retrieve online users handler singleton object - * @return e_online + * @return e_ranks */ public static function getRank() { @@ -1687,6 +1708,76 @@ class e107 return (isset($ret)) ? $ret : ""; } + /** + * Simplify importing of core Language files. + * All inputs are sanitized. + * Core Exceptions as e_LANGUAGE.'.php' and e_LANGUAGE.'_custom.php' are manually loaded. (see class2.php) + * + * Examples: + * + * e107::coreLan('comment'); + * + * // import defeinitions from /e107_languages/[CurrentLanguage]/admin/lan_banlist.php + * e107::coreLan('banlist', true); + * + * + * @param string $fname filename without the extension part (e.g. 'comment') + * @param boolean $admin true if it's an administration language file + * @return void + */ + public static function coreLan($fname, $admin = false) + { + $cstring = 'corelan/'.e_LANGUAGE.'_'.$fname.($admin ? '_admin' : '_front'); + if(e107::getRegistry($cstring)) return; + + $fname = ($admin ? 'admin/' : '').'lan_'.preg_replace('/[^\w]/', '', $fname).'.php'; + $path = e_LANGUAGEDIR.e_LANGUAGE.'/'.$fname; + + e107::setRegistry($cstring, true); + self::includeLan($path, false); + } + + /** + * Simplify importing of plugin Language files (following e107 plugin structure standards). + * All inputs are sanitized. + * + * Examples: + * + * e107::plugLan('forum', 'lan_forum'); + * + * // import defeinitions from /e107_plugins/featurebox/languages/[CurrentLanguage]_admin_featurebox.php + * e107::plugLan('featurebox', 'admin_featurebox', true); + * + * // import defeinitions from /e107_plugins/myplug/languages/[CurrentLanguage].php + * e107::plugLan('myplug'); + * + * // import defeinitions from /e107_plugins/myplug/languages/[CurrentLanguage].php + * e107::plugLan('myplug', 'admin/common'); + * + * + * @param string $plugin plugin name + * @param string $fname filename without the extension part (e.g. 'common') + * @param boolean $flat false (default, preferred) Language folder structure; true - prepend Language to file name + * @return void + */ + public static function plugLan($plugin, $fname = '', $flat = false) + { + $cstring = 'pluglan/'.e_LANGUAGE.'_'.$plugin.'_'.$fname.($flat ? '_1' : '_0'); + if(e107::getRegistry($cstring)) return; + + $plugin = preg_replace('/[^\w]/', '', $plugin); + + if($fname) $fname = e_LANGUAGE.($flat ? '_' : '/').preg_replace('#[^\w/]#', '', $fname); + else $fname = e_LANGUAGE; + + $path = e_PLUGIN.$plugin.'/languages/'.$fname.'.php'; + + e107::setRegistry($cstring, true); + self::includeLan($path, false); + } + /** * Routine looks in standard paths for language files associated with a plugin or * theme - primarily for core routines, which won't know for sure where the author has put them. @@ -1759,10 +1850,19 @@ class e107 /** * Prepare e107 environment * This is done before e107_dirs initilization and [TODO] config include + * @param bool $checkS basic security check (0.7 like), will be extended in the future * @return e107 */ - public function prepare_request() + public function prepare_request($checkS = true) { + + // Block common bad agents / queries / php issues. + array_walk($_SERVER, array('self', 'filter_request'), '_SERVER'); + if (isset($_GET)) array_walk($_GET, array('self', 'filter_request'), '_GET'); + if (isset($_POST)) array_walk($_POST, array('self', 'filter_request'), '_POST'); + if (isset($_COOKIE)) array_walk($_COOKIE, array('self', 'filter_request'), '_COOKIE'); + if (isset($_REQUEST)) array_walk($_REQUEST, array('self', 'filter_request'), '_REQUEST'); + // TODO - better ajax detection method (headers when possible) define('e_AJAX_REQUEST', isset($_REQUEST['ajax_used'])); unset($_REQUEST['ajax_used']); // removed because it's auto-appended from JS (AJAX), could break something... @@ -1792,6 +1892,7 @@ class e107 // remove ajax_used=1 from query string to avoid SELF problems, ajax should always be detected via e_AJAX_REQUEST constant $_SERVER['QUERY_STRING'] = trim(str_replace(array('ajax_used=1', '&&'), array('', '&'), $_SERVER['QUERY_STRING']), '&'); + /* PathInfo doesn't break anything, URLs should be always absolute. Disabling the below forever. // e107 uses relative url's, which are broken by "pretty" URL's. So for now we don't support / after .php if(($pos = strpos($_SERVER['PHP_SELF'], '.php/')) !== false) // redirect bad URLs to the correct one. { @@ -1800,8 +1901,10 @@ class e107 header('Location: '.$new_loc); exit(); } + */ + // If url contains a .php in it, PHP_SELF is set wrong (imho), affecting all paths. We need to 'fix' it if it does. - $_SERVER['PHP_SELF'] = (($pos = strpos($_SERVER['PHP_SELF'], '.php')) !== false ? substr($_SERVER['PHP_SELF'], 0, $pos+4) : $_SERVER['PHP_SELF']); + $_SERVER['PHP_SELF'] = (($pos = stripos($_SERVER['PHP_SELF'], '.php')) !== false ? substr($_SERVER['PHP_SELF'], 0, $pos+4) : $_SERVER['PHP_SELF']); // setup some php options e107::ini_set('magic_quotes_runtime', 0); @@ -1816,13 +1919,48 @@ class e107 { array_unshift($inc_path, '.'); $inc_path = implode(PATH_SEPARATOR, $inc_path); - e107_ini_set('include_path', $inc_path); + e107::ini_set('include_path', $inc_path); } unset($inc_path); return $this; } + /** + * Filter User Input - used by array_walk in prepare_request method above. + * @param string $input array value + * @param string $key array key + * @param string $type array type _SESSION, _GET etc. + * @return + */ + public static function filter_request($input,$key,$type) + { + if (is_array($input)) + { + return array_walk($input, array('self', 'filter_request'), $type); + } + + if($type == "_SERVER") + { + if(($key == "QUERY_STRING") && strpos(strtolower($input),"=http")!==FALSE) + { + exit(); + } + + if(($key == "HTTP_USER_AGENT") && strpos($input,"libwww-perl")!==FALSE) + { + exit(); + } + } + + if(strpos(str_replace('.', '', $input), '22250738585072011') !== FALSE) // php-bug 53632 + { + exit(); + } + } + + + /** * Set base system path * @return e107 @@ -2088,24 +2226,87 @@ class e107 * 3. any plugin file in a folder called admin/ * 4. any file that specifies $eplug_admin = TRUE; or ADMIN_AREA = TRUE; * NOTE: USER_AREA = true; will force e_ADMIN_AREA to FALSE + * + * @param boolean $no_cbrace remove curly brackets from the url * @return e107 */ - public function set_urls() + public function set_urls($no_cbrace = true) { //global $PLUGINS_DIRECTORY,$ADMIN_DIRECTORY, $eplug_admin; $PLUGINS_DIRECTORY = $this->getFolder('plugins'); $ADMIN_DIRECTORY = $this->getFolder('admin'); + + // Outdated + /*$requestQry = ''; + $requestUrl = $_SERVER['REQUEST_URI']; + if(strpos($_SERVER['REQUEST_URI'], '?') !== FALSE) + list($requestUrl, $requestQry) = explode("?", $_SERVER['REQUEST_URI'], 2); */ + $eplug_admin = vartrue($GLOBALS['eplug_admin'], false); $page = substr(strrchr($_SERVER['PHP_SELF'], '/'), 1); - define('e_PAGE', $page); - define('e_SELF', $this->HTTP_SCHEME . '://' . $_SERVER['HTTP_HOST'] . ($_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_FILENAME'])); - define('e_SIGNUP', e_BASE.(file_exists(e_BASE.'customsignup.php') ? 'customsignup.php' : 'signup.php')); - define('e_LOGIN', e_BASE.(file_exists(e_BASE.'customlogin.php') ? 'customlogin.php' : 'login.php')); + // Leave e_SELF BC, use e_REQUEST_SELF instead + /*// moved after page check - e_PAGE is important for BC + if($requestUrl && $requestUrl != $_SERVER['PHP_SELF']) + { + $_SERVER['PHP_SELF'] = $requestUrl; + }*/ + $eSelf = $_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_FILENAME']; + define('e_SELF', $this->HTTP_SCHEME.'://'.$_SERVER['HTTP_HOST'].$eSelf); + // START New - request uri/url detection, XSS protection + $requestUri = $requestUrl = ''; + if (isset($_SERVER['HTTP_X_REWRITE_URL'])) + { + // check this first so IIS will catch + $requestUri = $_SERVER['HTTP_X_REWRITE_URL']; + $requestUrl = $this->HTTP_SCHEME.'://'.$_SERVER['HTTP_HOST'].$requestUri; + // fix request uri + $_SERVER['REQUEST_URI'] = $requestUri; + } + elseif (isset($_SERVER['REQUEST_URI'])) + { + $requestUri = $_SERVER['REQUEST_URI']; + $requestUrl = $this->HTTP_SCHEME.'://'.$_SERVER['HTTP_HOST'].$requestUri; + } + else + { + // go back to e_SELF + $requestUri = $eSelf; + $requestUrl = e_SELF; + if (e_QUERY) + { + $requestUri .= '?'.e_QUERY; + $requestUrl .= '?'.e_QUERY; + } + } + // FIXME - basic security - add url sanitize method to e_parse + $check = rawurldecode($requestUri); // urlencoded by default + // a bit aggressive XSS protection... convert to e.g. htmlentities if you are not a bad guy + $checkregx = $no_cbrace ? '[<>\{\}]' : '[<>]'; + if(preg_match('/'.$checkregx.'/', $check)) + { + header('HTTP/1.1 403 Forbidden'); + exit; + } + + // e_MENU fix + if(e_MENU) + { + str_replace('['.e_MENU.']', '', $requestUri); + str_replace('['.e_MENU.']', '', $requestUrl); + } + + // the last anti-XSS measure, XHTML compliant URL to be used in forms instead e_SELF + define('e_REQUEST_URL', str_replace(array("'", '"'), array('%27', '%22'), $requestUrl)); // full request url string (including domain) + define('e_REQUEST_SELF', array_shift(explode('?', e_REQUEST_URL))); // full URL without the QUERY string + define('e_REQUEST_URI', str_replace(array("'", '"'), array('%27', '%22'), $requestUri)); // absolute http path + query string + define('e_REQUEST_HTTP', array_shift(explode('?', e_REQUEST_URI))); // SELF URL without the QUERY string and leading domain part + unset($requestUrl, $requestUri); + // END request uri/url detection, XSS protection // e_SELF has the full HTML path $inAdminDir = FALSE; @@ -2143,14 +2344,19 @@ class e107 define('SITEURLBASE', $this->HTTP_SCHEME.'://'.$_SERVER['HTTP_HOST']); define('SITEURL', SITEURLBASE.e_HTTP); + // login/signup + define('e_SIGNUP', SITEURL.(file_exists(e_BASE.'customsignup.php') ? 'customsignup.php' : 'signup.php')); + define('e_LOGIN', SITEURL.(file_exists(e_BASE.'customlogin.php') ? 'customlogin.php' : 'login.php')); + return $this; } /** * Set request related constants + * @param boolean $no_cbrace remove curly brackets from the url * @return e107 */ - public function set_request() + public function set_request($no_cbrace = true) { $inArray = array("'", ';', '/**/', '/UNION/', '/SELECT/', 'AS '); @@ -2165,7 +2371,7 @@ class e107 } } - if (strpos($_SERVER['QUERY_STRING'], ']') && preg_match("#\[(.*?)](.*)#", $_SERVER['QUERY_STRING'], $matches)) + if (strpos($_SERVER['QUERY_STRING'], ']') && preg_match('#\[(.*?)](.*)#', $_SERVER['QUERY_STRING'], $matches)) { define('e_MENU', $matches[1]); $e_QUERY = $matches[2]; @@ -2176,6 +2382,7 @@ class e107 $e_QUERY = $_SERVER['QUERY_STRING']; } + if ($no_cbrace) $e_QUERY = str_replace(array('{', '}', '%7B', '%7b', '%7D', '%7d'), '', rawurldecode($e_QUERY)); $e_QUERY = str_replace("&","&", self::getParser()->post_toForm($e_QUERY)); define('e_QUERY', $e_QUERY); @@ -2358,29 +2565,23 @@ class e107 { if(!$this->_ip_cache) { - if(getenv('HTTP_X_FORWARDED_FOR')) + $ip=$_SERVER['REMOTE_ADDR']; + if (getenv('HTTP_X_FORWARDED_FOR')) { - $ip = $_SERVER['REMOTE_ADDR']; - $ip3 = array(); - if(preg_match('/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/', getenv('HTTP_X_FORWARDED_FOR'), $ip3)) + if (preg_match('/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/', getenv('HTTP_X_FORWARDED_FOR'), $ip3)) { - $ip2 = array( - '#^0\..*#' , '#^127\..*#' , // Local loopbacks - '#^192\.168\..*#' , // RFC1918 - Private Network - '#^172\.(?:1[6789]|2\d|3[01])\..*#' , // RFC1918 - Private network - '#^10\..*#' , // RFC1918 - Private Network - '#^169\.254\..*#' , // RFC3330 - Link-local, auto-DHCP - '#^2(?:2[456789]|[345][0-9])\..*#' - ); // Single check for Class D and Class E - - $ip = preg_replace($ip2, $ip, $ip3[1]); + $ip2 = array('#^0\..*#', + '#^127\..*#', // Local loopbacks + '#^192\.168\..*#', // RFC1918 - Private Network + '#^172\.(?:1[6789]|2\d|3[01])\..*#', // RFC1918 - Private network + '#^10\..*#', // RFC1918 - Private Network + '#^169\.254\..*#', // RFC3330 - Link-local, auto-DHCP + '#^2(?:2[456789]|[345][0-9])\..*#' // Single check for Class D and Class E + ); + $ip = preg_replace($ip2, $ip3[1], $ip); } } - else - { - $ip = $_SERVER['REMOTE_ADDR']; - } - if($ip == "") + if ($ip == "") { $ip = "x.x.x.x"; }