Refactored all _runtime_* by merging them into the proper classes or by transforming them into Runtime Extensions.

This commit is contained in:
Simon Wisselink
2022-12-22 15:43:20 +01:00
parent cfd8c08d09
commit d88175de3e
41 changed files with 1571 additions and 1911 deletions

View File

@@ -1,3 +1,3 @@
- [ ] find ->ext-> calls, rewrite and remove first function call param
- [ ] review usages of ->_getSmartyObj and ->smarty: maybe change this so we can hide more
- [ ] ->_objType and ->objMap
- [ ] ->_objType and ->objMap
- [ ] refactor _isTplObj, _isDataObj

View File

@@ -71,7 +71,7 @@ abstract class Base
*
* @return boolean success
*/
abstract public function writeCachedContent(Smarty_Internal_Template $_template, $content);
abstract public function storeCachedContent(Smarty_Internal_Template $_template, $content);
/**
* Read cached template from cache
@@ -80,7 +80,7 @@ abstract class Base
*
* @return string content
*/
abstract public function readCachedContent(Smarty_Internal_Template $_template);
abstract public function retrieveCachedContent(Smarty_Internal_Template $_template);
/**
* Return cached content

View File

@@ -9,7 +9,7 @@ namespace Smarty\Cacheresource;
* @subpackage Cacher
*/
use Smarty\Cacheresource\Base;
use Smarty_Internal_Template;
/**
* Cache Handler API
@@ -171,7 +171,7 @@ abstract class Custom extends Base
*
* @return boolean success
*/
public function writeCachedContent(Smarty_Internal_Template $_template, $content)
public function storeCachedContent(Smarty_Internal_Template $_template, $content)
{
return $this->save(
$_template->cached->filepath,
@@ -190,7 +190,7 @@ abstract class Custom extends Base
*
* @return string|boolean content
*/
public function readCachedContent(Smarty_Internal_Template $_template)
public function retrieveCachedContent(Smarty_Internal_Template $_template)
{
$content = $_template->cached->content ?: null;
if ($content === null) {

View File

@@ -124,14 +124,9 @@ class File extends Base
* @return bool success
* @throws \SmartyException
*/
public function writeCachedContent(Smarty_Internal_Template $_template, $content)
public function storeCachedContent(Smarty_Internal_Template $_template, $content)
{
if ($_template->smarty->ext->_writeFile->writeFile(
$_template->cached->filepath,
$content,
$_template->smarty
) === true
) {
if ($_template->smarty->writeFile($_template->cached->filepath, $content) === true) {
if (function_exists('opcache_invalidate')
&& (!function_exists('ini_get') || strlen(ini_get('opcache.restrict_api'))) < 1
) {
@@ -156,7 +151,7 @@ class File extends Base
*
* @return string content
*/
public function readCachedContent(Smarty_Internal_Template $_template)
public function retrieveCachedContent(Smarty_Internal_Template $_template)
{
if (is_file($_template->cached->filepath)) {
return file_get_contents($_template->cached->filepath);
@@ -174,7 +169,7 @@ class File extends Base
*/
public function clearAll(Smarty $smarty, $exp_time = null)
{
return $smarty->ext->_cacheResourceFile->clear($smarty, null, null, null, $exp_time);
return $this->clear($smarty, null, null, null, $exp_time);
}
/**
@@ -190,7 +185,113 @@ class File extends Base
*/
public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time)
{
return $smarty->ext->_cacheResourceFile->clear($smarty, $resource_name, $cache_id, $compile_id, $exp_time);
$_cache_id = isset($cache_id) ? preg_replace('![^\w\|]+!', '_', $cache_id) : null;
$_compile_id = isset($compile_id) ? preg_replace('![^\w]+!', '_', $compile_id) : null;
$_dir_sep = $smarty->use_sub_dirs ? '/' : '^';
$_compile_id_offset = $smarty->use_sub_dirs ? 3 : 0;
$_dir = $smarty->getCacheDir();
if ($_dir === '/') { //We should never want to delete this!
return 0;
}
$_dir_length = strlen($_dir);
if (isset($_cache_id)) {
$_cache_id_parts = explode('|', $_cache_id);
$_cache_id_parts_count = count($_cache_id_parts);
if ($smarty->use_sub_dirs) {
foreach ($_cache_id_parts as $id_part) {
$_dir .= $id_part . '/';
}
}
}
if (isset($resource_name)) {
$_save_stat = $smarty->caching;
$smarty->caching = \Smarty\Smarty::CACHING_LIFETIME_CURRENT;
$tpl = new $smarty->template_class($resource_name, $smarty);
$smarty->caching = $_save_stat;
// remove from template cache
$tpl->source; // have the template registered before unset()
if ($tpl->source->exists) {
$_resourcename_parts = basename(str_replace('^', '/', $tpl->cached->filepath));
} else {
return 0;
}
}
$_count = 0;
$_time = time();
if (file_exists($_dir)) {
$_cacheDirs = new RecursiveDirectoryIterator($_dir);
$_cache = new RecursiveIteratorIterator($_cacheDirs, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($_cache as $_file) {
if (substr(basename($_file->getPathname()), 0, 1) === '.') {
continue;
}
$_filepath = (string)$_file;
// directory ?
if ($_file->isDir()) {
if (!$_cache->isDot()) {
// delete folder if empty
@rmdir($_file->getPathname());
}
} else {
// delete only php files
if (substr($_filepath, -4) !== '.php') {
continue;
}
$_parts = explode($_dir_sep, str_replace('\\', '/', substr($_filepath, $_dir_length)));
$_parts_count = count($_parts);
// check name
if (isset($resource_name)) {
if ($_parts[ $_parts_count - 1 ] !== $_resourcename_parts) {
continue;
}
}
// check compile id
if (isset($_compile_id) && (!isset($_parts[ $_parts_count - 2 - $_compile_id_offset ])
|| $_parts[ $_parts_count - 2 - $_compile_id_offset ] !== $_compile_id)
) {
continue;
}
// check cache id
if (isset($_cache_id)) {
// count of cache id parts
$_parts_count = (isset($_compile_id)) ? $_parts_count - 2 - $_compile_id_offset :
$_parts_count - 1 - $_compile_id_offset;
if ($_parts_count < $_cache_id_parts_count) {
continue;
}
for ($i = 0; $i < $_cache_id_parts_count; $i++) {
if ($_parts[ $i ] !== $_cache_id_parts[ $i ]) {
continue 2;
}
}
}
if (is_file($_filepath)) {
// expired ?
if (isset($exp_time)) {
if ($exp_time < 0) {
preg_match('#\'cache_lifetime\' =>\s*(\d*)#', file_get_contents($_filepath), $match);
if ($_time < (filemtime($_filepath) + $match[ 1 ])) {
continue;
}
} else {
if ($_time - filemtime($_filepath) < $exp_time) {
continue;
}
}
}
$_count += @unlink($_filepath) ? 1 : 0;
if (function_exists('opcache_invalidate')
&& (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api")) < 1)
) {
opcache_invalidate($_filepath, true);
} elseif (function_exists('apc_delete_file')) {
apc_delete_file($_filepath);
}
}
}
}
}
return $_count;
}
/**

View File

@@ -140,7 +140,7 @@ abstract class KeyValueStore extends Base
*
* @return boolean success
*/
public function writeCachedContent(Smarty_Internal_Template $_template, $content)
public function storeCachedContent(Smarty_Internal_Template $_template, $content)
{
$this->addMetaTimestamp($content);
return $this->write(array($_template->cached->filepath => $content), $_template->cache_lifetime);
@@ -153,7 +153,7 @@ abstract class KeyValueStore extends Base
*
* @return string|false content
*/
public function readCachedContent(Smarty_Internal_Template $_template)
public function retrieveCachedContent(Smarty_Internal_Template $_template)
{
$content = $_template->cached->content ? $_template->cached->content : null;
$timestamp = null;

View File

@@ -3,7 +3,6 @@
namespace Smarty\Compile;
use Smarty\ParseTree\Template;
use Smarty\Compiler\Template;
/**
* Smarty Internal Plugin Compile BlockClose Class

View File

@@ -81,10 +81,10 @@ class Call extends Base
// was there an assign attribute
if (isset($_assign)) {
$_output =
"<?php ob_start();\n\$_smarty_tpl->smarty->ext->_tplFunction->callTemplateFunction(\$_smarty_tpl, {$_name}, {$_params}, {$_nocache});\n\$_smarty_tpl->assign({$_assign}, ob_get_clean());?>\n";
"<?php ob_start();\n\$_smarty_tpl->smarty->getRuntime('TplFunction')->callTemplateFunction(\$_smarty_tpl, {$_name}, {$_params}, {$_nocache});\n\$_smarty_tpl->assign({$_assign}, ob_get_clean());?>\n";
} else {
$_output =
"<?php \$_smarty_tpl->smarty->ext->_tplFunction->callTemplateFunction(\$_smarty_tpl, {$_name}, {$_params}, {$_nocache});?>\n";
"<?php \$_smarty_tpl->smarty->getRuntime('TplFunction')->callTemplateFunction(\$_smarty_tpl, {$_name}, {$_params}, {$_nocache});?>\n";
}
return $_output;
}

View File

@@ -38,7 +38,7 @@ class Capture extends Base {
\Smarty\Compiler\Template $compiler,
$parameter = null
) {
return '$_smarty_tpl->smarty->ext->_capture->getBuffer($_smarty_tpl' .
return '$_smarty_tpl->smarty->getRuntime(\'Capture\')->getBuffer($_smarty_tpl' .
(isset($parameter[1]) ? ", {$parameter[ 1 ]})" : ')');
}
@@ -60,7 +60,7 @@ class Capture extends Base {
$compiler->_cache['capture_stack'][] = [$compiler->nocache];
// maybe nocache because of nocache variables
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
$_output = "<?php \$_smarty_tpl->smarty->ext->_capture->open(\$_smarty_tpl, $buffer, $assign, $append);?>";
$_output = "<?php \$_smarty_tpl->smarty->getRuntime('Capture')->open(\$_smarty_tpl, $buffer, $assign, $append);?>";
return $_output;
}
}

View File

@@ -37,6 +37,6 @@ class CaptureClose extends Base {
$compiler->tag_nocache = true;
}
[$compiler->nocache] = array_pop($compiler->_cache['capture_stack']);
return "<?php \$_smarty_tpl->smarty->ext->_capture->close(\$_smarty_tpl);?>";
return "<?php \$_smarty_tpl->smarty->getRuntime('Capture')->close(\$_smarty_tpl);?>";
}
}

View File

@@ -89,6 +89,6 @@ class ConfigLoad extends Base {
$_scope = $compiler->convertScope($_attr, $this->valid_scopes);
}
// create config object
return "<?php\n\$_smarty_tpl->smarty->ext->configLoad->_loadConfigFile(\$_smarty_tpl, {$conf_file}, {$section}, {$_scope});\n?>\n";
return "<?php\n\$_smarty_tpl->_loadConfigFile({$conf_file}, {$section}, {$_scope});\n?>\n";
}
}

View File

@@ -175,7 +175,7 @@ abstract class ForeachSection extends Base {
if ($_content !== '') {
// run pre filter if required
if (isset($nextCompiler->smarty->registered_filters['pre'])) {
$_content = $nextCompiler->smarty->ext->_filterHandler->runFilter(
$_content = $nextCompiler->smarty->runFilter(
'pre',
$_content,
$nextCompiler->template

View File

@@ -193,7 +193,7 @@ class ForeachTag extends ForeachSection {
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
// generate output code
$output = "<?php\n";
$output .= "\$_from = \$_smarty_tpl->smarty->ext->_foreach->init(\$_smarty_tpl, $from, " .
$output .= "\$_from = \$_smarty_tpl->smarty->getRuntime('Foreach')->init(\$_smarty_tpl, $from, " .
var_export($item, true);
if ($name || $needTotal || $key) {
$output .= ', ' . var_export($needTotal, true);
@@ -261,6 +261,6 @@ class ForeachTag extends ForeachSection {
* @return string compiled code
*/
public function compileRestore($levels) {
return "\$_smarty_tpl->smarty->ext->_foreach->restore(\$_smarty_tpl, {$levels});";
return "\$_smarty_tpl->smarty->getRuntime('Foreach')->restore(\$_smarty_tpl, {$levels});";
}
}

View File

@@ -77,7 +77,7 @@ class FunctionClose extends Base {
$output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new \\Smarty\\Variable(\$value, \$_smarty_tpl->isRenderingCache);\n}\n";
$output .= "\$params = var_export(\$params, true);\n";
$output .= "echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php ";
$output .= "\\\$_smarty_tpl->smarty->ext->_tplFunction->saveTemplateVariables(\\\$_smarty_tpl, '{$_name}');\nforeach (\$params as \\\$key => \\\$value) {\n\\\$_smarty_tpl->tpl_vars[\\\$key] = new \\Smarty\\Variable(\\\$value, \\\$_smarty_tpl->isRenderingCache);\n}\n?>";
$output .= "\\\$_smarty_tpl->smarty->getRuntime('TplFunction')->saveTemplateVariables(\\\$_smarty_tpl, '{$_name}');\nforeach (\$params as \\\$key => \\\$value) {\n\\\$_smarty_tpl->tpl_vars[\\\$key] = new \\Smarty\\Variable(\\\$value, \\\$_smarty_tpl->isRenderingCache);\n}\n?>";
$output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";?>";
$compiler->parser->current_buffer->append_subtree(
$compiler->parser,
@@ -88,7 +88,7 @@ class FunctionClose extends Base {
);
$compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode);
$output = "<?php echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php ";
$output .= "\\\$_smarty_tpl->smarty->ext->_tplFunction->restoreTemplateVariables(\\\$_smarty_tpl, '{$_name}');?>\n";
$output .= "\\\$_smarty_tpl->smarty->getRuntime('TplFunction')->restoreTemplateVariables(\\\$_smarty_tpl, '{$_name}');?>\n";
$output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";\n?>";
$output .= "<?php echo str_replace('{$compiler->template->compiled->nocache_hash}', \$_smarty_tpl->compiled->nocache_hash ?? '', ob_get_clean());\n";
$output .= "}\n}\n";

View File

@@ -55,7 +55,7 @@ class MakeNocache extends Base {
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($compiler->template->caching) {
$output = "<?php \$_smarty_tpl->smarty->ext->_make_nocache->save(\$_smarty_tpl, {$_attr[ 'var' ]});\n?>\n";
$output = "<?php \$_smarty_tpl->smarty->getRuntime('MakeNocache')->save(\$_smarty_tpl, {$_attr[ 'var' ]});\n?>\n";
$compiler->template->compiled->has_nocache_code = true;
$compiler->suppressNocacheProcessing = true;
return $output;

View File

@@ -5,14 +5,10 @@ namespace Smarty\Template;
/**
* Smarty Internal Extension
* This file contains the Smarty template extension to create a code frame
*
* @package Smarty
* @subpackage Template
* @author Uwe Tews
*/
/**
* Class Smarty_Internal_Extension_CodeFrame
* Create code frame for compiled and cached templates
*/
class CodeFrame

View File

@@ -59,22 +59,11 @@ abstract class Data
*/
public $config_vars = array();
/**
* extension handler
*
* @var Smarty_Internal_Extension_Handler
*/
public $ext = null;
/**
* \Smarty\Data constructor.
*
* Install extension handler
*/
public function __construct()
{
$this->ext = new Smarty_Internal_Extension_Handler();
$this->ext->objType = $this->_objType;
}
/**
@@ -379,19 +368,6 @@ abstract class Data
return $this->smarty;
}
/**
* Handle unknown class methods
*
* @param string $name unknown method-name
* @param array $args argument array
*
* @return mixed
*/
public function __call($name, $args)
{
return $this->ext->_callExternalMethod($this, $name, $args);
}
/**
* clear the given assigned template variable(s).
*

View File

@@ -172,7 +172,7 @@ class FilePlugin extends Smarty\Resource\BasePlugin {
}
// Use include path ?
if ($source->smarty->use_include_path) {
return $source->smarty->ext->_getIncludePath->getIncludePath($_directories, $file, $source->smarty);
return $source->smarty->getIncludePath($_directories, $file);
}
return false;
}

View File

@@ -0,0 +1,163 @@
<?php
namespace Smarty\Runtime;
use Smarty_Internal_Template;
/**
* Runtime Extension Capture
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
class CaptureRuntime {
/**
* Stack of capture parameter
*
* @var array
*/
private $captureStack = [];
/**
* Current open capture sections
*
* @var int
*/
private $captureCount = 0;
/**
* Count stack
*
* @var int[]
*/
private $countStack = [];
/**
* Named buffer
*
* @var string[]
*/
private $namedBuffer = [];
/**
* Flag if callbacks are registered
*
* @var bool
*/
private $isRegistered = false;
/**
* Open capture section
*
* @param \Smarty_Internal_Template $_template
* @param string $buffer capture name
* @param string $assign variable name
* @param string $append variable name
*/
public function open(Smarty_Internal_Template $_template, $buffer, $assign, $append) {
if (!$this->isRegistered) {
$this->register($_template);
}
$this->captureStack[] = [
$buffer,
$assign,
$append,
];
$this->captureCount++;
ob_start();
}
/**
* Register callbacks in template class
*
* @param \Smarty_Internal_Template $_template
*/
private function register(Smarty_Internal_Template $_template) {
$_template->startRenderCallbacks[] = [
$this,
'startRender',
];
$_template->endRenderCallbacks[] = [
$this,
'endRender',
];
$this->startRender($_template);
$this->isRegistered = true;
}
/**
* Start render callback
*
* @param \Smarty_Internal_Template $_template
*/
public function startRender(Smarty_Internal_Template $_template) {
$this->countStack[] = $this->captureCount;
$this->captureCount = 0;
}
/**
* Close capture section
*
* @param \Smarty_Internal_Template $_template
*
* @throws \SmartyException
*/
public function close(Smarty_Internal_Template $_template) {
if ($this->captureCount) {
[$buffer, $assign, $append] = array_pop($this->captureStack);
$this->captureCount--;
if (isset($assign)) {
$_template->assign($assign, ob_get_contents());
}
if (isset($append)) {
$_template->append($append, ob_get_contents());
}
$this->namedBuffer[$buffer] = ob_get_clean();
} else {
$this->error($_template);
}
}
/**
* Error exception on not matching {capture}{/capture}
*
* @param \Smarty_Internal_Template $_template
*
* @throws \SmartyException
*/
public function error(Smarty_Internal_Template $_template) {
throw new SmartyException("Not matching {capture}{/capture} in '{$_template->template_resource}'");
}
/**
* Return content of named capture buffer by key or as array
*
* @param \Smarty_Internal_Template $_template
* @param string|null $name
*
* @return string|string[]|null
*/
public function getBuffer(Smarty_Internal_Template $_template, $name = null) {
if (isset($name)) {
return $this->namedBuffer[$name] ?? null;
} else {
return $this->namedBuffer;
}
}
/**
* End render callback
*
* @param \Smarty_Internal_Template $_template
*
* @throws \SmartyException
*/
public function endRender(Smarty_Internal_Template $_template) {
if ($this->captureCount) {
$this->error($_template);
} else {
$this->captureCount = array_pop($this->countStack);
}
}
}

View File

@@ -0,0 +1,163 @@
<?php
namespace Smarty\Runtime;
use Smarty_Internal_Template;
/**
* Foreach Runtime Methods count(), init(), restore()
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
class ForeachRuntime {
/**
* Stack of saved variables
*
* @var array
*/
private $stack = [];
/**
* Init foreach loop
* - save item and key variables, named foreach property data if defined
* - init item and key variables, named foreach property data if required
* - count total if required
*
* @param \Smarty_Internal_Template $tpl
* @param mixed $from values to loop over
* @param string $item variable name
* @param bool $needTotal flag if we need to count values
* @param null|string $key variable name
* @param null|string $name of named foreach
* @param array $properties of named foreach
*
* @return mixed $from
*/
public function init(
Smarty_Internal_Template $tpl,
$from,
$item,
$needTotal = false,
$key = null,
$name = null,
$properties = []
) {
$needTotal = $needTotal || isset($properties['total']);
$saveVars = [];
$total = null;
if (!is_array($from)) {
if (is_object($from)) {
if ($needTotal) {
$total = $this->count($from);
}
} else {
settype($from, 'array');
}
}
if (!isset($total)) {
$total = empty($from) ? 0 : ($needTotal ? count($from) : 1);
}
if (isset($tpl->tpl_vars[$item])) {
$saveVars['item'] = [
$item,
$tpl->tpl_vars[$item],
];
}
$tpl->tpl_vars[$item] = new \Smarty\Variable(null, $tpl->isRenderingCache);
if ($total === 0) {
$from = null;
} else {
if ($key) {
if (isset($tpl->tpl_vars[$key])) {
$saveVars['key'] = [
$key,
$tpl->tpl_vars[$key],
];
}
$tpl->tpl_vars[$key] = new \Smarty\Variable(null, $tpl->isRenderingCache);
}
}
if ($needTotal) {
$tpl->tpl_vars[$item]->total = $total;
}
if ($name) {
$namedVar = "__smarty_foreach_{$name}";
if (isset($tpl->tpl_vars[$namedVar])) {
$saveVars['named'] = [
$namedVar,
$tpl->tpl_vars[$namedVar],
];
}
$namedProp = [];
if (isset($properties['total'])) {
$namedProp['total'] = $total;
}
if (isset($properties['iteration'])) {
$namedProp['iteration'] = 0;
}
if (isset($properties['index'])) {
$namedProp['index'] = -1;
}
if (isset($properties['show'])) {
$namedProp['show'] = ($total > 0);
}
$tpl->tpl_vars[$namedVar] = new \Smarty\Variable($namedProp);
}
$this->stack[] = $saveVars;
return $from;
}
/**
* [util function] counts an array, arrayAccess/traversable or PDOStatement object
*
* @param mixed $value
*
* @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0
* for empty elements
*/
public function count($value) {
if ($value instanceof IteratorAggregate) {
// Note: getIterator() returns a Traversable, not an Iterator
// thus rewind() and valid() methods may not be present
return iterator_count($value->getIterator());
} elseif ($value instanceof Iterator) {
return $value instanceof Generator ? 1 : iterator_count($value);
} elseif ($value instanceof Countable) {
return count($value);
} elseif ($value instanceof PDOStatement) {
return $value->rowCount();
} elseif ($value instanceof Traversable) {
return iterator_count($value);
}
return count((array)$value);
}
/**
* Restore saved variables
*
* will be called by {break n} or {continue n} for the required number of levels
*
* @param \Smarty_Internal_Template $tpl
* @param int $levels number of levels
*/
public function restore(Smarty_Internal_Template $tpl, $levels = 1) {
while ($levels) {
$saveVars = array_pop($this->stack);
if (!empty($saveVars)) {
if (isset($saveVars['item'])) {
$item = &$saveVars['item'];
$tpl->tpl_vars[$item[0]]->value = $item[1]->value;
}
if (isset($saveVars['key'])) {
$tpl->tpl_vars[$saveVars['key'][0]] = $saveVars['key'][1];
}
if (isset($saveVars['named'])) {
$tpl->tpl_vars[$saveVars['named'][0]] = $saveVars['named'][1];
}
}
$levels--;
}
}
}

View File

@@ -0,0 +1,250 @@
<?php
namespace Smarty\Runtime;
use Smarty_Internal_Template;
use Smarty_Template_Source;
use SmartyException;
/**
* Inheritance Runtime Methods processBlock, endChild, init
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
**/
class InheritanceRuntime {
/**
* State machine
* - 0 idle next extends will create a new inheritance tree
* - 1 processing child template
* - 2 wait for next inheritance template
* - 3 assume parent template, if child will loaded goto state 1
* a call to a sub template resets the state to 0
*
* @var int
*/
public $state = 0;
/**
* Array of root child {block} objects
*
* @var \Smarty\Block[]
*/
public $childRoot = [];
/**
* inheritance template nesting level
*
* @var int
*/
public $inheritanceLevel = 0;
/**
* inheritance template index
*
* @var int
*/
public $tplIndex = -1;
/**
* Array of template source objects
*
* @var Smarty_Template_Source[]
*/
public $sources = [];
/**
* Stack of source objects while executing block code
*
* @var Smarty_Template_Source[]
*/
public $sourceStack = [];
/**
* Initialize inheritance
*
* @param \Smarty_Internal_Template $tpl template object of caller
* @param bool $initChild if true init for child template
* @param array $blockNames outer level block name
*/
public function init(Smarty_Internal_Template $tpl, $initChild, $blockNames = []) {
// if called while executing parent template it must be a sub-template with new inheritance root
if ($initChild && $this->state === 3 && (strpos($tpl->template_resource, 'extendsall') === false)) {
$tpl->inheritance = new InheritanceRuntime();
$tpl->inheritance->init($tpl, $initChild, $blockNames);
return;
}
++$this->tplIndex;
$this->sources[$this->tplIndex] = $tpl->source;
// start of child sub template(s)
if ($initChild) {
$this->state = 1;
if (!$this->inheritanceLevel) {
//grab any output of child templates
ob_start();
}
++$this->inheritanceLevel;
// $tpl->startRenderCallbacks[ 'inheritance' ] = array($this, 'subTemplateStart');
// $tpl->endRenderCallbacks[ 'inheritance' ] = array($this, 'subTemplateEnd');
}
// if state was waiting for parent change state to parent
if ($this->state === 2) {
$this->state = 3;
}
}
/**
* End of child template(s)
* - if outer level is reached flush output buffer and switch to wait for parent template state
*
* @param \Smarty_Internal_Template $tpl
* @param null|string $template optional name of inheritance parent template
* @param null|string $uid uid of inline template
* @param null|string $func function call name of inline template
*
* @throws \Exception
* @throws \SmartyException
*/
public function endChild(Smarty_Internal_Template $tpl, $template = null, $uid = null, $func = null) {
--$this->inheritanceLevel;
if (!$this->inheritanceLevel) {
ob_end_clean();
$this->state = 2;
}
if (isset($template) && (($tpl->parent->_isTplObj() && $tpl->parent->source->type !== 'extends')
|| $tpl->smarty->extends_recursion)
) {
$tpl->_subTemplateRender(
$template,
$tpl->cache_id,
$tpl->compile_id,
$tpl->caching ? 9999 : 0,
$tpl->cache_lifetime,
[],
2,
false,
$uid,
$func
);
}
}
/**
* \Smarty\Block constructor.
* - if outer level {block} of child template ($state === 1) save it as child root block
* - otherwise process inheritance and render
*
* @param \Smarty_Internal_Template $tpl
* @param $className
* @param string $name
* @param int|null $tplIndex index of outer level {block} if nested
*
* @throws \SmartyException
*/
public function instanceBlock(Smarty_Internal_Template $tpl, $className, $name, $tplIndex = null) {
$block = new $className($name, isset($tplIndex) ? $tplIndex : $this->tplIndex);
if (isset($this->childRoot[$name])) {
$block->child = $this->childRoot[$name];
}
if ($this->state === 1) {
$this->childRoot[$name] = $block;
return;
}
// make sure we got child block of child template of current block
while ($block->child && $block->child->child && $block->tplIndex <= $block->child->tplIndex) {
$block->child = $block->child->child;
}
$this->process($tpl, $block);
}
/**
* Goto child block or render this
*
* @param Smarty_Internal_Template $tpl
* @param \Smarty\Block $block
* @param \Smarty\Block|null $parent
*
* @throws SmartyException
*/
public function process(
Smarty_Internal_Template $tpl,
\Smarty\Block $block,
\Smarty\Block $parent = null
) {
if ($block->hide && !isset($block->child)) {
return;
}
if (isset($block->child) && $block->child->hide && !isset($block->child->child)) {
$block->child = null;
}
$block->parent = $parent;
if ($block->append && !$block->prepend && isset($parent)) {
$this->callParent($tpl, $block, '\'{block append}\'');
}
if ($block->callsChild || !isset($block->child) || ($block->child->hide && !isset($block->child->child))) {
$this->callBlock($block, $tpl);
} else {
$this->process($tpl, $block->child, $block);
}
if ($block->prepend && isset($parent)) {
$this->callParent($tpl, $block, '{block prepend}');
if ($block->append) {
if ($block->callsChild || !isset($block->child)
|| ($block->child->hide && !isset($block->child->child))
) {
$this->callBlock($block, $tpl);
} else {
$this->process($tpl, $block->child, $block);
}
}
}
$block->parent = null;
}
/**
* Render child on \$smarty.block.child
*
* @param Smarty_Internal_Template $tpl
* @param \Smarty\Block $block
*
* @return null|string block content
* @throws SmartyException
*/
public function callChild(Smarty_Internal_Template $tpl, \Smarty\Block $block) {
if (isset($block->child)) {
$this->process($tpl, $block->child, $block);
}
}
/**
* Render parent block on \$smarty.block.parent or {block append/prepend}
*
* @param Smarty_Internal_Template $tpl
* @param \Smarty\Block $block
* @param string $tag
*
* @return null|string block content
* @throws SmartyException
*/
public function callParent(Smarty_Internal_Template $tpl, \Smarty\Block $block, $tag) {
if (isset($block->parent)) {
$this->callBlock($block->parent, $tpl);
} else {
throw new SmartyException("inheritance: illegal '{$tag}' used in child template '{$tpl->inheritance->sources[$block->tplIndex]->filepath}' block '{$block->name}'");
}
}
/**
* render block
*
* @param \Smarty\Block $block
* @param Smarty_Internal_Template $tpl
*/
public function callBlock(\Smarty\Block $block, Smarty_Internal_Template $tpl) {
$this->sourceStack[] = $tpl->source;
$tpl->source = $this->sources[$block->tplIndex];
$block->callBlock($tpl);
$tpl->source = array_pop($this->sourceStack);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Smarty\Runtime;
use Smarty_Internal_Template;
/**
* {make_nocache} Runtime Methods save(), store()
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
class MakeNocacheRuntime {
/**
* Save current variable value while rendering compiled template and inject nocache code to
* assign variable value in cached template
*
* @param \Smarty_Internal_Template $tpl
* @param string $var variable name
*
* @throws \SmartyException
*/
public function save(Smarty_Internal_Template $tpl, $var) {
if (isset($tpl->tpl_vars[$var])) {
$export =
preg_replace('/^\\\\Smarty\\\\Variable::__set_state[(]|[)]$/', '', var_export($tpl->tpl_vars[$var], true));
if (preg_match('/(\w+)::__set_state/', $export, $match)) {
throw new SmartyException("{make_nocache \${$var}} in template '{$tpl->source->name}': variable does contain object '{$match[1]}' not implementing method '__set_state'");
}
echo "/*%%SmartyNocache:{$tpl->compiled->nocache_hash}%%*/<?php " .
addcslashes("\$_smarty_tpl->smarty->getRuntime('MakeNocache')->store(\$_smarty_tpl, '{$var}', ", '\\') .
$export . ");?>\n/*/%%SmartyNocache:{$tpl->compiled->nocache_hash}%%*/";
}
}
/**
* Store variable value saved while rendering compiled template in cached template context
*
* @param \Smarty_Internal_Template $tpl
* @param string $var variable name
* @param array $properties
*/
public function store(Smarty_Internal_Template $tpl, $var, $properties) {
// do not overwrite existing nocache variables
if (!isset($tpl->tpl_vars[$var]) || !$tpl->tpl_vars[$var]->nocache) {
$newVar = new \Smarty\Variable();
unset($properties['nocache']);
foreach ($properties as $k => $v) {
$newVar->$k = $v;
}
$tpl->tpl_vars[$var] = $newVar;
}
}
}

View File

@@ -0,0 +1,173 @@
<?php
namespace Smarty\Runtime;
use Smarty_Internal_Template;
use Smarty_Internal_TemplateBase;
/**
* TplFunction Runtime Methods callTemplateFunction
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
**/
class TplFunctionRuntime {
/**
* Call template function
*
* @param \Smarty_Internal_Template $tpl template object
* @param string $name template function name
* @param array $params parameter array
* @param bool $nocache true if called nocache
*
* @throws \SmartyException
*/
public function callTemplateFunction(Smarty_Internal_Template $tpl, $name, $params, $nocache) {
$funcParam = $tpl->tplFunctions[$name] ?? ($tpl->smarty->tplFunctions[$name] ?? null);
if (isset($funcParam)) {
if (!$tpl->caching || ($tpl->caching && $nocache)) {
$function = $funcParam['call_name'];
} else {
if (isset($funcParam['call_name_caching'])) {
$function = $funcParam['call_name_caching'];
} else {
$function = $funcParam['call_name'];
}
}
if (function_exists($function)) {
$this->saveTemplateVariables($tpl, $name);
$function($tpl, $params);
$this->restoreTemplateVariables($tpl, $name);
return;
}
// try to load template function dynamically
if ($this->addTplFuncToCache($tpl, $name, $function)) {
$this->saveTemplateVariables($tpl, $name);
$function($tpl, $params);
$this->restoreTemplateVariables($tpl, $name);
return;
}
}
throw new SmartyException("Unable to find template function '{$name}'");
}
/**
* Register template functions defined by template
*
* @param \Smarty|\Smarty_Internal_Template|\Smarty_Internal_TemplateBase $obj
* @param array $tplFunctions source information array of
* template functions defined
* in template
* @param bool $override if true replace existing
* functions with same name
*/
public function registerTplFunctions(Smarty_Internal_TemplateBase $obj, $tplFunctions, $override = true) {
$obj->tplFunctions =
$override ? array_merge($obj->tplFunctions, $tplFunctions) : array_merge($tplFunctions, $obj->tplFunctions);
// make sure that the template functions are known in parent templates
if ($obj->_isSubTpl()) {
$this->registerTplFunctions($obj->parent, $tplFunctions, false);
} else {
$obj->smarty->tplFunctions = $override ? array_merge($obj->smarty->tplFunctions, $tplFunctions) :
array_merge($tplFunctions, $obj->smarty->tplFunctions);
}
}
/**
* Return source parameter array for single or all template functions
*
* @param \Smarty_Internal_Template $tpl template object
* @param null|string $name template function name
*
* @return array|bool|mixed
*/
public function getTplFunction(Smarty_Internal_Template $tpl, $name = null) {
if (isset($name)) {
return $tpl->tplFunctions[$name] ?? ($tpl->smarty->tplFunctions[$name] ?? false);
} else {
return empty($tpl->tplFunctions) ? $tpl->smarty->tplFunctions : $tpl->tplFunctions;
}
}
/**
* Add template function to cache file for nocache calls
*
* @param Smarty_Internal_Template $tpl
* @param string $_name template function name
* @param string $_function PHP function name
*
* @return bool
*/
public function addTplFuncToCache(Smarty_Internal_Template $tpl, $_name, $_function) {
$funcParam = $tpl->tplFunctions[$_name];
if (is_file($funcParam['compiled_filepath'])) {
// read compiled file
$code = file_get_contents($funcParam['compiled_filepath']);
// grab template function
if (preg_match("/\/\* {$_function} \*\/([\S\s]*?)\/\*\/ {$_function} \*\//", $code, $match)) {
// grab source info from file dependency
preg_match("/\s*'{$funcParam['uid']}'([\S\s]*?)\),/", $code, $match1);
unset($code);
// make PHP function known
eval($match[0]);
if (function_exists($_function)) {
// search cache file template
$tplPtr = $tpl;
while (!isset($tplPtr->cached) && isset($tplPtr->parent)) {
$tplPtr = $tplPtr->parent;
}
// add template function code to cache file
if (isset($tplPtr->cached)) {
$content = $tplPtr->cached->readCache($tplPtr);
if ($content) {
// check if we must update file dependency
if (!preg_match("/'{$funcParam['uid']}'(.*?)'nocache_hash'/", $content, $match2)) {
$content = preg_replace("/('file_dependency'(.*?)\()/", "\\1{$match1[0]}", $content);
}
$tplPtr->cached->writeCache(
$tplPtr,
preg_replace('/\s*\?>\s*$/', "\n", $content) .
"\n" . preg_replace(
[
'/^\s*<\?php\s+/',
'/\s*\?>\s*$/',
],
"\n",
$match[0]
)
);
}
}
return true;
}
}
}
return false;
}
/**
* Save current template variables on stack
*
* @param \Smarty_Internal_Template $tpl
* @param string $name stack name
*/
public function saveTemplateVariables(Smarty_Internal_Template $tpl, $name) {
$tpl->_var_stack[] =
['tpl' => $tpl->tpl_vars, 'config' => $tpl->config_vars, 'name' => "_tplFunction_{$name}"];
}
/**
* Restore saved variables into template objects
*
* @param \Smarty_Internal_Template $tpl
* @param string $name stack name
*/
public function restoreTemplateVariables(Smarty_Internal_Template $tpl, $name) {
if (isset($tpl->_var_stack)) {
$vars = array_pop($tpl->_var_stack);
$tpl->tpl_vars = $vars['tpl'];
$tpl->config_vars = $vars['config'];
}
}
}

View File

@@ -1,68 +0,0 @@
<?php
/**
* Inline Runtime Methods render, setSourceByUid, setupSubTemplate
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
**/
class Smarty_Internal_Runtime_CacheModify
{
/**
* check client side cache
*
* @param \Smarty_Template_Cached $cached
* @param \Smarty_Internal_Template $_template
* @param string $content
*
* @throws \Exception
* @throws \SmartyException
*/
public function cacheModifiedCheck(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template, $content)
{
$_isCached = $_template->isCached() && !$_template->compiled->has_nocache_code;
$_last_modified_date =
@substr($_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ], 0, strpos($_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ], 'GMT') + 3);
if ($_isCached && $cached->timestamp <= strtotime($_last_modified_date)) {
switch (PHP_SAPI) {
case 'cgi': // php-cgi < 5.3
case 'cgi-fcgi': // php-cgi >= 5.3
case 'fpm-fcgi': // php-fpm >= 5.3.3
header('Status: 304 Not Modified');
break;
case 'cli':
if (/* ^phpunit */
!empty($_SERVER[ 'SMARTY_PHPUNIT_DISABLE_HEADERS' ]) /* phpunit$ */
) {
$_SERVER[ 'SMARTY_PHPUNIT_HEADERS' ][] = '304 Not Modified';
}
break;
default:
if (/* ^phpunit */
!empty($_SERVER[ 'SMARTY_PHPUNIT_DISABLE_HEADERS' ]) /* phpunit$ */
) {
$_SERVER[ 'SMARTY_PHPUNIT_HEADERS' ][] = '304 Not Modified';
} else {
header($_SERVER[ 'SERVER_PROTOCOL' ] . ' 304 Not Modified');
}
break;
}
} else {
switch (PHP_SAPI) {
case 'cli':
if (/* ^phpunit */
!empty($_SERVER[ 'SMARTY_PHPUNIT_DISABLE_HEADERS' ]) /* phpunit$ */
) {
$_SERVER[ 'SMARTY_PHPUNIT_HEADERS' ][] =
'Last-Modified: ' . gmdate('D, d M Y H:i:s', $cached->timestamp) . ' GMT';
}
break;
default:
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $cached->timestamp) . ' GMT');
break;
}
echo $content;
}
}
}

View File

@@ -1,139 +0,0 @@
<?php
/**
* Smarty cache resource file clear method
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
/**
* Smarty Internal Runtime Cache Resource File Class
*
* @package Smarty
* @subpackage PluginsInternal
*/
class Smarty_Internal_Runtime_CacheResourceFile
{
/**
* Empty cache for a specific template
*
* @param Smarty $smarty
* @param string $resource_name template name
* @param string $cache_id cache id
* @param string $compile_id compile id
* @param integer $exp_time expiration time (number of seconds, not timestamp)
*
* @return integer number of cache files deleted
*/
public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time)
{
$_cache_id = isset($cache_id) ? preg_replace('![^\w\|]+!', '_', $cache_id) : null;
$_compile_id = isset($compile_id) ? preg_replace('![^\w]+!', '_', $compile_id) : null;
$_dir_sep = $smarty->use_sub_dirs ? '/' : '^';
$_compile_id_offset = $smarty->use_sub_dirs ? 3 : 0;
$_dir = $smarty->getCacheDir();
if ($_dir === '/') { //We should never want to delete this!
return 0;
}
$_dir_length = strlen($_dir);
if (isset($_cache_id)) {
$_cache_id_parts = explode('|', $_cache_id);
$_cache_id_parts_count = count($_cache_id_parts);
if ($smarty->use_sub_dirs) {
foreach ($_cache_id_parts as $id_part) {
$_dir .= $id_part . '/';
}
}
}
if (isset($resource_name)) {
$_save_stat = $smarty->caching;
$smarty->caching = \Smarty\Smarty::CACHING_LIFETIME_CURRENT;
$tpl = new $smarty->template_class($resource_name, $smarty);
$smarty->caching = $_save_stat;
// remove from template cache
$tpl->source; // have the template registered before unset()
if ($tpl->source->exists) {
$_resourcename_parts = basename(str_replace('^', '/', $tpl->cached->filepath));
} else {
return 0;
}
}
$_count = 0;
$_time = time();
if (file_exists($_dir)) {
$_cacheDirs = new RecursiveDirectoryIterator($_dir);
$_cache = new RecursiveIteratorIterator($_cacheDirs, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($_cache as $_file) {
if (substr(basename($_file->getPathname()), 0, 1) === '.') {
continue;
}
$_filepath = (string)$_file;
// directory ?
if ($_file->isDir()) {
if (!$_cache->isDot()) {
// delete folder if empty
@rmdir($_file->getPathname());
}
} else {
// delete only php files
if (substr($_filepath, -4) !== '.php') {
continue;
}
$_parts = explode($_dir_sep, str_replace('\\', '/', substr($_filepath, $_dir_length)));
$_parts_count = count($_parts);
// check name
if (isset($resource_name)) {
if ($_parts[ $_parts_count - 1 ] !== $_resourcename_parts) {
continue;
}
}
// check compile id
if (isset($_compile_id) && (!isset($_parts[ $_parts_count - 2 - $_compile_id_offset ])
|| $_parts[ $_parts_count - 2 - $_compile_id_offset ] !== $_compile_id)
) {
continue;
}
// check cache id
if (isset($_cache_id)) {
// count of cache id parts
$_parts_count = (isset($_compile_id)) ? $_parts_count - 2 - $_compile_id_offset :
$_parts_count - 1 - $_compile_id_offset;
if ($_parts_count < $_cache_id_parts_count) {
continue;
}
for ($i = 0; $i < $_cache_id_parts_count; $i++) {
if ($_parts[ $i ] !== $_cache_id_parts[ $i ]) {
continue 2;
}
}
}
if (is_file($_filepath)) {
// expired ?
if (isset($exp_time)) {
if ($exp_time < 0) {
preg_match('#\'cache_lifetime\' =>\s*(\d*)#', file_get_contents($_filepath), $match);
if ($_time < (filemtime($_filepath) + $match[ 1 ])) {
continue;
}
} else {
if ($_time - filemtime($_filepath) < $exp_time) {
continue;
}
}
}
$_count += @unlink($_filepath) ? 1 : 0;
if (function_exists('opcache_invalidate')
&& (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api")) < 1)
) {
opcache_invalidate($_filepath, true);
} elseif (function_exists('apc_delete_file')) {
apc_delete_file($_filepath);
}
}
}
}
}
return $_count;
}
}

View File

@@ -1,168 +0,0 @@
<?php
/**
* Runtime Extension Capture
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
class Smarty_Internal_Runtime_Capture
{
/**
* Stack of capture parameter
*
* @var array
*/
private $captureStack = array();
/**
* Current open capture sections
*
* @var int
*/
private $captureCount = 0;
/**
* Count stack
*
* @var int[]
*/
private $countStack = array();
/**
* Named buffer
*
* @var string[]
*/
private $namedBuffer = array();
/**
* Flag if callbacks are registered
*
* @var bool
*/
private $isRegistered = false;
/**
* Open capture section
*
* @param \Smarty_Internal_Template $_template
* @param string $buffer capture name
* @param string $assign variable name
* @param string $append variable name
*/
public function open(Smarty_Internal_Template $_template, $buffer, $assign, $append)
{
if (!$this->isRegistered) {
$this->register($_template);
}
$this->captureStack[] = array(
$buffer,
$assign,
$append
);
$this->captureCount++;
ob_start();
}
/**
* Register callbacks in template class
*
* @param \Smarty_Internal_Template $_template
*/
private function register(Smarty_Internal_Template $_template)
{
$_template->startRenderCallbacks[] = array(
$this,
'startRender'
);
$_template->endRenderCallbacks[] = array(
$this,
'endRender'
);
$this->startRender($_template);
$this->isRegistered = true;
}
/**
* Start render callback
*
* @param \Smarty_Internal_Template $_template
*/
public function startRender(Smarty_Internal_Template $_template)
{
$this->countStack[] = $this->captureCount;
$this->captureCount = 0;
}
/**
* Close capture section
*
* @param \Smarty_Internal_Template $_template
*
* @throws \SmartyException
*/
public function close(Smarty_Internal_Template $_template)
{
if ($this->captureCount) {
list($buffer, $assign, $append) = array_pop($this->captureStack);
$this->captureCount--;
if (isset($assign)) {
$_template->assign($assign, ob_get_contents());
}
if (isset($append)) {
$_template->append($append, ob_get_contents());
}
$this->namedBuffer[ $buffer ] = ob_get_clean();
} else {
$this->error($_template);
}
}
/**
* Error exception on not matching {capture}{/capture}
*
* @param \Smarty_Internal_Template $_template
*
* @throws \SmartyException
*/
public function error(Smarty_Internal_Template $_template)
{
throw new SmartyException("Not matching {capture}{/capture} in '{$_template->template_resource}'");
}
/**
* Return content of named capture buffer by key or as array
*
* @param \Smarty_Internal_Template $_template
* @param string|null $name
*
* @return string|string[]|null
*/
public function getBuffer(Smarty_Internal_Template $_template, $name = null)
{
if (isset($name)) {
return isset($this->namedBuffer[ $name ]) ? $this->namedBuffer[ $name ] : null;
} else {
return $this->namedBuffer;
}
}
/**
* End render callback
*
* @param \Smarty_Internal_Template $_template
*
* @throws \SmartyException
*/
public function endRender(Smarty_Internal_Template $_template)
{
if ($this->captureCount) {
$this->error($_template);
} else {
$this->captureCount = array_pop($this->countStack);
}
}
}

View File

@@ -1,44 +0,0 @@
<?php
/**
* Smarty Internal Plugin Filter Handler
* Smarty filter handler class
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
/**
* Class for filter processing
*
* @package Smarty
* @subpackage PluginsInternal
*/
class Smarty_Internal_Runtime_FilterHandler
{
/**
* Run filters over content
* The filters will be lazy loaded if required
* class name format: Smarty_FilterType_FilterName
* plugin filename format: filtertype.filtername.php
* Smarty2 filter plugins could be used
*
* @param string $type the type of filter ('pre','post','output') which shall run
* @param string $content the content which shall be processed by the filters
* @param Smarty_Internal_Template $template template object
*
* @throws SmartyException
* @return string the filtered content
*/
public function runFilter($type, $content, Smarty_Internal_Template $template)
{
// loop over registered filters of specified type
if (!empty($template->smarty->registered_filters[ $type ])) {
foreach ($template->smarty->registered_filters[ $type ] as $key => $name) {
$content = call_user_func($template->smarty->registered_filters[ $type ][ $key ], $content, $template);
}
}
// return filtered output
return $content;
}
}

View File

@@ -1,162 +0,0 @@
<?php
/**
* Foreach Runtime Methods count(), init(), restore()
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
class Smarty_Internal_Runtime_Foreach
{
/**
* Stack of saved variables
*
* @var array
*/
private $stack = array();
/**
* Init foreach loop
* - save item and key variables, named foreach property data if defined
* - init item and key variables, named foreach property data if required
* - count total if required
*
* @param \Smarty_Internal_Template $tpl
* @param mixed $from values to loop over
* @param string $item variable name
* @param bool $needTotal flag if we need to count values
* @param null|string $key variable name
* @param null|string $name of named foreach
* @param array $properties of named foreach
*
* @return mixed $from
*/
public function init(
Smarty_Internal_Template $tpl,
$from,
$item,
$needTotal = false,
$key = null,
$name = null,
$properties = array()
) {
$needTotal = $needTotal || isset($properties[ 'total' ]);
$saveVars = array();
$total = null;
if (!is_array($from)) {
if (is_object($from)) {
if ($needTotal) {
$total = $this->count($from);
}
} else {
settype($from, 'array');
}
}
if (!isset($total)) {
$total = empty($from) ? 0 : ($needTotal ? count($from) : 1);
}
if (isset($tpl->tpl_vars[ $item ])) {
$saveVars[ 'item' ] = array(
$item,
$tpl->tpl_vars[ $item ]
);
}
$tpl->tpl_vars[ $item ] = new \Smarty\Variable(null, $tpl->isRenderingCache);
if ($total === 0) {
$from = null;
} else {
if ($key) {
if (isset($tpl->tpl_vars[ $key ])) {
$saveVars[ 'key' ] = array(
$key,
$tpl->tpl_vars[ $key ]
);
}
$tpl->tpl_vars[ $key ] = new \Smarty\Variable(null, $tpl->isRenderingCache);
}
}
if ($needTotal) {
$tpl->tpl_vars[ $item ]->total = $total;
}
if ($name) {
$namedVar = "__smarty_foreach_{$name}";
if (isset($tpl->tpl_vars[ $namedVar ])) {
$saveVars[ 'named' ] = array(
$namedVar,
$tpl->tpl_vars[ $namedVar ]
);
}
$namedProp = array();
if (isset($properties[ 'total' ])) {
$namedProp[ 'total' ] = $total;
}
if (isset($properties[ 'iteration' ])) {
$namedProp[ 'iteration' ] = 0;
}
if (isset($properties[ 'index' ])) {
$namedProp[ 'index' ] = -1;
}
if (isset($properties[ 'show' ])) {
$namedProp[ 'show' ] = ($total > 0);
}
$tpl->tpl_vars[ $namedVar ] = new \Smarty\Variable($namedProp);
}
$this->stack[] = $saveVars;
return $from;
}
/**
* [util function] counts an array, arrayAccess/traversable or PDOStatement object
*
* @param mixed $value
*
* @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0
* for empty elements
*/
public function count($value)
{
if ($value instanceof IteratorAggregate) {
// Note: getIterator() returns a Traversable, not an Iterator
// thus rewind() and valid() methods may not be present
return iterator_count($value->getIterator());
} elseif ($value instanceof Iterator) {
return $value instanceof Generator ? 1 : iterator_count($value);
} elseif ($value instanceof Countable) {
return count($value);
} elseif ($value instanceof PDOStatement) {
return $value->rowCount();
} elseif ($value instanceof Traversable) {
return iterator_count($value);
}
return count((array)$value);
}
/**
* Restore saved variables
*
* will be called by {break n} or {continue n} for the required number of levels
*
* @param \Smarty_Internal_Template $tpl
* @param int $levels number of levels
*/
public function restore(Smarty_Internal_Template $tpl, $levels = 1)
{
while ($levels) {
$saveVars = array_pop($this->stack);
if (!empty($saveVars)) {
if (isset($saveVars[ 'item' ])) {
$item = &$saveVars[ 'item' ];
$tpl->tpl_vars[ $item[ 0 ] ]->value = $item[ 1 ]->value;
}
if (isset($saveVars[ 'key' ])) {
$tpl->tpl_vars[ $saveVars[ 'key' ][ 0 ] ] = $saveVars[ 'key' ][ 1 ];
}
if (isset($saveVars[ 'named' ])) {
$tpl->tpl_vars[ $saveVars[ 'named' ][ 0 ] ] = $saveVars[ 'named' ][ 1 ];
}
}
$levels--;
}
}
}

View File

@@ -1,181 +0,0 @@
<?php
/**
* Smarty read include path plugin
*
* @package Smarty
* @subpackage PluginsInternal
* @author Monte Ohrt
*/
/**
* Smarty Internal Read Include Path Class
*
* @package Smarty
* @subpackage PluginsInternal
*/
class Smarty_Internal_Runtime_GetIncludePath
{
/**
* include path cache
*
* @var string
*/
public $_include_path = '';
/**
* include path directory cache
*
* @var array
*/
public $_include_dirs = array();
/**
* include path directory cache
*
* @var array
*/
public $_user_dirs = array();
/**
* stream cache
*
* @var string[][]
*/
public $isFile = array();
/**
* stream cache
*
* @var string[]
*/
public $isPath = array();
/**
* stream cache
*
* @var int[]
*/
public $number = array();
/**
* status cache
*
* @var bool
*/
public $_has_stream_include = null;
/**
* Number for array index
*
* @var int
*/
public $counter = 0;
/**
* Check if include path was updated
*
* @param \Smarty $smarty
*
* @return bool
*/
public function isNewIncludePath(Smarty $smarty)
{
$_i_path = get_include_path();
if ($this->_include_path !== $_i_path) {
$this->_include_dirs = array();
$this->_include_path = $_i_path;
$_dirs = (array)explode(PATH_SEPARATOR, $_i_path);
foreach ($_dirs as $_path) {
if (is_dir($_path)) {
$this->_include_dirs[] = $smarty->_realpath($_path . DIRECTORY_SEPARATOR, true);
}
}
return true;
}
return false;
}
/**
* return array with include path directories
*
* @param \Smarty $smarty
*
* @return array
*/
public function getIncludePathDirs(Smarty $smarty)
{
$this->isNewIncludePath($smarty);
return $this->_include_dirs;
}
/**
* Return full file path from PHP include_path
*
* @param string[] $dirs
* @param string $file
* @param \Smarty $smarty
*
* @return bool|string full filepath or false
*/
public function getIncludePath($dirs, $file, Smarty $smarty)
{
//if (!(isset($this->_has_stream_include) ? $this->_has_stream_include : $this->_has_stream_include = false)) {
if (!(isset($this->_has_stream_include) ? $this->_has_stream_include :
$this->_has_stream_include = function_exists('stream_resolve_include_path'))
) {
$this->isNewIncludePath($smarty);
}
// try PHP include_path
foreach ($dirs as $dir) {
$dir_n = isset($this->number[ $dir ]) ? $this->number[ $dir ] : $this->number[ $dir ] = $this->counter++;
if (isset($this->isFile[ $dir_n ][ $file ])) {
if ($this->isFile[ $dir_n ][ $file ]) {
return $this->isFile[ $dir_n ][ $file ];
} else {
continue;
}
}
if (isset($this->_user_dirs[ $dir_n ])) {
if (false === $this->_user_dirs[ $dir_n ]) {
continue;
} else {
$dir = $this->_user_dirs[ $dir_n ];
}
} else {
if ($dir[ 0 ] === '/' || $dir[ 1 ] === ':') {
$dir = str_ireplace(getcwd(), '.', $dir);
if ($dir[ 0 ] === '/' || $dir[ 1 ] === ':') {
$this->_user_dirs[ $dir_n ] = false;
continue;
}
}
$dir = substr($dir, 2);
$this->_user_dirs[ $dir_n ] = $dir;
}
if ($this->_has_stream_include) {
$path = stream_resolve_include_path($dir . (isset($file) ? $file : ''));
if ($path) {
return $this->isFile[ $dir_n ][ $file ] = $path;
}
} else {
foreach ($this->_include_dirs as $key => $_i_path) {
$path = isset($this->isPath[ $key ][ $dir_n ]) ? $this->isPath[ $key ][ $dir_n ] :
$this->isPath[ $key ][ $dir_n ] = is_dir($_dir_path = $_i_path . $dir) ? $_dir_path : false;
if ($path === false) {
continue;
}
if (isset($file)) {
$_file = $this->isFile[ $dir_n ][ $file ] = (is_file($path . $file)) ? $path . $file : false;
if ($_file) {
return $_file;
}
} else {
// no file was given return directory path
return $path;
}
}
}
}
return false;
}
}

View File

@@ -1,251 +0,0 @@
<?php
/**
* Inheritance Runtime Methods processBlock, endChild, init
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
**/
class Smarty_Internal_Runtime_Inheritance
{
/**
* State machine
* - 0 idle next extends will create a new inheritance tree
* - 1 processing child template
* - 2 wait for next inheritance template
* - 3 assume parent template, if child will loaded goto state 1
* a call to a sub template resets the state to 0
*
* @var int
*/
public $state = 0;
/**
* Array of root child {block} objects
*
* @var \Smarty\Block[]
*/
public $childRoot = array();
/**
* inheritance template nesting level
*
* @var int
*/
public $inheritanceLevel = 0;
/**
* inheritance template index
*
* @var int
*/
public $tplIndex = -1;
/**
* Array of template source objects
*
* @var Smarty_Template_Source[]
*/
public $sources = array();
/**
* Stack of source objects while executing block code
*
* @var Smarty_Template_Source[]
*/
public $sourceStack = array();
/**
* Initialize inheritance
*
* @param \Smarty_Internal_Template $tpl template object of caller
* @param bool $initChild if true init for child template
* @param array $blockNames outer level block name
*/
public function init(Smarty_Internal_Template $tpl, $initChild, $blockNames = array())
{
// if called while executing parent template it must be a sub-template with new inheritance root
if ($initChild && $this->state === 3 && (strpos($tpl->template_resource, 'extendsall') === false)) {
$tpl->inheritance = new Smarty_Internal_Runtime_Inheritance();
$tpl->inheritance->init($tpl, $initChild, $blockNames);
return;
}
++$this->tplIndex;
$this->sources[ $this->tplIndex ] = $tpl->source;
// start of child sub template(s)
if ($initChild) {
$this->state = 1;
if (!$this->inheritanceLevel) {
//grab any output of child templates
ob_start();
}
++$this->inheritanceLevel;
// $tpl->startRenderCallbacks[ 'inheritance' ] = array($this, 'subTemplateStart');
// $tpl->endRenderCallbacks[ 'inheritance' ] = array($this, 'subTemplateEnd');
}
// if state was waiting for parent change state to parent
if ($this->state === 2) {
$this->state = 3;
}
}
/**
* End of child template(s)
* - if outer level is reached flush output buffer and switch to wait for parent template state
*
* @param \Smarty_Internal_Template $tpl
* @param null|string $template optional name of inheritance parent template
* @param null|string $uid uid of inline template
* @param null|string $func function call name of inline template
*
* @throws \Exception
* @throws \SmartyException
*/
public function endChild(Smarty_Internal_Template $tpl, $template = null, $uid = null, $func = null)
{
--$this->inheritanceLevel;
if (!$this->inheritanceLevel) {
ob_end_clean();
$this->state = 2;
}
if (isset($template) && (($tpl->parent->_isTplObj() && $tpl->parent->source->type !== 'extends')
|| $tpl->smarty->extends_recursion)
) {
$tpl->_subTemplateRender(
$template,
$tpl->cache_id,
$tpl->compile_id,
$tpl->caching ? 9999 : 0,
$tpl->cache_lifetime,
array(),
2,
false,
$uid,
$func
);
}
}
/**
* \Smarty\Block constructor.
* - if outer level {block} of child template ($state === 1) save it as child root block
* - otherwise process inheritance and render
*
* @param \Smarty_Internal_Template $tpl
* @param $className
* @param string $name
* @param int|null $tplIndex index of outer level {block} if nested
*
* @throws \SmartyException
*/
public function instanceBlock(Smarty_Internal_Template $tpl, $className, $name, $tplIndex = null)
{
$block = new $className($name, isset($tplIndex) ? $tplIndex : $this->tplIndex);
if (isset($this->childRoot[ $name ])) {
$block->child = $this->childRoot[ $name ];
}
if ($this->state === 1) {
$this->childRoot[ $name ] = $block;
return;
}
// make sure we got child block of child template of current block
while ($block->child && $block->child->child && $block->tplIndex <= $block->child->tplIndex) {
$block->child = $block->child->child;
}
$this->process($tpl, $block);
}
/**
* Goto child block or render this
*
* @param Smarty_Internal_Template $tpl
* @param \Smarty\Block $block
* @param \Smarty\Block|null $parent
*
* @throws SmartyException
*/
public function process(
Smarty_Internal_Template $tpl,
\Smarty\Block $block,
\Smarty\Block $parent = null
) {
if ($block->hide && !isset($block->child)) {
return;
}
if (isset($block->child) && $block->child->hide && !isset($block->child->child)) {
$block->child = null;
}
$block->parent = $parent;
if ($block->append && !$block->prepend && isset($parent)) {
$this->callParent($tpl, $block, '\'{block append}\'');
}
if ($block->callsChild || !isset($block->child) || ($block->child->hide && !isset($block->child->child))) {
$this->callBlock($block, $tpl);
} else {
$this->process($tpl, $block->child, $block);
}
if ($block->prepend && isset($parent)) {
$this->callParent($tpl, $block, '{block prepend}');
if ($block->append) {
if ($block->callsChild || !isset($block->child)
|| ($block->child->hide && !isset($block->child->child))
) {
$this->callBlock($block, $tpl);
} else {
$this->process($tpl, $block->child, $block);
}
}
}
$block->parent = null;
}
/**
* Render child on \$smarty.block.child
*
* @param Smarty_Internal_Template $tpl
* @param \Smarty\Block $block
*
* @return null|string block content
* @throws SmartyException
*/
public function callChild(Smarty_Internal_Template $tpl, \Smarty\Block $block)
{
if (isset($block->child)) {
$this->process($tpl, $block->child, $block);
}
}
/**
* Render parent block on \$smarty.block.parent or {block append/prepend}
*
* @param Smarty_Internal_Template $tpl
* @param \Smarty\Block $block
* @param string $tag
*
* @return null|string block content
* @throws SmartyException
*/
public function callParent(Smarty_Internal_Template $tpl, \Smarty\Block $block, $tag)
{
if (isset($block->parent)) {
$this->callBlock($block->parent, $tpl);
} else {
throw new SmartyException("inheritance: illegal '{$tag}' used in child template '{$tpl->inheritance->sources[$block->tplIndex]->filepath}' block '{$block->name}'");
}
}
/**
* render block
*
* @param \Smarty\Block $block
* @param Smarty_Internal_Template $tpl
*/
public function callBlock(\Smarty\Block $block, Smarty_Internal_Template $tpl)
{
$this->sourceStack[] = $tpl->source;
$tpl->source = $this->sources[ $block->tplIndex ];
$block->callBlock($tpl);
$tpl->source = array_pop($this->sourceStack);
}
}

View File

@@ -1,54 +0,0 @@
<?php
/**
* {make_nocache} Runtime Methods save(), store()
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
class Smarty_Internal_Runtime_Make_Nocache
{
/**
* Save current variable value while rendering compiled template and inject nocache code to
* assign variable value in cahed template
*
* @param \Smarty_Internal_Template $tpl
* @param string $var variable name
*
* @throws \SmartyException
*/
public function save(Smarty_Internal_Template $tpl, $var)
{
if (isset($tpl->tpl_vars[ $var ])) {
$export =
preg_replace('/^\\\\Smarty\\\\Variable::__set_state[(]|[)]$/', '', var_export($tpl->tpl_vars[ $var ], true));
if (preg_match('/(\w+)::__set_state/', $export, $match)) {
throw new SmartyException("{make_nocache \${$var}} in template '{$tpl->source->name}': variable does contain object '{$match[1]}' not implementing method '__set_state'");
}
echo "/*%%SmartyNocache:{$tpl->compiled->nocache_hash}%%*/<?php " .
addcslashes("\$_smarty_tpl->smarty->ext->_make_nocache->store(\$_smarty_tpl, '{$var}', ", '\\') .
$export . ");?>\n/*/%%SmartyNocache:{$tpl->compiled->nocache_hash}%%*/";
}
}
/**
* Store variable value saved while rendering compiled template in cached template context
*
* @param \Smarty_Internal_Template $tpl
* @param string $var variable name
* @param array $properties
*/
public function store(Smarty_Internal_Template $tpl, $var, $properties)
{
// do not overwrite existing nocache variables
if (!isset($tpl->tpl_vars[ $var ]) || !$tpl->tpl_vars[ $var ]->nocache) {
$newVar = new \Smarty\Variable();
unset($properties[ 'nocache' ]);
foreach ($properties as $k => $v) {
$newVar->$k = $v;
}
$tpl->tpl_vars[ $var ] = $newVar;
}
}
}

View File

@@ -1,177 +0,0 @@
<?php
/**
* TplFunction Runtime Methods callTemplateFunction
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
**/
class Smarty_Internal_Runtime_TplFunction
{
/**
* Call template function
*
* @param \Smarty_Internal_Template $tpl template object
* @param string $name template function name
* @param array $params parameter array
* @param bool $nocache true if called nocache
*
* @throws \SmartyException
*/
public function callTemplateFunction(Smarty_Internal_Template $tpl, $name, $params, $nocache)
{
$funcParam = isset($tpl->tplFunctions[ $name ]) ? $tpl->tplFunctions[ $name ] :
(isset($tpl->smarty->tplFunctions[ $name ]) ? $tpl->smarty->tplFunctions[ $name ] : null);
if (isset($funcParam)) {
if (!$tpl->caching || ($tpl->caching && $nocache)) {
$function = $funcParam[ 'call_name' ];
} else {
if (isset($funcParam[ 'call_name_caching' ])) {
$function = $funcParam[ 'call_name_caching' ];
} else {
$function = $funcParam[ 'call_name' ];
}
}
if (function_exists($function)) {
$this->saveTemplateVariables($tpl, $name);
$function($tpl, $params);
$this->restoreTemplateVariables($tpl, $name);
return;
}
// try to load template function dynamically
if ($this->addTplFuncToCache($tpl, $name, $function)) {
$this->saveTemplateVariables($tpl, $name);
$function($tpl, $params);
$this->restoreTemplateVariables($tpl, $name);
return;
}
}
throw new SmartyException("Unable to find template function '{$name}'");
}
/**
* Register template functions defined by template
*
* @param \Smarty|\Smarty_Internal_Template|\Smarty_Internal_TemplateBase $obj
* @param array $tplFunctions source information array of
* template functions defined
* in template
* @param bool $override if true replace existing
* functions with same name
*/
public function registerTplFunctions(Smarty_Internal_TemplateBase $obj, $tplFunctions, $override = true)
{
$obj->tplFunctions =
$override ? array_merge($obj->tplFunctions, $tplFunctions) : array_merge($tplFunctions, $obj->tplFunctions);
// make sure that the template functions are known in parent templates
if ($obj->_isSubTpl()) {
$obj->smarty->ext->_tplFunction->registerTplFunctions($obj->parent, $tplFunctions, false);
} else {
$obj->smarty->tplFunctions = $override ? array_merge($obj->smarty->tplFunctions, $tplFunctions) :
array_merge($tplFunctions, $obj->smarty->tplFunctions);
}
}
/**
* Return source parameter array for single or all template functions
*
* @param \Smarty_Internal_Template $tpl template object
* @param null|string $name template function name
*
* @return array|bool|mixed
*/
public function getTplFunction(Smarty_Internal_Template $tpl, $name = null)
{
if (isset($name)) {
return isset($tpl->tplFunctions[ $name ]) ? $tpl->tplFunctions[ $name ] :
(isset($tpl->smarty->tplFunctions[ $name ]) ? $tpl->smarty->tplFunctions[ $name ] : false);
} else {
return empty($tpl->tplFunctions) ? $tpl->smarty->tplFunctions : $tpl->tplFunctions;
}
}
/**
* Add template function to cache file for nocache calls
*
* @param Smarty_Internal_Template $tpl
* @param string $_name template function name
* @param string $_function PHP function name
*
* @return bool
*/
public function addTplFuncToCache(Smarty_Internal_Template $tpl, $_name, $_function)
{
$funcParam = $tpl->tplFunctions[ $_name ];
if (is_file($funcParam[ 'compiled_filepath' ])) {
// read compiled file
$code = file_get_contents($funcParam[ 'compiled_filepath' ]);
// grab template function
if (preg_match("/\/\* {$_function} \*\/([\S\s]*?)\/\*\/ {$_function} \*\//", $code, $match)) {
// grab source info from file dependency
preg_match("/\s*'{$funcParam['uid']}'([\S\s]*?)\),/", $code, $match1);
unset($code);
// make PHP function known
eval($match[ 0 ]);
if (function_exists($_function)) {
// search cache file template
$tplPtr = $tpl;
while (!isset($tplPtr->cached) && isset($tplPtr->parent)) {
$tplPtr = $tplPtr->parent;
}
// add template function code to cache file
if (isset($tplPtr->cached)) {
$content = $tplPtr->cached->read($tplPtr);
if ($content) {
// check if we must update file dependency
if (!preg_match("/'{$funcParam['uid']}'(.*?)'nocache_hash'/", $content, $match2)) {
$content = preg_replace("/('file_dependency'(.*?)\()/", "\\1{$match1[0]}", $content);
}
$tplPtr->smarty->ext->_updateCache->write(
$tplPtr,
preg_replace('/\s*\?>\s*$/', "\n", $content) .
"\n" . preg_replace(
array(
'/^\s*<\?php\s+/',
'/\s*\?>\s*$/',
),
"\n",
$match[ 0 ]
)
);
}
}
return true;
}
}
}
return false;
}
/**
* Save current template variables on stack
*
* @param \Smarty_Internal_Template $tpl
* @param string $name stack name
*/
public function saveTemplateVariables(Smarty_Internal_Template $tpl, $name)
{
$tpl->_var_stack[] =
array('tpl' => $tpl->tpl_vars, 'config' => $tpl->config_vars, 'name' => "_tplFunction_{$name}");
}
/**
* Restore saved variables into template objects
*
* @param \Smarty_Internal_Template $tpl
* @param string $name stack name
*/
public function restoreTemplateVariables(Smarty_Internal_Template $tpl, $name)
{
if (isset($tpl->_var_stack)) {
$vars = array_pop($tpl->_var_stack);
$tpl->tpl_vars = $vars[ 'tpl' ];
$tpl->config_vars = $vars[ 'config' ];
}
}
}

View File

@@ -1,184 +0,0 @@
<?php
/**
* Inline Runtime Methods render, setSourceByUid, setupSubTemplate
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
**/
class Smarty_Internal_Runtime_UpdateCache
{
/**
* check client side cache
*
* @param \Smarty_Template_Cached $cached
* @param Smarty_Internal_Template $_template
* @param string $content
*/
public function cacheModifiedCheck(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template, $content)
{
}
/**
* Cache was invalid , so render from compiled and write to cache
*
* @param \Smarty_Template_Cached $cached
* @param \Smarty_Internal_Template $_template
* @param $no_output_filter
*
* @throws \Exception
*/
public function updateCache(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template, $no_output_filter)
{
ob_start();
if (!isset($_template->compiled)) {
$_template->loadCompiled();
}
$_template->compiled->render($_template);
if ($_template->smarty->debugging) {
$_template->smarty->_debug->start_cache($_template);
}
$this->removeNoCacheHash($cached, $_template, $no_output_filter);
$compile_check = (int)$_template->compile_check;
$_template->compile_check = \Smarty\Smarty::COMPILECHECK_OFF;
if ($_template->_isSubTpl()) {
$_template->compiled->unifunc = $_template->parent->compiled->unifunc;
}
if (!$_template->cached->processed) {
$_template->cached->process($_template, true);
}
$_template->compile_check = $compile_check;
$cached->getRenderedTemplateCode($_template);
if ($_template->smarty->debugging) {
$_template->smarty->_debug->end_cache($_template);
}
}
/**
* Sanitize content and write it to cache resource
*
* @param \Smarty_Template_Cached $cached
* @param Smarty_Internal_Template $_template
* @param bool $no_output_filter
*
* @throws \SmartyException
*/
private function removeNoCacheHash(
Smarty_Template_Cached $cached,
Smarty_Internal_Template $_template,
$no_output_filter
) {
$php_pattern = '/(<%|%>|<\?php|<\?|\?>|<script\s+language\s*=\s*[\"\']?\s*php\s*[\"\']?\s*>)/';
$content = ob_get_clean();
$hash_array = $cached->hashes;
$hash_array[ $_template->compiled->nocache_hash ] = true;
$hash_array = array_keys($hash_array);
$nocache_hash = '(' . implode('|', $hash_array) . ')';
$_template->cached->has_nocache_code = false;
// get text between non-cached items
$cache_split =
preg_split(
"!/\*%%SmartyNocache:{$nocache_hash}%%\*\/(.+?)/\*/%%SmartyNocache:{$nocache_hash}%%\*/!s",
$content
);
// get non-cached items
preg_match_all(
"!/\*%%SmartyNocache:{$nocache_hash}%%\*\/(.+?)/\*/%%SmartyNocache:{$nocache_hash}%%\*/!s",
$content,
$cache_parts
);
$content = '';
// loop over items, stitch back together
foreach ($cache_split as $curr_idx => $curr_split) {
if (preg_match($php_pattern, $curr_split)) {
// escape PHP tags in template content
$php_split = preg_split(
$php_pattern,
$curr_split
);
preg_match_all(
$php_pattern,
$curr_split,
$php_parts
);
foreach ($php_split as $idx_php => $curr_php) {
$content .= $curr_php;
if (isset($php_parts[ 0 ][ $idx_php ])) {
$content .= "<?php echo '{$php_parts[ 1 ][ $idx_php ]}'; ?>\n";
}
}
} else {
$content .= $curr_split;
}
if (isset($cache_parts[ 0 ][ $curr_idx ])) {
$_template->cached->has_nocache_code = true;
$content .= $cache_parts[ 2 ][ $curr_idx ];
}
}
if (
!$no_output_filter
&& !$_template->cached->has_nocache_code
&& isset($_template->smarty->registered_filters[ 'output' ])
) {
$content = $_template->smarty->ext->_filterHandler->runFilter('output', $content, $_template);
}
// write cache file content
$this->writeCachedContent($_template, $content);
}
/**
* Writes the content to cache resource
*
* @param Smarty_Internal_Template $_template
* @param string $content
*
* @return bool
*/
public function writeCachedContent(Smarty_Internal_Template $_template, $content)
{
if ($_template->source->handler->recompiled || !$_template->caching
) {
// don't write cache file
return false;
}
if (!isset($_template->cached)) {
$_template->loadCached();
}
$content = $_template->createCodeFrame($content, '', true);
return $this->write($_template, $content);
}
/**
* Write this cache object to handler
*
* @param Smarty_Internal_Template $_template template object
* @param string $content content to cache
*
* @return bool success
*/
public function write(Smarty_Internal_Template $_template, $content)
{
if (!$_template->source->handler->recompiled) {
$cached = $_template->cached;
if ($cached->handler->writeCachedContent($_template, $content)) {
$cached->content = null;
$cached->timestamp = time();
$cached->exists = true;
$cached->valid = true;
$cached->cache_lifetime = $_template->cache_lifetime;
$cached->processed = false;
if ($_template->smarty->cache_locking) {
$cached->handler->releaseLock($_template->smarty, $cached);
}
return true;
}
$cached->content = null;
$cached->timestamp = false;
$cached->exists = false;
$cached->valid = false;
$cached->processed = false;
}
return false;
}
}

View File

@@ -1,115 +0,0 @@
<?php
/**
* Runtime Extension updateScope
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
**/
class Smarty_Internal_Runtime_UpdateScope
{
/**
* Update new assigned template or config variable in other effected scopes
*
* @param Smarty_Internal_Template $tpl data object
* @param string|null $varName variable name
* @param int $tagScope tag scope to which bubble up variable value
*/
public function _updateScope(Smarty_Internal_Template $tpl, $varName, $tagScope = 0)
{
if ($tagScope) {
$this->_updateVarStack($tpl, $varName);
$tagScope = $tagScope & ~\Smarty\Smarty::SCOPE_LOCAL;
if (!$tpl->scope && !$tagScope) {
return;
}
}
$mergedScope = $tagScope | $tpl->scope;
if ($mergedScope) {
if ($mergedScope & \Smarty\Smarty::SCOPE_GLOBAL && $varName) {
\Smarty\Smarty::$global_tpl_vars[ $varName ] = $tpl->tpl_vars[ $varName ];
}
// update scopes
foreach ($this->_getAffectedScopes($tpl, $mergedScope) as $ptr) {
$this->_updateVariableInOtherScope($ptr->tpl_vars, $tpl, $varName);
if ($tagScope && $ptr->_isTplObj() && isset($tpl->_var_stack)) {
$this->_updateVarStack($ptr, $varName);
}
}
}
}
/**
* Get array of objects which needs to be updated by given scope value
*
* @param Smarty_Internal_Template $tpl
* @param int $mergedScope merged tag and template scope to which bubble up variable value
*
* @return array
*/
public function _getAffectedScopes(Smarty_Internal_Template $tpl, $mergedScope)
{
$_stack = array();
$ptr = $tpl->parent;
if ($mergedScope && isset($ptr) && $ptr->_isTplObj()) {
$_stack[] = $ptr;
$mergedScope = $mergedScope & ~\Smarty\Smarty::SCOPE_PARENT;
if (!$mergedScope) {
// only parent was set, we are done
return $_stack;
}
$ptr = $ptr->parent;
}
while (isset($ptr) && $ptr->_isTplObj()) {
$_stack[] = $ptr;
$ptr = $ptr->parent;
}
if ($mergedScope & \Smarty\Smarty::SCOPE_SMARTY) {
if (isset($tpl->smarty)) {
$_stack[] = $tpl->smarty;
}
} elseif ($mergedScope & \Smarty\Smarty::SCOPE_ROOT) {
while (isset($ptr)) {
if (!$ptr->_isTplObj()) {
$_stack[] = $ptr;
break;
}
$ptr = $ptr->parent;
}
}
return $_stack;
}
/**
* Update variable in other scope
*
* @param array $tpl_vars template variable array
* @param \Smarty_Internal_Template $from
* @param string $varName variable name
*/
public function _updateVariableInOtherScope(&$tpl_vars, Smarty_Internal_Template $from, $varName)
{
if (!isset($tpl_vars[ $varName ])) {
$tpl_vars[ $varName ] = clone $from->tpl_vars[ $varName ];
} else {
$tpl_vars[ $varName ] = clone $tpl_vars[ $varName ];
$tpl_vars[ $varName ]->value = $from->tpl_vars[ $varName ]->value;
}
}
/**
* Update variable in template local variable stack
*
* @param \Smarty_Internal_Template $tpl
* @param string|null $varName variable name or null for config variables
*/
public function _updateVarStack(Smarty_Internal_Template $tpl, $varName)
{
$i = 0;
while (isset($tpl->_var_stack[ $i ])) {
$this->_updateVariableInOtherScope($tpl->_var_stack[ $i ][ 'tpl' ], $tpl, $varName);
$i++;
}
}
}

View File

@@ -1,91 +0,0 @@
<?php
/**
* Smarty write file plugin
*
* @package Smarty
* @subpackage PluginsInternal
* @author Monte Ohrt
*/
/**
* Smarty Internal Write File Class
*
* @package Smarty
* @subpackage PluginsInternal
*/
class Smarty_Internal_Runtime_WriteFile
{
/**
* Writes file in a safe way to disk
*
* @param string $_filepath complete filepath
* @param string $_contents file content
* @param Smarty $smarty smarty instance
*
* @throws SmartyException
* @return boolean true
*/
public function writeFile($_filepath, $_contents, Smarty $smarty)
{
$_error_reporting = error_reporting();
error_reporting($_error_reporting & ~E_NOTICE & ~E_WARNING);
$_dirpath = dirname($_filepath);
// if subdirs, create dir structure
if ($_dirpath !== '.') {
$i = 0;
// loop if concurrency problem occurs
// see https://bugs.php.net/bug.php?id=35326
while (!is_dir($_dirpath)) {
if (@mkdir($_dirpath, 0777, true)) {
break;
}
clearstatcache();
if (++$i === 3) {
error_reporting($_error_reporting);
throw new SmartyException("unable to create directory {$_dirpath}");
}
sleep(1);
}
}
// write to tmp file, then move to overt file lock race condition
$_tmp_file = $_dirpath . DIRECTORY_SEPARATOR . str_replace(array('.', ','), '_', uniqid('wrt', true));
if (!file_put_contents($_tmp_file, $_contents)) {
error_reporting($_error_reporting);
throw new SmartyException("unable to write file {$_tmp_file}");
}
/*
* Windows' rename() fails if the destination exists,
* Linux' rename() properly handles the overwrite.
* Simply unlink()ing a file might cause other processes
* currently reading that file to fail, but linux' rename()
* seems to be smart enough to handle that for us.
*/
if (\Smarty\Smarty::$_IS_WINDOWS) {
// remove original file
if (is_file($_filepath)) {
@unlink($_filepath);
}
// rename tmp file
$success = @rename($_tmp_file, $_filepath);
} else {
// rename tmp file
$success = @rename($_tmp_file, $_filepath);
if (!$success) {
// remove original file
if (is_file($_filepath)) {
@unlink($_filepath);
}
// rename tmp file
$success = @rename($_tmp_file, $_filepath);
}
}
if (!$success) {
error_reporting($_error_reporting);
throw new SmartyException("unable to write file {$_filepath}");
}
// set file permissions
@chmod($_filepath, 0666 & ~umask());
error_reporting($_error_reporting);
return true;
}
}

View File

@@ -2,6 +2,12 @@
namespace Smarty;
use Smarty\Smarty\Runtime\CaptureRuntime;
use Smarty\Smarty\Runtime\ForeachRuntime;
use Smarty\Smarty\Runtime\InheritanceRuntime;
use Smarty\Smarty\Runtime\MakeNocacheRuntime;
use Smarty\Smarty\Runtime\TplFunctionRuntime;
/**
* Project: Smarty: the PHP compiling template engine
*
@@ -1464,8 +1470,6 @@ class Smarty extends \Smarty_Internal_TemplateBase
$_smarty = clone $this;
//
$_smarty->_cache = array();
$_smarty->ext = new Smarty_Internal_Extension_Handler();
$_smarty->ext->objType = $_smarty->_objType;
$_smarty->force_compile = $force_compile;
try {
/* @var Smarty_Internal_Template $_tpl */
@@ -1499,4 +1503,364 @@ class Smarty extends \Smarty_Internal_TemplateBase
return $_count;
}
/**
* check client side cache
*
* @param \Smarty_Template_Cached $cached
* @param \Smarty_Internal_Template $_template
* @param string $content
*
* @throws \Exception
* @throws \SmartyException
*/
public function cacheModifiedCheck(\Smarty_Template_Cached $cached, \Smarty_Internal_Template $_template, $content)
{
$_isCached = $_template->isCached() && !$_template->compiled->has_nocache_code;
$_last_modified_date =
@substr($_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ], 0, strpos($_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ], 'GMT') + 3);
if ($_isCached && $cached->timestamp <= strtotime($_last_modified_date)) {
switch (PHP_SAPI) {
case 'cgi': // php-cgi < 5.3
case 'cgi-fcgi': // php-cgi >= 5.3
case 'fpm-fcgi': // php-fpm >= 5.3.3
header('Status: 304 Not Modified');
break;
case 'cli':
if (/* ^phpunit */
!empty($_SERVER[ 'SMARTY_PHPUNIT_DISABLE_HEADERS' ]) /* phpunit$ */
) {
$_SERVER[ 'SMARTY_PHPUNIT_HEADERS' ][] = '304 Not Modified';
}
break;
default:
if (/* ^phpunit */
!empty($_SERVER[ 'SMARTY_PHPUNIT_DISABLE_HEADERS' ]) /* phpunit$ */
) {
$_SERVER[ 'SMARTY_PHPUNIT_HEADERS' ][] = '304 Not Modified';
} else {
header($_SERVER[ 'SERVER_PROTOCOL' ] . ' 304 Not Modified');
}
break;
}
} else {
switch (PHP_SAPI) {
case 'cli':
if (/* ^phpunit */
!empty($_SERVER[ 'SMARTY_PHPUNIT_DISABLE_HEADERS' ]) /* phpunit$ */
) {
$_SERVER[ 'SMARTY_PHPUNIT_HEADERS' ][] =
'Last-Modified: ' . gmdate('D, d M Y H:i:s', $cached->timestamp) . ' GMT';
}
break;
default:
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $cached->timestamp) . ' GMT');
break;
}
echo $content;
}
}
/**
* Run filters over content
* The filters will be lazy loaded if required
* class name format: Smarty_FilterType_FilterName
* plugin filename format: filtertype.filtername.php
* Smarty2 filter plugins could be used
*
* @param string $type the type of filter ('pre','post','output') which shall run
* @param string $content the content which shall be processed by the filters
* @param Smarty_Internal_Template $template template object
*
* @throws SmartyException
* @return string the filtered content
*/
public function runFilter($type, $content, Smarty_Internal_Template $template)
{
// loop over registered filters of specified type
if (!empty($this->registered_filters[ $type ])) {
foreach ($this->registered_filters[ $type ] as $key => $name) {
$content = call_user_func($this->registered_filters[ $type ][ $key ], $content, $template);
}
}
// return filtered output
return $content;
}
/**
* include path cache
*
* @var string
*/
private $_include_path = '';
/**
* include path directory cache
*
* @var array
*/
private $_include_dirs = array();
/**
* include path directory cache
*
* @var array
*/
private $_user_dirs = array();
/**
* stream cache
*
* @var string[][]
*/
private $isFile = array();
/**
* stream cache
*
* @var string[]
*/
private $isPath = array();
/**
* stream cache
*
* @var int[]
*/
private $number = array();
/**
* status cache
*
* @var bool
*/
private $_has_stream_include = null;
/**
* Number for array index
*
* @var int
*/
private $counter = 0;
/**
* Check if include path was updated
*
* @return bool
*/
private function isNewIncludePath()
{
$_i_path = get_include_path();
if ($this->_include_path !== $_i_path) {
$this->_include_dirs = array();
$this->_include_path = $_i_path;
$_dirs = (array)explode(PATH_SEPARATOR, $_i_path);
foreach ($_dirs as $_path) {
if (is_dir($_path)) {
$this->_include_dirs[] = $this->_realpath($_path . DIRECTORY_SEPARATOR, true);
}
}
return true;
}
return false;
}
/**
* return array with include path directories
*
* @return array
*/
public function getIncludePathDirs()
{
$this->isNewIncludePath();
return $this->_include_dirs;
}
/**
* Return full file path from PHP include_path
*
* @param string[] $dirs
* @param string $file
*
* @return bool|string full filepath or false
*/
public function getIncludePath($dirs, $file)
{
if (!($this->_has_stream_include ?? $this->_has_stream_include = function_exists('stream_resolve_include_path'))
) {
$this->isNewIncludePath();
}
// try PHP include_path
foreach ($dirs as $dir) {
$dir_n = $this->number[$dir] ?? $this->number[$dir] = $this->counter++;
if (isset($this->isFile[ $dir_n ][ $file ])) {
if ($this->isFile[ $dir_n ][ $file ]) {
return $this->isFile[ $dir_n ][ $file ];
} else {
continue;
}
}
if (isset($this->_user_dirs[ $dir_n ])) {
if (false === $this->_user_dirs[ $dir_n ]) {
continue;
} else {
$dir = $this->_user_dirs[ $dir_n ];
}
} else {
if ($dir[ 0 ] === '/' || $dir[ 1 ] === ':') {
$dir = str_ireplace(getcwd(), '.', $dir);
if ($dir[ 0 ] === '/' || $dir[ 1 ] === ':') {
$this->_user_dirs[ $dir_n ] = false;
continue;
}
}
$dir = substr($dir, 2);
$this->_user_dirs[ $dir_n ] = $dir;
}
if ($this->_has_stream_include) {
$path = stream_resolve_include_path($dir . ($file ?? ''));
if ($path) {
return $this->isFile[ $dir_n ][ $file ] = $path;
}
} else {
foreach ($this->_include_dirs as $key => $_i_path) {
$path = $this->isPath[$key][$dir_n] ?? $this->isPath[$key][$dir_n] = is_dir($_dir_path = $_i_path . $dir) ? $_dir_path : false;
if ($path === false) {
continue;
}
if (isset($file)) {
$_file = $this->isFile[ $dir_n ][ $file ] = (is_file($path . $file)) ? $path . $file : false;
if ($_file) {
return $_file;
}
} else {
// no file was given return directory path
return $path;
}
}
}
}
return false;
}
/**
* Writes file in a safe way to disk
*
* @param string $_filepath complete filepath
* @param string $_contents file content
*
* @throws SmartyException
* @return boolean true
*/
public function writeFile($_filepath, $_contents)
{
$_error_reporting = error_reporting();
error_reporting($_error_reporting & ~E_NOTICE & ~E_WARNING);
$_dirpath = dirname($_filepath);
// if subdirs, create dir structure
if ($_dirpath !== '.') {
$i = 0;
// loop if concurrency problem occurs
// see https://bugs.php.net/bug.php?id=35326
while (!is_dir($_dirpath)) {
if (@mkdir($_dirpath, 0777, true)) {
break;
}
clearstatcache();
if (++$i === 3) {
error_reporting($_error_reporting);
throw new SmartyException("unable to create directory {$_dirpath}");
}
sleep(1);
}
}
// write to tmp file, then move to overt file lock race condition
$_tmp_file = $_dirpath . DIRECTORY_SEPARATOR . str_replace(array('.', ','), '_', uniqid('wrt', true));
if (!file_put_contents($_tmp_file, $_contents)) {
error_reporting($_error_reporting);
throw new SmartyException("unable to write file {$_tmp_file}");
}
/*
* Windows' rename() fails if the destination exists,
* Linux' rename() properly handles the overwrite.
* Simply unlink()ing a file might cause other processes
* currently reading that file to fail, but linux' rename()
* seems to be smart enough to handle that for us.
*/
if (\Smarty\Smarty::$_IS_WINDOWS) {
// remove original file
if (is_file($_filepath)) {
@unlink($_filepath);
}
// rename tmp file
$success = @rename($_tmp_file, $_filepath);
} else {
// rename tmp file
$success = @rename($_tmp_file, $_filepath);
if (!$success) {
// remove original file
if (is_file($_filepath)) {
@unlink($_filepath);
}
// rename tmp file
$success = @rename($_tmp_file, $_filepath);
}
}
if (!$success) {
error_reporting($_error_reporting);
throw new SmartyException("unable to write file {$_filepath}");
}
// set file permissions
@chmod($_filepath, 0666 & ~umask());
error_reporting($_error_reporting);
return true;
}
private $runtimes = [];
/**
* Loads and returns a runtime extension or null if not found
* @param string $type
*
* @return object|null
*/
public function getRuntime(string $type) {
if (isset($this->runtimes[$type])) {
return $this->runtimes[$type];
}
// Lazy load runtimes when/if needed
switch ($type) {
case 'Capture':
return $this->runtimes[$type] = new Smarty\Runtime\CaptureRuntime();
case 'Foreach':
return $this->runtimes[$type] = new Smarty\Runtime\ForeachRuntime();
case 'Inheritance':
return $this->runtimes[$type] = new Smarty\Runtime\InheritanceRuntime();
case 'MakeNocache':
return $this->runtimes[$type] = new Smarty\Runtime\MakeNocacheRuntime();
case 'TplFunction':
return $this->runtimes[$type] = new Smarty\Runtime\TplFunctionRuntime();
}
throw new \SmartyException('Trying to load invalid runtime ' . $type);
}
/**
* Indicates if a runtime is available.
*
* @param string $type
*
* @return bool
*/
public function hasRuntime(string $type): bool {
try {
$this->getRuntime($type);
return true;
} catch (\SmartyException $e) {
return false;
}
}
}

View File

@@ -137,7 +137,7 @@ class Smarty_Template_Cached extends Smarty_Template_Resource_Base
}
return;
} else {
$_template->smarty->ext->_updateCache->updateCache($this, $_template, $no_output_filter);
$this->updateCache($_template, $no_output_filter);
}
}
@@ -244,11 +244,144 @@ class Smarty_Template_Cached extends Smarty_Template_Resource_Base
*
* @return string|false content
*/
public function read(Smarty_Internal_Template $_template)
public function readCache(Smarty_Internal_Template $_template)
{
if (!$_template->source->handler->recompiled) {
return $this->handler->readCachedContent($_template);
return $this->handler->retrieveCachedContent($_template);
}
return false;
}
/**
* Write this cache object to handler
*
* @param string $content content to cache
*
* @return bool success
*/
public function writeCache(Smarty_Internal_Template $_template, $content)
{
if (!$_template->source->handler->recompiled) {
if ($this->handler->storeCachedContent($_template, $content)) {
$this->content = null;
$this->timestamp = time();
$this->exists = true;
$this->valid = true;
$this->cache_lifetime = $_template->cache_lifetime;
$this->processed = false;
if ($_template->smarty->cache_locking) {
$this->handler->releaseLock($_template->smarty, $this);
}
return true;
}
$this->content = null;
$this->timestamp = false;
$this->exists = false;
$this->valid = false;
$this->processed = false;
}
return false;
}
/**
* Cache was invalid , so render from compiled and write to cache
*
* @param \Smarty_Template_Cached $cached
* @param $no_output_filter
*
* @throws \Exception
*/
public function updateCache(Smarty_Internal_Template $_template, $no_output_filter)
{
ob_start();
if (!isset($_template->compiled)) {
$_template->loadCompiled();
}
$_template->compiled->render($_template);
if ($_template->smarty->debugging) {
$_template->smarty->_debug->start_cache($_template);
}
$this->removeNoCacheHash($_template, $no_output_filter);
$compile_check = (int)$_template->compile_check;
$_template->compile_check = \Smarty\Smarty::COMPILECHECK_OFF;
if ($_template->_isSubTpl()) {
$_template->compiled->unifunc = $_template->parent->compiled->unifunc;
}
if (!$_template->cached->processed) {
$_template->cached->process($_template, true);
}
$_template->compile_check = $compile_check;
$this->getRenderedTemplateCode($_template);
if ($_template->smarty->debugging) {
$_template->smarty->_debug->end_cache($_template);
}
}
/**
* Sanitize content and write it to cache resource
*
* @param Smarty_Internal_Template $_template
* @param bool $no_output_filter
*
* @throws \SmartyException
*/
private function removeNoCacheHash(Smarty_Internal_Template $_template, $no_output_filter) {
$php_pattern = '/(<%|%>|<\?php|<\?|\?>|<script\s+language\s*=\s*[\"\']?\s*php\s*[\"\']?\s*>)/';
$content = ob_get_clean();
$hash_array = $this->hashes;
$hash_array[ $_template->compiled->nocache_hash ] = true;
$hash_array = array_keys($hash_array);
$nocache_hash = '(' . implode('|', $hash_array) . ')';
$_template->cached->has_nocache_code = false;
// get text between non-cached items
$cache_split =
preg_split(
"!/\*%%SmartyNocache:{$nocache_hash}%%\*\/(.+?)/\*/%%SmartyNocache:{$nocache_hash}%%\*/!s",
$content
);
// get non-cached items
preg_match_all(
"!/\*%%SmartyNocache:{$nocache_hash}%%\*\/(.+?)/\*/%%SmartyNocache:{$nocache_hash}%%\*/!s",
$content,
$cache_parts
);
$content = '';
// loop over items, stitch back together
foreach ($cache_split as $curr_idx => $curr_split) {
if (preg_match($php_pattern, $curr_split)) {
// escape PHP tags in template content
$php_split = preg_split(
$php_pattern,
$curr_split
);
preg_match_all(
$php_pattern,
$curr_split,
$php_parts
);
foreach ($php_split as $idx_php => $curr_php) {
$content .= $curr_php;
if (isset($php_parts[ 0 ][ $idx_php ])) {
$content .= "<?php echo '{$php_parts[ 1 ][ $idx_php ]}'; ?>\n";
}
}
} else {
$content .= $curr_split;
}
if (isset($cache_parts[ 0 ][ $curr_idx ])) {
$_template->cached->has_nocache_code = true;
$content .= $cache_parts[ 2 ][ $curr_idx ];
}
}
if (
!$no_output_filter
&& !$_template->cached->has_nocache_code
&& isset($_template->smarty->registered_filters[ 'output' ])
) {
$content = $_template->smarty->runFilter('output', $content, $_template);
}
// write cache file content
$_template->writeCachedContent($content);
}
}

