summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEW_FEATURES.txt23
-rw-r--r--change_log.txt4
-rw-r--r--lexer/smarty_internal_templatelexer.plex506
-rw-r--r--lexer/smarty_internal_templateparser.y25
-rw-r--r--libs/Smarty.class.php9
-rw-r--r--libs/sysplugins/smarty_internal_extension_handler.php110
6 files changed, 385 insertions, 292 deletions
diff --git a/NEW_FEATURES.txt b/NEW_FEATURES.txt
index bddc631f..43b7ee85 100644
--- a/NEW_FEATURES.txt
+++ b/NEW_FEATURES.txt
@@ -3,6 +3,29 @@
This file contains a brief description of new features which have been added to Smarty 3.1
Smarty 3.1.32
+
+ Using literals containing Smarty's left and right delimiter
+ ===========================================================
+ New Methods
+ $smarty->setLiterals(array $literals)
+ $smarty->addLiterals(array $literals)
+ to define lietrals containing Smarty delimiter. This can avoid the need for extreme usage
+ of {literal} {/literal} tags.
+ A) Treat '{{' and '}}' as literal
+ If Smarty::$auto_literal is enabled
+ {{ foo }}
+ will be treated now as literal. (This does apply for any number of delimiter repeatations).
+ However {{foo}} is not an literal but will be interpreted as a recursive Smarty tag.
+ If you use
+ $smarty->setLiteral(array('{{','}}'));
+ {{foo}} is now a literal as well.
+ NOTE: In the last example nested Smarty tags starting with '{{' or ending with '}}' will not
+ work any longer, but this should be very very raw occouring restriction.
+ B) Example 2
+ Assume your delimiter are '<-' , '->' and '<--' , '-->' shall be lietrals
+ $smarty->setLiteral(array('<--','-->'));
+
+
The capture buffers can now be accessed as array
================================================
{capture name='foo'}
diff --git a/change_log.txt b/change_log.txt
index 6f6a9d94..7f5bcae5 100644
--- a/change_log.txt
+++ b/change_log.txt
@@ -1,4 +1,8 @@
===== 3.1.32 - dev ===
+07.10.2017
+ - bugfix modification of 9.8.2017 did fail on some recursive
+ tag nesting. https://github.com/smarty-php/smarty/issues/389
+
26.8.2017
- bugfix chained modifier failed when last modifier parameter is a signed value
https://github.com/smarty-php/smarty/issues/327
diff --git a/lexer/smarty_internal_templatelexer.plex b/lexer/smarty_internal_templatelexer.plex
index 53213285..d70fabad 100644
--- a/lexer/smarty_internal_templatelexer.plex
+++ b/lexer/smarty_internal_templatelexer.plex
@@ -82,6 +82,13 @@ class Smarty_Internal_Templatelexer
public $ldel = '';
/**
+ * escaped left delimiter with space
+ *
+ * @var string
+ */
+ public $ldel_q = '';
+
+ /**
* escaped left delimiter length
*
* @var int
@@ -124,19 +131,6 @@ class Smarty_Internal_Templatelexer
public $compiler = null;
/**
- * literal tag nesting level
- *
- * @var int
- */
- private $literal_cnt = 0;
-
- /**
- * PHP start tag string
- *
- * @var string
- */
-
- /**
* trace file
*
* @var resource
@@ -151,10 +145,10 @@ class Smarty_Internal_Templatelexer
public $yyTracePrompt;
/**
- * XML flag true while processing xml
- *
- * @var bool
- */
+ * XML flag true while processing xml
+ *
+ * @var bool
+ */
public $is_xml = false;
/**
@@ -165,74 +159,108 @@ class Smarty_Internal_Templatelexer
public $state_name = array(1 => 'TEXT', 2 => 'TAG', 3 => 'TAGBODY', 4 => 'LITERAL', 5 => 'DOUBLEQUOTEDSTRING',);
/**
- * storage for assembled token patterns
+ * token names
+ *
+ * @var array
+ */
+ public $smarty_token_names = array( // Text for parser error messages
+ 'NOT' => '(!,not)',
+ 'OPENP' => '(',
+ 'CLOSEP' => ')',
+ 'OPENB' => '[',
+ 'CLOSEB' => ']',
+ 'PTR' => '->',
+ 'APTR' => '=>',
+ 'EQUAL' => '=',
+ 'NUMBER' => 'number',
+ 'UNIMATH' => '+" , "-',
+ 'MATH' => '*" , "/" , "%',
+ 'INCDEC' => '++" , "--',
+ 'SPACE' => ' ',
+ 'DOLLAR' => '$',
+ 'SEMICOLON' => ';',
+ 'COLON' => ':',
+ 'DOUBLECOLON' => '::',
+ 'AT' => '@',
+ 'HATCH' => '#',
+ 'QUOTE' => '"',
+ 'BACKTICK' => '`',
+ 'VERT' => '"|" modifier',
+ 'DOT' => '.',
+ 'COMMA' => '","',
+ 'QMARK' => '"?"',
+ 'ID' => 'id, name',
+ 'TEXT' => 'text',
+ 'LDELSLASH' => '{/..} closing tag',
+ 'LDEL' => '{...} Smarty tag',
+ 'COMMENT' => 'comment',
+ 'AS' => 'as',
+ 'TO' => 'to',
+ 'PHP' => '"<?php", "<%", "{php}" tag',
+ 'LOGOP' => '"<", "==" ... logical operator',
+ 'TLOGOP' => '"lt", "eq" ... logical operator; "is div by" ... if condition',
+ 'SCOND' => '"is even" ... if condition',
+ );
+
+ /**
+ * preg string of user defined litereals
+ *
+ * @var string
+ */
+ public $literals = '';
+
+ /**
+ * literal tag nesting level
+ *
+ * @var int
+ */
+ private $literal_cnt = 0;
+
+ /**
+ * preg token pattern for state TEXT
*
* @var string
*/
private $yy_global_pattern1 = null;
+ /**
+ * preg token pattern for state TAG
+ *
+ * @var string
+ */
private $yy_global_pattern2 = null;
+ /**
+ * preg token pattern for state TAGBODY
+ *
+ * @var string
+ */
private $yy_global_pattern3 = null;
+ /**
+ * preg token pattern for state LITERAL
+ *
+ * @var string
+ */
private $yy_global_pattern4 = null;
- private $yy_global_pattern5 = null;
-
/**
- * token names
+ * preg token pattern for state DOUBLEQUOTEDSTRING
*
- * @var array
+ * @var null
*/
- public $smarty_token_names = array( // Text for parser error messages
- 'NOT' => '(!,not)',
- 'OPENP' => '(',
- 'CLOSEP' => ')',
- 'OPENB' => '[',
- 'CLOSEB' => ']',
- 'PTR' => '->',
- 'APTR' => '=>',
- 'EQUAL' => '=',
- 'NUMBER' => 'number',
- 'UNIMATH' => '+" , "-',
- 'MATH' => '*" , "/" , "%',
- 'INCDEC' => '++" , "--',
- 'SPACE' => ' ',
- 'DOLLAR' => '$',
- 'SEMICOLON' => ';',
- 'COLON' => ':',
- 'DOUBLECOLON' => '::',
- 'AT' => '@',
- 'HATCH' => '#',
- 'QUOTE' => '"',
- 'BACKTICK' => '`',
- 'VERT' => '"|" modifier',
- 'DOT' => '.',
- 'COMMA' => '","',
- 'QMARK' => '"?"',
- 'ID' => 'id, name',
- 'TEXT' => 'text',
- 'LDELSLASH' => '{/..} closing tag',
- 'LDEL' => '{...} Smarty tag',
- 'COMMENT' => 'comment',
- 'AS' => 'as',
- 'TO' => 'to',
- 'PHP' => '"<?php", "<%", "{php}" tag',
- 'LOGOP' => '"<", "==" ... logical operator',
- 'TLOGOP' => '"lt", "eq" ... logical operator; "is div by" ... if condition',
- 'SCOND' => '"is even" ... if condition',
- );
+ private $yy_global_pattern5 = null;
/**
* constructor
*
- * @param string $data template source
+ * @param string $source template source
* @param Smarty_Internal_TemplateCompilerBase $compiler
*/
- function __construct($data, Smarty_Internal_TemplateCompilerBase $compiler)
+ function __construct($source, Smarty_Internal_TemplateCompilerBase $compiler)
{
- $this->data = $data;
- $this->dataLength = strlen($data);
+ $this->data = $source;
+ $this->dataLength = strlen($this->data);
$this->counter = 0;
if (preg_match('/^\xEF\xBB\xBF/i', $this->data, $match)) {
$this->counter += strlen($match[0]);
@@ -240,31 +268,63 @@ class Smarty_Internal_Templatelexer
$this->line = 1;
$this->smarty = $compiler->smarty;
$this->compiler = $compiler;
- $this->pldel = preg_quote($this->smarty->left_delimiter, '/');
- $this->ldel = $this->pldel . ($this->smarty->auto_literal ? '(?!\\s+)' : '\\s*');
+ $this->ldel = preg_quote($this->smarty->left_delimiter, '/') . ($this->smarty->auto_literal ? '' : '\\s*');
$this->ldel_length = strlen($this->smarty->left_delimiter);
$this->rdel = preg_quote($this->smarty->right_delimiter, '/');
$this->rdel_length = strlen($this->smarty->right_delimiter);
$this->smarty_token_names['LDEL'] = $this->smarty->left_delimiter;
$this->smarty_token_names['RDEL'] = $this->smarty->right_delimiter;
+ $literals = $this->smarty->getLiterals();
+ if (!empty($literals)) {
+ foreach ($literals as $key => $literal) {
+ $literals[$key] = preg_quote($literal, '/');
+ }
+ }
+
+ if ($this->smarty->auto_literal) {
+ $literals[] = $this->ldel . '{1,}\\s+';
+ }
+ if (!empty($literals)) {
+ $this->literals = implode('|', $literals);
+ } else {
+ $this->literals = preg_quote('^$', '/');
+ }
}
- public function PrintTrace()
- {
+ /**
+ * open lexer/parser trace file
+ *
+ */
+ public function PrintTrace()
+ {
$this->yyTraceFILE = fopen('php://output', 'w');
$this->yyTracePrompt = '<br>';
- }
- /*
- * Check if this tag is autoliteral
- */
- public function isAutoLiteral ()
+ }
+
+ /**
+ * replace placeholders with runtime preg code
+ *
+ * @param string $input
+ *
+ * @return string
+ */
+ public function replace($input)
{
- return $this->smarty->auto_literal && isset($this->value[$this->ldel_length]) ? strpos(" \n\t\r", $this->value[$this->ldel_length]) !== false : false;
+ return str_replace(array('SMARTYldel', 'SMARTYliteral', 'SMARTYrdel'),
+ array($this->ldel, $this->literals, $this->rdel),
+ $input);
}
- public function replace ($input) {
- return str_replace(array('SMARTYldel','SMARTYrawldel','SMARTYrdel'),array($this->ldel,$this->pldel,$this->rdel),$input);
- }
+ /**
+ * check if current value is an autoliteral left delimiter
+ *
+ * @return bool
+ */
+ public function isAutoLiteral()
+ {
+ return $this->smarty->auto_literal && isset($this->value[ $this->ldel_length ]) ?
+ strpos(" \n\t\r", $this->value[ $this->ldel_length ]) !== false : false;
+ }
/*!lex2php
%input $this->data
@@ -272,15 +332,13 @@ class Smarty_Internal_Templatelexer
%token $this->token
%value $this->value
%line $this->line
- linebreak = ~[\t ]*[\r\n]+[\t ]*~
- ldelrepeat = ~SMARTYrawldel{2,}~
- text = ~[\S\s]~
- textdoublequoted = ~([^"\\]*?)((?:\\.[^"\\]*?)*?)(?=(SMARTYldel|\$|`\$|"))~
+ userliteral = ~SMARTYliteral~
+ char = ~[\S\s]~
+ textdoublequoted = ~([^"\\]*?)((?:\\.[^"\\]*?)*?)(?=(SMARTYliteral|SMARTYldel|\$|`\$|"))~
namespace = ~([0-9]*[a-zA-Z_]\w*)?(\\[0-9]*[a-zA-Z_]\w*)+~
- all = ~[\S\s]+~
emptyjava = ~[{][}]~
phptag = ~(SMARTYldelphp([ ].*?)?SMARTYrdel)|(SMARTYldel[/]phpSMARTYrdel)~
- phpstart = ~(<[?]((php\s+|=)|\s+))|(<[%])|(<[?]xml\s+)|(<script\s+language\s*=\s*["']?\s*php\s*["']?\s*>)|([?][>])|([%][>])~
+ phpstart = ~([<][?]((php\s+|=)|\s+))|([<][%])|([<][?]xml\s+)|([<]script\s+language\s*=\s*["']?\s*php\s*["']?\s*[>])|([?][>])|([%][>])~
slash = ~[/]~
ldel = ~SMARTYldel~
rdel = ~\s*SMARTYrdel~
@@ -336,12 +394,14 @@ class Smarty_Internal_Templatelexer
not = ~([!]\s*)|(not\s+)~
typecast = ~[(](int(eger)?|bool(ean)?|float|double|real|string|binary|array|object)[)]\s*~
double_quote = ~["]~
- single_quote = ~[']~
+ text = ~((.*?)(?=(SMARTYliteral|[{]|([<][?]((php\s+|=)|\s+))|([<][%])|([<][?]xml\s+)|([<]script\s+language\s*=\s*["']?\s*php\s*["']?\s*[>])|([?][>])|([%][>]))))|(.*)~
+ literaltext = ~(.*?)(?=SMARTYldel[/]?literalSMARTYrdel)~
+ anytext = ~.*~
*/
/*!lex2php
%statename TEXT
emptyjava {
- $this->token = Smarty_Internal_Templateparser::TP_TEXT;
+ $this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
comment {
preg_match("/[*]{$this->rdel}/",$this->data,$match,PREG_OFFSET_CAPTURE,$this->counter);
@@ -354,201 +414,195 @@ class Smarty_Internal_Templatelexer
return false;
}
phptag {
- $this->compiler->getTagCompiler('private_php')->parsePhp($this);
+ $this->compiler->getTagCompiler('private_php')->parsePhp($this);
}
- ldelrepeat {
+ userliteral {
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
ldel literal rdel {
- $this->token = Smarty_Internal_Templateparser::TP_LITERALSTART;
- $this->yypushstate(self::LITERAL);
+ $this->token = Smarty_Internal_Templateparser::TP_LITERALSTART;
+ $this->yypushstate(self::LITERAL);
}
ldel slash literal rdel {
- $this->token = Smarty_Internal_Templateparser::TP_LITERALEND;
- $this->yypushstate(self::LITERAL);
+ $this->token = Smarty_Internal_Templateparser::TP_LITERALEND;
+ $this->yypushstate(self::LITERAL);
}
ldel {
- $this->yypushstate(self::TAG);
- return true;
+ $this->yypushstate(self::TAG);
+ return true;
}
phpstart {
- $this->compiler->getTagCompiler('private_php')->parsePhp($this);
+ $this->compiler->getTagCompiler('private_php')->parsePhp($this);
}
text {
- $to = $this->dataLength;
- preg_match("/((?<!$this->pldel){$this->ldel})|(<[?]((php\s+|=)|\s+))|(<[%])|(<[?]xml\s+)|(<script\s+language\s*=\s*[\"']?\s*php\s*[\"']?\s*>)|([?][>])|([%][>])/i",$this->data,$match,PREG_OFFSET_CAPTURE,$this->counter);
- if (isset($match[0][1])) {
- $to = $match[0][1];
- }
- $this->value = substr($this->data,$this->counter,$to-$this->counter);
- $this->token = Smarty_Internal_Templateparser::TP_TEXT;
+ $this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
*/
/*!lex2php
%statename TAG
ldel if {
- $this->token = Smarty_Internal_Templateparser::TP_LDELIF;
- $this->yybegin(self::TAGBODY);
- $this->taglineno = $this->line;
+ $this->token = Smarty_Internal_Templateparser::TP_LDELIF;
+ $this->yybegin(self::TAGBODY);
+ $this->taglineno = $this->line;
}
ldel for {
- $this->token = Smarty_Internal_Templateparser::TP_LDELFOR;
- $this->yybegin(self::TAGBODY);
- $this->taglineno = $this->line;
+ $this->token = Smarty_Internal_Templateparser::TP_LDELFOR;
+ $this->yybegin(self::TAGBODY);
+ $this->taglineno = $this->line;
}
ldel foreach {
- $this->token = Smarty_Internal_Templateparser::TP_LDELFOREACH;
- $this->yybegin(self::TAGBODY);
- $this->taglineno = $this->line;
+ $this->token = Smarty_Internal_Templateparser::TP_LDELFOREACH;
+ $this->yybegin(self::TAGBODY);
+ $this->taglineno = $this->line;
}
ldel setfilter {
- $this->token = Smarty_Internal_Templateparser::TP_LDELSETFILTER;
- $this->yybegin(self::TAGBODY);
- $this->taglineno = $this->line;
+ $this->token = Smarty_Internal_Templateparser::TP_LDELSETFILTER;
+ $this->yybegin(self::TAGBODY);
+ $this->taglineno = $this->line;
}
ldel makenocache {
- $this->token = Smarty_Internal_Templateparser::TP_LDELMAKENOCACHE;
- $this->yybegin(self::TAGBODY);
- $this->taglineno = $this->line;
+ $this->token = Smarty_Internal_Templateparser::TP_LDELMAKENOCACHE;
+ $this->yybegin(self::TAGBODY);
+ $this->taglineno = $this->line;
}
ldel id nocacherdel {
- $this->yypopstate();
- $this->token = Smarty_Internal_Templateparser::TP_SIMPLETAG;
- $this->taglineno = $this->line;
+ $this->yypopstate();
+ $this->token = Smarty_Internal_Templateparser::TP_SIMPLETAG;
+ $this->taglineno = $this->line;
}
ldel slash notblockid rdel {
- $this->yypopstate();
- $this->token = Smarty_Internal_Templateparser::TP_CLOSETAG;
- $this->taglineno = $this->line;
+ $this->yypopstate();
+ $this->token = Smarty_Internal_Templateparser::TP_CLOSETAG;
+ $this->taglineno = $this->line;
}
ldel dollar id nocacherdel {
- if ($this->_yy_stack[count($this->_yy_stack)-1] == self::TEXT) {
+ if ($this->_yy_stack[count($this->_yy_stack)-1] == self::TEXT) {
$this->yypopstate();
$this->token = Smarty_Internal_Templateparser::TP_SIMPELOUTPUT;
$this->taglineno = $this->line;
- } else {
+ } else {
$this->value = $this->smarty->left_delimiter;
$this->token = Smarty_Internal_Templateparser::TP_LDEL;
$this->yybegin(self::TAGBODY);
$this->taglineno = $this->line;
- }
+ }
}
ldel slash {
- $this->token = Smarty_Internal_Templateparser::TP_LDELSLASH;
- $this->yybegin(self::TAGBODY);
- $this->taglineno = $this->line;
+ $this->token = Smarty_Internal_Templateparser::TP_LDELSLASH;
+ $this->yybegin(self::TAGBODY);
+ $this->taglineno = $this->line;
}
ldel {
- $this->token = Smarty_Internal_Templateparser::TP_LDEL;
- $this->yybegin(self::TAGBODY);
- $this->taglineno = $this->line;
+ $this->token = Smarty_Internal_Templateparser::TP_LDEL;
+ $this->yybegin(self::TAGBODY);
+ $this->taglineno = $this->line;
}
*/
/*!lex2php
%statename TAGBODY
rdel {
- $this->token = Smarty_Internal_Templateparser::TP_RDEL;
- $this->yypopstate();
+ $this->token = Smarty_Internal_Templateparser::TP_RDEL;
+ $this->yypopstate();
}
ldel {
- $this->yypushstate(self::TAG);
- return true;
+ $this->yypushstate(self::TAG);
+ return true;
}
- double_quote {
- $this->token = Smarty_Internal_Templateparser::TP_QUOTE;
- $this->yypushstate(self::DOUBLEQUOTEDSTRING);
+ double_quote {
+ $this->token = Smarty_Internal_Templateparser::TP_QUOTE;
+ $this->yypushstate(self::DOUBLEQUOTEDSTRING);
}
singlequotestring {
- $this->token = Smarty_Internal_Templateparser::TP_SINGLEQUOTESTRING;
+ $this->token = Smarty_Internal_Templateparser::TP_SINGLEQUOTESTRING;
}
smartyblockchildparent {
- $this->token = Smarty_Internal_Templateparser::TP_SMARTYBLOCKCHILDPARENT;
- $this->taglineno = $this->line;
+ $this->token = Smarty_Internal_Templateparser::TP_SMARTYBLOCKCHILDPARENT;
+ $this->taglineno = $this->line;
}
dollar id {
- $this->token = Smarty_Internal_Templateparser::TP_DOLLARID;
+ $this->token = Smarty_Internal_Templateparser::TP_DOLLARID;
}
dollar {
- $this->token = Smarty_Internal_Templateparser::TP_DOLLAR;
+ $this->token = Smarty_Internal_Templateparser::TP_DOLLAR;
}
isin {
- $this->token = Smarty_Internal_Templateparser::TP_ISIN;
+ $this->token = Smarty_Internal_Templateparser::TP_ISIN;
}
as {
- $this->token = Smarty_Internal_Templateparser::TP_AS;
+ $this->token = Smarty_Internal_Templateparser::TP_AS;
}
to {
- $this->token = Smarty_Internal_Templateparser::TP_TO;
+ $this->token = Smarty_Internal_Templateparser::TP_TO;
}
step {
- $this->token = Smarty_Internal_Templateparser::TP_STEP;
+ $this->token = Smarty_Internal_Templateparser::TP_STEP;
}
instanceof {
- $this->token = Smarty_Internal_Templateparser::TP_INSTANCEOF;
+ $this->token = Smarty_Internal_Templateparser::TP_INSTANCEOF;
}
lop {
- $this->token = Smarty_Internal_Templateparser::TP_LOGOP;
+ $this->token = Smarty_Internal_Templateparser::TP_LOGOP;
}
slop {
- $this->token = Smarty_Internal_Templateparser::TP_SLOGOP;
+ $this->token = Smarty_Internal_Templateparser::TP_SLOGOP;
}
tlop {
- $this->token = Smarty_Internal_Templateparser::TP_TLOGOP;
+ $this->token = Smarty_Internal_Templateparser::TP_TLOGOP;
}
scond {
- $this->token = Smarty_Internal_Templateparser::TP_SINGLECOND;
+ $this->token = Smarty_Internal_Templateparser::TP_SINGLECOND;
}
not{
- $this->token = Smarty_Internal_Templateparser::TP_NOT;
+ $this->token = Smarty_Internal_Templateparser::TP_NOT;
}
typecast {
- $this->token = Smarty_Internal_Templateparser::TP_TYPECAST;
+ $this->token = Smarty_Internal_Templateparser::TP_TYPECAST;
}
openP {
- $this->token = Smarty_Internal_Templateparser::TP_OPENP;
+ $this->token = Smarty_Internal_Templateparser::TP_OPENP;
}
closeP {
- $this->token = Smarty_Internal_Templateparser::TP_CLOSEP;
+ $this->token = Smarty_Internal_Templateparser::TP_CLOSEP;
}
openB {
- $this->token = Smarty_Internal_Templateparser::TP_OPENB;
+ $this->token = Smarty_Internal_Templateparser::TP_OPENB;
}
closeB {
- $this->token = Smarty_Internal_Templateparser::TP_CLOSEB;
+ $this->token = Smarty_Internal_Templateparser::TP_CLOSEB;
}
ptr {
- $this->token = Smarty_Internal_Templateparser::TP_PTR;
+ $this->token = Smarty_Internal_Templateparser::TP_PTR;
}
aptr {
- $this->token = Smarty_Internal_Templateparser::TP_APTR;
+ $this->token = Smarty_Internal_Templateparser::TP_APTR;
}
equal {
- $this->token = Smarty_Internal_Templateparser::TP_EQUAL;
+ $this->token = Smarty_Internal_Templateparser::TP_EQUAL;
}
incdec {
- $this->token = Smarty_Internal_Templateparser::TP_INCDEC;
+ $this->token = Smarty_Internal_Templateparser::TP_INCDEC;
}
unimath {
- $this->token = Smarty_Internal_Templateparser::TP_UNIMATH;
+ $this->token = Smarty_Internal_Templateparser::TP_UNIMATH;
}
math {
- $this->token = Smarty_Internal_Templateparser::TP_MATH;
+ $this->token = Smarty_Internal_Templateparser::TP_MATH;
}
at {
- $this->token = Smarty_Internal_Templateparser::TP_AT;
+ $this->token = Smarty_Internal_Templateparser::TP_AT;
}
hatch {
- $this->token = Smarty_Internal_Templateparser::TP_HATCH;
+ $this->token = Smarty_Internal_Templateparser::TP_HATCH;
}
attr {
- // resolve conflicts with shorttag and right_delimiter starting with '='
- if (substr($this->data, $this->counter + strlen($this->value) - 1, $this->rdel_length) == $this->smarty->right_delimiter) {
- preg_match("/\s+/",$this->value,$match);
- $this->value = $match[0];
- $this->token = Smarty_Internal_Templateparser::TP_SPACE;
- } else {
- $this->token = Smarty_Internal_Templateparser::TP_ATTR;
- }
+ // resolve conflicts with shorttag and right_delimiter starting with '='
+ if (substr($this->data, $this->counter + strlen($this->value) - 1, $this->rdel_length) == $this->smarty->right_delimiter) {
+ preg_match("/\s+/",$this->value,$match);
+ $this->value = $match[0];
+ $this->token = Smarty_Internal_Templateparser::TP_SPACE;
+ } else {
+ $this->token = Smarty_Internal_Templateparser::TP_ATTR;
+ }
}
namespace {
$this->token = Smarty_Internal_Templateparser::TP_NAMESPACE;
@@ -557,118 +611,108 @@ class Smarty_Internal_Templatelexer
$this->token = Smarty_Internal_Templateparser::TP_ID;
}
integer {
- $this->token = Smarty_Internal_Templateparser::TP_INTEGER;
+ $this->token = Smarty_Internal_Templateparser::TP_INTEGER;
}
backtick {
- $this->token = Smarty_Internal_Templateparser::TP_BACKTICK;
- $this->yypopstate();
+ $this->token = Smarty_Internal_Templateparser::TP_BACKTICK;
+ $this->yypopstate();
}
vert {
- $this->token = Smarty_Internal_Templateparser::TP_VERT;
+ $this->token = Smarty_Internal_Templateparser::TP_VERT;
}
dot {
- $this->token = Smarty_Internal_Templateparser::TP_DOT;
+ $this->token = Smarty_Internal_Templateparser::TP_DOT;
}
comma {
- $this->token = Smarty_Internal_Templateparser::TP_COMMA;
+ $this->token = Smarty_Internal_Templateparser::TP_COMMA;
}
semicolon {
- $this->token = Smarty_Internal_Templateparser::TP_SEMICOLON;
+ $this->token = Smarty_Internal_Templateparser::TP_SEMICOLON;
}
doublecolon {
- $this->token = Smarty_Internal_Templateparser::TP_DOUBLECOLON;
+ $this->token = Smarty_Internal_Templateparser::TP_DOUBLECOLON;
}
colon {
- $this->token = Smarty_Internal_Templateparser::TP_COLON;
+ $this->token = Smarty_Internal_Templateparser::TP_COLON;
}
qmark {
- $this->token = Smarty_Internal_Templateparser::TP_QMARK;
+ $this->token = Smarty_Internal_Templateparser::TP_QMARK;
}
hex {
- $this->token = Smarty_Internal_Templateparser::TP_HEX;
+ $this->token = Smarty_Internal_Templateparser::TP_HEX;
}
space {
- $this->token = Smarty_Internal_Templateparser::TP_SPACE;
+ $this->token = Smarty_Internal_Templateparser::TP_SPACE;
}
- text {
- $this->token = Smarty_Internal_Templateparser::TP_TEXT;
+ char {
+ $this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
*/
/*!lex2php
%statename LITERAL
ldel literal rdel {
- $this->literal_cnt++;
- $this->token = Smarty_Internal_Templateparser::TP_LITERAL;
+ $this->literal_cnt++;
+ $this->token = Smarty_Internal_Templateparser::TP_LITERAL;
}
ldel slash literal rdel {
- if ($this->literal_cnt) {
- $this->literal_cnt--;
- $this->token = Smarty_Internal_Templateparser::TP_LITERAL;
- } else {
- $this->token = Smarty_Internal_Templateparser::TP_LITERALEND;
- $this->yypopstate();
- }
+ if ($this->literal_cnt) {
+ $this->literal_cnt--;
+ $this->token = Smarty_Internal_Templateparser::TP_LITERAL;
+ } else {
+ $this->token = Smarty_Internal_Templateparser::TP_LITERALEND;
+ $this->yypopstate();
+ }
}
- text {
- $to = $this->dataLength;
- preg_match("/{$this->ldel}[\/]?literal{$this->rdel}/i",$this->data,$match,PREG_OFFSET_CAPTURE,$this->counter);
- if (isset($match[0][1])) {
- $to = $match[0][1];
- } else {
- $this->compiler->trigger_template_error ("missing or misspelled literal closing tag");
- }
- $this->value = substr($this->data,$this->counter,$to-$this->counter);
- $this->token = Smarty_Internal_Templateparser::TP_LITERAL;
+ literaltext {
+ $this->token = Smarty_Internal_Templateparser::TP_LITERAL;
+ }
+ anytext {
+ $this->token = Smarty_Internal_Templateparser::TP_LITERAL;
}
*/
/*!lex2php
%statename DOUBLEQUOTEDSTRING
- ldelrepeat {
+ userliteral {
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
ldel literal rdel {
- $this->token = Smarty_Internal_Templateparser::TP_TEXT;
+ $this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
ldel slash literal rdel {
- $this->token = Smarty_Internal_Templateparser::TP_TEXT;
+ $this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
ldel slash {
- $this->yypushstate(self::TAG);
- return true;
+ $this->yypushstate(self::TAG);
+ return true;
}
ldel id {
- $this->yypushstate(self::TAG);
- return true;
+ $this->yypushstate(self::TAG);
+ return true;
}
ldel {
- $this->token = Smarty_Internal_Templateparser::TP_LDEL;
- $this->taglineno = $this->line;
- $this->yypushstate(self::TAGBODY);
+ $this->token = Smarty_Internal_Templateparser::TP_LDEL;
+ $this->taglineno = $this->line;
+ $this->yypushstate(self::TAGBODY);
}
double_quote {
- $this->token = Smarty_Internal_Templateparser::TP_QUOTE;
- $this->yypopstate();
+ $this->token = Smarty_Internal_Templateparser::TP_QUOTE;
+ $this->yypopstate();
}
backtick dollar {
- $this->token = Smarty_Internal_Templateparser::TP_BACKTICK;
- $this->value = substr($this->value,0,-1);
- $this->yypushstate(self::TAGBODY);
- $this->taglineno = $this->line;
+ $this->token = Smarty_Internal_Templateparser::TP_BACKTICK;
+ $this->value = substr($this->value,0,-1);
+ $this->yypushstate(self::TAGBODY);
+ $this->taglineno = $this->line;
}
dollar id {
- $this->token = Smarty_Internal_Templateparser::TP_DOLLARID;
+ $this->token = Smarty_Internal_Templateparser::TP_DOLLARID;
}
dollar {
- $this->token = Smarty_Internal_Templateparser::TP_TEXT;
+ $this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
textdoublequoted {
- $this->token = Smarty_Internal_Templateparser::TP_TEXT;
- }
- text {
- $to = $this->dataLength;
- $this->value = substr($this->data,$this->counter,$to-$this->counter);
- $this->token = Smarty_Internal_Templateparser::TP_TEXT;
+ $this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
*/
}
diff --git a/lexer/smarty_internal_templateparser.y b/lexer/smarty_internal_templateparser.y
index 40cbe72a..e4e00f6f 100644
--- a/lexer/smarty_internal_templateparser.y
+++ b/lexer/smarty_internal_templateparser.y
@@ -21,9 +21,9 @@ class Smarty_Internal_Templateparser
}
%include_class
{
- const Err1 = "Security error: Call to private object member not allowed";
- const Err2 = "Security error: Call to dynamic object member not allowed";
- const Err3 = "PHP in template not allowed. Use SmartyBC to enable it";
+ const Err1 = 'Security error: Call to private object member not allowed';
+ const Err2 = 'Security error: Call to dynamic object member not allowed';
+ const Err3 = 'PHP in template not allowed. Use SmartyBC to enable it';
/**
* result status
@@ -209,7 +209,8 @@ class Smarty_Internal_Templateparser
$this->compiler->trigger_template_error("Stack overflow in template parser");
}
-%left VERT.
+
+%right VERT.
%left COLON.
%left UNIMATH.
@@ -493,19 +494,6 @@ tag(res) ::= LDELFOR statement(st) TO expr(v) STEP expr(v2) attributes(a). {
}
// {foreach} tag
-tag(res) ::= LDELFOREACH attributes(a). {
- res = $this->compiler->compileTag('foreach',a);
-}
-
- // {foreach $array as $var} tag
-tag(res) ::= LDELFOREACH SPACE value(v1) AS varvar(v0) attributes(a). {
- res = $this->compiler->compileTag('foreach',array_merge(a,array(array('from'=>v1),array('item'=>v0))));
-}
-
-tag(res) ::= LDELFOREACH SPACE value(v1) AS varvar(v2) APTR varvar(v0) attributes(a). {
- res = $this->compiler->compileTag('foreach',array_merge(a,array(array('from'=>v1),array('item'=>v0),array('key'=>v2))));
-}
-
tag(res) ::= LDELFOREACH SPACE expr(e) AS varvar(v0) attributes(a). {
res = $this->compiler->compileTag('foreach',array_merge(a,array(array('from'=>e),array('item'=>v0))));
}
@@ -513,6 +501,9 @@ tag(res) ::= LDELFOREACH SPACE expr(e) AS varvar(v0) attributes(a). {
tag(res) ::= LDELFOREACH SPACE expr(e) AS varvar(v1) APTR varvar(v0) attributes(a). {
res = $this->compiler->compileTag('foreach',array_merge(a,array(array('from'=>e),array('item'=>v0),array('key'=>v1))));
}
+tag(res) ::= LDELFOREACH attributes(a). {
+ res = $this->compiler->compileTag('foreach',a);
+}
// {setfilter}
tag(res) ::= LDELSETFILTER ID(m) modparameters(p). {
diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php
index 7d39e6c1..23f56818 100644
--- a/libs/Smarty.class.php
+++ b/libs/Smarty.class.php
@@ -108,7 +108,7 @@ class Smarty extends Smarty_Internal_TemplateBase
/**
* smarty version
*/
- const SMARTY_VERSION = '3.1.32-dev-22';
+ const SMARTY_VERSION = '3.1.32-dev-23';
/**
* define variable scopes
@@ -456,6 +456,13 @@ class Smarty extends Smarty_Internal_TemplateBase
*/
public $right_delimiter = "}";
+ /**
+ * array of strings which shall be treated as literal by compiler
+ *
+ * @var array string
+ */
+ public $literals = array();
+
/**#@+
* security
*/
diff --git a/libs/sysplugins/smarty_internal_extension_handler.php b/libs/sysplugins/smarty_internal_extension_handler.php
index 340e6dee..cdda69fa 100644
--- a/libs/sysplugins/smarty_internal_extension_handler.php
+++ b/libs/sysplugins/smarty_internal_extension_handler.php
@@ -47,9 +47,9 @@ class Smarty_Internal_Extension_Handler
*
* @var array
*/
- private $_property_info = array('AutoloadFilters' => 0, 'DefaultModifiers' => 0, 'ConfigVars' => 0,
- 'DebugTemplate' => 0, 'RegisteredObject' => 0, 'StreamVariable' => 0,
- 'TemplateVars' => 0,);#
+ private $_property_info = array('AutoloadFilters' => 0, 'DefaultModifiers' => 0, 'ConfigVars' => 0,
+ 'DebugTemplate' => 0, 'RegisteredObject' => 0, 'StreamVariable' => 0,
+ 'TemplateVars' => 0, 'Literals' => 'Literals',);#
private $resolvedProperties = array();
@@ -68,38 +68,62 @@ class Smarty_Internal_Extension_Handler
/* @var Smarty $data ->smarty */
$smarty = isset($data->smarty) ? $data->smarty : $data;
if (!isset($smarty->ext->$name)) {
- $class = 'Smarty_Internal_Method_' . $this->upperCase($name);
- if (preg_match('/^(set|get)([A-Z].*)$/', $name, $match)) {
- $pn = '';
- if (!isset($this->_property_info[ $prop = $match[ 2 ] ])) {
- // convert camel case to underscored name
- $this->resolvedProperties[ $prop ] = $pn = strtolower(join('_',
- preg_split('/([A-Z][^A-Z]*)/', $prop,
- - 1, PREG_SPLIT_NO_EMPTY |
- PREG_SPLIT_DELIM_CAPTURE)));
- $this->_property_info[ $prop ] =
- property_exists($data, $pn) ? 1 : ($data->_isTplObj() && property_exists($smarty, $pn) ? 2 : 0);
+ 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 ($this->_property_info[ $prop ]) {
- $pn = $this->resolvedProperties[ $prop ];
- if ($match[ 1 ] == 'get') {
- return $this->_property_info[ $prop ] == 1 ? $data->$pn : $data->smarty->$pn;
- } else {
- return $this->_property_info[ $prop ] == 1 ? $data->$pn = $args[ 0 ] :
- $data->smarty->$pn = $args[ 0 ];
+ 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 = isset($this->resolvedProperties['property'][ $basename ]) ?
+ $this->resolvedProperties['property'][ $basename ] :
+ $property = $this->resolvedProperties['property'][ $basename ] = strtolower(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;
+ } else if (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;
+ } else if ($match[2] == 'set') {
+ return $obj->$property = $args[0];
+ }
+ }
}
- } elseif (!class_exists($class)) {
- throw new SmartyException("property '$pn' does not exist.");
}
}
- if (class_exists($class)) {
- $callback = array($smarty->ext->$name = new $class(), $name);
- }
- } else {
- $callback = array($smarty->ext->$name, $name);
}
+ $callback = array($smarty->ext->$name, $name);
array_unshift($args, $data);
- if (isset($callback) && $callback[ 0 ]->objMap | $data->_objType) {
+ 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);
@@ -120,19 +144,6 @@ class Smarty_Internal_Extension_Handler
}
/**
- * set extension property
- *
- * @param string $property_name property name
- * @param mixed $value value
- *
- * @throws SmartyException
- */
- public function __set($property_name, $value)
- {
- $this->$property_name = $value;
- }
-
- /**
* get extension object
*
* @param string $property_name property name
@@ -143,7 +154,7 @@ class Smarty_Internal_Extension_Handler
public function __get($property_name)
{
// object properties of runtime template extensions will start with '_'
- if ($property_name[ 0 ] == '_') {
+ if ($property_name[0] == '_') {
$class = 'Smarty_Internal_Runtime' . $this->upperCase($property_name);
} else {
$class = 'Smarty_Internal_Method_' . $this->upperCase($property_name);
@@ -155,6 +166,19 @@ class Smarty_Internal_Extension_Handler
}
/**
+ * set extension property
+ *
+ * @param string $property_name property name
+ * @param mixed $value value
+ *
+ * @throws SmartyException
+ */
+ public function __set($property_name, $value)
+ {
+ $this->$property_name = $value;
+ }
+
+ /**
* Call error handler for undefined method
*
* @param string $name unknown method-name