- bugfix and enhancement

Because several recent problems with template inheritance the {block} tag compiler has been rewriten
   - Error messages shown now the correct child template file and line number
   - The compiler could fail on some larger UTF-8 text block (forum topic 24455}
   - The {strip} tag can now be placed outside {block} tags in child templates (forum topic 24289}
- change SmartyException::$escape  is now false by default
- change PHP traceback has been remove for SmartyException and SmartyCompilerException
This commit is contained in:
Uwe.Tews@googlemail.com
2013-08-24 18:46:31 +00:00
parent e206ba63f0
commit 98c1dd29cd
18 changed files with 4577 additions and 4192 deletions

View File

@@ -1,4 +1,13 @@
===== trunk ===== ===== trunk =====
24.08.2013
- bugfix and enhancement
Because several recent problems with template inheritance the {block} tag compiler has been rewriten
- Error messages shown now the correct child template file and line number
- The compiler could fail on some larger UTF-8 text block (forum topic 24455}
- The {strip} tag can now be placed outside {block} tags in child templates (forum topic 24289}
- change SmartyException::$escape is now false by default
- change PHP traceback has been remove for SmartyException and SmartyCompilerException
14.08.2013 14.08.2013
- bugfix compiled filepath of config file did not observe different config_dir (forum topic 24493) - bugfix compiled filepath of config file did not observe different config_dir (forum topic 24493)

View File

