- optimization of capture and security handling

This commit is contained in:
uwetews
2016-03-11 02:55:55 +01:00
parent 62bf9eeddc
commit af71fda639
8 changed files with 262 additions and 82 deletions

View File

@@ -1,4 +1,7 @@
 ===== 3.1.30-dev ===== (xx.xx.xx)  ===== 3.1.30-dev ===== (xx.xx.xx)
11.03.2014
- optimization of capture and security handling
10.03.2014 10.03.2014
- optimization of resource processing - optimization of resource processing

View File

@@ -121,7 +121,7 @@ class Smarty extends Smarty_Internal_TemplateBase
/** /**
* smarty version * smarty version
*/ */
const SMARTY_VERSION = '3.1.30-dev/55'; const SMARTY_VERSION = '3.1.30-dev/56';
/** /**
* define variable scopes * define variable scopes

View File

@@ -32,51 +32,53 @@ class Smarty_Internal_Compile_Capture extends Smarty_Internal_CompileBase
*/ */
public $optional_attributes = array('name', 'assign', 'append'); public $optional_attributes = array('name', 'assign', 'append');
/**
* Compiles code for the {$smarty.capture.xxx}
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase$compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public static function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter = null)
{
// make all lower case
$parameter = array_map('strtolower', $parameter);
$tag = trim($parameter[ 0 ], '"\'');
$name = isset($parameter[ 1 ]) ? $compiler->getId($parameter[ 1 ]) : false;
if (!$name) {
$compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", null, true);
}
return "\$_smarty_tpl->ext->_capture->getBuffer(\$_smarty_tpl, '{$name}')";
}
/** /**
* Compiles code for the {capture} tag * Compiles code for the {capture} tag
* *
* @param array $args array with attributes from parser * @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param null $parameter
* *
* @return string compiled code * @return string compiled code
*/ */
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler) public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter = null)
{ {
// check and get attributes // check and get attributes
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args, $parameter, 'capture');
$buffer = isset($_attr[ 'name' ]) ? $_attr[ 'name' ] : "'default'"; $buffer = isset($_attr[ 'name' ]) ? $_attr[ 'name' ] : "'default'";
$assign = isset($_attr[ 'assign' ]) ? $_attr[ 'assign' ] : 'null'; $assign = isset($_attr[ 'assign' ]) ? $_attr[ 'assign' ] : 'null';
$append = isset($_attr[ 'append' ]) ? $_attr[ 'append' ] : 'null'; $append = isset($_attr[ 'append' ]) ? $_attr[ 'append' ] : 'null';
$this->openTag($compiler, 'capture', array($buffer, $assign, $append, $compiler->nocache)); $compiler->_cache[ 'capture_stack' ][] = array($compiler->nocache);
// maybe nocache because of nocache variables // maybe nocache because of nocache variables
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache; $compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
$_output = $_output = "<?php \$_smarty_tpl->ext->_capture->open(\$_smarty_tpl, $buffer, $assign, $append);\n?>\n";
"<?php \$_smarty_tpl->smarty->_cache['capture_stack'][] = array($buffer, $assign, $append); ob_start(); ?>";
return $_output; return $_output;
} }
/**
* Compiles code for the {$smarty.capture.xxx}
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public static function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
$tag = strtolower(trim($parameter[ 0 ], '"\''));
$name = isset($parameter[ 1 ]) ? $compiler->getId($parameter[ 1 ]) : false;
if (!$name) {
$compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", null, true);
}
return "(isset(\$_smarty_tpl->smarty->_cache['__smarty_capture']['{$name}']) ? \$_smarty_tpl->smarty->_cache['__smarty_capture']['{$name}'] : null)";
}
} }
/** /**
@@ -90,29 +92,23 @@ class Smarty_Internal_Compile_CaptureClose extends Smarty_Internal_CompileBase
/** /**
* Compiles code for the {/capture} tag * Compiles code for the {/capture} tag
* *
* @param array $args array with attributes from parser * @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param null $parameter
* *
* @return string compiled code * @return string compiled code
*/ */
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler) public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{ {
// check and get attributes // check and get attributes
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args, $parameter, '/capture');
// must endblock be nocache? // must endblock be nocache?
if ($compiler->nocache) { if ($compiler->nocache) {
$compiler->tag_nocache = true; $compiler->tag_nocache = true;
} }
list($buffer, $assign, $append, $compiler->nocache) = $this->closeTag($compiler, array('capture'));
$_output = list($compiler->nocache) = array_pop($compiler->_cache[ 'capture_stack' ]);
"<?php list(\$_capture_buffer, \$_capture_assign, \$_capture_append) = array_pop(\$_smarty_tpl->smarty->_cache['capture_stack']);\n";
$_output .= "if (!empty(\$_capture_buffer)) {\n";
$_output .= " if (isset(\$_capture_assign)) \$_smarty_tpl->assign(\$_capture_assign, ob_get_contents());\n";
$_output .= " if (isset( \$_capture_append)) \$_smarty_tpl->append( \$_capture_append, ob_get_contents());\n";
$_output .= "\$_smarty_tpl->smarty->_cache['__smarty_capture'][\$_capture_buffer]=ob_get_clean();\n";
$_output .= "} else \$_smarty_tpl->capture_error();?>";
return $_output; return "<?php \$_smarty_tpl->ext->_capture->close(\$_smarty_tpl);\n?>\n";
} }
} }