View File

@@ -206,7 +206,7 @@ class Smarty_Template_Compiled extends Smarty_Template_Resource_Base
public function write(Smarty_Internal_Template $_template, $code)
{
if (!$_template->source->handler->recompiled) {
if ($_template->smarty->ext->_writeFile->writeFile($this->filepath, $code, $_template->smarty) === true) {
if ($_template->smarty->writeFile($this->filepath, $code) === true) {
$this->timestamp = $this->exists = is_file($this->filepath);
if ($this->exists) {
$this->timestamp = filemtime($this->filepath);

View File

@@ -48,7 +48,7 @@ class TestInstall
if ($_stream_resolve_include_path) {
$template_dir = stream_resolve_include_path($_template_dir);
} else {
$template_dir = $smarty->ext->_getIncludePath->getIncludePath($_template_dir, null, $smarty);
$template_dir = $smarty->getIncludePath($_template_dir, null);
}
if ($template_dir !== false) {
if ($errors === null) {
@@ -201,7 +201,7 @@ class TestInstall
if ($_stream_resolve_include_path) {
$config_dir = stream_resolve_include_path($_config_dir);
} else {
$config_dir = $smarty->ext->_getIncludePath->getIncludePath($_config_dir, null, $smarty);
$config_dir = $smarty->getIncludePath($_config_dir, null);
}
if ($config_dir !== false) {
if ($errors === null) {

View File

@@ -1,195 +0,0 @@
<?php
/**
* Smarty Extension handler
*
* Load extensions dynamically
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
* Runtime extensions
* @property Smarty_Internal_Runtime_CacheModify $_cacheModify
* @property Smarty_Internal_Runtime_CacheResourceFile $_cacheResourceFile
* @property Smarty_Internal_Runtime_Capture $_capture
* @property Smarty_Internal_Runtime_FilterHandler $_filterHandler
* @property Smarty_Internal_Runtime_Foreach $_foreach
* @property Smarty_Internal_Runtime_GetIncludePath $_getIncludePath
* @property Smarty_Internal_Runtime_Make_Nocache $_make_nocache
* @property Smarty_Internal_Runtime_UpdateCache $_updateCache
* @property Smarty_Internal_Runtime_UpdateScope $_updateScope
* @property Smarty_Internal_Runtime_TplFunction $_tplFunction
* @property Smarty_Internal_Runtime_WriteFile $_writeFile
*
* Method extensions
* @property Smarty_Internal_Method_GetTemplateVars $getTemplateVars
* @property Smarty_Internal_Method_Append $append
* @property Smarty_Internal_Method_AppendByRef $appendByRef
* @property Smarty_Internal_Method_AssignGlobal $assignGlobal
* @property Smarty_Internal_Method_AssignByRef $assignByRef
* @property Smarty_Internal_Method_LoadFilter $loadFilter
* @property Smarty_Internal_Method_RegisterFilter $registerFilter
* @property Smarty_Internal_Method_RegisterObject $registerObject
* @property Smarty_Internal_Method_RegisterPlugin $registerPlugin
* @property mixed|\Smarty_Template_Cached configLoad
*/
#[\AllowDynamicProperties]
class Smarty_Internal_Extension_Handler
{
public $objType = null;
/**
* Cache for property information from generic getter/setter
* Preloaded with names which should not use with generic getter/setter
*
* @var array
*/
private $_property_info = array(
'DefaultModifiers' => 0, 'ConfigVars' => 0,
'DebugTemplate' => 0, 'RegisteredObject' => 0, 'StreamVariable' => 0,
'TemplateVars' => 0, 'Literals' => 'Literals',
);//
private $resolvedProperties = array();
/**
* Call external Method
*
* @param \Smarty\Data $data
* @param string $name external method names
* @param array $args argument array
*
* @return mixed
*/
public function _callExternalMethod(\Smarty\Data $data, $name, $args)
{
/* @var Smarty $data ->smarty */
$smarty = isset($data->smarty) ? $data->smarty : $data;
if (!isset($smarty->ext->$name)) {
if (preg_match('/^((set|get)|(.*?))([A-Z].*)$/', $name, $match)) {
$basename = $this->upperCase($match[ 4 ]);
if (!isset($smarty->ext->$basename) && isset($this->_property_info[ $basename ])
&& is_string($this->_property_info[ $basename ])
) {
$class = 'Smarty_Internal_Method_' . $this->_property_info[ $basename ];
if (class_exists($class)) {
$classObj = new $class();
$methodes = get_class_methods($classObj);
foreach ($methodes as $method) {
$smarty->ext->$method = $classObj;
}
}
}
if (!empty($match[ 2 ]) && !isset($smarty->ext->$name)) {
$class = 'Smarty_Internal_Method_' . $this->upperCase($name);
if (!class_exists($class)) {
$objType = $data->_objType;
$propertyType = false;
if (!isset($this->resolvedProperties[ $match[ 0 ] ][ $objType ])) {
$property = $this->resolvedProperties['property'][$basename] ??
$this->resolvedProperties['property'][$basename] = smarty_strtolower_ascii(
join(
'_',
preg_split(
'/([A-Z][^A-Z]*)/',
$basename,
-1,
PREG_SPLIT_NO_EMPTY |
PREG_SPLIT_DELIM_CAPTURE
)
)
);
if ($property !== false) {
if (property_exists($data, $property)) {
$propertyType = $this->resolvedProperties[ $match[ 0 ] ][ $objType ] = 1;
} elseif (property_exists($smarty, $property)) {
$propertyType = $this->resolvedProperties[ $match[ 0 ] ][ $objType ] = 2;
} else {
$this->resolvedProperties[ 'property' ][ $basename ] = $property = false;
}
}
} else {
$propertyType = $this->resolvedProperties[ $match[ 0 ] ][ $objType ];
$property = $this->resolvedProperties[ 'property' ][ $basename ];
}
if ($propertyType) {
$obj = $propertyType === 1 ? $data : $smarty;
if ($match[ 2 ] === 'get') {
return $obj->$property;
} elseif ($match[ 2 ] === 'set') {
return $obj->$property = $args[ 0 ];
}
}
}
}
}
}
$callback = array($smarty->ext->$name, $name);
array_unshift($args, $data);
if (isset($callback) && $callback[ 0 ]->objMap | $data->_objType) {
return call_user_func_array($callback, $args);
}
return call_user_func_array(array(new Smarty_Internal_Undefined(), $name), $args);
}
/**
* Make first character of name parts upper case
*
* @param string $name
*
* @return string
*/
public function upperCase($name)
{
$_name = explode('_', $name);
$_name = array_map('smarty_ucfirst_ascii', $_name);
return implode('_', $_name);
}
/**
* get extension object
*
* @param string $property_name property name
*
* @return mixed|Smarty_Template_Cached
*/
public function __get($property_name)
{
// object properties of runtime template extensions will start with '_'
if ($property_name[ 0 ] === '_') {
$class = 'Smarty_Internal_Runtime' . $this->upperCase($property_name);
} else {
$class = 'Smarty_Internal_Method_' . $this->upperCase($property_name);
}
if (!class_exists($class)) {
return $this->$property_name = new Smarty_Internal_Undefined($class);
}
return $this->$property_name = new $class();
}
/**
* set extension property
*
* @param string $property_name property name
* @param mixed $value value
*
*/
public function __set($property_name, $value)
{
$this->$property_name = $value;
}
/**
* Call error handler for undefined method
*
* @param string $name unknown method-name
* @param array $args argument array
*
* @return mixed
*/
public function __call($name, $args)
{
return call_user_func_array(array(new Smarty_Internal_Undefined(), $name), array($this));
}
}

View File

@@ -9,6 +9,7 @@
*/
use Smarty\Data;
use Smarty\Runtime\InheritanceRuntime;
/**
* Main class with template data structures and methods
@@ -61,7 +62,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
/**
* Inheritance runtime extension
*
* @var Smarty_Internal_Runtime_Inheritance
* @var InheritanceRuntime
*/
public $inheritance = null;
@@ -113,8 +114,12 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
* @var callback[]
*/
public $endRenderCallbacks = array();
/**
* @var \Smarty\Compiler\CodeFrame
*/
private $codeFrameCompiler;
/**
/**
* Create template data object
* Some of the global Smarty settings copied to template scope
* It load the required template resources and caching plugins
@@ -158,6 +163,8 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
if ($smarty->security_policy && method_exists($smarty->security_policy, 'registerCallBacks')) {
$smarty->security_policy->registerCallBacks($this);
}
$this->codeFrameCompiler = new Smarty\Compiler\CodeFrame($this);
}
/**
@@ -206,7 +213,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
// display or fetch
if ($display) {
if ($this->caching && $this->smarty->cache_modified_check) {
$this->smarty->ext->_cacheModify->cacheModifiedCheck(
$this->smarty->cacheModifiedCheck(
$this->cached,
$this,
isset($content) ? $content : ob_get_clean()
@@ -215,7 +222,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
if ((!$this->caching || $this->cached->has_nocache_code || $this->source->handler->recompiled)
&& !$no_output_filter && isset($this->smarty->registered_filters[ 'output' ])
) {
echo $this->smarty->ext->_filterHandler->runFilter('output', ob_get_clean(), $this);
echo $this->smarty->runFilter('output', ob_get_clean(), $this);
} else {
echo ob_get_clean();
}
@@ -238,7 +245,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
&& (!$this->caching || $this->cached->has_nocache_code || $this->source->handler->recompiled)
&& isset($this->smarty->registered_filters[ 'output' ])
) {
return $this->smarty->ext->_filterHandler->runFilter('output', ob_get_clean(), $this);
return $this->smarty->runFilter('output', ob_get_clean(), $this);
}
// return cache content
return null;
@@ -419,7 +426,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
}
if ($scope >= 0) {
if ($scope > 0 || $this->scope > 0) {
$this->smarty->ext->_updateScope->_updateScope($this, $varName, $scope);
$this->_updateScope($varName, $scope);
}
}
}
@@ -520,7 +527,16 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
*/
public function writeCachedContent($content)
{
return $this->smarty->ext->_updateCache->writeCachedContent($this, $content);
if ($this->source->handler->recompiled || !$this->caching
) {
// don't write cache file
return false;
}
if (!isset($this->cached)) {
$this->loadCached();
}
$codeframe = $this->createCodeFrame($content, '', true);
return $this->cached->writeCache($this, $codeframe);
}
/**
@@ -531,8 +547,8 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
*/
public function _getTemplateId()
{
return isset($this->templateId) ? $this->templateId : $this->templateId =
$this->smarty->_getTemplateId($this->template_resource, $this->cache_id, $this->compile_id);
return $this->templateId ?? $this->templateId =
$this->smarty->_getTemplateId($this->template_resource, $this->cache_id, $this->compile_id);
}
/**
@@ -575,7 +591,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
public function _loadInheritance()
{
if (!isset($this->inheritance)) {
$this->inheritance = new Smarty_Internal_Runtime_Inheritance();
$this->inheritance = new InheritanceRuntime();
}
}
@@ -615,7 +631,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
* @return string
*/
public function createCodeFrame($content = '', $functions = '', $cache = false, \Smarty\Compiler\Template $compiler = null) {
return \Smarty\Template\CodeFrame::create($this, $content, $functions, $cache, $compiler);
return $this->codeFrameCompiler->create($content, $functions, $cache, $compiler);
}
/**
@@ -725,7 +741,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
if ($mergedScope) {
// update scopes
/* @var \Smarty_Internal_Template|\Smarty|Data $ptr */
foreach ($this->smarty->ext->_updateScope->_getAffectedScopes($this->parent, $mergedScope) as $ptr) {
foreach ($this->parent->_getAffectedScopes($mergedScope) as $ptr) {
$this->_assignConfigVars($ptr->config_vars, $new_config_vars);
if ($tagScope && $ptr->_isTplObj() && isset($this->_var_stack)) {
$this->_updateConfigVarStack($new_config_vars);
@@ -811,4 +827,104 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
return $this->mustCompile;
}
/**
* Update new assigned template or config variable in other effected scopes
*
* @param string|null $varName variable name
* @param int $tagScope tag scope to which bubble up variable value
*/
protected function _updateScope($varName, $tagScope = 0)
{
if ($tagScope) {
$this->_updateVarStack($this, $varName);
$tagScope = $tagScope & ~\Smarty\Smarty::SCOPE_LOCAL;
if (!$this->scope && !$tagScope) {
return;
}
}
$mergedScope = $tagScope | $this->scope;
if ($mergedScope) {
if ($mergedScope & \Smarty\Smarty::SCOPE_GLOBAL && $varName) {
\Smarty\Smarty::$global_tpl_vars[ $varName ] = $this->tpl_vars[ $varName ];
}
// update scopes
foreach ($this->_getAffectedScopes($mergedScope) as $ptr) {
$this->_updateVariableInOtherScope($ptr->tpl_vars, $varName);
if ($tagScope && $ptr->_isTplObj() && isset($this->_var_stack)) {
$this->_updateVarStack($ptr, $varName);
}
}
}
}
/**
* Get array of objects which needs to be updated by given scope value
*
* @param int $mergedScope merged tag and template scope to which bubble up variable value
*
* @return array
*/
private function _getAffectedScopes($mergedScope)
{
$_stack = array();
$ptr = $this->parent;
if ($mergedScope && isset($ptr) && $ptr->_isTplObj()) {
$_stack[] = $ptr;
$mergedScope = $mergedScope & ~\Smarty\Smarty::SCOPE_PARENT;
if (!$mergedScope) {
// only parent was set, we are done
return $_stack;
}
$ptr = $ptr->parent;
}
while (isset($ptr) && $ptr->_isTplObj()) {
$_stack[] = $ptr;
$ptr = $ptr->parent;
}
if ($mergedScope & \Smarty\Smarty::SCOPE_SMARTY) {
if (isset($this->smarty)) {
$_stack[] = $this->smarty;
}
} elseif ($mergedScope & \Smarty\Smarty::SCOPE_ROOT) {
while (isset($ptr)) {
if (!$ptr->_isTplObj()) {
$_stack[] = $ptr;
break;
}
$ptr = $ptr->parent;
}
}
return $_stack;
}
/**
* Update variable in other scope
*
* @param array $tpl_vars template variable array
* @param string $varName variable name
*/
private function _updateVariableInOtherScope(&$tpl_vars, $varName)
{
if (!isset($tpl_vars[ $varName ])) {
$tpl_vars[ $varName ] = clone $this->tpl_vars[ $varName ];
} else {
$tpl_vars[ $varName ] = clone $tpl_vars[ $varName ];
$tpl_vars[ $varName ]->value = $this->tpl_vars[ $varName ]->value;
}
}
/**
* Update variable in template local variable stack
*
* @param \Smarty_Internal_Template $tpl
* @param string|null $varName variable name or null for config variables
*/
private function _updateVarStack(Smarty_Internal_Template $tpl, $varName)
{
$i = 0;
while (isset($tpl->_var_stack[ $i ])) {
$this->_updateVariableInOtherScope($tpl->_var_stack[ $i ][ 'tpl' ], $varName);
$i++;
}
}
}

View File

@@ -498,7 +498,7 @@ class Smarty_Security
{
if ($this->_include_path_status !== $this->smarty->use_include_path) {
$_dir =
$this->smarty->use_include_path ? $this->smarty->ext->_getIncludePath->getIncludePathDirs($this->smarty) : array();
$this->smarty->use_include_path ? $this->smarty->getIncludePathDirs() : array();
if ($this->_include_dir !== $_dir) {
$this->_updateResourceDir($this->_include_dir, $_dir);
$this->_include_dir = $_dir;