@@ -1510,10 +1510,11 @@ if (Smarty::$_CHARSET !== 'UTF-8') {
*/ */
class SmartyException extends Exception class SmartyException extends Exception
{ {
public static $escape = true; public static $escape = false;
public function __construct($message)
public function __toString()
{ {
$this->message = self::$escape ? htmlentities($message) : $message; return ' --> Smarty: ' . (self::$escape ? htmlentities($this->message) : $this->message) . ' <-- ';
} }
} }
@@ -1523,6 +1524,11 @@ class SmartyException extends Exception
*/ */
class SmartyCompilerException extends SmartyException class SmartyCompilerException extends SmartyException
{ {
public function __toString()
{
return ' --> Smarty Compiler: ' . $this->message . ' <-- ';
}
} }
/** /**

View File

@@ -18,6 +18,8 @@
*/ */
class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase
{ {
const parent = '____SMARTY_BLOCK_PARENT____';
/** /**
* Attribute definition: Overwrites base class. * Attribute definition: Overwrites base class.
* *
@@ -32,7 +34,7 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $shorttag_order = array('name', 'hide'); public $shorttag_order = array('name');
/** /**
* Attribute definition: Overwrites base class. * Attribute definition: Overwrites base class.
@@ -40,7 +42,28 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $optional_attributes = array('hide'); public $option_flags = array('hide', 'append', 'prepend', 'nocache');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('internal_file', 'internal_uid', 'internal_line');
/**
* nested child block names
*
* @var array
*/
public static $nested_block_names = array();
/**
* child block source buffer
*
* @var array
*/
public static $block_data = array();
/** /**
* Compiles code for the {block} tag * Compiles code for the {block} tag
@@ -53,15 +76,37 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase
{ {
// check and get attributes // check and get attributes
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args);
$save = array($_attr, $compiler->parser->current_buffer, $compiler->nocache, $compiler->smarty->merge_compiled_includes, $compiler->merged_templates, $compiler->smarty->merged_templates_func, $compiler->template->properties, $compiler->template->has_nocache_code); $_name = trim($_attr['name'], "\"'");
$this->openTag($compiler, 'block', $save);
if ($_attr['nocache'] == true) { // check if we process an inheritance child template
$compiler->nocache = true; if ($compiler->inheritance_child) {
array_unshift(self::$nested_block_names, $_name);
$this->template->block_data[$_name]['source'] = '';
// build {block} for child block
self::$block_data[$_name]['source'] =
"{$compiler->smarty->left_delimiter}private_child_block name={$_attr['name']} file='{$compiler->template->source->filepath}'" .
" uid='{$compiler->template->source->uid}' line={$compiler->lex->line}";
if ($_attr['nocache']) {
self::$block_data[$_name]['source'] .= ' nocache';
}
self::$block_data[$_name]['source'] .= $compiler->smarty->right_delimiter;
$save = array($_attr, $compiler->inheritance);
$this->openTag($compiler, 'block', $save);
// set flag for {block} tag
$compiler->inheritance = true;
$compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK);
$compiler->has_code = false;
return;
} }
// set flag for {block} tag
$compiler->inheritance = true;
// must merge includes // must merge includes
$compiler->smarty->merge_compiled_includes = true; if ($_attr['nocache'] == true) {
$compiler->tag_nocache = true;
}
$save = array($_attr, $compiler->inheritance, $compiler->parser->current_buffer, $compiler->nocache);
$this->openTag($compiler, 'block', $save);
$compiler->inheritance = true;
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
$compiler->parser->current_buffer = new _smarty_template_buffer($compiler->parser); $compiler->parser->current_buffer = new _smarty_template_buffer($compiler->parser);
$compiler->has_code = false; $compiler->has_code = false;
@@ -69,167 +114,69 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase
return true; return true;
} }
/**
* Save or replace child block source by block name during parsing
*
* @param string $block_content block source content
* @param string $block_tag opening block tag
* @param object $template template object
* @param string $filepath filepath of template source
*/
static function saveBlockData($block_content, $block_tag, $template, $filepath)
{
$nesting = array();
$hide_level = 0;
$child_flag = false;
$_rdl = preg_quote($template->smarty->right_delimiter);
$_ldl = preg_quote($template->smarty->left_delimiter);
if (!$template->smarty->auto_literal) {
$al = '\s*';
} else {
$al = '';
}
if (0 == preg_match("!({$_ldl}{$al}block\s+)(name=)?(\w+|'.*'|\".*\")(\s*?)?((append|prepend|nocache)?(\s*)?(hide)?)?(\s*{$_rdl})!", $block_tag, $_match)) {
$error_text = 'Syntax Error in template "' . $template->source->filepath . '" "' . $block_tag . '" illegal options';
throw new SmartyCompilerException($error_text);
} else {
$_name = trim($_match[3], '\'"');
// replace {$smarty.block.child}
// get nested block tags
preg_match_all("%({$_ldl}{$al}block\s+)(name=)?(\w+|'.*?'|\".*?\")([\s\S]*?)(hide)?(\s*{$_rdl})|({$_ldl}{$al}/block\s*{$_rdl})|({$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl})|({$_ldl}|{$_rdl})|([\s\S]*?(?=({$_ldl}|{$_rdl})))%", $block_tag . $block_content . "{$template->smarty->left_delimiter}/block{$template->smarty->right_delimiter}", $_match2);
$block_content = '';
foreach ($_match2[0] as $key => $text) {
// {block} tag
if (!empty($_match2[3][$key])) {
$name = trim($_match2[3][$key], '\'"');
array_push($nesting, array($name, $block_content, $child_flag));
$block_content = '';
// hide option
if (!empty($_match2[5][$key]) && $hide_level == 0 && !isset($template->block_data[$name])) {
$hide_level = count($nesting);
}
continue;
}
// {/block} tag
if (!empty($_match2[7][$key])) {
list($name, $content, $cf) = array_pop($nesting);
if (isset($template->block_data[$name]) && !$child_flag) {
if ($template->block_data[$name]['mode'] == 'prepend') {
$block_content = $content . $template->block_data[$name]['source'] . $block_content;
} elseif ($template->block_data[$name]['mode'] == 'append') {
$block_content = $content . $block_content . $template->block_data[$name]['source'];
} else {
// check if {$smarty.block.parent} will be later replaced
if (strpos($template->block_data[$name]['source'], '%%%%SMARTY_PARENT%%%%') === false) {
$block_content = $content . $template->block_data[$name]['source'];
}
}
} else {
$block_content = $content . $block_content;
$cf = true;
}
$child_flag = $cf;
if (count($nesting) < $hide_level) {
$hide_level = 0;
}
continue;
}
// hide option active
if ($hide_level && $hide_level <= count($nesting)) {
continue;
}
// {$smarty.block.child} tag
if (!empty($_match2[8][$key])) {
list($name, $content, $cf) = end($nesting);
if (isset($template->block_data[$name])) {
$child_flag = true;
$block_content .= $template->block_data[$name]['source'];
}
continue;
}
$block_content .= $_match2[0][$key];
}
// $block_content = preg_replace_callback("%({$_ldl}{$al}block\s+)(name=)?(\w+|'.*?'|\".*?\")([\s\S]*?)(hide)?(\s*{$_rdl})|({$_ldl}{$al}/block\s*{$_rdl})|({$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl})|({$_ldl}|{$_rdl})|([\s\S]*?(?=({$_ldl}|{$_rdl})))%", array('Smarty_Internal_Compile_Block', 'replaceBlockChild'), $block_tag.$block_content."{$template->smarty->left_delimiter}/block{$template->smarty->right_delimiter}");
if (isset($template->block_data[$_name])) {
if (strpos($template->block_data[$_name]['source'], '%%%%SMARTY_PARENT%%%%') !== false) {
$template->block_data[$_name]['source'] =
str_replace('%%%%SMARTY_PARENT%%%%', $block_content, $template->block_data[$_name]['source']);
} elseif ($template->block_data[$_name]['mode'] == 'prepend') {
$template->block_data[$_name]['source'] .= $block_content;
} elseif ($template->block_data[$_name]['mode'] == 'append') {
$template->block_data[$_name]['source'] = $block_content . $template->block_data[$_name]['source'];
}
} else {
$template->block_data[$_name]['source'] = $block_content;
$template->block_data[$_name]['file'] = $filepath;
}
if ($child_flag) {
$template->block_data[$_name]['source'] = $block_content;
$template->block_data[$_name]['file'] = $filepath;
}
if ($_match[6] == 'append') {
$template->block_data[$_name]['mode'] = 'append';
} elseif ($_match[6] == 'prepend') {
$template->block_data[$_name]['mode'] = 'prepend';
} else {
$template->block_data[$_name]['mode'] = 'replace';
}
}
}
/** /**
* Compile saved child block source * Compile saved child block source
* *
* @param object $compiler compiler object * @param object $compiler compiler object
* @param string $_name optional name of child block * @param string $_name optional name of child block
* @return string compiled code of schild block * @return string compiled code of child block
*/ */
static function compileChildBlock($compiler, $_name = null) static function compileChildBlock($compiler, $_name = null)
{ {
$_output = ''; if ($compiler->inheritance_child) {
$name1 = Smarty_Internal_Compile_Block::$nested_block_names[0];
if (isset($compiler->template->block_data[$name1])) {
// replace inner block name with generic
Smarty_Internal_Compile_Block::$block_data[$name1]['source'] .= $compiler->template->block_data[$name1]['source'];
Smarty_Internal_Compile_Block::$block_data[$name1]['child'] = true;
}
$compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK);
$compiler->has_code = false;
return;
}
// if called by {$smarty.block.child} we must search the name of enclosing {block} // if called by {$smarty.block.child} we must search the name of enclosing {block}
if ($_name == null) { if ($_name == null) {
$stack_count = count($compiler->_tag_stack); $stack_count = count($compiler->_tag_stack);
while (--$stack_count >= 0) { while (--$stack_count >= 0) {
if ($compiler->_tag_stack[$stack_count][0] == 'block') { if ($compiler->_tag_stack[$stack_count][0] == 'block') {
$_name = trim($compiler->_tag_stack[$stack_count][1][0]['name'], "'\""); $_name = trim($compiler->_tag_stack[$stack_count][1][0]['name'], "\"'");
break; break;
} }
} }
// flag that child is already compile by {$smarty.block.child} inclusion
$compiler->template->block_data[$_name]['compiled'] = true;
} }
if ($_name == null) { if ($_name == null) {
$compiler->trigger_template_error('{$smarty.block.child} used out of context', $compiler->lex->taglineno); $compiler->trigger_template_error(' tag {$smarty.block.child} used outside {block} tags ', $compiler->lex->taglineno);
} }
// undefined child? // undefined child?
if (!isset($compiler->template->block_data[$_name]['source'])) { if (!isset($compiler->template->block_data[$_name]['source'])) {
$compiler->popTrace();
return ''; return '';
} }
// flag that child is already compile by {$smarty.block.child} inclusion
$compiler->template->block_data[$_name]['compiled'] = true;
$_tpl = new Smarty_Internal_template('string:' . $compiler->template->block_data[$_name]['source'], $compiler->smarty, $compiler->template, $compiler->template->cache_id, $_tpl = new Smarty_Internal_template('string:' . $compiler->template->block_data[$_name]['source'], $compiler->smarty, $compiler->template, $compiler->template->cache_id,
$compiler->template->compile_id, $compiler->template->caching, $compiler->template->cache_lifetime); $compiler->template->compile_id, $compiler->template->caching, $compiler->template->cache_lifetime);
if ($compiler->smarty->debugging) {
Smarty_Internal_Debug::ignore($_tpl);
}
$_tpl->variable_filters = $compiler->template->variable_filters; $_tpl->variable_filters = $compiler->template->variable_filters;
$_tpl->properties['nocache_hash'] = $compiler->template->properties['nocache_hash']; $_tpl->properties['nocache_hash'] = $compiler->template->properties['nocache_hash'];
$_tpl->source->filepath = $compiler->template->block_data[$_name]['file'];
$_tpl->allow_relative_path = true; $_tpl->allow_relative_path = true;
if ($compiler->nocache) { $_tpl->compiler->inheritance = true;
$_tpl->compiler->forceNocache = 2;
} else {
$_tpl->compiler->forceNocache = 1;
}
$_tpl->compiler->suppressHeader = true; $_tpl->compiler->suppressHeader = true;
$_tpl->compiler->suppressFilter = true; $_tpl->compiler->suppressFilter = true;
$_tpl->compiler->suppressTemplatePropertyHeader = true; $_tpl->compiler->suppressTemplatePropertyHeader = true;
$_tpl->compiler->suppressMergedTemplates = true; $_tpl->compiler->suppressMergedTemplates = true;
if (strpos($compiler->template->block_data[$_name]['source'], '%%%%SMARTY_PARENT%%%%') !== false) { $nocache = $compiler->nocache || $compiler->tag_nocache;
$_output = str_replace('%%%%SMARTY_PARENT%%%%', $compiler->parser->current_buffer->to_smarty_php(), $_tpl->compiler->compileTemplate($_tpl)); if (strpos($compiler->template->block_data[$_name]['source'], self::parent) !== false) {
$_output = str_replace(self::parent, $compiler->parser->current_buffer->to_smarty_php(), $_tpl->compiler->compileTemplate($_tpl, $nocache));
} elseif ($compiler->template->block_data[$_name]['mode'] == 'prepend') { } elseif ($compiler->template->block_data[$_name]['mode'] == 'prepend') {
$_output = $_tpl->compiler->compileTemplate($_tpl) . $compiler->parser->current_buffer->to_smarty_php(); $_output = $_tpl->compiler->compileTemplate($_tpl, $nocache) . $compiler->parser->current_buffer->to_smarty_php();
} elseif ($compiler->template->block_data[$_name]['mode'] == 'append') { } elseif ($compiler->template->block_data[$_name]['mode'] == 'append') {
$_output = $compiler->parser->current_buffer->to_smarty_php() . $_tpl->compiler->compileTemplate($_tpl); $_output = $compiler->parser->current_buffer->to_smarty_php() . $_tpl->compiler->compileTemplate($_tpl, $nocache);
} elseif (!empty($compiler->template->block_data[$_name])) { } elseif (!empty($compiler->template->block_data[$_name])) {
$_output = $_tpl->compiler->compileTemplate($_tpl); $_output = $_tpl->compiler->compileTemplate($_tpl, $nocache);
} }
$compiler->template->properties['file_dependency'] = array_merge($compiler->template->properties['file_dependency'], $_tpl->properties['file_dependency']); $compiler->template->properties['file_dependency'] = array_merge($compiler->template->properties['file_dependency'], $_tpl->properties['file_dependency']);
$compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $_tpl->properties['function']); $compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $_tpl->properties['function']);
@@ -251,12 +198,55 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase
} }
} }
unset($_tpl); unset($_tpl);
$compiler->has_code = true;
return $_output; return $_output;
} }
/**
* Compile $smarty.block.parent
*
* @param object $compiler compiler object
* @param string $_name optional name of child block
* @return string compiled code of schild block
*/
static function compileParentBlock($compiler, $_name = null)
{
// if called by {$smarty.block.parent} we must search the name of enclosing {block}
if ($_name == null) {
$stack_count = count($compiler->_tag_stack);
while (--$stack_count >= 0) {
if ($compiler->_tag_stack[$stack_count][0] == 'block') {
$_name = trim($compiler->_tag_stack[$stack_count][1][0]['name'], "\"'");
break;
}
}
}
if ($_name == null) {
$compiler->trigger_template_error(' tag {$smarty.block.parent} used outside {block} tags ', $compiler->lex->taglineno);
}
if (empty(Smarty_Internal_Compile_Block::$nested_block_names)) {
$compiler->trigger_template_error(' illegal {$smarty.block.parent} in parent template ', $compiler->lex->taglineno);
}
Smarty_Internal_Compile_Block::$block_data[Smarty_Internal_Compile_Block::$nested_block_names[0]]['source'] .= Smarty_Internal_Compile_Block::parent;
$compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK);
$compiler->has_code = false;
return;
}
/**
* Process block source
*
* @param string $source source text
* @return ''
*/
static function blockSource($compiler, $source)
{
Smarty_Internal_Compile_Block::$block_data[Smarty_Internal_Compile_Block::$nested_block_names[0]]['source'] .= $source;
}
} }
/** /**
* Smarty Internal Plugin Compile BlockClose Class * Smarty Internal Plugin Compile BlockClose Class
* *
@@ -279,19 +269,63 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_CompileBase
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args);
$saved_data = $this->closeTag($compiler, array('block')); $saved_data = $this->closeTag($compiler, array('block'));
$_name = trim($saved_data[0]['name'], "\"'"); $_name = trim($saved_data[0]['name'], "\"'");
// reset flag for {block} tag
$compiler->inheritance = $saved_data[1];
// check if we process an inheritance child template
if ($compiler->inheritance_child) {
$name1 = Smarty_Internal_Compile_Block::$nested_block_names[0];
Smarty_Internal_Compile_Block::$block_data[$name1]['source'] .= "{$compiler->smarty->left_delimiter}/private_child_block{$compiler->smarty->right_delimiter}";
$level = count(Smarty_Internal_Compile_Block::$nested_block_names);
array_shift(Smarty_Internal_Compile_Block::$nested_block_names);
if (!empty(Smarty_Internal_Compile_Block::$nested_block_names)) {
$name2 = Smarty_Internal_Compile_Block::$nested_block_names[0];
if (isset($compiler->template->block_data[$name1]) || !$saved_data[0]['hide']) {
if (isset(Smarty_Internal_Compile_Block::$block_data[$name1]['child']) || !isset($compiler->template->block_data[$name1])) {
Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= Smarty_Internal_Compile_Block::$block_data[$name1]['source'];
} else {
if ($compiler->template->block_data[$name1]['mode'] == 'append') {
Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= Smarty_Internal_Compile_Block::$block_data[$name1]['source'] . $compiler->template->block_data[$name1]['source'];
} elseif ($compiler->template->block_data[$name1]['mode'] == 'prepend') {
Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= $compiler->template->block_data[$name1]['source'] . Smarty_Internal_Compile_Block::$block_data[$name1]['source'];
} else {
Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= $compiler->template->block_data[$name1]['source'];
}
}
}
unset(Smarty_Internal_Compile_Block::$block_data[$name1]);
$compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK);
} else {
if (isset($compiler->template->block_data[$name1]) || !$saved_data[0]['hide']) {
if (isset($compiler->template->block_data[$name1]) && !isset(Smarty_Internal_Compile_Block::$block_data[$name1]['child'])) {
if (strpos($compiler->template->block_data[$name1]['source'], Smarty_Internal_Compile_Block::parent) !== false) {
$compiler->template->block_data[$name1]['source'] =
str_replace(Smarty_Internal_Compile_Block::parent, Smarty_Internal_Compile_Block::$block_data[$name1]['source'], $compiler->template->block_data[$name1]['source']);
} elseif ($compiler->template->block_data[$name1]['mode'] == 'prepend') {
$compiler->template->block_data[$name1]['source'] .= Smarty_Internal_Compile_Block::$block_data[$name1]['source'];
} elseif ($compiler->template->block_data[$name1]['mode'] == 'append') {
$compiler->template->block_data[$name1]['source'] = Smarty_Internal_Compile_Block::$block_data[$name1]['source'] . $compiler->template->block_data[$name1]['source'];
}
} else {
$compiler->template->block_data[$name1]['source'] = Smarty_Internal_Compile_Block::$block_data[$name1]['source'];
}
$compiler->template->block_data[$name1]['mode'] = 'replace';
if ($saved_data[0]['append']) {
$compiler->template->block_data[$name1]['mode'] = 'append';
}
if ($saved_data[0]['prepend']) {
$compiler->template->block_data[$name1]['mode'] = 'prepend';
}
}
unset(Smarty_Internal_Compile_Block::$block_data[$name1]);
$compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBODY);
}
$compiler->has_code = false;
return;
}
if (isset($compiler->template->block_data[$_name]) && !isset($compiler->template->block_data[$_name]['compiled'])) { if (isset($compiler->template->block_data[$_name]) && !isset($compiler->template->block_data[$_name]['compiled'])) {
// restore to status before {block} tag as new subtemplate code of parent {block} is not needed
// TODO: Below code was disabled in 3.1.8 because of problems with {include} in nested {block} tags in child templates
// combined with append/prepend or $smarty.block.parent
// For later versions it should be checked under which conditions it could run for optimisation
//
//$compiler->merged_templates = $saved_data[4];
//$compiler->smarty->merged_templates_func = $saved_data[5];
//$compiler->template->properties = $saved_data[6];
//$compiler->template->has_nocache_code = $saved_data[7];
$_output = Smarty_Internal_Compile_Block::compileChildBlock($compiler, $_name); $_output = Smarty_Internal_Compile_Block::compileChildBlock($compiler, $_name);
} else { } else {
if (isset($saved_data[0]['hide']) && !isset($compiler->template->block_data[$_name]['source'])) { if ($saved_data[0]['hide'] && !isset($compiler->template->block_data[$_name]['source'])) {
$_output = ''; $_output = '';
} else { } else {
$_output = $compiler->parser->current_buffer->to_smarty_php(); $_output = $compiler->parser->current_buffer->to_smarty_php();
@@ -299,15 +333,96 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_CompileBase
unset($compiler->template->block_data[$_name]['compiled']); unset($compiler->template->block_data[$_name]['compiled']);
} }
// reset flags // reset flags
$compiler->parser->current_buffer = $saved_data[1]; $compiler->parser->current_buffer = $saved_data[2];
$compiler->nocache = $saved_data[2]; if ($compiler->nocache) {
$compiler->smarty->merge_compiled_includes = $saved_data[3]; $compiler->tag_nocache = true;
// reset flag for {block} tag }
$compiler->inheritance = false; $compiler->nocache = $saved_data[3];
// $_output content has already nocache code processed // $_output content has already nocache code processed
$compiler->suppressNocacheProcessing = true; $compiler->suppressNocacheProcessing = true;
return $_output; return $_output;
} }
}
/**
* Smarty Internal Plugin Compile Child Block Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Private_Child_Block extends Smarty_Internal_CompileBase
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $required_attributes = array('name', 'file', 'uid', 'line');
/**
* Compiles code for the {private_child_block} tag
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
* @return boolean true
*/
public function compile($args, $compiler)
{
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
// must merge includes
if ($_attr['nocache'] == true) {
$compiler->tag_nocache = true;
}
$save = array($_attr, $compiler->nocache);
// set trace back to child block
$compiler->pushTrace(trim($_attr['file'], "\"'"), trim($_attr['uid'], "\"'"), $_attr['line'] - $compiler->lex->line);
$this->openTag($compiler, 'private_child_block', $save);
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
$compiler->has_code = false;
return true;
}
}
/**
* Smarty Internal Plugin Compile Child Block Close Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Private_Child_Blockclose extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {/private_child_block} tag
*
* @param array $args array with attributes from parser
* @param object $compiler compiler object
* @return boolean true
*/
public function compile($args, $compiler)
{
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$saved_data = $this->closeTag($compiler, array('private_child_block'));
// end of child block
$compiler->popTrace();
$compiler->nocache = $saved_data[1];
$compiler->has_code = false;
return true;
}
} }