View File

@@ -0,0 +1,155 @@
<?php
/**
* Runtime Extension Capture
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
class Smarty_Internal_Runtime_Capture
{
/**
* Flag that this instance will not be cached
*
* @var bool
*/
public $isPrivateExtension = true;
/**
* 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();
/**
* 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;
$_template->_cache[ 'capture' ] = array();
}
/**
* 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());
}
$_template->_cache[ 'capture' ][ $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
*
* @param \Smarty_Internal_Template $_template
* @param $name
*
* @return null
*/
public function getBuffer(Smarty_Internal_Template $_template, $name)
{
return isset($_template->_cache[ 'capture' ][ $name ]) ? $_template->_cache[ 'capture' ][ $name ] : null;
}
/**
* End render callback
*
* @param \Smarty_Internal_Template $_template
*
* @throws \SmartyException
*/
public function endRender(Smarty_Internal_Template $_template)
{
if ($this->captureCount) {
$this->error($_template);
} else {
$this->captureCount = array_pop($this->countStack);
}
}
}

View File

@@ -87,6 +87,21 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
*/ */
public $isRenderingCache = false; public $isRenderingCache = false;
/**
* Callbacks called before rendering template
*
* @var callback[]
*/
public $startRenderCallbacks = array();
/**
* Callbacks called after rendering template
*
* @var callback[]
*/
public $endRenderCallbacks = array();
/** /**
* Create template data object * Create template data object
* Some of the global Smarty settings copied to template scope * Some of the global Smarty settings copied to template scope
@@ -120,6 +135,9 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
$this->template_resource = $template_resource; $this->template_resource = $template_resource;
$this->source = Smarty_Template_Source::load($this); $this->source = Smarty_Template_Source::load($this);
parent::__construct(); parent::__construct();
if ($smarty->security_policy && method_exists($smarty->security_policy, 'registerCallBacks')) {
$smarty->security_policy->registerCallBacks($this);
}
} }
/** /**

View File

@@ -387,15 +387,21 @@ class Smarty_Internal_TestInstall
'smarty_internal_compile_make_nocache.php' => true, 'smarty_internal_compile_make_nocache.php' => true,
'smarty_internal_compile_nocache.php' => true, 'smarty_internal_compile_nocache.php' => true,
'smarty_internal_compile_private_block_plugin.php' => true, 'smarty_internal_compile_private_block_plugin.php' => true,
'smarty_internal_compile_private_compiler_plugin.php' => true,
'smarty_internal_compile_private_foreachsection.php' => true, 'smarty_internal_compile_private_foreachsection.php' => true,
'smarty_internal_compile_private_function_plugin.php' => true, 'smarty_internal_compile_private_function_plugin.php' => true,
'smarty_internal_compile_private_modifier.php' => true, 'smarty_internal_compile_private_modifier.php' => true,
'smarty_internal_compile_private_modifiercompiler_plugin.php' => true,
'smarty_internal_compile_private_modifier_plugin.php' => true,
'smarty_internal_compile_private_object.php' => true,
'smarty_internal_compile_private_object_block_function.php' => true, 'smarty_internal_compile_private_object_block_function.php' => true,
'smarty_internal_compile_private_object_function.php' => true, 'smarty_internal_compile_private_object_function.php' => true,
'smarty_internal_compile_private_php.php' => true, 'smarty_internal_compile_private_php.php' => true,
'smarty_internal_compile_private_print_expression.php' => true, 'smarty_internal_compile_private_print_expression.php' => true,
'smarty_internal_compile_private_registered_block.php' => true, 'smarty_internal_compile_private_registered_block.php' => true,
'smarty_internal_compile_private_registered_compiler.php' => true,
'smarty_internal_compile_private_registered_function.php' => true, 'smarty_internal_compile_private_registered_function.php' => true,
'smarty_internal_compile_private_registered_modifier.php' => true,
'smarty_internal_compile_private_special_variable.php' => true, 'smarty_internal_compile_private_special_variable.php' => true,
'smarty_internal_compile_rdelim.php' => true, 'smarty_internal_compile_rdelim.php' => true,
'smarty_internal_compile_section.php' => true, 'smarty_internal_compile_section.php' => true,
@@ -469,7 +475,9 @@ class Smarty_Internal_TestInstall
'smarty_internal_resource_registered.php' => true, 'smarty_internal_resource_registered.php' => true,
'smarty_internal_resource_stream.php' => true, 'smarty_internal_resource_stream.php' => true,
'smarty_internal_resource_string.php' => true, 'smarty_internal_resource_string.php' => true,
'smarty_internal_runtime_assignindexed.php' => true,
'smarty_internal_runtime_cachemodify.php' => true, 'smarty_internal_runtime_cachemodify.php' => true,
'smarty_internal_runtime_capture.php' => true,
'smarty_internal_runtime_codeframe.php' => true, 'smarty_internal_runtime_codeframe.php' => true,
'smarty_internal_runtime_filterhandler.php' => true, 'smarty_internal_runtime_filterhandler.php' => true,
'smarty_internal_runtime_foreach.php' => true, 'smarty_internal_runtime_foreach.php' => true,

View File

@@ -625,33 +625,7 @@ class Smarty_Security
$this->_checkDir($this->smarty->_realpath($filepath, true), $this->_php_resource_dir); $this->_checkDir($this->smarty->_realpath($filepath, true), $this->_php_resource_dir);
return true; return true;
} }
/**
* Start template processing
*
* @param $template
*
* @throws SmartyException
*/
public function startTemplate($template)
{
if ($this->max_template_nesting > 0 && $this->_current_template_nesting ++ >= $this->max_template_nesting) {
throw new SmartyException("maximum template nesting level of '{$this->max_template_nesting}' exceeded when calling '{$template->template_resource}'");
}
}
/**
* Exit template processing
*
* @internal param $template
*/
public function exitTemplate()
{
if ($this->max_template_nesting > 0) {
$this->_current_template_nesting --;
}
}
/** /**
* Check if file is inside a valid directory * Check if file is inside a valid directory
* *
@@ -716,4 +690,39 @@ class Smarty_Security
} }
return; return;
} }
/**
* Start template processing
*
* @param $template
*
* @throws SmartyException
*/
public function startTemplate($template)
{
if ($this->max_template_nesting > 0 && $this->_current_template_nesting ++ >= $this->max_template_nesting) {
throw new SmartyException("maximum template nesting level of '{$this->max_template_nesting}' exceeded when calling '{$template->template_resource}'");
}
}
/**
* Exit template processing
*
*/
public function endTemplate()
{
if ($this->max_template_nesting > 0) {
$this->_current_template_nesting --;
}
}
/**
* Register callback functions call at start/end of template rendering
*
* @param \Smarty_Internal_Template $template
*/
public function registerCallBacks(Smarty_Internal_Template $template)
{
$template->startRenderCallbacks[] = array($this, 'startTemplate');
$template->endRenderCallbacks[] = array($this, 'endTemplate');
}
} }

