mirror of
https://github.com/smarty-php/smarty.git
synced 2025-08-02 17:34:26 +02:00
Refactored all _runtime_* by merging them into the proper classes or by transforming them into Runtime Extensions.
This commit is contained in:
4
TODO.txt
4
TODO.txt
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
|
@@ -3,7 +3,6 @@
|
||||
namespace Smarty\Compile;
|
||||
|
||||
use Smarty\ParseTree\Template;
|
||||
use Smarty\Compiler\Template;
|
||||
|
||||
/**
|
||||
* Smarty Internal Plugin Compile BlockClose Class
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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);?>";
|
||||
}
|
||||
}
|
||||
|
@@ -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";
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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});";
|
||||
}
|
||||
}
|
@@ -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";
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
24
src/Data.php
24
src/Data.php
@@ -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).
|
||||
*
|
||||
|
@@ -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;
|
||||
}
|
||||
|
163
src/Runtime/CaptureRuntime.php
Normal file
163
src/Runtime/CaptureRuntime.php
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
163
src/Runtime/ForeachRuntime.php
Normal file
163
src/Runtime/ForeachRuntime.php
Normal 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--;
|
||||
}
|
||||
}
|
||||
}
|
250
src/Runtime/InheritanceRuntime.php
Normal file
250
src/Runtime/InheritanceRuntime.php
Normal 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);
|
||||
}
|
||||
}
|
55
src/Runtime/MakeNocacheRuntime.php
Normal file
55
src/Runtime/MakeNocacheRuntime.php
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
173
src/Runtime/TplFunctionRuntime.php
Normal file
173
src/Runtime/TplFunctionRuntime.php
Normal 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'];
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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' ];
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
368
src/Smarty.php
368
src/Smarty.php
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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) {
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user