BasePath = FULL_PATH . THEMES_PATH; $this->_compileToDatabase = defined('SAFE_MODE') && SAFE_MODE; $this->_compressOutput = $this->Application->ConfigValue('UseTemplateCompression'); if ($this->Application->isAdmin) { // prepare module template paths for quick access $module_paths = Array (); foreach ($this->Application->ModuleInfo as $module_name => $module_info) { $module_paths[ mb_strtolower($module_name) ] = rtrim($module_info['Path'], '/'); } $this->_modulePaths = $module_paths; } } /** * Based on template name gets it's location on disk and owner module * * @param string $filename * @return Array 0 - path on disk, 1 - template name */ function GetTemplatePaths($filename) { if ($this->Application->isAdmin && array_key_exists($filename, $this->Application->ReplacementTemplates)) { // process admin template replacement $filename = $this->Application->ReplacementTemplates[$filename]; } // allows to use non-replaced version of replaced template $filename = preg_replace('/^original:(.*)/', '\\1', $filename); if (preg_match('#^[\/]{0,1}([^\/]*)\/(.*)#', $filename, $regs)) { $first_dir = $regs[1]; $module_filename = $regs[2]; } else { $first_dir = ''; $module_filename = $filename; } if (is_string($this->forceThemeName)) { // when defined, then all templates are read from given theme name $first_dir = 'theme:' . $this->forceThemeName . ($first_dir ? '/' . $first_dir : ''); } if ($this->Application->isAdmin && array_key_exists($first_dir, $this->_modulePaths)) { // template belongs to one of the modules $path = FULL_PATH . '/' . $this->_modulePaths[$first_dir] . '/admin_templates'; } elseif ($this->forceThemeName && preg_match('/^theme:(.*)/', $first_dir, $regs)) { // ability to use Front-End templates in admin (only during mass compilation) $path = FULL_PATH . '/themes/' . $regs[1]; } else { // template from "core" module $path = $this->BasePath; $module_filename = $first_dir . '/' . $module_filename; } return Array ($path, $module_filename); } /** * Returns template filename by given template name * * @param string $filename * @return string */ function GetRealFilename($filename) { list ($path, $module_filename) = $this->GetTemplatePaths($filename); return $path.'/'.trim($module_filename, '/'); } /** * Checks, that given template exists on disk * * @param string $filename * @return bool */ function TemplateExists($filename) { if ((strpos($filename, '../') !== false) || (trim($filename) !== $filename)) { // when relative paths or special chars are found template names from url, then it's hacking attempt return false; } $real_file = $this->GetRealFilename($filename); if (substr($real_file, -4) != '.tpl') { // add ".tpl" file extension, when not specified in template name $real_file .= '.tpl'; } return file_exists($real_file); } /** * Returns information about template compilation status * * @param string $template * @return Array */ function GetPreParsed($template) { $real_name = $this->GetRealFilename($template); $fname = str_replace(FULL_PATH, WRITEABLE . '/cache', $real_name . '.php'); $tname = $real_name . '.tpl'; if (!file_exists($tname)) { // given template doesn't exist return false; } if ($this->_compileToDatabase) { $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'SystemCache WHERE VarName = "' . $fname . '"'; $cached = $this->Conn->GetRow($sql); if ($cached !== false && $cached['Cached'] > filemtime($tname)) { return Array ('active' => 1, 'fname' => $fname, 'tname' => $tname, 'mode' => 'db', 'content' => $cached['Data']); } } else { if (file_exists($fname) && file_exists($tname) && filemtime($fname) > filemtime($tname)) { return Array ('active' => 1, 'fname' => $fname, 'tname' => $tname, 'mode' => 'file'); } if (!file_exists($fname)) { // make sure to create directory if pre-parsed file does not exist $this->CheckDir(dirname($fname), WRITEABLE . '/cache'); } } // when compiled template is expired or doesn't exist return Array ('active' => 0, 'fname' => $fname, 'tname' => $tname, 'mode' => 'file'); } /** * Saves compiled template version to database or disk * * @param string $filename * @param string $compiled_template */ function saveTemplate($filename, &$compiled_template) { if ($this->_compileToDatabase) { $fields_hash = Array ( 'VarName' => $filename, 'Data' => &$compiled_template, 'Cached' => adodb_mktime(), ); $this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'SystemCache', 'REPLACE'); return ; } $fp = fopen($filename, 'w'); if ($this->_compressOutput) { $compiled_template = $this->_compress($compiled_template); } if ( !fwrite($fp, $compiled_template) ) { throw new ParserException('Saving compiled template failed'); } fclose($fp); } /** * Runs template and returns result (template already should be compiled by now) * * @param NParser $_parser * @param Array $pre_parsed * @return string */ function &runTemplate(&$_parser, &$pre_parsed) { ob_start(); if ($this->_compileToDatabase) { $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'SystemCache WHERE VarName = "' . $pre_parsed['fname'] . '"'; $cached = $this->Conn->GetRow($sql); if (($cached !== false) && ($cached['Cached'] > filemtime($pre_parsed['tname']))) { eval('?' . '>' . $cached['Data']); } } else { if ($pre_parsed['mode'] == 'file') { include($pre_parsed['fname']); } else { eval('?' . '>' . $pre_parsed['content']); } } $output = ob_get_clean(); return $output; } /** * Compress given php code * * @param string $src * @return string */ function _compress($src) { // Whitespaces left and right from this signs can be ignored static $IW = array( T_CONCAT_EQUAL, // .= T_DOUBLE_ARROW, // => T_BOOLEAN_AND, // && T_BOOLEAN_OR, // || T_IS_EQUAL, // == T_IS_NOT_EQUAL, // != or <> T_IS_SMALLER_OR_EQUAL, // <= T_IS_GREATER_OR_EQUAL, // >= T_INC, // ++ T_DEC, // -- T_PLUS_EQUAL, // += T_MINUS_EQUAL, // -= T_MUL_EQUAL, // *= T_DIV_EQUAL, // /= T_IS_IDENTICAL, // === T_IS_NOT_IDENTICAL, // !== T_DOUBLE_COLON, // :: T_PAAMAYIM_NEKUDOTAYIM, // :: T_OBJECT_OPERATOR, // -> T_DOLLAR_OPEN_CURLY_BRACES, // ${ T_AND_EQUAL, // &= T_MOD_EQUAL, // %= T_XOR_EQUAL, // ^= T_OR_EQUAL, // |= T_SL, // << T_SR, // >> T_SL_EQUAL, // <<= T_SR_EQUAL, // >>= ); $tokens = token_get_all($src); $new = ""; $c = sizeof($tokens); $iw = false; // ignore whitespace $ih = false; // in HEREDOC $ls = ""; // last sign $ot = null; // open tag for ($i = 0; $i < $c; $i++) { $token = $tokens[$i]; if (is_array($token)) { list ($tn, $ts) = $token; // tokens: number, string, line $tname = token_name($tn); if ($tn == T_INLINE_HTML) { $new .= $ts; $iw = false; } else { if ($tn == T_OPEN_TAG) { if (strpos($ts, " ") || strpos($ts, "\n") || strpos($ts, "\t") || strpos($ts, "\r")) { $ts = rtrim($ts); } $ts .= " "; $new .= $ts; $ot = T_OPEN_TAG; $iw = true; } elseif ($tn == T_OPEN_TAG_WITH_ECHO) { $new .= $ts; $ot = T_OPEN_TAG_WITH_ECHO; $iw = true; } elseif ($tn == T_CLOSE_TAG) { if ($ot == T_OPEN_TAG_WITH_ECHO) { $new = rtrim($new, "; "); } else { $ts = " ".$ts; } $new .= $ts; $ot = null; $iw = false; } elseif (in_array($tn, $IW)) { $new .= $ts; $iw = true; } elseif ($tn == T_CONSTANT_ENCAPSED_STRING || $tn == T_ENCAPSED_AND_WHITESPACE) { if ($ts[0] == '"') { $ts = addcslashes($ts, "\n\t\r"); } $new .= $ts; $iw = true; } elseif ($tn == T_WHITESPACE) { $nt = @$tokens[$i+1]; if (!$iw && (!is_string($nt) || $nt == '$') && !in_array($nt[0], $IW)) { $new .= " "; } $iw = false; } elseif ($tn == T_START_HEREDOC) { $new .= "<<