*/ class HTMLDisplayHandler { /** * Reserved scripts */ public static $reservedCSS = '@\bcommon/css/(?:xe|mobile)\.(?:min\.)?css$@'; public static $reservedJS = '@\bcommon/js/(?:jquery(?:-[123][0-9.x-]+)?|xe?|common|js_app|xml_handler|xml_js_filter)\.(?:min\.)?js$@'; /** * Replacement table for XE compatibility */ public static $replacements = array( '@\bcommon/xeicon/@' => 'common/css/xeicon/', ); /** * Produce HTML compliant content given a module object.\n * @param ModuleObject $oModule the module object * @return string compiled template string */ function toDoc(&$oModule) { $oTemplate = TemplateHandler::getInstance(); // compile module tpl // deprecated themes skin $template_path = $oModule->getTemplatePath(); if(!is_dir($template_path)) { if($oModule->module_info->module == $oModule->module) { $skin = $oModule->origin_module_info->skin; } else { $skin = $oModule->module_config->skin; } if(Context::get('module') != 'admin' && strpos(Context::get('act'), 'Admin') === false) { if($skin && is_string($skin)) { $theme_skin = explode('|@|', $skin); $template_path = $oModule->getTemplatePath(); if(count($theme_skin) == 2) { $theme_path = sprintf('./themes/%s', $theme_skin[0]); // FIXME $theme_path $theme_path $theme_path ?? if(substr($theme_path, 0, strlen($theme_path)) != $theme_path) { $template_path = sprintf('%s/modules/%s/', $theme_path, $theme_skin[1]); } } } else { $template_path = $oModule->getTemplatePath(); } } else { $template_path = $oModule->getTemplatePath(); } } $tpl_file = $oModule->getTemplateFile(); $output = $oTemplate->compile($template_path, $tpl_file); // SECISSUE https://github.com/xpressengine/xe-core/issues/1583 $oSecurity = new Security(); $oSecurity->encodeHTML('is_keyword'); // add .x div for adminitration pages if(Context::getResponseMethod() == 'HTML') { if(Context::get('module') != 'admin' && strpos(Context::get('act'), 'Admin') > 0 && Context::get('act') != 'dispPageAdminContentModify' && Context::get('act') != 'dispPageAdminMobileContentModify') { $output = '
' . $output . '
'; } if(Context::get('layout') != 'none') { if(__DEBUG__ == 3) { $start = microtime(true); } Context::set('content', $output, false); $layout_path = $oModule->getLayoutPath(); $layout_file = $oModule->getLayoutFile(); $edited_layout_file = $oModule->getEditedLayoutFile(); // get the layout information currently requested $oLayoutModel = getModel('layout'); $layout_info = Context::get('layout_info'); $layout_srl = $layout_info->layout_srl; // compile if connected to the layout if($layout_srl > 0) { // handle separately if the layout is faceoff if($layout_info && $layout_info->type == 'faceoff') { $oLayoutModel->doActivateFaceOff($layout_info); Context::set('layout_info', $layout_info); } // search if the changes CSS exists in the admin layout edit window $edited_layout_css = $oLayoutModel->getUserLayoutCss($layout_srl); if(FileHandler::exists($edited_layout_css)) { Context::loadFile(array($edited_layout_css, 'all', '', 100)); } } if(!$layout_path) { $layout_path = './common/tpl'; } if(!$layout_file) { $layout_file = 'default_layout'; } $output = $oTemplate->compile($layout_path, $layout_file, $edited_layout_file); // if popup_layout, remove admin bar. $realLayoutPath = FileHandler::getRealPath($layout_path); if(substr_compare($realLayoutPath, '/', -1) !== 0) { $realLayoutPath .= '/'; } $pathInfo = pathinfo($layout_file); $onlyLayoutFile = $pathInfo['filename']; if(__DEBUG__ == 3) { $GLOBALS['__layout_compile_elapsed__'] = microtime(true) - $start; } if(stripos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE && (Context::get('_use_ssl') == 'optional' || Context::get('_use_ssl') == 'always')) { Context::addHtmlFooter(''); } } } return $output; } /** * when display mode is HTML, prepare code before print. * @param string $output compiled template string * @return void */ function prepareToPrint(&$output) { if(Context::getResponseMethod() != 'HTML') { return; } if(__DEBUG__ == 3) { $start = microtime(true); } // move in body to the header $output = preg_replace_callback('!(.*?)<\/style>!is', array($this, '_moveStyleToHeader'), $output); // move in body to the header $output = preg_replace_callback('!!is', array($this, '_moveLinkToHeader'), $output); // move in body to the header $output = preg_replace_callback('!!is', array($this, '_moveMetaToHeader'), $output); // change a meta fine(widget often put the tag like to the content because of caching) $output = preg_replace_callback('//is', array($this, '_transMeta'), $output); // handles a relative path generated by using the rewrite module if(Context::isAllowRewrite()) { $url = parse_url(Context::getRequestUri()); $real_path = $url['path']; $pattern = '/src=("|\'){1}(\.\/)?(files\/attach|files\/cache|files\/faceOff|files\/member_extra_info|modules|common|widgets|widgetstyle|layouts|addons)\/([^"\']+)\.(jpg|jpeg|png|gif)("|\'){1}/s'; $output = preg_replace($pattern, 'src=$1' . $real_path . '$3/$4.$5$6', $output); $pattern = '/href=("|\'){1}(\?[^"\']+)/s'; $output = preg_replace($pattern, 'href=$1' . $real_path . '$2', $output); if(Context::get('vid')) { $pattern = '/\/' . Context::get('vid') . '\?([^=]+)=/is'; $output = preg_replace($pattern, '/?$1=', $output); } } // prevent the 2nd request due to url(none) of the background-image $output = preg_replace('/url\((["\']?)none(["\']?)\)/is', 'none', $output); if(is_array(Context::get('INPUT_ERROR'))) { $INPUT_ERROR = Context::get('INPUT_ERROR'); $keys = array_keys($INPUT_ERROR); $keys = '(' . implode('|', $keys) . ')'; $output = preg_replace_callback('@(]*?)\sname="' . $keys . '"([^>]*?)/?>@is', array(&$this, '_preserveValue'), $output); $output = preg_replace_callback('@]*\sname="' . $keys . '".+@isU', array(&$this, '_preserveSelectValue'), $output); $output = preg_replace_callback('@]*\sname="' . $keys . '".+@isU', array(&$this, '_preserveTextAreaValue'), $output); } if(__DEBUG__ == 3) { $GLOBALS['__trans_content_elapsed__'] = microtime(true) - $start; } // Remove unnecessary information $output = preg_replace('/member\_\-([0-9]+)/s', 'member_0', $output); // set icon $oAdminModel = getAdminModel('admin'); $favicon_url = $oAdminModel->getFaviconUrl(false); $mobicon_url = $oAdminModel->getMobileIconUrl(false); Context::set('favicon_url', $favicon_url); Context::set('mobicon_url', $mobicon_url); // convert the final layout Context::set('content', $output); $oTemplate = TemplateHandler::getInstance(); if(Mobile::isFromMobilePhone()) { $this->_loadMobileJSCSS(); $output = $oTemplate->compile('./common/tpl', 'mobile_layout'); } else { $this->_loadDesktopJSCSS(); $output = $oTemplate->compile('./common/tpl', 'common_layout'); } // replace the user-defined-language $oModuleController = getController('module'); $oModuleController->replaceDefinedLangCode($output); } /** * when display mode is HTML, prepare code before print about tag value. * @param array $match input value. * @return string input value. */ function _preserveValue($match) { $INPUT_ERROR = Context::get('INPUT_ERROR'); $str = $match[1] . $match[2] . ' name="' . $match[3] . '"' . $match[4]; // get type $type = 'text'; if(preg_match('/\stype="([a-z]+)"/i', $str, $m)) { $type = strtolower($m[1]); } switch($type) { case 'text': case 'hidden': case 'email': case 'search': case 'tel': case 'url': case 'email': case 'datetime': case 'date': case 'month': case 'week': case 'time': case 'datetime-local': case 'number': case 'range': case 'color': $str = preg_replace('@\svalue="[^"]*?"@', ' ', $str) . ' value="' . htmlspecialchars($INPUT_ERROR[$match[3]], ENT_COMPAT | ENT_HTML401, 'UTF-8', false) . '"'; break; case 'password': $str = preg_replace('@\svalue="[^"]*?"@', ' ', $str); break; case 'radio': case 'checkbox': $str = preg_replace('@\schecked(="[^"]*?")?@', ' ', $str); if(@preg_match('@\s(?i:value)="' . $INPUT_ERROR[$match[3]] . '"@', $str)) { $str .= ' checked="checked"'; } break; } return $str . ' />'; } /** * when display mode is HTML, prepare code before print about '; } /** * when display mode is HTML, prepare code before print about '; } /** * add html style code extracted from html body to Context, which will be * printed inside
later. * @param array $matches * @return void */ function _moveStyleToHeader($matches) { if(isset($matches[1]) && stristr($matches[1], 'scoped')) { return $matches[0]; } Context::addHtmlHeader($matches[0]); } /** * add html link code extracted from html body to Context, which will be * printed inside
later. * @param array $matches * @return void */ function _moveLinkToHeader($matches) { Context::addHtmlHeader($matches[0]); } /** * add meta code extracted from html body to Context, which will be * printed inside
later. * @param array $matches * @return void */ function _moveMetaToHeader($matches) { Context::addHtmlHeader($matches[0]); } /** * add given .css or .js file names in widget code to Context * @param array $matches * @return void */ function _transMeta($matches) { if($matches[1]) { return ''; } Context::loadFile($matches[2]); } /** * import basic .js files. * @return void */ function _loadDesktopJSCSS() { $lang_type = Context::getLangType(); $this->_loadCommonJSCSS(); // for admin page, add admin css if(Context::get('module') == 'admin' || strpos(Context::get('act'), 'Admin') > 0) { Context::loadFile(array('./modules/admin/tpl/css/admin.css', '', '', 10), true); Context::loadFile(array("./modules/admin/tpl/css/admin_{$lang_type}.css", '', '', 10), true); Context::loadFile(array("./modules/admin/tpl/css/admin.iefix.css", '', 'ie', 10), true); Context::loadFile('./modules/admin/tpl/js/admin.js', true); Context::loadFile(array('./modules/admin/tpl/css/admin.bootstrap.css', '', '', 1), true); Context::loadFile(array('./modules/admin/tpl/js/jquery.tmpl.js', '', '', 1), true); Context::loadFile(array('./modules/admin/tpl/js/jquery.jstree.js', '', '', 1), true); } } /** * import basic .js files for mobile */ private function _loadMobileJSCSS() { $this->_loadCommonJSCSS(); Context::loadFile(array('./common/css/mobile.css', '', '', -1500000), true); } /** * import common .js and .css files for (both desktop and mobile) */ private function _loadCommonJSCSS() { Context::loadFile(array('./common/css/xe.css', '', '', -1600000), true); $original_file_list = array('x', 'common', 'js_app', 'xml_handler', 'xml_js_filter'); $jquery_version = preg_match('/MSIE [5-8]\./', $_SERVER['HTTP_USER_AGENT']) ? '1.11.3' : '2.1.4'; if(Context::getDBInfo()->minify_scripts === 'none') { Context::loadFile(array('./common/js/jquery-' . $jquery_version . '.js', 'head', '', -1730000), true); Context::loadFile(array('./common/js/plugins/jquery.migrate/jquery-migrate-1.2.1.js', 'head', '', -1720000), true); foreach($original_file_list as $filename) { Context::loadFile(array('./common/js/' . $filename . '.js', 'head', '', -1700000), true); } } else { Context::loadFile(array('./common/js/jquery-' . $jquery_version . '.min.js', 'head', '', -1730000), true); Context::loadFile(array('./common/js/plugins/jquery.migrate/jquery-migrate-1.2.1.min.js', 'head', '', -1720000), true); $concat_target_filename = 'files/cache/minify/xe.min.js'; if(file_exists(_XE_PATH_ . $concat_target_filename)) { $concat_target_mtime = filemtime(_XE_PATH_ . $concat_target_filename); $original_mtime = 0; foreach($original_file_list as $filename) { $original_mtime = max($original_mtime, filemtime(_XE_PATH_ . 'common/js/' . $filename . '.js')); } if($concat_target_mtime > $original_mtime) { Context::loadFile(array('./' . $concat_target_filename, 'head', '', -100000), true); return; } } $minifier = new MatthiasMullie\Minify\JS(); foreach($original_file_list as $filename) { $minifier->add(_XE_PATH_ . 'common/js/' . $filename . '.js'); } FileHandler::writeFile(_XE_PATH_ . $concat_target_filename, $minifier->execute()); Context::loadFile(array('./' . $concat_target_filename, 'head', '', -100000), true); } } } /* End of file HTMLDisplayHandler.class.php */ /* Location: ./classes/display/HTMLDisplayHandler.class.php */