config = new stdClass; $this->handler_mtime = filemtime(__FILE__); $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( $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; } $latest_mtime = max(filemtime($this->file), $this->handler_mtime); // make compiled file if(!file_exists($this->compiled_file) || filemtime($this->compiled_file) < $latest_mtime) { $buff = $this->parse(); if(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( $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 = FileHandler::readFile($this->file); } // 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; // 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('/(