From 513f136c3469852299afd59fdb6b6baadebcfe21 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Fri, 2 Mar 2018 21:02:59 +0900 Subject: [PATCH 1/9] Isolate user-created template vars (Context::set) from Context instance properties --- classes/context/Context.class.php | 118 +++++++++------------ classes/template/TemplateHandler.class.php | 2 +- 2 files changed, 53 insertions(+), 67 deletions(-) diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index 2bce4d24d..2a378b1ba 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -62,6 +62,12 @@ class Context */ public $oFrontEndFileHandler; + /** + * site's browser title + * @var string + */ + public $browser_title = ''; + /** * script codes in .. * @var string @@ -104,12 +110,6 @@ class Context */ public $canonical_url = ''; - /** - * path of Xpress Engine - * @var string - */ - public $path = ''; - /** * language type - changed by HTTP_USER_AGENT or user's cookie * @var string @@ -122,30 +122,6 @@ class Context */ public $lang = NULL; - /** - * list of loaded languages (to avoid re-loading them) - * @var array - */ - public $loaded_lang_files = array(); - - /** - * site's browser title - * @var string - */ - public $site_title = ''; - - /** - * variables from GET or form submit - * @var mixed - */ - public $get_vars = NULL; - - /** - * variables from user (Context::get, Context::set) - * @var mixed - */ - private static $_user_vars = NULL; - /** * Checks uploaded * @var bool TRUE if attached file exists @@ -198,6 +174,18 @@ class Context */ private static $_instance = null; + /** + * variables from current request + * @var object + */ + private static $_get_vars = NULL; + + /** + * variables from user (Context::get, Context::set) + * @var object + */ + private static $_tpl_vars = NULL; + /** * returns static context object (Singleton). It's to use Context without declaration of an object * @@ -220,8 +208,8 @@ class Context private function __construct() { $this->oFrontEndFileHandler = new FrontEndFileHandler(); - $this->get_vars = new stdClass; - self::$_user_vars = new stdClass; + self::$_get_vars = self::$_get_vars ?: new stdClass; + self::$_tpl_vars = self::$_tpl_vars ?: new stdClass; // include ssl action cache file $this->sslActionCacheFile = FileHandler::getRealPath($this->sslActionCacheFile); @@ -358,11 +346,10 @@ class Context } self::setLangType($this->lang_type); - $this->lang = Rhymix\Framework\Lang::getInstance($this->lang_type); $this->lang->loadDirectory(RX_BASEDIR . 'common/lang', 'common'); $this->lang->loadDirectory(RX_BASEDIR . 'modules/module/lang', 'module'); - $GLOBALS['lang'] = $this->lang; + self::set('lang', $GLOBALS['lang'] = $this->lang); // set session handler if(self::isInstalled() && config('session.use_db')) @@ -375,10 +362,9 @@ class Context } // start session - $relax_key_checks = ($this->act === 'procFileUpload' && preg_match('/shockwave\s?flash/i', $_SERVER['HTTP_USER_AGENT'])); + $relax_key_checks = (self::$_get_vars->act === 'procFileUpload' && preg_match('/shockwave\s?flash/i', $_SERVER['HTTP_USER_AGENT'])); Rhymix\Framework\Session::checkSSO($site_module_info); Rhymix\Framework\Session::start(false, $relax_key_checks); - $this->_COOKIE = $_COOKIE; // start output buffer if (\PHP_SAPI !== 'cli') @@ -405,9 +391,9 @@ class Context // set locations for javascript use $current_url = $request_uri = self::getRequestUri(); - if ($_SERVER['REQUEST_METHOD'] == 'GET' && $this->get_vars) + if ($_SERVER['REQUEST_METHOD'] == 'GET' && self::$_get_vars) { - if ($query_string = http_build_query($this->get_vars)) + if ($query_string = http_build_query(self::$_get_vars)) { $current_url .= '?' . $query_string; } @@ -739,7 +725,7 @@ class Context /** * Append string to browser title * - * @param string $site_title Browser title to be appended + * @param string $title Browser title to be appended * @return void */ public static function addBrowserTitle($title) @@ -748,20 +734,20 @@ class Context { return; } - if(self::$_instance->site_title) + if(self::$_instance->browser_title) { - self::$_instance->site_title .= ' - ' . $title; + self::$_instance->browser_title .= ' - ' . $title; } else { - self::$_instance->site_title = $title; + self::$_instance->browser_title = $title; } } /** * Prepend string to browser title * - * @param string $site_title Browser title to be prepended + * @param string $title Browser title to be prepended * @return void */ public static function prependBrowserTitle($title) @@ -770,20 +756,20 @@ class Context { return; } - if(self::$_instance->site_title) + if(self::$_instance->browser_title) { - self::$_instance->site_title = $title . ' - ' . self::$_instance->site_title; + self::$_instance->browser_title = $title . ' - ' . self::$_instance->browser_title; } else { - self::$_instance->site_title = $title; + self::$_instance->browser_title = $title; } } /** * Set string to browser title * - * @param string $site_title Browser title to be set + * @param string $title Browser title to be set * @param array $vars * @return void */ @@ -799,7 +785,7 @@ class Context return isset($vars[strtolower($matches[1])]) ? $vars[strtolower($matches[1])] : $matches[0]; }, $title), ' -')); } - self::$_instance->site_title = $title; + self::$_instance->browser_title = $title; } /** @@ -809,12 +795,12 @@ class Context */ public static function getBrowserTitle() { - if (!self::$_instance->site_title) + if (!self::$_instance->browser_title) { return ''; } - getController('module')->replaceDefinedLangCode(self::$_instance->site_title); - return htmlspecialchars(self::$_instance->site_title, ENT_COMPAT | ENT_HTML401, 'UTF-8', FALSE); + getController('module')->replaceDefinedLangCode(self::$_instance->browser_title); + return htmlspecialchars(self::$_instance->browser_title, ENT_COMPAT | ENT_HTML401, 'UTF-8', FALSE); } /** @@ -1428,6 +1414,7 @@ class Context } $val['name'] = htmlspecialchars($val['name'], ENT_COMPAT | ENT_HTML401, 'UTF-8', FALSE); self::set($key, $val, TRUE); + self::set('is_uploaded', TRUE); $this->is_uploaded = TRUE; } else @@ -1629,7 +1616,7 @@ class Context } // Get URL parameters. If the first argument is '', reset existing parameters. - if (!self::$_instance->get_vars || strval($args_list[0]) === '') + if (!self::$_get_vars || strval($args_list[0]) === '') { $get_vars = array(); if(is_array($args_list) && strval($args_list[0]) === '') @@ -1639,13 +1626,13 @@ class Context } elseif ($_SERVER['REQUEST_METHOD'] === 'GET') { - $get_vars = get_object_vars(self::$_instance->get_vars); + $get_vars = get_object_vars(self::$_get_vars); } else { $preserve_vars = array('module', 'mid', 'act', 'page', 'document_srl', 'search_target', 'search_keyword'); $preserve_keys = array_combine($preserve_vars, array_fill(0, count($preserve_vars), true)); - $get_vars = array_intersect_key(get_object_vars(self::$_instance->get_vars), $preserve_keys); + $get_vars = array_intersect_key(get_object_vars(self::$_get_vars), $preserve_keys); } // arrange args_list @@ -1830,18 +1817,17 @@ class Context */ public static function set($key, $val, $set_to_get_vars = 0) { - self::$_user_vars->{$key} = $val; - self::$_instance->{$key} = $val; + self::$_tpl_vars->{$key} = $val; - if($set_to_get_vars || isset(self::$_instance->get_vars->{$key})) + if($set_to_get_vars || isset(self::$_get_vars->{$key})) { if($val === NULL || $val === '') { - unset(self::$_instance->get_vars->{$key}); + unset(self::$_get_vars->{$key}); } else { - self::$_instance->get_vars->{$key} = $val; + self::$_get_vars->{$key} = $val; } } } @@ -1854,9 +1840,9 @@ class Context */ public static function get($key) { - if(isset(self::$_user_vars->{$key})) + if(isset(self::$_tpl_vars->{$key})) { - return self::$_user_vars->{$key}; + return self::$_tpl_vars->{$key}; } elseif(isset(self::$_instance->{$key})) { @@ -1883,10 +1869,10 @@ class Context $args_list = func_get_args(); $output = new stdClass; - self::$_user_vars = self::$_user_vars !== null ? self::$_user_vars : new stdClass; + self::$_tpl_vars = self::$_tpl_vars !== null ? self::$_tpl_vars : new stdClass; foreach($args_list as $key) { - $output->{$key} = isset(self::$_user_vars->{$key}) ? self::$_user_vars->{$key} : (isset(self::$_instance->{$key}) ? self::$_instance->{$key} : null); + $output->{$key} = isset(self::$_tpl_vars->{$key}) ? self::$_tpl_vars->{$key} : (isset(self::$_instance->{$key}) ? self::$_instance->{$key} : null); } return $output; } @@ -1898,7 +1884,7 @@ class Context */ public static function getAll() { - return self::$_user_vars !== null ? self::$_user_vars : new stdClass; + return self::$_tpl_vars !== null ? self::$_tpl_vars : new stdClass; } /** @@ -1908,9 +1894,9 @@ class Context */ public static function getRequestVars() { - if(self::$_instance->get_vars) + if(self::$_get_vars) { - return clone(self::$_instance->get_vars); + return clone(self::$_get_vars); } return new stdClass; } diff --git a/classes/template/TemplateHandler.class.php b/classes/template/TemplateHandler.class.php index d30f31791..0d66e535d 100644 --- a/classes/template/TemplateHandler.class.php +++ b/classes/template/TemplateHandler.class.php @@ -344,7 +344,7 @@ class TemplateHandler */ private function _fetch($filename) { - $__Context = Context::getInstance(); + $__Context = Context::getAll(); $__Context->tpl_path = $this->path; $__ob_level_before_fetch = ob_get_level(); From 76aafac4a79a5113a9cebfa4215f004c07b10d1a Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Fri, 2 Mar 2018 21:17:52 +0900 Subject: [PATCH 2/9] Set Context::$_tpl_vars to global $__Context__ --- classes/context/Context.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index 2a378b1ba..19c88fa8b 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -244,7 +244,7 @@ class Context } // Set global variables for backward compatibility. - $GLOBALS['__Context__'] = $this; + $GLOBALS['__Context__'] = &self::$_tpl_vars; // Set information about the current request. $this->setRequestMethod(); From 9d06f6a9e2e676396fa33a772fc73653f5bc76d9 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Sat, 3 Mar 2018 01:44:05 +0900 Subject: [PATCH 3/9] Enable static calling of Context::init() and convert unnecessary instance properties into static properties --- classes/context/Context.class.php | 166 ++++++++++++--------- classes/template/TemplateHandler.class.php | 4 + index.php | 3 +- 3 files changed, 97 insertions(+), 76 deletions(-) diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index 19c88fa8b..d91862208 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -45,19 +45,7 @@ class Context public $ftp_info = NULL; /** - * ssl action cache file - * @var array - */ - public $sslActionCacheFile = './files/cache/sslCacheFile.php'; - - /** - * List of actions to be sent via ssl (it is used by javascript xml handler for ajax) - * @var array - */ - public $ssl_actions = array(); - - /** - * obejct oFrontEndFileHandler() + * object oFrontEndFileHandler() * @var object */ public $oFrontEndFileHandler; @@ -134,22 +122,34 @@ class Context */ public $is_site_locked = FALSE; - /** - * Pattern for request vars check - * @var array - */ - public $patterns = array( - '/<\?/iUsm', - '/<\%/iUsm', - '/sslActionCacheFile = FileHandler::getRealPath($this->sslActionCacheFile); - if(is_readable($this->sslActionCacheFile)) + self::$_ssl_actions_cache_file = FileHandler::getRealPath(self::$_ssl_actions_cache_file); + if(is_readable(self::$_ssl_actions_cache_file)) { - require($this->sslActionCacheFile); + include self::$_ssl_actions_cache_file; if(isset($sslActions)) { - $this->ssl_actions = $sslActions; + self::$_ssl_actions = $sslActions; } } } @@ -226,11 +230,23 @@ class Context /** * Initialization, it sets DB information, request arguments and so on. * - * @see This function should be called only once * @return void */ - public function init() + public static function init() { + // Prevent calling init() twice. + if(self::$_init_called) + { + return; + } + self::$_init_called = true; + + // Obtain a singleton instance if not already given. + if(self::$_instance === null) + { + self::$_instance = self::getInstance(); + } + // Fix missing HTTP_RAW_POST_DATA in PHP 5.6 and above. if(!isset($GLOBALS['HTTP_RAW_POST_DATA']) && !count($_FILES) && version_compare(PHP_VERSION, '5.6.0', '>=') === TRUE) { @@ -243,16 +259,13 @@ class Context } } - // Set global variables for backward compatibility. - $GLOBALS['__Context__'] = &self::$_tpl_vars; - // Set information about the current request. - $this->setRequestMethod(); - $this->_checkGlobalVars(); - $this->_setXmlRpcArgument(); - $this->_setJSONRequestArgument(); - $this->_setRequestArgument(); - $this->_setUploadedArgument(); + self::$_instance->setRequestMethod(); + self::$_instance->_checkGlobalVars(); + self::$_instance->_setXmlRpcArgument(); + self::$_instance->_setJSONRequestArgument(); + self::$_instance->_setRequestArgument(); + self::$_instance->_setUploadedArgument(); // Fabricate methods for compatibility of XE third-party. if(isset($_POST['_rx_ajax_compat']) && $_POST['_rx_ajax_compat'] === 'XMLRPC') @@ -262,7 +275,7 @@ class Context } // Load system configuration. - $this->loadDBInfo(); + self::$_instance->loadDBInfo(); // If Rhymix is installed, get virtual site information. if(self::isInstalled()) @@ -307,16 +320,16 @@ class Context $enabled_langs = self::loadLangSelected(); self::set('lang_supported', $enabled_langs); - if($this->lang_type = self::get('l')) + if($lang_type = self::get('l')) { - if($_COOKIE['lang_type'] !== $this->lang_type) + if($_COOKIE['lang_type'] !== $lang_type) { - setcookie('lang_type', $this->lang_type, $_SERVER['REQUEST_TIME'] + 3600 * 24 * 1000, '/'); + setcookie('lang_type', $lang_type, $_SERVER['REQUEST_TIME'] + 3600 * 24 * 1000, '/'); } } elseif($_COOKIE['lang_type']) { - $this->lang_type = $_COOKIE['lang_type']; + $lang_type = $_COOKIE['lang_type']; } elseif(config('locale.auto_select_lang') && count($enabled_langs) > 1) { @@ -326,30 +339,36 @@ class Context { if(!strncasecmp($lang_code, $_SERVER['HTTP_ACCEPT_LANGUAGE'], strlen($lang_code))) { - $this->lang_type = $lang_code; - setcookie('lang_type', $this->lang_type, $_SERVER['REQUEST_TIME'] + 3600 * 24 * 1000, '/'); + $lang_type = $lang_code; + setcookie('lang_type', $lang_type, $_SERVER['REQUEST_TIME'] + 3600 * 24 * 1000, '/'); } } } } - if(!$this->lang_type || !isset($enabled_langs[$this->lang_type])) + if(!$lang_type || !isset($enabled_langs[$lang_type])) { if($site_module_info->settings->language) { - $this->lang_type = $this->db_info->lang_type = $site_module_info->settings->language; + $lang_type = self::$_instance->db_info->lang_type = $site_module_info->settings->language; } else { - $this->lang_type = $this->db_info->lang_type ?: 'ko'; + $lang_type = self::$_instance->db_info->lang_type ?: 'ko'; } } - self::setLangType($this->lang_type); - $this->lang = Rhymix\Framework\Lang::getInstance($this->lang_type); - $this->lang->loadDirectory(RX_BASEDIR . 'common/lang', 'common'); - $this->lang->loadDirectory(RX_BASEDIR . 'modules/module/lang', 'module'); - self::set('lang', $GLOBALS['lang'] = $this->lang); + $lang = Rhymix\Framework\Lang::getInstance($lang_type); + $lang->loadDirectory(RX_BASEDIR . 'common/lang', 'common'); + $lang->loadDirectory(RX_BASEDIR . 'modules/module/lang', 'module'); + self::setLangType(self::$_instance->lang_type = $lang_type); + self::set('lang', self::$_instance->lang = $lang); + + // Set global variables for backward compatibility. + $GLOBALS['oContext'] = self::$_instance; + $GLOBALS['__Context__'] = &self::$_tpl_vars; + $GLOBALS['_time_zone'] = self::$_instance->db_info->time_zone; + $GLOBALS['lang'] = &$lang; // set session handler if(self::isInstalled() && config('session.use_db')) @@ -504,7 +523,6 @@ class Context // Copy to old format for backward compatibility. self::$_instance->db_info = self::convertDBInfo($config); self::$_instance->allow_rewrite = self::$_instance->db_info->use_rewrite === 'Y'; - $GLOBALS['_time_zone'] = self::$_instance->db_info->time_zone; } /** @@ -1197,7 +1215,7 @@ class Context { if(is_string($val)) { - foreach($this->patterns as $pattern) + foreach(self::$_check_patterns as $pattern) { if(preg_match($pattern, $val)) { @@ -1909,17 +1927,17 @@ class Context */ public static function addSSLAction($action) { - if(!is_readable(self::$_instance->sslActionCacheFile)) + if(!is_readable(self::$_ssl_actions_cache_file)) { $buff = 'sslActionCacheFile, $buff); + FileHandler::writeFile(self::$_ssl_actions_cache_file, $buff); } - if(!isset(self::$_instance->ssl_actions[$action])) + if(!isset(self::$_ssl_actions[$action])) { - self::$_instance->ssl_actions[$action] = 1; + self::$_ssl_actions[$action] = 1; $sslActionCacheString = sprintf('$sslActions[\'%s\'] = 1;', $action); - FileHandler::writeFile(self::$_instance->sslActionCacheFile, $sslActionCacheString, 'a'); + FileHandler::writeFile(self::$_ssl_actions_cache_file, $sslActionCacheString, 'a'); } } @@ -1931,20 +1949,20 @@ class Context */ public static function addSSLActions($action_array) { - if(!is_readable(self::$_instance->sslActionCacheFile)) + if(!is_readable(self::$_ssl_actions_cache_file)) { - unset(self::$_instance->ssl_actions); + self::$_ssl_actions = array(); $buff = 'sslActionCacheFile, $buff); + FileHandler::writeFile(self::$_ssl_actions_cache_file, $buff); } foreach($action_array as $action) { - if(!isset(self::$_instance->ssl_actions[$action])) + if(!isset(self::$_ssl_actions[$action])) { - self::$_instance->ssl_actions[$action] = 1; + self::$_ssl_actions[$action] = 1; $sslActionCacheString = sprintf('$sslActions[\'%s\'] = 1;', $action); - FileHandler::writeFile(self::$_instance->sslActionCacheFile, $sslActionCacheString, 'a'); + FileHandler::writeFile(self::$_ssl_actions_cache_file, $sslActionCacheString, 'a'); } } } @@ -1960,9 +1978,9 @@ class Context if(self::isExistsSSLAction($action)) { $sslActionCacheString = sprintf('$sslActions[\'%s\'] = 1;', $action); - $buff = FileHandler::readFile(self::$_instance->sslActionCacheFile); + $buff = FileHandler::readFile(self::$_ssl_actions_cache_file); $buff = str_replace($sslActionCacheString, '', $buff); - FileHandler::writeFile(self::$_instance->sslActionCacheFile, $buff); + FileHandler::writeFile(self::$_ssl_actions_cache_file, $buff); } } @@ -1975,7 +1993,7 @@ class Context { if(self::getSslStatus() == 'optional') { - return self::$_instance->ssl_actions; + return self::$_ssl_actions; } else { @@ -1991,7 +2009,7 @@ class Context */ public static function isExistsSSLAction($action) { - return isset(self::$_instance->ssl_actions[$action]); + return isset(self::$_ssl_actions[$action]); } /** diff --git a/classes/template/TemplateHandler.class.php b/classes/template/TemplateHandler.class.php index 0d66e535d..afb8bbcea 100644 --- a/classes/template/TemplateHandler.class.php +++ b/classes/template/TemplateHandler.class.php @@ -983,6 +983,10 @@ class TemplateHandler { return '$' . $matches[1]; } + elseif ($matches[1] === 'lang') + { + return '$GLOBALS[\'lang\']'; + } else { return '$__Context->' . $matches[1]; diff --git a/index.php b/index.php index 27aaa6a15..1eedbc214 100644 --- a/index.php +++ b/index.php @@ -43,8 +43,7 @@ require dirname(__FILE__) . '/common/autoload.php'; * @brief Initialize by creating Context object * Set all Request Argument/Environment variables **/ -$oContext = Context::getInstance(); -$oContext->init(); +Context::init(); /** * @brief Initialize and execute Module Handler From e0a762d03afe6970838ccc8f90b51a91b15bc04d Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Sat, 3 Mar 2018 01:57:16 +0900 Subject: [PATCH 4/9] Use $lang as a local variable in template handler --- classes/template/TemplateHandler.class.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/classes/template/TemplateHandler.class.php b/classes/template/TemplateHandler.class.php index afb8bbcea..f66bbabd4 100644 --- a/classes/template/TemplateHandler.class.php +++ b/classes/template/TemplateHandler.class.php @@ -344,22 +344,27 @@ class TemplateHandler */ private function _fetch($filename) { + // Import Context and lang as local variables. $__Context = Context::getAll(); $__Context->tpl_path = $this->path; - + global $lang; + + // Start the output buffer. $__ob_level_before_fetch = ob_get_level(); ob_start(); + // Include the compiled template. include $filename; + // Fetch contents of the output buffer until the buffer level is the same as before. $contents = ''; while (ob_get_level() > $__ob_level_before_fetch) { $contents .= ob_get_clean(); } - // insert template path comment tag - if(config('debug.enabled') && Rhymix\Framework\Debug::isEnabledForCurrentUser()) + // Insert template path comment tag. + if(config('debug.enabled') && Rhymix\Framework\Debug::isEnabledForCurrentUser() && !starts_with('web_path . $this->filename . ' -->' . PHP_EOL; $contents = sprintf($sign, 'start') . $contents . sprintf($sign, 'end'); @@ -979,14 +984,10 @@ class TemplateHandler } return preg_replace_callback('@(?' . $matches[1]; From b2852e19366767477c5ed0e0c882a0fc4a90a247 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Sat, 3 Mar 2018 02:06:19 +0900 Subject: [PATCH 5/9] Clean up SSL action cache file handling --- classes/context/Context.class.php | 53 ++++++++++++++----------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index d91862208..86255622c 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -143,7 +143,7 @@ class Context * SSL action cache file * @var array */ - private static $_ssl_actions_cache_file = './files/cache/sslCacheFile.php'; + private static $_ssl_actions_cache_file = './files/cache/common/ssl_actions.php'; /** * SSL action cache @@ -219,11 +219,7 @@ class Context self::$_ssl_actions_cache_file = FileHandler::getRealPath(self::$_ssl_actions_cache_file); if(is_readable(self::$_ssl_actions_cache_file)) { - include self::$_ssl_actions_cache_file; - if(isset($sslActions)) - { - self::$_ssl_actions = $sslActions; - } + self::$_ssl_actions = (include self::$_ssl_actions_cache_file) ?: array(); } } @@ -1927,18 +1923,14 @@ class Context */ public static function addSSLAction($action) { - if(!is_readable(self::$_ssl_actions_cache_file)) + if(isset(self::$_ssl_actions[$action])) { - $buff = ' Date: Sat, 3 Mar 2018 12:07:13 +0900 Subject: [PATCH 6/9] Fix unit test for $lang in templates --- tests/unit/classes/TemplateHandlerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/classes/TemplateHandlerTest.php b/tests/unit/classes/TemplateHandlerTest.php index 5a01d0389..64353518f 100644 --- a/tests/unit/classes/TemplateHandlerTest.php +++ b/tests/unit/classes/TemplateHandlerTest.php @@ -205,7 +205,7 @@ class TemplateHandlerTest extends \Codeception\TestCase\Test // issue 512 - ignores array( '
{$lang->sl_show_topimgtext}
', - '?>
lang->sl_show_topimgtext ?>
' + '?>
sl_show_topimgtext ?>
' ), // issue 584 array( From 61114c5198c409d0ac84c9e85e5903be43e3c839 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Sat, 3 Mar 2018 12:30:22 +0900 Subject: [PATCH 7/9] Clean up Context::getInstance(), constructor, and oFrontEndFileHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 대부분의 Context 함수가 static으로 바뀌었기 때문에 기존 자료 호환성을 제외하면 instance를 사용할 일은 이제 거의 없음. instance에는 최소한의 속성만 남기고 생성자(__construct)에 있던 기능도 모두 getInstance()로 옮김. --- classes/context/Context.class.php | 78 ++++++++++++++++--------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index 86255622c..df7dee13f 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -20,18 +20,18 @@ class Context */ public $request_method = 'GET'; - /** - * js callback function name. - * @var string - */ - public $js_callback_func = ''; - /** * Response method.If it's not set, it follows request method. * @var string HTML|XMLRPC|JSON|JS_CALLBACK */ public $response_method = ''; + /** + * js callback function name. + * @var string + */ + public $js_callback_func = ''; + /** * DB info * @var object @@ -44,12 +44,6 @@ class Context */ public $ftp_info = NULL; - /** - * object oFrontEndFileHandler() - * @var object - */ - public $oFrontEndFileHandler; - /** * site's browser title * @var string @@ -60,7 +54,7 @@ class Context * script codes in .. * @var string */ - public $html_header = NULL; + public $html_header = ''; /** * class names of @@ -72,13 +66,13 @@ class Context * codes after * @var string */ - public $body_header = NULL; + public $body_header = ''; /** * class names before * @var string */ - public $html_footer = NULL; + public $html_footer = ''; /** * Meta tags @@ -139,11 +133,17 @@ class Context */ private static $_init_called = false; + /** + * object oFrontEndFileHandler() + * @var object + */ + private static $_oFrontEndFileHandler = null; + /** * SSL action cache file * @var array */ - private static $_ssl_actions_cache_file = './files/cache/common/ssl_actions.php'; + private static $_ssl_actions_cache_file = 'files/cache/common/ssl_actions.php'; /** * SSL action cache @@ -191,7 +191,7 @@ class Context private static $_tpl_vars = NULL; /** - * returns static context object (Singleton). It's to use Context without declaration of an object + * Obtain a singleton instance of Context. * * @return object Instance */ @@ -199,7 +199,18 @@ class Context { if(self::$_instance === null) { + // Create a singleton instance and initialize static properties. self::$_instance = new Context(); + self::$_oFrontEndFileHandler = self::$_instance->oFrontEndFileHandler = new FrontEndFileHandler(); + self::$_get_vars = self::$_get_vars ?: new stdClass; + self::$_tpl_vars = self::$_tpl_vars ?: new stdClass; + + // Include SSL action cache file. + self::$_ssl_actions_cache_file = RX_BASEDIR . self::$_ssl_actions_cache_file; + if(Rhymix\Framework\Storage::exists(self::$_ssl_actions_cache_file)) + { + self::$_ssl_actions = (include self::$_ssl_actions_cache_file) ?: array(); + } } return self::$_instance; } @@ -211,16 +222,7 @@ class Context */ private function __construct() { - $this->oFrontEndFileHandler = new FrontEndFileHandler(); - self::$_get_vars = self::$_get_vars ?: new stdClass; - self::$_tpl_vars = self::$_tpl_vars ?: new stdClass; - - // include ssl action cache file - self::$_ssl_actions_cache_file = FileHandler::getRealPath(self::$_ssl_actions_cache_file); - if(is_readable(self::$_ssl_actions_cache_file)) - { - self::$_ssl_actions = (include self::$_ssl_actions_cache_file) ?: array(); - } + } /** @@ -2067,7 +2069,7 @@ class Context */ public static function loadFile($args) { - self::$_instance->oFrontEndFileHandler->loadFile($args); + self::$_oFrontEndFileHandler->loadFile($args); } /** @@ -2080,7 +2082,7 @@ class Context */ public static function unloadFile($file, $targetIe = '', $media = 'all') { - self::$_instance->oFrontEndFileHandler->unloadFile($file, $targetIe, $media); + self::$_oFrontEndFileHandler->unloadFile($file, $targetIe, $media); } /** @@ -2091,7 +2093,7 @@ class Context */ public static function unloadAllFiles($type = 'all') { - self::$_instance->oFrontEndFileHandler->unloadAllFiles($type); + self::$_oFrontEndFileHandler->unloadAllFiles($type); } /** @@ -2124,7 +2126,7 @@ class Context $file = $validator->getJsPath(); } - self::$_instance->oFrontEndFileHandler->loadFile(array($file, $type, $targetie, $index)); + self::$_oFrontEndFileHandler->loadFile(array($file, $type, $targetie, $index)); } /** @@ -2138,7 +2140,7 @@ class Context */ public static function unloadJsFile($file, $optimized = FALSE, $targetie = '') { - self::$_instance->oFrontEndFileHandler->unloadFile($file, $targetie); + self::$_oFrontEndFileHandler->unloadFile($file, $targetie); } /** @@ -2148,7 +2150,7 @@ class Context */ public static function unloadAllJsFiles() { - self::$_instance->oFrontEndFileHandler->unloadAllFiles('js'); + self::$_oFrontEndFileHandler->unloadAllFiles('js'); } /** @@ -2197,7 +2199,7 @@ class Context */ public static function getJsFile($type = 'head', $finalize = false) { - return self::$_instance->oFrontEndFileHandler->getJsFileList($type, $finalize); + return self::$_oFrontEndFileHandler->getJsFileList($type, $finalize); } /** @@ -2214,7 +2216,7 @@ class Context */ public static function addCSSFile($file, $optimized = FALSE, $media = 'all', $targetie = '', $index = 0) { - self::$_instance->oFrontEndFileHandler->loadFile(array($file, $media, $targetie, $index)); + self::$_oFrontEndFileHandler->loadFile(array($file, $media, $targetie, $index)); } /** @@ -2229,7 +2231,7 @@ class Context */ public static function unloadCSSFile($file, $optimized = FALSE, $media = 'all', $targetie = '') { - self::$_instance->oFrontEndFileHandler->unloadFile($file, $targetie, $media); + self::$_oFrontEndFileHandler->unloadFile($file, $targetie, $media); } /** @@ -2239,7 +2241,7 @@ class Context */ public static function unloadAllCSSFiles() { - self::$_instance->oFrontEndFileHandler->unloadAllFiles('css'); + self::$_oFrontEndFileHandler->unloadAllFiles('css'); } /** @@ -2250,7 +2252,7 @@ class Context */ public static function getCSSFile($finalize = false) { - return self::$_instance->oFrontEndFileHandler->getCssFileList($finalize); + return self::$_oFrontEndFileHandler->getCssFileList($finalize); } /** From a1848f5e89048e3b833af738e9ef1725dc9b26c8 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Sun, 4 Mar 2018 00:14:53 +0900 Subject: [PATCH 8/9] Fix more unnecessary non-static method calls --- classes/context/Context.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index df7dee13f..c7b5a7804 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -258,7 +258,7 @@ class Context } // Set information about the current request. - self::$_instance->setRequestMethod(); + self::setRequestMethod(); self::$_instance->_checkGlobalVars(); self::$_instance->_setXmlRpcArgument(); self::$_instance->_setJSONRequestArgument(); @@ -273,7 +273,7 @@ class Context } // Load system configuration. - self::$_instance->loadDBInfo(); + self::loadDBInfo(); // If Rhymix is installed, get virtual site information. if(self::isInstalled()) @@ -1121,7 +1121,7 @@ class Context */ public static function setRequestMethod($type = '') { - self::$_instance->js_callback_func = self::$_instance->getJSCallbackFunc(); + self::$_instance->js_callback_func = self::getJSCallbackFunc(); if ($type) { From ed7ed13bb911376e787aa778146bf071926dd435 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Tue, 6 Mar 2018 20:30:52 +0900 Subject: [PATCH 9/9] Remove and consolidate remainder of non-static methods in Context --- classes/context/Context.class.php | 383 +++++++++++++++--------------- 1 file changed, 191 insertions(+), 192 deletions(-) diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index c7b5a7804..ff37356be 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -245,32 +245,11 @@ class Context self::$_instance = self::getInstance(); } - // Fix missing HTTP_RAW_POST_DATA in PHP 5.6 and above. - if(!isset($GLOBALS['HTTP_RAW_POST_DATA']) && !count($_FILES) && version_compare(PHP_VERSION, '5.6.0', '>=') === TRUE) - { - $GLOBALS['HTTP_RAW_POST_DATA'] = file_get_contents("php://input"); - - // If content is not XML or JSON, unset - if(!preg_match('/^[\<\{\[]/', $GLOBALS['HTTP_RAW_POST_DATA']) && strpos($_SERVER['CONTENT_TYPE'], 'json') === false && strpos($_SERVER['HTTP_CONTENT_TYPE'], 'json') === false) - { - unset($GLOBALS['HTTP_RAW_POST_DATA']); - } - } - // Set information about the current request. + self::_checkGlobalVars(); self::setRequestMethod(); - self::$_instance->_checkGlobalVars(); - self::$_instance->_setXmlRpcArgument(); - self::$_instance->_setJSONRequestArgument(); - self::$_instance->_setRequestArgument(); - self::$_instance->_setUploadedArgument(); - - // Fabricate methods for compatibility of XE third-party. - if(isset($_POST['_rx_ajax_compat']) && $_POST['_rx_ajax_compat'] === 'XMLRPC') - { - self::$_instance->request_method = 'XMLRPC'; - self::$_instance->response_method = 'XMLRPC'; - } + self::setRequestArguments(); + self::setUploadInfo(); // Load system configuration. self::loadDBInfo(); @@ -707,7 +686,7 @@ class Context * * @return bool True : Module handling is necessary in the control path of current request , False : Otherwise */ - public function checkSSO() + public static function checkSSO() { return true; } @@ -863,7 +842,7 @@ class Context * Get browser title * @deprecated */ - public function _getBrowserTitle() + public static function _getBrowserTitle() { return self::getBrowserTitle(); } @@ -1083,6 +1062,19 @@ class Context return Rhymix\Framework\URL::decodeIdna($domain); } + /** + * Check the hostname for invalid characters. + * + * @return void + */ + private static function _checkGlobalVars() + { + if (!self::_recursiveCheckVar($_SERVER['HTTP_HOST']) || preg_match("/[\,\"\'\{\}\[\]\(\);$]/", $_SERVER['HTTP_HOST'])) + { + self::$_instance->isSuccessInit = FALSE; + } + } + /** * Force to set response method * @@ -1113,6 +1105,15 @@ class Context return isset($methods[$method]) ? $method : 'HTML'; } + /** + * Return request method + * @return string Request method type. (Optional - GET|POST|XMLRPC|JSON) + */ + public static function getRequestMethod() + { + return self::$_instance->request_method; + } + /** * Determine request method * @@ -1145,71 +1146,173 @@ class Context } } - /** - * handle global arguments - * - * @return void - */ - private function _checkGlobalVars() - { - $this->_recursiveCheckVar($_SERVER['HTTP_HOST']); - - $pattern = "/[\,\"\'\{\}\[\]\(\);$]/"; - if(preg_match($pattern, $_SERVER['HTTP_HOST'])) - { - $this->isSuccessInit = FALSE; - } - } - /** * handle request arguments for GET/POST * * @return void */ - private function _setRequestArgument() + private static function setRequestArguments() { - if(!count($_REQUEST)) + // Get the request method. + $request_method = self::getRequestMethod(); + + // Fix missing HTTP_RAW_POST_DATA in PHP 5.6 and above. + if($request_method !== 'GET' && !isset($GLOBALS['HTTP_RAW_POST_DATA']) && !count($_FILES) && version_compare(PHP_VERSION, '5.6.0', '>=')) + { + $GLOBALS['HTTP_RAW_POST_DATA'] = file_get_contents("php://input"); + + // If content is not XML or JSON, unset + if(!preg_match('/^[\<\{\[]/', $GLOBALS['HTTP_RAW_POST_DATA']) && strpos($_SERVER['CONTENT_TYPE'], 'json') === false && strpos($_SERVER['HTTP_CONTENT_TYPE'], 'json') === false) + { + unset($GLOBALS['HTTP_RAW_POST_DATA']); + } + } + + // Handle XMLRPC request parameters (Deprecated). + if ($request_method === 'XMLRPC') + { + $xml = $GLOBALS['HTTP_RAW_POST_DATA']; + if(!Rhymix\Framework\Security::checkXEE($xml)) + { + header("HTTP/1.0 400 Bad Request"); + exit; + } + if(function_exists('libxml_disable_entity_loader')) + { + libxml_disable_entity_loader(true); + } + + $oXml = new XmlParser(); + $xml_obj = $oXml->parse($xml); + $params = $xml_obj->methodcall->params; + unset($params->node_name, $params->attrs, $params->body); + if(count(get_object_vars($params))) + { + foreach($params as $key => $val) + { + self::set($key, $this->_filterXmlVars($key, $val), true); + } + } + } + + // Handle JSON request parameters (Deprecated). + if ($request_method === 'JSON' && !count($_POST)) + { + $params = array(); + parse_str($GLOBALS['HTTP_RAW_POST_DATA'], $params); + foreach($params as $key => $val) + { + self::set($key, self::_filterRequestVar($key, $val), true); + } + } + + // Handle regular HTTP request parameters. + if (count($_REQUEST)) + { + foreach($_REQUEST as $key => $val) + { + if($val === '' || isset(self::$_reserved_keys[$key]) || self::get($key)) + { + continue; + } + $key = escape($key); + $val = self::_filterRequestVar($key, $val); + + if($request_method == 'GET' && isset($_GET[$key])) + { + $set_to_vars = true; + } + elseif(($request_method == 'POST' || $request_method == 'JSON') && isset($_POST[$key])) + { + $set_to_vars = true; + } + elseif($request_method == 'JS_CALLBACK' && (isset($_GET[$key]) || isset($_POST[$key]))) + { + $set_to_vars = true; + } + else + { + $set_to_vars = false; + } + + if($set_to_vars) + { + self::_recursiveCheckVar($val); + } + + self::set($key, $val, $set_to_vars); + } + } + + // Pretend that this request is XMLRPC for compatibility with XE third-party. + if(isset($_POST['_rx_ajax_compat']) && $_POST['_rx_ajax_compat'] === 'XMLRPC') + { + self::$_instance->request_method = 'XMLRPC'; + self::$_instance->response_method = 'XMLRPC'; + } + } + + /** + * Handle uploaded file info. + * + * @return void + */ + private static function setUploadInfo() + { + if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !$_FILES) + { + return; + } + if (stripos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') === false && stripos($_SERVER['HTTP_CONTENT_TYPE'], 'multipart/form-data') === false) { return; } - $requestMethod = self::getRequestMethod(); - foreach($_REQUEST as $key => $val) + foreach ($_FILES as $key => $val) { - if($val === '' || isset(self::$_reserved_keys[$key]) || self::get($key)) + $tmp_name = $val['tmp_name']; + if(!is_array($tmp_name)) { - continue; - } - $key = escape($key); - $val = $this->_filterRequestVar($key, $val); - - if($requestMethod == 'GET' && isset($_GET[$key])) - { - $set_to_vars = TRUE; - } - elseif(($requestMethod == 'POST' || $requestMethod == 'JSON') && isset($_POST[$key])) - { - $set_to_vars = TRUE; - } - elseif($requestMethod == 'JS_CALLBACK' && (isset($_GET[$key]) || isset($_POST[$key]))) - { - $set_to_vars = TRUE; + if(!$tmp_name || !is_uploaded_file($tmp_name) || $val['size'] <= 0) + { + continue; + } + $val['name'] = escape($val['name'], false); + self::set($key, $val, true); + self::set('is_uploaded', true); + self::$_instance->is_uploaded = true; } else { - $set_to_vars = FALSE; + $files = array(); + foreach ($tmp_name as $i => $j) + { + if($val['size'][$i] > 0) + { + $file = array(); + $file['name'] = $val['name'][$i]; + $file['type'] = $val['type'][$i]; + $file['tmp_name'] = $val['tmp_name'][$i]; + $file['error'] = $val['error'][$i]; + $file['size'] = $val['size'][$i]; + $files[] = $file; + } + } + if(count($files)) + { + self::set($key, $files, true); + } } - - if($set_to_vars) - { - $this->_recursiveCheckVar($val); - } - - self::set($key, $val, $set_to_vars); } } - private function _recursiveCheckVar($val) + /** + * Check if a value (or array of values) matches a pattern defined in this class. + * + * @param mixed $val Values to check + * @return bool + */ + private static function _recursiveCheckVar($val) { if(is_string($val)) { @@ -1217,8 +1320,8 @@ class Context { if(preg_match($pattern, $val)) { - $this->isSuccessInit = FALSE; - return; + self::$_instance->isSuccessInit = false; + return false; } } } @@ -1226,68 +1329,15 @@ class Context { foreach($val as $val2) { - $this->_recursiveCheckVar($val2); + $result = self::_recursiveCheckVar($val2); + if(!$result) + { + return false; + } } } - } - - /** - * Handle request arguments for JSON - * - * @return void - */ - private function _setJSONRequestArgument() - { - if(count($_POST) || self::getRequestMethod() != 'JSON') - { - return; - } - $params = array(); - parse_str($GLOBALS['HTTP_RAW_POST_DATA'], $params); - foreach($params as $key => $val) - { - self::set($key, $this->_filterRequestVar($key, $val, 1), TRUE); - } - } - - /** - * Handle request arguments for XML RPC - * - * @return void - */ - private function _setXmlRpcArgument() - { - if(self::getRequestMethod() != 'XMLRPC') - { - return; - } - - $xml = $GLOBALS['HTTP_RAW_POST_DATA']; - if(!Rhymix\Framework\Security::checkXEE($xml)) - { - header("HTTP/1.0 400 Bad Request"); - exit; - } - if(function_exists('libxml_disable_entity_loader')) - { - libxml_disable_entity_loader(true); - } - - $oXml = new XmlParser(); - $xml_obj = $oXml->parse($xml); - - $params = $xml_obj->methodcall->params; - unset($params->node_name, $params->attrs, $params->body); - - if(!count(get_object_vars($params))) - { - return; - } - - foreach($params as $key => $val) - { - self::set($key, $this->_filterXmlVars($key, $val), TRUE); - } + + return true; } /** @@ -1297,14 +1347,14 @@ class Context * @param object $val Variable value * @return mixed filtered value */ - private function _filterXmlVars($key, $val) + private static function _filterXmlVars($key, $val) { if(is_array($val)) { $stack = array(); foreach($val as $k => $v) { - $stack[$k] = $this->_filterXmlVars($k, $v); + $stack[$k] = self::_filterXmlVars($k, $v); } return $stack; @@ -1314,13 +1364,13 @@ class Context unset($val->node_name, $val->attrs, $val->body); if(!count(get_object_vars($val))) { - return $this->_filterRequestVar($key, $body, 0); + return self::_filterRequestVar($key, $body, 0); } $stack = new stdClass; foreach($val as $k => $v) { - $output = $this->_filterXmlVars($k, $v); + $output = self::_filterXmlVars($k, $v); if(is_object($v) && $v->attrs->type == 'array') { $output = array($output); @@ -1349,7 +1399,7 @@ class Context * @param string $val Variable value * @return mixed filtered value. Type are string or array */ - public function _filterRequestVar($key, $val) + private static function _filterRequestVar($key, $val) { if(!($isArray = is_array($val))) { @@ -1412,51 +1462,9 @@ class Context * * @return void */ - public function _setUploadedArgument() + public static function _setUploadedArgument() { - if($_SERVER['REQUEST_METHOD'] != 'POST' || !$_FILES || (stripos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') === FALSE && stripos($_SERVER['HTTP_CONTENT_TYPE'], 'multipart/form-data') === FALSE)) - { - return; - } - - foreach($_FILES as $key => $val) - { - $tmp_name = $val['tmp_name']; - if(!is_array($tmp_name)) - { - if(!$tmp_name || !is_uploaded_file($tmp_name)) - { - continue; - } - $val['name'] = htmlspecialchars($val['name'], ENT_COMPAT | ENT_HTML401, 'UTF-8', FALSE); - self::set($key, $val, TRUE); - self::set('is_uploaded', TRUE); - $this->is_uploaded = TRUE; - } - else - { - $files = array(); - $count_files = count($tmp_name); - - for($i = 0; $i < $count_files; $i++) - { - if($val['size'][$i] > 0) - { - $file = array(); - $file['name'] = $val['name'][$i]; - $file['type'] = $val['type'][$i]; - $file['tmp_name'] = $val['tmp_name'][$i]; - $file['error'] = $val['error'][$i]; - $file['size'] = $val['size'][$i]; - $files[] = $file; - } - } - if(count($files)) - { - self::set($key, $files, true); - } - } - } + self::setUploadInfo(); } /** @@ -1543,15 +1551,6 @@ class Context $oModuleHandler = new ModuleHandler; $oModuleHandler->displayContent($oMessageObject); } - - /** - * Return request method - * @return string Request method type. (Optional - GET|POST|XMLRPC|JSON) - */ - public static function getRequestMethod() - { - return self::$_instance->request_method; - } /** * Return request URL