diff --git a/classes/template/TemplateHandler.class.php b/classes/template/TemplateHandler.class.php index 242a88f2e..52ccdc19a 100644 --- a/classes/template/TemplateHandler.class.php +++ b/classes/template/TemplateHandler.class.php @@ -1,1215 +1,6 @@ config = new stdClass; - $this->handler_mtime = filemtime(__FILE__); - $this->delay_compile = config('view.delay_compile') ?? 0; - $this->user = Rhymix\Framework\Session::getMemberInfo(); - } - - /** - * returns TemplateHandler's singleton object - * @return TemplateHandler instance - */ - public static function getInstance() - { - static $oTemplate = NULL; - - if(!isset($GLOBALS['__TemplateHandlerCalled__'])) - { - $GLOBALS['__TemplateHandlerCalled__'] = 1; - } - else - { - $GLOBALS['__TemplateHandlerCalled__']++; - } - - if(!$oTemplate) - { - $oTemplate = new TemplateHandler(); - } - - return $oTemplate; - } - - /** - * Reset all instance properties to the default state. - * - * @return void - */ - protected function resetState() - { - $this->path = null; - $this->web_path = null; - $this->filename = null; - $this->file = null; - $this->compiled_file = null; - $this->source_type = null; - $this->config = new stdClass; - $this->skipTags = null; - self::$rootTpl = null; - } - - /** - * set variables for template compile - * @param string $tpl_path - * @param string $tpl_filename - * @param string $tpl_file - * @return void - */ - protected function init($tpl_path, $tpl_filename, $tpl_file = '') - { - // verify arguments - $tpl_path = trim(preg_replace('@^' . preg_quote(\RX_BASEDIR, '@') . '|\./@', '', str_replace('\\', '/', $tpl_path)), '/') . '/'; - $tpl_path = preg_replace('/[\{\}\(\)\[\]<>\$\'"]/', '', $tpl_path); - if($tpl_path === '/') - { - $tpl_path = ''; - } - elseif(!is_dir(\RX_BASEDIR . $tpl_path)) - { - $this->resetState(); - return; - } - - if(!file_exists(\RX_BASEDIR . $tpl_path . $tpl_filename) && file_exists(\RX_BASEDIR . $tpl_path . $tpl_filename . '.html')) - { - $tpl_filename .= '.html'; - } - - // create tpl_file variable - if($tpl_file) - { - $tpl_file = trim(preg_replace('@^' . preg_quote(\RX_BASEDIR, '@') . '|\./@', '', str_replace('\\', '/', $tpl_file)), '/'); - } - else - { - $tpl_file = $tpl_path . $tpl_filename; - } - - // set template file infos. - $this->path = \RX_BASEDIR . $tpl_path; - $this->web_path = \RX_BASEURL . $tpl_path; - $this->filename = $tpl_filename; - $this->file = \RX_BASEDIR . $tpl_file; - - // set compiled file name - $converted_path = ltrim(str_replace(array('\\', '..'), array('/', 'dotdot'), $tpl_file), '/'); - $this->compiled_file = \RX_BASEDIR . 'files/cache/template/' . $converted_path . '.php'; - $this->source_type = preg_match('!^((?:m\.)?[a-z]+)/!', $tpl_path, $matches) ? $matches[1] : null; - } - - /** - * compiles specified tpl file and execution result in Context into resultant content - * @param string $tpl_path path of the directory containing target template file - * @param string $tpl_filename target template file's name - * @param string $tpl_file if specified use it as template file's full path - * @return string Returns compiled result in case of success, NULL otherwise - */ - public function compile($tpl_path, $tpl_filename, $tpl_file = '') - { - // store the starting time for debug information - $start = microtime(true); - - // initiation - $this->init($tpl_path, $tpl_filename, $tpl_file); - - // if target file does not exist exit - if(!$this->file || !file_exists($this->file)) - { - $tpl_path = rtrim(str_replace('\\', '/', $tpl_path), '/') . '/'; - $error_message = vsprintf('Template not found: %s%s%s', array( - starts_with(\RX_BASEDIR, $tpl_path) ? substr($tpl_path, strlen(\RX_BASEDIR)) : $tpl_path, - preg_replace('/\.html$/i', '', $tpl_filename) . '.html', - $tpl_file ? " ($tpl_file)" : '', - )); - trigger_error($error_message, \E_USER_WARNING); - return escape($error_message); - } - - // for backward compatibility - if(is_null(self::$rootTpl)) - { - self::$rootTpl = $this->file; - } - - // Don't try to compile files that are less than 1 second old - $filemtime = filemtime($this->file); - if ($filemtime > time() - $this->delay_compile) - { - $latest_mtime = $this->handler_mtime; - } - else - { - $latest_mtime = max($filemtime, $this->handler_mtime); - } - - // make compiled file - if(!file_exists($this->compiled_file) || filemtime($this->compiled_file) < $latest_mtime) - { - $buff = $this->parse(); - if($buff === null && file_exists($this->compiled_file)) - { - $error_message = 'Template compile failed: Source file is unreadable: ' . $this->file; - trigger_error($error_message, \E_USER_WARNING); - } - elseif(Rhymix\Framework\Storage::write($this->compiled_file, $buff) === false) - { - $tmpfilename = tempnam(sys_get_temp_dir(), 'rx-compiled'); - if($tmpfilename === false || Rhymix\Framework\Storage::write($tmpfilename, $buff) === false) - { - $error_message = 'Template compile failed: Cannot create temporary file. Please check permissions.'; - trigger_error($error_message, \E_USER_WARNING); - return escape($error_message); - } - - $this->compiled_file = $tmpfilename; - } - } - - Rhymix\Framework\Debug::addFilenameAlias($this->file, $this->compiled_file); - $output = $this->_fetch($this->compiled_file); - - // delete tmpfile - if(isset($tmpfilename)) - { - Rhymix\Framework\Storage::delete($tmpfilename); - } - - if(isset($__templatehandler_root_tpl) && $__templatehandler_root_tpl == $this->file) - { - $__templatehandler_root_tpl = null; - } - - // store the ending time for debug information - if (!isset($GLOBALS['__template_elapsed__'])) - { - $GLOBALS['__template_elapsed__'] = 0; - } - $GLOBALS['__template_elapsed__'] += microtime(true) - $start; - - return $output; - } - - /** - * compile specified file and immediately return - * @param string $tpl_path path of the directory containing target template file - * @param string $tpl_filename target template file's name - * @return string Returns compiled content in case of success or NULL in case of failure - */ - public function compileDirect($tpl_path, $tpl_filename) - { - $this->init($tpl_path, $tpl_filename, null); - - // if target file does not exist exit - if(!$this->file || !file_exists($this->file)) - { - $tpl_path = rtrim(str_replace('\\', '/', $tpl_path), '/') . '/'; - $error_message = vsprintf('Template not found: %s%s', array( - starts_with(\RX_BASEDIR, $tpl_path) ? substr($tpl_path, strlen(\RX_BASEDIR)) : $tpl_path, - preg_replace('/\.html$/i', '', $tpl_filename) . '.html', - )); - trigger_error($error_message, \E_USER_WARNING); - return escape($error_message); - } - - return $this->parse(); - } - - /** - * parse syntax. - * @param string $buff template file - * @return string compiled result in case of success or NULL in case of error - */ - protected function parse($buff = null) - { - if(is_null($buff)) - { - if(!is_readable($this->file)) - { - return; - } - - // read tpl file - $buff = Rhymix\Framework\Storage::read($this->file); - if ($buff === false) - { - return; - } - $buff_type = 'file'; - } - else - { - $buff_type = 'string'; - } - - // HTML tags to skip - if(is_null($this->skipTags)) - { - $this->skipTags = array('marquee'); - } - - // reset config for this buffer (this step is necessary because we use a singleton for every template) - $previous_config = clone $this->config; - $this->config = new stdClass(); - - // detect existence of autoescape config - $this->config->autoescape = (strpos($buff, ' autoescape="') === false) ? null : false; - - // remove UTF-8 BOM and convert CRLF to LF - $buff = preg_replace(['/^\xEF\xBB\xBF/', '/\r\n/'], ['', "\n"], $buff); - - // replace comments - $buff = preg_replace('@@s', '', $buff); - - // replace value of src in img/input/script tag - $buff = preg_replace_callback('/<(?:img|input|script)(?:[^<>]*?)(?(?=cond=")(?:cond="[^"]+"[^<>]*)+|)[^<>]* src="(?!(?:https?|file|data):|[\/\{])([^"]+)"/is', array($this, '_replacePath'), $buff); - - // replace value of srcset in img/source/link tag - $buff = preg_replace_callback('/<(?:img|source|link)(?:[^<>]*?)(?(?=cond=")(?:cond="[^"]+"[^<>]*)+|)[^<>]* srcset="([^"]+)"/is', array($this, '_replaceSrcsetPath'), $buff); - - // replace loop and cond template syntax - $buff = $this->_parseInline($buff); - - // include, unload/load, import - $buff = preg_replace_callback('/{(@[\s\S]+?|(?=[\$\\\\]\w+|_{1,2}[A-Z]+|[!\(+-]|\w+(?:\(|::)|\d+|[\'"].*?[\'"]).+?)}|<(!--[#%])?(include|import|(un)?load(?(4)|(?:_js_plugin)?)|config)(?(2)\(["\']([^"\']+)["\'])(.*?)(?(2)\)--|\/)>|(\s*)/', array($this, '_parseResource'), $buff); - - // remove block which is a virtual tag - $buff = preg_replace('@?block\s*>@is', '', $buff); - - // form auto generation - $temp = preg_replace_callback('/(