getSource()->handler->supportsCompiledTemplates()) { $compiled->populateCompiledFilepath($_template); } return $compiled; } /** * populate Compiled Object with compiled filepath * * @param Template $_template template object **/ private function populateCompiledFilepath(Template $_template) { $source = $_template->getSource(); $smarty = $_template->getSmarty(); $this->filepath = $smarty->getCompileDir(); if (isset($_template->compile_id)) { $this->filepath .= preg_replace('![^\w]+!', '_', $_template->compile_id) . ($smarty->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'); } // if use_sub_dirs, break file into directories if ($smarty->use_sub_dirs) { $this->filepath .= $source->uid[0] . $source->uid[1] . DIRECTORY_SEPARATOR . $source->uid[2] . $source->uid[3] . DIRECTORY_SEPARATOR . $source->uid[4] . $source->uid[5] . DIRECTORY_SEPARATOR; } $this->filepath .= $source->uid . '_'; if ($source->isConfig) { $this->filepath .= (int)$smarty->config_read_hidden + (int)$smarty->config_booleanize * 2 + (int)$smarty->config_overwrite * 4; } else { $this->filepath .= (int)$smarty->escape_html * 2; } $this->filepath .= '.' . $source->type . '_' . $source->getBasename(); if ($_template->caching) { $this->filepath .= '.cache'; } $this->filepath .= '.php'; $this->timestamp = $this->exists = is_file($this->filepath); if ($this->exists) { $this->timestamp = filemtime($this->filepath); } } /** * render compiled template code * * @param Template $_template * * @return string * @throws \Smarty\Exception */ public function render(Template $_template) { if ($_template->getSmarty()->debugging) { $_template->getSmarty()->getDebug()->start_render($_template); } if (!$this->processed) { $this->compileAndLoad($_template); } // @TODO Can't Cached handle this? Maybe introduce an event to decouple. if ($_template->caching) { $_template->getCached()->file_dependency = array_merge($_template->getCached()->file_dependency, $this->file_dependency); } $this->getRenderedTemplateCode($_template, $this->unifunc); // @TODO Can't Cached handle this? Maybe introduce an event to decouple and remove the $_template->caching property. if ($_template->caching && $this->getNocacheCode()) { $_template->getCached()->hashes[$this->nocache_hash] = true; } if ($_template->getSmarty()->debugging) { $_template->getSmarty()->getDebug()->end_render($_template); } } /** * load compiled template or compile from source * * @param Template $_smarty_tpl do not change variable name, is used by compiled template * * @throws Exception */ private function compileAndLoad(Template $_smarty_tpl) { if ($_smarty_tpl->getSource()->handler->recompiled) { $this->recompile($_smarty_tpl); return; } if ($this->exists && !$_smarty_tpl->getSmarty()->force_compile && !($_smarty_tpl->compile_check && $_smarty_tpl->getSource()->getTimeStamp() > $this->getTimeStamp()) ) { $this->loadCompiledTemplate($_smarty_tpl, false); } if (!$this->isValid) { $this->compileAndWrite($_smarty_tpl); $this->loadCompiledTemplate($_smarty_tpl); } $this->processed = true; } /** * compile template from source * * @param Template $_smarty_tpl do not change variable name, is used by compiled template * * @throws Exception */ private function recompile(Template $_smarty_tpl) { $level = ob_get_level(); ob_start(); // call compiler try { eval('?>' . $this->doCompile($_smarty_tpl)); } catch (\Exception $e) { while (ob_get_level() > $level) { ob_end_clean(); } throw $e; } ob_get_clean(); $this->timestamp = time(); $this->exists = true; } /** * compile template from source * * @param Template $_template * * @throws Exception */ public function compileAndWrite(Template $_template) { // compile locking if ($saved_timestamp = (!$_template->getSource()->handler->recompiled && is_file($this->filepath))) { $saved_timestamp = $this->getTimeStamp(); touch($this->filepath); } // compile locking try { // call compiler $this->write($_template, $this->doCompile($_template)); } catch (\Exception $e) { // restore old timestamp in case of error if ($saved_timestamp && is_file($this->filepath)) { touch($this->filepath, $saved_timestamp); } throw $e; } } /** * Do the actual compiling. * * @param Template $_smarty_tpl * * @return string * @throws Exception */ private function doCompile(Template $_smarty_tpl): string { $this->file_dependency = []; $this->includes = []; $this->nocache_hash = null; $this->unifunc = null; return $_smarty_tpl->getCompiler()->compileTemplate($_smarty_tpl); } /** * Write compiled code by handler * * @param Template $_template template object * @param string $code compiled code * * @return bool success * @throws \Smarty\Exception */ private function write(Template $_template, $code) { if (!$_template->getSource()->handler->recompiled) { if ($_template->getSmarty()->writeFile($this->filepath, $code) === true) { $this->timestamp = $this->exists = is_file($this->filepath); if ($this->exists) { $this->timestamp = filemtime($this->filepath); return true; } } return false; } return true; } /** * Load fresh compiled template by including the PHP file * HHVM requires a workaround because of a PHP incompatibility * * @param Template $_smarty_tpl do not change/remove variable name, is used by compiled template * @param bool $invalidateCachedFiles forces a revalidation of the file in opcache or apc cache (if available) * */ private function loadCompiledTemplate(Template $_smarty_tpl, bool $invalidateCachedFiles = true) { if ($invalidateCachedFiles) { if (function_exists('opcache_invalidate') && (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api")) < 1) ) { opcache_invalidate($this->filepath, true); } elseif (function_exists('apc_compile_file')) { apc_compile_file($this->filepath); } } if (defined('HHVM_VERSION')) { eval('?>' . file_get_contents($this->filepath)); } else { include $this->filepath; } } /** * This function is executed automatically when a compiled or cached template file is included * - Decode saved properties from compiled template and cache files * - Check if compiled or cache file is valid * * @param Template $_template * @param array $properties special template properties * * @return bool flag if compiled or cache file is valid * @throws Exception */ public function isFresh(Template $_template, array $properties): bool { // on cache resources other than file check version stored in cache code if (\Smarty\Smarty::SMARTY_VERSION !== $properties['version']) { return false; } $is_valid = true; if (!empty($properties['file_dependency']) && $_template->compile_check) { $is_valid = $this->checkFileDependencies($properties['file_dependency'], $_template); } $this->isValid = $is_valid; $this->includes = $properties['includes'] ?? []; if ($is_valid) { $this->unifunc = $properties['unifunc']; $this->setNocacheCode($properties['has_nocache_code']); $this->file_dependency = $properties['file_dependency']; } return $is_valid && !function_exists($properties['unifunc']); } /** * This method is here only to fix an issue when upgrading from Smarty v4 to v5. */ public function _decodeProperties($a, $b, $c = false): bool { return false; } }