View File

@@ -68,7 +68,6 @@ class Smarty_Internal_Compile_Break extends Smarty_Internal_CompileBase
if ($level_count != 0) { if ($level_count != 0) {
$compiler->trigger_template_error("cannot break {$_levels} level(s)", $compiler->lex->taglineno); $compiler->trigger_template_error("cannot break {$_levels} level(s)", $compiler->lex->taglineno);
} }
$compiler->has_code = true;
return "<?php break {$_levels}?>"; return "<?php break {$_levels}?>";
} }

View File

@@ -69,7 +69,6 @@ class Smarty_Internal_Compile_Continue extends Smarty_Internal_CompileBase
if ($level_count != 0) { if ($level_count != 0) {
$compiler->trigger_template_error("cannot continue {$_levels} level(s)", $compiler->lex->taglineno); $compiler->trigger_template_error("cannot continue {$_levels} level(s)", $compiler->lex->taglineno);
} }
$compiler->has_code = true;
return "<?php continue {$_levels}?>"; return "<?php continue {$_levels}?>";
} }

View File

@@ -1,132 +1,87 @@
<?php <?php
/** /**
* Smarty Internal Plugin Compile extend * Smarty Internal Plugin Compile extend
* *
* Compiles the {extends} tag * Compiles the {extends} tag
* *
* @package Smarty * @package Smarty
* @subpackage Compiler * @subpackage Compiler
* @author Uwe Tews * @author Uwe Tews
*/ */
/** /**
* Smarty Internal Plugin Compile extend Class * Smarty Internal Plugin Compile extend Class
* *
* @package Smarty * @package Smarty
* @subpackage Compiler * @subpackage Compiler
*/ */
class Smarty_Internal_Compile_Extends extends Smarty_Internal_CompileBase class Smarty_Internal_Compile_Extends extends Smarty_Internal_CompileBase
{ {
/** /**
* Attribute definition: Overwrites base class. * Attribute definition: Overwrites base class.
* *
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $required_attributes = array('file'); public $required_attributes = array('file');
/** /**
* Attribute definition: Overwrites base class. * Attribute definition: Overwrites base class.
* *
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $shorttag_order = array('file'); public $shorttag_order = array('file');
/**
* mbstring.overload flag
*
* @var int
*/
public $mbstring_overload = 0;
/** /**
* Compiles code for the {extends} tag * Compiles code for the {extends} tag
* *
* @param array $args array with attributes from parser * @param array $args array with attributes from parser
* @param object $compiler compiler object * @param object $compiler compiler object
* @return string compiled code * @return string compiled code
*/ */
public function compile($args, $compiler) public function compile($args, $compiler)
{ {
static $_is_stringy = array('string' => true, 'eval' => true);
$this->_rdl = preg_quote($compiler->smarty->right_delimiter);
$this->_ldl = preg_quote($compiler->smarty->left_delimiter);
if (!$compiler->smarty->auto_literal) {
$al = '\s*';
} else {
$al = '';
}
$filepath = $compiler->template->source->filepath;
$this->mbstring_overload = ini_get('mbstring.func_overload') & 2;
// check and get attributes // check and get attributes
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache'] === true) { if ($_attr['nocache'] === true) {
$compiler->trigger_template_error('nocache option not allowed', $compiler->lex->taglineno); $compiler->trigger_template_error('nocache option not allowed', $compiler->lex->taglineno);
} }
$_smarty_tpl = $compiler->template;
$include_file = null;
if (strpos($_attr['file'], '$_tmp') !== false) { if (strpos($_attr['file'], '$_tmp') !== false) {
$compiler->trigger_template_error('illegal value for file attribute', $compiler->lex->taglineno); $compiler->trigger_template_error('illegal value for file attribute', $compiler->lex->taglineno);
} }
eval('$include_file = ' . $_attr['file'] . ';'); // add tag to call parent template at the end of source
// create template object
$_template = new $compiler->smarty->template_class($include_file, $compiler->smarty, $compiler->template);
// save file dependency
if (isset($_is_stringy[$_template->source->type])) {
$template_sha1 = sha1($include_file);
} else {
$template_sha1 = sha1($_template->source->filepath);
}
if (isset($compiler->template->properties['file_dependency'][$template_sha1])) {
$compiler->trigger_template_error("illegal recursive call of \"{$include_file}\"", $compiler->lex->line - 1);
}
$compiler->template->properties['file_dependency'][$template_sha1] = array($_template->source->filepath, $_template->source->timestamp, $_template->source->type);
$_content = ($this->mbstring_overload ? mb_substr($compiler->lex->data, $compiler->lex->counter - 1, 20000000, 'latin1') : substr($compiler->lex->data, $compiler->lex->counter - 1));
if (preg_match_all("!({$this->_ldl}{$al}block\s(.+?)\s*{$this->_rdl})!", $_content, $s) !=
preg_match_all("!({$this->_ldl}{$al}/block\s*{$this->_rdl})!", $_content, $c)) {
$compiler->trigger_template_error('unmatched {block} {/block} pairs');
}
preg_match_all("!{$this->_ldl}{$al}block\s(.+?)\s*{$this->_rdl}|{$this->_ldl}{$al}/block\s*{$this->_rdl}|{$this->_ldl}\*([\S\s]*?)\*{$this->_rdl}!", $_content, $_result, PREG_OFFSET_CAPTURE);
$_result_count = count($_result[0]);
$_start = 0;
while ($_start+1 < $_result_count) {
$_end = 0;
$_level = 1;
if (($this->mbstring_overload ? mb_substr($_result[0][$_start][0],0,mb_strlen($compiler->smarty->left_delimiter,'latin1')+1, 'latin1') : substr($_result[0][$_start][0],0,strlen($compiler->smarty->left_delimiter)+1)) == $compiler->smarty->left_delimiter.'*') {
$_start++;
continue;
}
while ($_level != 0) {
$_end++;
if (($this->mbstring_overload ? mb_substr($_result[0][$_start + $_end][0],0,mb_strlen($compiler->smarty->left_delimiter,'latin1')+1, 'latin1') : substr($_result[0][$_start + $_end][0],0,strlen($compiler->smarty->left_delimiter)+1)) == $compiler->smarty->left_delimiter.'*') {
continue;
}
if (!strpos($_result[0][$_start + $_end][0], '/')) {
$_level++;
} else {
$_level--;
}
}
$_block_content = str_replace($compiler->smarty->left_delimiter . '$smarty.block.parent' . $compiler->smarty->right_delimiter, '%%%%SMARTY_PARENT%%%%',
($this->mbstring_overload ? mb_substr($_content, $_result[0][$_start][1] + mb_strlen($_result[0][$_start][0], 'latin1'), $_result[0][$_start + $_end][1] - $_result[0][$_start][1] - + mb_strlen($_result[0][$_start][0], 'latin1'), 'latin1') : substr($_content, $_result[0][$_start][1] + strlen($_result[0][$_start][0]), $_result[0][$_start + $_end][1] - $_result[0][$_start][1] - + strlen($_result[0][$_start][0]))));
Smarty_Internal_Compile_Block::saveBlockData($_block_content, $_result[0][$_start][0], $compiler->template, $filepath);
$_start = $_start + $_end + 1;
}
if ($_template->source->type == 'extends') {
$_template->block_data = $compiler->template->block_data;
}
$compiler->template->source->content = $_template->source->content;
if ($_template->source->type == 'extends') {
$compiler->template->block_data = $_template->block_data;
foreach ($_template->source->components as $key => $component) {
$compiler->template->properties['file_dependency'][$key] = array($component->filepath, $component->timestamp, $component->type);
}
}
$compiler->template->source->filepath = $_template->source->filepath;
$compiler->abort_and_recompile = true;
if ($compiler->has_variable_string || !((substr_count($_attr['file'], '"') == 2 || substr_count($_attr['file'], "'") == 2))
|| substr_count($_attr['file'], '(') != 0 || substr_count($_attr['file'], '$_smarty_tpl->') != 0
) {
$compiler->trigger_template_error('variable template file name not allowed', $compiler->lex->taglineno);
}
$name = trim($_attr['file'],"\"'");
// create template object
$_template = new $compiler->smarty->template_class($name, $compiler->smarty, $compiler->template);
// check for recursion
$uid = $_template->source->uid;
if (isset($compiler->extends_uid[$uid])) {
$compiler->trigger_template_error("illegal recursive call of \"$include_file\"", $this->lex->line - 1);
}
$compiler->extends_uid[$uid] = true;
if (empty($_template->source->components)) {
array_unshift($compiler->sources, $_template->source);
} else {
foreach ($_template->source->components as $source) {
array_unshift($compiler->sources, $source);
$uid = $source->uid;
if (isset($compiler->extends_uid[$uid])) {
$compiler->trigger_template_error("illegal recursive call of \"{$sorce->filepath}\"", $this->lex->line - 1);
}
$compiler->extends_uid[$uid] = true;
}
}
unset ($_template);
$compiler->inheritance_child = true;
$compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBODY);
return ''; return '';
} }
} }