View File

@@ -121,23 +121,14 @@ abstract class Smarty_Template_Resource_Base
if (empty($unifunc) || !function_exists($unifunc)) { if (empty($unifunc) || !function_exists($unifunc)) {
throw new SmartyException("Invalid compiled template for '{$_template->template_resource}'"); throw new SmartyException("Invalid compiled template for '{$_template->template_resource}'");
} }
if (isset($smarty->security_policy)) { if ($_template->startRenderCallbacks) {
$smarty->security_policy->startTemplate($_template); foreach ($_template->startRenderCallbacks as $callback) {
call_user_func($callback, $_template);
}
} }
//
// render compiled or saved template code
//
if (!isset($_template->_cache[ 'capture_stack' ])) {
$_template->_cache[ 'capture_stack' ] = array();
}
$_saved_capture_level = count($_template->_cache[ 'capture_stack' ]);
$unifunc($_template); $unifunc($_template);
// any unclosed {capture} tags ? foreach ($_template->endRenderCallbacks as $callback) {
if ($_saved_capture_level != count($_template->_cache[ 'capture_stack' ])) { call_user_func($callback, $_template);
$_template->capture_error();
}
if (isset($smarty->security_policy)) {
$smarty->security_policy->exitTemplate();
} }
$_template->isRenderingCache = false; $_template->isRenderingCache = false;
return null; return null;
@@ -148,7 +139,7 @@ abstract class Smarty_Template_Resource_Base
ob_end_clean(); ob_end_clean();
} }
if (isset($smarty->security_policy)) { if (isset($smarty->security_policy)) {
$smarty->security_policy->exitTemplate(); $smarty->security_policy->endTemplate();
} }
throw $e; throw $e;
} }