View File

@@ -86,7 +86,6 @@ class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase
$compiler->template->has_nocache_code = false; $compiler->template->has_nocache_code = false;
$compiler->has_code = false; $compiler->has_code = false;
$compiler->template->properties['function'][$_name]['compiled'] = ''; $compiler->template->properties['function'][$_name]['compiled'] = '';
return true; return true;
} }

View File

@@ -1,61 +1,61 @@
<?php <?php
/** /**
* Smarty Internal Plugin Compile Include * Smarty Internal Plugin Compile Include
* *
* Compiles the {include} tag * Compiles the {include} tag
* *
* @package Smarty * @package Smarty
* @subpackage Compiler * @subpackage Compiler
* @author Uwe Tews * @author Uwe Tews
*/ */
/** /**
* Smarty Internal Plugin Compile Include Class * Smarty Internal Plugin Compile Include Class
* *
* @package Smarty * @package Smarty
* @subpackage Compiler * @subpackage Compiler
*/ */
class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
{ {
/** /**
* caching mode to create nocache code but no cache file * caching mode to create nocache code but no cache file
*/ */
const CACHING_NOCACHE_CODE = 9999; const CACHING_NOCACHE_CODE = 9999;
/** /**
* Attribute definition: Overwrites base class. * Attribute definition: Overwrites base class.
* *
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $required_attributes = array('file'); public $required_attributes = array('file');
/** /**
* Attribute definition: Overwrites base class. * Attribute definition: Overwrites base class.
* *
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $shorttag_order = array('file'); public $shorttag_order = array('file');
/** /**
* Attribute definition: Overwrites base class. * Attribute definition: Overwrites base class.
* *
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $option_flags = array('nocache', 'inline', 'caching'); public $option_flags = array('nocache', 'inline', 'caching');
/** /**
* Attribute definition: Overwrites base class. * Attribute definition: Overwrites base class.
* *
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $optional_attributes = array('_any'); public $optional_attributes = array('_any');
/** /**
* Compiles code for the {include} tag * Compiles code for the {include} tag
* *
* @param array $args array with attributes from parser * @param array $args array with attributes from parser
* @param object $compiler compiler object * @param object $compiler compiler object
* @param array $parameter array with compilation parameter * @param array $parameter array with compilation parameter
* @return string compiled code * @return string compiled code
*/ */
public function compile($args, $compiler, $parameter) public function compile($args, $compiler, $parameter)
@@ -81,12 +81,15 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
$_parent_scope = Smarty::SCOPE_GLOBAL; $_parent_scope = Smarty::SCOPE_GLOBAL;
} }
} }
$_caching = 'null';
if ($compiler->nocache || $compiler->tag_nocache) { $_caching = Smarty::CACHING_OFF;
$_caching = Smarty::CACHING_OFF;
} // flag if included template code should be merged into caller
// default for included templates $merge_compiled_includes = ($compiler->smarty->merge_compiled_includes || $_attr['inline'] === true) && !$compiler->template->source->recompiled;
if ($compiler->template->caching && !$compiler->nocache && !$compiler->tag_nocache) {
// set default when in nocache mode
// if ($compiler->template->caching && ($compiler->nocache || $compiler->tag_nocache || $compiler->forceNocache == 2)) {
if ($compiler->template->caching && ((!$compiler->inheritance && !$compiler->nocache && !$compiler->tag_nocache) || ($compiler->inheritance && ($compiler->nocache ||$compiler->tag_nocache)))) {
$_caching = self::CACHING_NOCACHE_CODE; $_caching = self::CACHING_NOCACHE_CODE;
} }
/* /*
@@ -118,53 +121,89 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
} }
if ($_attr['nocache'] === true) { if ($_attr['nocache'] === true) {
$compiler->tag_nocache = true; $compiler->tag_nocache = true;
if ($merge_compiled_includes || $compiler->inheritance) {
$_caching = self::CACHING_NOCACHE_CODE;
} else {
$_caching = Smarty::CACHING_OFF; $_caching = Smarty::CACHING_OFF;
}
} }
$has_compiled_template = false; $has_compiled_template = false;
if (($compiler->smarty->merge_compiled_includes || $_attr['inline'] === true) && !$compiler->template->source->recompiled if ($merge_compiled_includes || $compiler->inheritance) {
&& !($compiler->template->caching && ($compiler->tag_nocache || $compiler->nocache)) && $_caching != Smarty::CACHING_LIFETIME_CURRENT) { // variable template name ?
// check if compiled code can be merged (contains no variable part) if ($compiler->has_variable_string || !((substr_count($include_file, '"') == 2 || substr_count($include_file, "'") == 2))
if (!$compiler->has_variable_string && (substr_count($include_file, '"') == 2 or substr_count($include_file, "'") == 2) || substr_count($include_file, '(') != 0 || substr_count($include_file, '$_smarty_tpl->') != 0
and substr_count($include_file, '(') == 0 and substr_count($include_file, '$_smarty_tpl->') == 0) { ) {
$tpl_name = null; $merge_compiled_includes = false;
eval("\$tpl_name = $include_file;"); if ($compiler->inheritance) {
if (!isset($compiler->smarty->merged_templates_func[$tpl_name]) || $compiler->inheritance) { $compiler->trigger_template_error(' variable template file names not allow within {block} tags');
$tpl = new $compiler->smarty->template_class ($tpl_name, $compiler->smarty, $compiler->template, $compiler->template->cache_id, $compiler->template->compile_id);
// save unique function name
$compiler->smarty->merged_templates_func[$tpl_name]['func'] = $tpl->properties['unifunc'] = 'content_'. str_replace('.', '_', uniqid('', true));
// use current nocache hash for inlined code
$compiler->smarty->merged_templates_func[$tpl_name]['nocache_hash'] = $tpl->properties['nocache_hash'] = $compiler->template->properties['nocache_hash'];
if ($compiler->template->caching) {
// needs code for cached page but no cache file
$tpl->caching = self::CACHING_NOCACHE_CODE;
}
// make sure whole chain gest compiled
$tpl->mustCompile = true;
if (!($tpl->source->uncompiled) && $tpl->source->exists) {
// get compiled code
$compiled_code = $tpl->compiler->compileTemplate($tpl);
// release compiler object to free memory
unset($tpl->compiler);
// merge compiled code for {function} tags
$compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $tpl->properties['function']);
// merge filedependency
$tpl->properties['file_dependency'][$tpl->source->uid] = array($tpl->source->filepath, $tpl->source->timestamp,$tpl->source->type);
$compiler->template->properties['file_dependency'] = array_merge($compiler->template->properties['file_dependency'], $tpl->properties['file_dependency']);
// remove header code
$compiled_code = preg_replace("/(<\?php \/\*%%SmartyHeaderCode:{$tpl->properties['nocache_hash']}%%\*\/(.+?)\/\*\/%%SmartyHeaderCode%%\*\/\?>\n)/s", '', $compiled_code);
if ($tpl->has_nocache_code) {
// replace nocache_hash
$compiled_code = str_replace("{$tpl->properties['nocache_hash']}", $compiler->template->properties['nocache_hash'], $compiled_code);
$compiler->template->has_nocache_code = true;
}
$compiler->merged_templates[$tpl->properties['unifunc']] = $compiled_code;
$has_compiled_template = true;
}
} else {
$has_compiled_template = true;
} }
} }
// variable compile_id?
if (isset($_attr['compile_id'])) {
if (!((substr_count($_attr['compile_id'], '"') == 2 || substr_count($_attr['compile_id'], "'") == 2))
|| substr_count($_attr['compile_id'], '(') != 0 || substr_count($_attr['compile_id'], '$_smarty_tpl->') != 0
) {
$merge_compiled_includes = false;
if ($compiler->inheritance) {
$compiler->trigger_template_error(' variable compile_id not allow within {block} tags');
}
}
}
if ($compiler->template->caching && ($compiler->tag_nocache || $compiler->nocache) && $_caching != self::CACHING_NOCACHE_CODE) {
$merge_compiled_includes = false;
if ($compiler->inheritance) {
$compiler->trigger_template_error(' invalid caching mode of subtemplate within {block} tags');
}
}
}
if ($merge_compiled_includes || $compiler->inheritance) {
// we must observe different compile_id
$uid = sha1($_compile_id);
$tpl_name = null;
$nocache = false;
eval("\$tpl_name = $include_file;");
if (!isset($compiler->smarty->merged_templates_func[$tpl_name][$uid]) || $compiler->inheritance) {
$tpl = new $compiler->smarty->template_class ($tpl_name, $compiler->smarty, $compiler->template, $compiler->template->cache_id, $compiler->template->compile_id);
// save unique function name
$compiler->smarty->merged_templates_func[$tpl_name][$uid]['func'] = $tpl->properties['unifunc'] = 'content_' . str_replace('.', '_', uniqid('', true));
// use current nocache hash for inlined code
$compiler->smarty->merged_templates_func[$tpl_name][$uid]['nocache_hash'] = $tpl->properties['nocache_hash'] = $compiler->template->properties['nocache_hash'];
if ($compiler->template->caching && $_caching == self::CACHING_NOCACHE_CODE) {
// all code must be nocache
$nocache = true;
}
if ($compiler->inheritance) {
$tpl->compiler->inheritance = true;
}
// make sure whole chain gets compiled
$tpl->mustCompile = true;
if (!($tpl->source->uncompiled) && $tpl->source->exists) {
// get compiled code
$compiled_code = $tpl->compiler->compileTemplate($tpl, $nocache);
// release compiler object to free memory
unset($tpl->compiler);
// merge compiled code for {function} tags
$compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $tpl->properties['function']);
// merge filedependency
$tpl->properties['file_dependency'][$tpl->source->uid] = array($tpl->source->filepath, $tpl->source->timestamp, $tpl->source->type);
$compiler->template->properties['file_dependency'] = array_merge($compiler->template->properties['file_dependency'], $tpl->properties['file_dependency']);
// remove header code
$compiled_code = preg_replace("/(<\?php \/\*%%SmartyHeaderCode:{$tpl->properties['nocache_hash']}%%\*\/(.+?)\/\*\/%%SmartyHeaderCode%%\*\/\?>\n)/s", '', $compiled_code);
if ($tpl->has_nocache_code) {
// replace nocache_hash
$compiled_code = str_replace("{$tpl->properties['nocache_hash']}", $compiler->template->properties['nocache_hash'], $compiled_code);
$compiler->template->has_nocache_code = true;
}
$compiler->merged_templates[$tpl->properties['unifunc']] = $compiled_code;
$has_compiled_template = true;
unset ($tpl);
}
} else {
$has_compiled_template = true;
}
} }
// delete {include} standard attributes // delete {include} standard attributes
unset($_attr['file'], $_attr['assign'], $_attr['cache_id'], $_attr['compile_id'], $_attr['cache_lifetime'], $_attr['nocache'], $_attr['caching'], $_attr['scope'], $_attr['inline']); unset($_attr['file'], $_attr['assign'], $_attr['cache_id'], $_attr['compile_id'], $_attr['cache_lifetime'], $_attr['nocache'], $_attr['caching'], $_attr['scope'], $_attr['inline']);
@@ -175,7 +214,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
foreach ($_attr as $key => $value) { foreach ($_attr as $key => $value) {
$_pairs[] = "'$key'=>$value"; $_pairs[] = "'$key'=>$value";
} }
$_vars = 'array('.join(',',$_pairs).')'; $_vars = 'array(' . join(',', $_pairs) . ')';
$_has_vars = true; $_has_vars = true;
} else { } else {
$compiler->trigger_template_error('variable passing not allowed in parent/global scope', $compiler->lex->taglineno); $compiler->trigger_template_error('variable passing not allowed in parent/global scope', $compiler->lex->taglineno);
@@ -185,19 +224,21 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
$_has_vars = false; $_has_vars = false;
} }
if ($has_compiled_template) { if ($has_compiled_template) {
$_hash = $compiler->smarty->merged_templates_func[$tpl_name]['nocache_hash']; // never call inline templates in nocache mode
$compiler->suppressNocacheProcessing = true;
$_hash = $compiler->smarty->merged_templates_func[$tpl_name][$uid]['nocache_hash'];
$_output = "<?php /* Call merged included template \"" . $tpl_name . "\" */\n"; $_output = "<?php /* Call merged included template \"" . $tpl_name . "\" */\n";
$_output .= "\$_tpl_stack[] = \$_smarty_tpl;\n"; $_output .= "\$_tpl_stack[] = \$_smarty_tpl;\n";
$_output .= " \$_smarty_tpl = \$_smarty_tpl->setupInlineSubTemplate($include_file, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_parent_scope, '$_hash');\n"; $_output .= " \$_smarty_tpl = \$_smarty_tpl->setupInlineSubTemplate($include_file, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_parent_scope, '$_hash');\n";
if (isset($_assign)) { if (isset($_assign)) {
$_output .= 'ob_start(); '; $_output .= 'ob_start(); ';
} }
$_output .= $compiler->smarty->merged_templates_func[$tpl_name]['func']. "(\$_smarty_tpl);\n"; $_output .= $compiler->smarty->merged_templates_func[$tpl_name][$uid]['func'] . "(\$_smarty_tpl);\n";
$_output .= "\$_smarty_tpl = array_pop(\$_tpl_stack); "; $_output .= "\$_smarty_tpl = array_pop(\$_tpl_stack); ";
if (isset($_assign)) { if (isset($_assign)) {
$_output .= " \$_smarty_tpl->tpl_vars[$_assign] = new Smarty_variable(ob_get_clean());"; $_output .= " \$_smarty_tpl->tpl_vars[$_assign] = new Smarty_variable(ob_get_clean());";
} }
$_output .= "/* End of included template \"" . $tpl_name . "\" */?>"; $_output .= "\n/* End of included template \"" . $tpl_name . "\" */?>";
return $_output; return $_output;
} }
@@ -211,5 +252,4 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
return $_output; return $_output;
} }
} }

View File

@@ -32,8 +32,11 @@ class Smarty_Internal_Compile_Nocache extends Smarty_Internal_CompileBase
if ($_attr['nocache'] === true) { if ($_attr['nocache'] === true) {
$compiler->trigger_template_error('nocache option not allowed', $compiler->lex->taglineno); $compiler->trigger_template_error('nocache option not allowed', $compiler->lex->taglineno);
} }
if ($compiler->template->caching) {
// enter nocache mode // enter nocache mode
$this->openTag($compiler, 'nocache', $compiler->nocache);
$compiler->nocache = true; $compiler->nocache = true;
}
// this tag does not return compiled code // this tag does not return compiled code
$compiler->has_code = false; $compiler->has_code = false;
@@ -62,8 +65,10 @@ class Smarty_Internal_Compile_Nocacheclose extends Smarty_Internal_CompileBase
public function compile($args, $compiler) public function compile($args, $compiler)
{ {
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args);
// leave nocache mode if ($compiler->template->caching) {
$compiler->nocache = false; // restore old nocache mode
$compiler->nocache = $this->closeTag($compiler, 'nocache');
}
// this tag does not return compiled code // this tag does not return compiled code
$compiler->has_code = false; $compiler->has_code = false;

View File

@@ -24,6 +24,27 @@ class Smarty_Internal_Debug extends Smarty_Internal_Data
*/ */
public static $template_data = array(); public static $template_data = array();
/**
* List of uid's which shall be ignored
*
* @var array
*/
public static $ignore_uid = array();
/**
* Ignore template
*
* @param object $template
*/
public static function ignore($template)
{
// calculate Uid if not already done
if ($template->source->uid == '') {
$template->source->filepath;
}
self::$ignore_uid[$template->source->uid] = true;
}
/** /**
* Start logging of compile time * Start logging of compile time
* *
@@ -31,7 +52,25 @@ class Smarty_Internal_Debug extends Smarty_Internal_Data
*/ */
public static function start_compile($template) public static function start_compile($template)
{ {
$key = self::get_key($template); static $_is_stringy = array('string' => true, 'eval' => true);
if (!empty($template->compiler->trace_uid)) {
$key = $template->compiler->trace_uid;
if (!isset(self::$template_data[$key])) {
if (isset($_is_stringy[$template->source->type])) {
self::$template_data[$key]['name'] = '\'' . substr($template->source->name, 0, 25) . '...\'';
} else {
self::$template_data[$key]['name'] = $template->source->filepath;
}
self::$template_data[$key]['compile_time'] = 0;
self::$template_data[$key]['render_time'] = 0;
self::$template_data[$key]['cache_time'] = 0;
}
} else {
if (isset(self::$ignore_uid[$template->source->uid])) {
return;
}
$key = self::get_key($template);
}
self::$template_data[$key]['start_time'] = microtime(true); self::$template_data[$key]['start_time'] = microtime(true);
} }
@@ -42,7 +81,15 @@ class Smarty_Internal_Debug extends Smarty_Internal_Data
*/ */
public static function end_compile($template) public static function end_compile($template)
{ {
$key = self::get_key($template); if (!empty($template->compiler->trace_uid)) {
$key = $template->compiler->trace_uid;
} else {
if (isset(self::$ignore_uid[$template->source->uid])) {
return;
}
$key = self::get_key($template);
}
self::$template_data[$key]['compile_time'] += microtime(true) - self::$template_data[$key]['start_time']; self::$template_data[$key]['compile_time'] += microtime(true) - self::$template_data[$key]['start_time'];
} }
@@ -171,7 +218,7 @@ class Smarty_Internal_Debug extends Smarty_Internal_Data
} }
} }
return (object) array('tpl_vars' => $tpl_vars, 'config_vars' => $config_vars); return (object)array('tpl_vars' => $tpl_vars, 'config_vars' => $config_vars);
} }
/** /**
@@ -192,7 +239,7 @@ class Smarty_Internal_Debug extends Smarty_Internal_Data
return $key; return $key;
} else { } else {
if (isset($_is_stringy[$template->source->type])) { if (isset($_is_stringy[$template->source->type])) {
self::$template_data[$key]['name'] = '\''.substr($template->source->name,0,25).'...\''; self::$template_data[$key]['name'] = '\'' . substr($template->source->name, 0, 25) . '...\'';
} else { } else {
self::$template_data[$key]['name'] = $template->source->filepath; self::$template_data[$key]['name'] = $template->source->filepath;
} }

View File

@@ -1,37 +1,37 @@
<?php <?php
/** /**
* Smarty Internal Plugin Resource Extends * Smarty Internal Plugin Resource Extends
* *
* @package Smarty * @package Smarty
* @subpackage TemplateResources * @subpackage TemplateResources
* @author Uwe Tews * @author Uwe Tews
* @author Rodney Rehm * @author Rodney Rehm
*/ */
/** /**
* Smarty Internal Plugin Resource Extends * Smarty Internal Plugin Resource Extends
* *
* Implements the file system as resource for Smarty which {extend}s a chain of template files templates * Implements the file system as resource for Smarty which {extend}s a chain of template files templates
* *
* @package Smarty * @package Smarty
* @subpackage TemplateResources * @subpackage TemplateResources
*/ */
class Smarty_Internal_Resource_Extends extends Smarty_Resource class Smarty_Internal_Resource_Extends extends Smarty_Resource
{ {
/** /**
* mbstring.overload flag * mbstring.overload flag
* *
* @var int * @var int
*/ */
public $mbstring_overload = 0; public $mbstring_overload = 0;
/** /**
* populate Source Object with meta data from Resource * populate Source Object with meta data from Resource
* *
* @param Smarty_Template_Source $source source object * @param Smarty_Template_Source $source source object
* @param Smarty_Internal_Template $_template template object * @param Smarty_Internal_Template $_template template object
*/ */
public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template=null) public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null)
{ {
$uid = ''; $uid = '';
$sources = array(); $sources = array();
@@ -60,10 +60,10 @@ class Smarty_Internal_Resource_Extends extends Smarty_Resource
} }
/** /**
* populate Source Object with timestamp and exists from Resource * populate Source Object with timestamp and exists from Resource
* *
* @param Smarty_Template_Source $source source object * @param Smarty_Template_Source $source source object
*/ */
public function populateTimestamp(Smarty_Template_Source $source) public function populateTimestamp(Smarty_Template_Source $source)
{ {
$source->exists = true; $source->exists = true;
@@ -74,84 +74,34 @@ class Smarty_Internal_Resource_Extends extends Smarty_Resource
} }
/** /**
* Load template's source from files into current template object * Load template's source from files into current template object
* *
* @param Smarty_Template_Source $source source object * @param Smarty_Template_Source $source source object
* @return string template source * @return string template source
* @throws SmartyException if source cannot be loaded * @throws SmartyException if source cannot be loaded
*/ */
public function getContent(Smarty_Template_Source $source) public function getContent(Smarty_Template_Source $source)
{ {
if (!$source->exists) { if (!$source->exists) {
throw new SmartyException("Unable to read template {$source->type} '{$source->name}'"); throw new SmartyException("Unable to read template {$source->type} '{$source->name}'");
} }
$this->mbstring_overload = ini_get('mbstring.func_overload') & 2;
$_rdl = preg_quote($source->smarty->right_delimiter);
$_ldl = preg_quote($source->smarty->left_delimiter);
if (!$source->smarty->auto_literal) {
$al = '\s*';
} else {
$al = '';
}
$_components = array_reverse($source->components); $_components = array_reverse($source->components);
$_first = reset($_components);
$_last = end($_components);
$_content = '';
foreach ($_components as $_component) { foreach ($_components as $_component) {
// register dependency
if ($_component != $_first) {
$source->template->properties['file_dependency'][$_component->uid] = array($_component->filepath, $_component->timestamp, $_component->type);
}
// read content // read content
$source->filepath = $_component->filepath; $_content .= $_component->content;
$_content = $_component->content;
// extend sources
if ($_component != $_last) {
if (preg_match_all("!({$_ldl}{$al}block\s(.+?)\s*{$_rdl})!", $_content, $_open) !=
preg_match_all("!({$_ldl}{$al}/block\s*{$_rdl})!", $_content, $_close)) {
throw new SmartyException("unmatched {block} {/block} pairs in template {$_component->type} '{$_component->name}'");
}
preg_match_all("!{$_ldl}{$al}block\s(.+?)\s*{$_rdl}|{$_ldl}{$al}/block\s*{$_rdl}|{$_ldl}\*([\S\s]*?)\*{$_rdl}!", $_content, $_result, PREG_OFFSET_CAPTURE);
$_result_count = count($_result[0]);
$_start = 0;
while ($_start+1 < $_result_count) {
$_end = 0;
$_level = 1;
if (($this->mbstring_overload ? mb_substr($_result[0][$_start][0],0,mb_strlen($source->smarty->left_delimiter,'latin1')+1, 'latin1') : substr($_result[0][$_start][0],0,strlen($source->smarty->left_delimiter)+1)) == $source->smarty->left_delimiter.'*') {
$_start++;
continue;
}
while ($_level != 0) {
$_end++;
if (($this->mbstring_overload ? mb_substr($_result[0][$_start + $_end][0],0,mb_strlen($source->smarty->left_delimiter,'latin1')+1, 'latin1') : substr($_result[0][$_start + $_end][0],0,strlen($source->smarty->left_delimiter)+1)) == $source->smarty->left_delimiter.'*') {
continue;
}
if (!strpos($_result[0][$_start + $_end][0], '/')) {
$_level++;
} else {
$_level--;
}
}
$_block_content = str_replace($source->smarty->left_delimiter . '$smarty.block.parent' . $source->smarty->right_delimiter, '%%%%SMARTY_PARENT%%%%',
($this->mbstring_overload ? mb_substr($_content, $_result[0][$_start][1] + mb_strlen($_result[0][$_start][0], 'latin1'), $_result[0][$_start + $_end][1] - $_result[0][$_start][1] - + mb_strlen($_result[0][$_start][0], 'latin1'), 'latin1') : substr($_content, $_result[0][$_start][1] + strlen($_result[0][$_start][0]), $_result[0][$_start + $_end][1] - $_result[0][$_start][1] - + strlen($_result[0][$_start][0]))));
Smarty_Internal_Compile_Block::saveBlockData($_block_content, $_result[0][$_start][0], $source->template, $_component->filepath);
$_start = $_start + $_end + 1;
}
} else {
return $_content;
}
} }
return $_content;
} }
/** /**
* Determine basename for compiled filename * Determine basename for compiled filename
* *
* @param Smarty_Template_Source $source source object * @param Smarty_Template_Source $source source object
* @return string resource's basename * @return string resource's basename
*/ */
public function getBasename(Smarty_Template_Source $source) public function getBasename(Smarty_Template_Source $source)
{ {
return str_replace(':', '.', basename($source->filepath)); return str_replace(':', '.', basename($source->filepath));

View File

@@ -94,6 +94,10 @@ class Smarty_Internal_SmartyTemplateCompiler extends Smarty_Internal_TemplateCom
// init the lexer/parser to compile the template // init the lexer/parser to compile the template
$this->lex = new $this->lexer_class($_content, $this); $this->lex = new $this->lexer_class($_content, $this);
$this->parser = new $this->parser_class($this->lex, $this); $this->parser = new $this->parser_class($this->lex, $this);
if ($this->inheritance_child) {
// start state on child templates
$this->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBODY);
}
if ($this->smarty->_parserdebug) if ($this->smarty->_parserdebug)
$this->parser->PrintTrace(); $this->parser->PrintTrace();
// get tokens from lexer and parse them // get tokens from lexer and parse them

View File

@@ -167,16 +167,14 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
if (!$this->source->recompiled) { if (!$this->source->recompiled) {
$this->properties['file_dependency'] = array(); $this->properties['file_dependency'] = array();
if ($this->source->components) { if ($this->source->components) {
// for the extends resource the compiler will fill it
// uses real resource for file dependency // uses real resource for file dependency
$source = end($this->source->components); // $source = end($this->source->components);
$this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $source->type); // $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $source->type);
} else { } else {
$this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $this->source->type); $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $this->source->type);
} }
} }
if ($this->smarty->debugging) {
Smarty_Internal_Debug::start_compile($this);
}
// compile locking // compile locking
if ($this->smarty->compile_locking && !$this->source->recompiled) { if ($this->smarty->compile_locking && !$this->source->recompiled) {
if ($saved_timestamp = $this->compiled->timestamp) { if ($saved_timestamp = $this->compiled->timestamp) {
@@ -203,9 +201,6 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
$this->compiled->exists = true; $this->compiled->exists = true;
$this->compiled->isCompiled = true; $this->compiled->isCompiled = true;
} }
if ($this->smarty->debugging) {
Smarty_Internal_Debug::end_compile($this);
}
// release compiler object to free memory // release compiler object to free memory
unset($this->compiler); unset($this->compiler);
} }
@@ -413,7 +408,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
$output .= $plugins_string; $output .= $plugins_string;
$output .= $content; $output .= $content;
if (!$this->source->recompiled) { if (!$this->source->recompiled) {
$output .= '<?php }} ?>'; $output .= "<?php }} ?>\n";
} }
return $output; return $output;

View File

@@ -132,13 +132,7 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data
if (!$_template->source->uncompiled) { if (!$_template->source->uncompiled) {
$_smarty_tpl = $_template; $_smarty_tpl = $_template;
if ($_template->source->recompiled) { if ($_template->source->recompiled) {
if ($this->smarty->debugging) {
Smarty_Internal_Debug::start_compile($_template);
}
$code = $_template->compiler->compileTemplate($_template); $code = $_template->compiler->compileTemplate($_template);
if ($this->smarty->debugging) {
Smarty_Internal_Debug::end_compile($_template);
}
if ($this->smarty->debugging) { if ($this->smarty->debugging) {
Smarty_Internal_Debug::start_render($_template); Smarty_Internal_Debug::start_render($_template);
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff