diff --git a/change_log.txt b/change_log.txt
index 9166559d..4000a53b 100644
--- a/change_log.txt
+++ b/change_log.txt
@@ -1,4 +1,8 @@
===== 3.1.24.dev ===== (xx.xx.2015)
+ 23.05.2015
+ - improvement on php_handling to allow very large PHP sections, better error handling
+ - improvement allow extreme large comment sections (forum 25538)
+
21.05.2015
- bugfix broken PHP 5.2 compatibility when compiling 1 did compile into wrong code https://github.com/smarty-php/smarty/issues/41
diff --git a/lexer/smarty_internal_templatelexer.plex b/lexer/smarty_internal_templatelexer.plex
index c6e3d0a9..bd9b7a94 100644
--- a/lexer/smarty_internal_templatelexer.plex
+++ b/lexer/smarty_internal_templatelexer.plex
@@ -56,12 +56,6 @@ class Smarty_Internal_Templatelexer
*/
public $taglineno;
/**
- * flag if parsing php script
- *
- * @var bool
- */
- public $is_phpScript = false;
- /**
* php code type
*
* @var string
@@ -108,25 +102,35 @@ class Smarty_Internal_Templatelexer
*
* @var Smarty_Internal_TemplateCompilerBase
*/
- private $compiler = null;
+ public $compiler = null;
/**
* literal tag nesting level
*
* @var int
*/
private $literal_cnt = 0;
+
+ /**
+ * PHP start tag string
+ *
+ * @var string
+ */
+
/**
* trace file
*
* @var resource
*/
public $yyTraceFILE;
+
/**
* trace prompt
*
* @var string
*/
+
public $yyTracePrompt;
+
/**
* state names
*
@@ -138,15 +142,22 @@ class Smarty_Internal_Templatelexer
/**
* storage for assembled token patterns
*
- * @var sring
+ * @var string
*/
private $yy_global_pattern1 = null;
+
private $yy_global_pattern2 = null;
+
private $yy_global_pattern3 = null;
+
private $yy_global_pattern4 = null;
+
private $yy_global_pattern5 = null;
+
private $yy_global_pattern6 = null;
+
private $yy_global_pattern7 = null;
+
private $yy_global_pattern8 = null;
/**
@@ -203,25 +214,33 @@ class Smarty_Internal_Templatelexer
{
$this->data = $data;
$this->counter = 0;
- if (preg_match('/^\xEF\xBB\xBF/', $this->data, $match)) {
+ if (preg_match('~^\xEF\xBB\xBF~i', $this->data, $match)) {
$this->counter += strlen($match[0]);
}
$this->line = 1;
$this->smarty = $compiler->smarty;
$this->compiler = $compiler;
- $this->ldel = preg_quote($this->smarty->left_delimiter, '/');
+ $this->ldel = preg_quote($this->smarty->left_delimiter, '~');
$this->ldel_length = strlen($this->smarty->left_delimiter);
- $this->rdel = preg_quote($this->smarty->right_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;
}
- public function PrintTrace()
- {
+ public function PrintTrace()
+ {
$this->yyTraceFILE = fopen('php://output', 'w');
$this->yyTracePrompt = '
';
- }
+ }
+
+ /*
+ * Check if this tag is autoliteral
+ */
+ 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
@@ -229,72 +248,67 @@ class Smarty_Internal_Templatelexer
%token $this->token
%value $this->value
%line $this->line
- linebreak = /[\t ]*[\r\n]+[\t ]*/
- text = /[\S\s]/
- textdoublequoted = /([^"\\]*?)((?:\\.[^"\\]*?)*?)(?=(SMARTYldel|\$|`\$|"))/
- namespace = /([0-9]*[a-zA-Z_]\w*)?(\\[0-9]*[a-zA-Z_]\w*)+/
- all = /[\S\s]+/
- emptyjava = /\{\}/
- xmltag = /<[?]xml\s+([\S\s]*?)[?]>/
- php = #<[?](?:php(?=[\s=]))?((?:(?![?]>)[^/][^?'"/]*)(([/][*](?:(?![*][/])[\S\s][^*]*)*[*][/])|([/][/][^\n]*)|('[^'\\]*(?:\\.[^'\\]*)*')|("[^"\\]*(?:\\.[^"\\]*)*"))*)*[?]>#
- asp = #<[%]((?:(?![%]>)[^/][^%'"/]*)(([/][*](?:(?![*][/])[\S\s][^*]*)*[*][/])|([/][/][^\n]*)|('[^'\\]*(?:\\.[^'\\]*)*')|("[^"\\]*(?:\\.[^"\\]*)*"))*)*[%]>#
- phpscript = #)[^/][^<'"/]*)(([/][*](?:(?![*][/])[\S\s][^*]*)*[*][/])|([/][/][^\n]*)|('[^'\\]*(?:\\.[^'\\]*)*')|("[^"\\]*(?:\\.[^"\\]*)*"))*)*#
- phptag = #((SMARTYldel\s*php\s*(.)*?SMARTYrdel)((?:(?!(SMARTYldel\s*[/]php\s*SMARTYrdel))[^/\{][^SMARTYldelFIRST'"/]*)(([/][*](?:(?![*][/])[\S\s][^*]*)*[*][/])|([/][/][^\n]*)|('[^'\\]*(?:\\.[^'\\]*)*')|("[^"\\]*(?:\\.[^"\\]*)*"))*)*(SMARTYldel\s*[/]php\s*SMARTYrdel)?)|(SMARTYldel\s*[/]?php\s*SMARTYrdel)#
- unmatched = /((<[?](?:php\s+|=)?)|(';
+ } elseif (strpos($lex->value, $lex->smarty->left_delimiter) === 0) {
+ if ($lex->isAutoLiteral()) {
+ $lex->token = Smarty_Internal_Templateparser::TP_TEXT;
+ return;
+ }
+ $closeTag = "{$lex->smarty->left_delimiter}/php{$lex->smarty->right_delimiter}";
+ if ($lex->value == $closeTag) {
+ $lex->compiler->trigger_template_error("unexpected closing tag '{$closeTag}'");
+ }
+ $lex->phpType = 'tag';
+ }
+ if ($lex->phpType == 'unmatched') {
+ return;
+ }
+ if (($lex->phpType == 'php' || $lex->phpType == 'asp') && ($lex->compiler->php_handling == Smarty::PHP_PASSTHRU || $lex->compiler->php_handling == Smarty::PHP_QUOTE)) {
+ return;
+ }
+ $start = $lex->counter + strlen($lex->value);
+ $body = true;
+ if (preg_match('~' . preg_quote($closeTag, '~') . '~i', $lex->data, $match, PREG_OFFSET_CAPTURE, $start)) {
+ $close = $match[0][1];
+ } else {
+ $lex->compiler->trigger_template_error("missing closing tag '{$closeTag}'");
+ }
+ while ($body) {
+ if (preg_match('~([/][*])|([/][/][^\n]*)|(\'[^\'\\\\]*(?:\\.[^\'\\\\]*)*\')|("[^"\\\\]*(?:\\.[^"\\\\]*)*")~', $lex->data, $match, PREG_OFFSET_CAPTURE, $start)) {
+ $value = $match[0][0];
+ $from = $pos = $match[0][1];
+ if ($pos > $close) {
+ $body = false;
+ } else {
+ $start = $pos + strlen($value);
+ $phpCommentStart = $value == '/*';
+ if ($phpCommentStart) {
+ $phpCommentEnd = preg_match('~([*][/])~', $lex->data, $match, PREG_OFFSET_CAPTURE, $start);
+ if ($phpCommentEnd) {
+ $pos2 = $match[0][1];
+ $start = $pos2 + strlen($match[0][0]);
+ }
+ }
+ while ($close > $pos && $close < $start) {
+ if (preg_match('~' . preg_quote($closeTag, '~') . '~i', $lex->data, $match, PREG_OFFSET_CAPTURE, $from)) {
+ $close = $match[0][1];
+ $from = $close + strlen($match[0][0]);
+ } else {
+ $lex->compiler->trigger_template_error("missing closing tag '{$closeTag}'");
+ }
+ }
+ if ($phpCommentStart && (!$phpCommentEnd || $pos2 > $close)) {
+ $lex->taglineno = $lex->line + substr_count(substr($lex->data, $lex->counter, $start), "\n");
+ $lex->compiler->trigger_template_error("missing PHP comment closing tag '*/'");
+ }
+ }
+ } else {
+ $body = false;
+ }
+ }
+ $lex->value = substr($lex->data, $lex->counter, $close + strlen($closeTag) - $lex->counter);
+ }
+
/*
- * Call back function for $php_handling = PHP_QUOTE
- *
- */
+ * Call back function for $php_handling = PHP_QUOTE
+ *
+ */
private function quote($match)
{
return htmlspecialchars($match[0], ENT_QUOTES);
diff --git a/libs/sysplugins/smarty_internal_parsetree_template.php b/libs/sysplugins/smarty_internal_parsetree_template.php
index a0717e50..7d814eda 100644
--- a/libs/sysplugins/smarty_internal_parsetree_template.php
+++ b/libs/sysplugins/smarty_internal_parsetree_template.php
@@ -73,7 +73,7 @@ class Smarty_Internal_ParseTree_Template extends Smarty_Internal_ParseTree
if ($subtree == '') {
continue;
}
- $code .= preg_replace('/(<%|%>|<\?php|<\?|\?>|<\/?script)/', "\n", $subtree);
+ $code .= preg_replace('/((<%)|(%>)|(<\?php)|(<\?)|(\?>)|(<\/?script))/', "\n", $subtree);
continue;
}
if ($this->subtrees[$key] instanceof Smarty_Internal_ParseTree_Tag) {
diff --git a/libs/sysplugins/smarty_internal_templatelexer.php b/libs/sysplugins/smarty_internal_templatelexer.php
index 904461ed..9b0ade35 100644
--- a/libs/sysplugins/smarty_internal_templatelexer.php
+++ b/libs/sysplugins/smarty_internal_templatelexer.php
@@ -62,13 +62,6 @@ class Smarty_Internal_Templatelexer
*/
public $taglineno;
- /**
- * flag if parsing php script
- *
- * @var bool
- */
- public $is_phpScript = false;
-
/**
* php code type
*
@@ -123,7 +116,7 @@ class Smarty_Internal_Templatelexer
*
* @var Smarty_Internal_TemplateCompilerBase
*/
- private $compiler = null;
+ public $compiler = null;
/**
* literal tag nesting level
@@ -132,6 +125,12 @@ class Smarty_Internal_Templatelexer
*/
private $literal_cnt = 0;
+ /**
+ * PHP start tag string
+ *
+ * @var string
+ */
+
/**
* trace file
*
@@ -144,6 +143,7 @@ class Smarty_Internal_Templatelexer
*
* @var string
*/
+
public $yyTracePrompt;
/**
@@ -151,12 +151,13 @@ class Smarty_Internal_Templatelexer
*
* @var array
*/
- public $state_name = array(1 => 'TEXT', 2 => 'TAG', 3 => 'TAGBODY', 4 => 'LITERAL', 5 => 'DOUBLEQUOTEDSTRING', 6 => 'CHILDBODY', 7 => 'CHILDBLOCK', 8 => 'CHILDLITERAL');
+ public $state_name = array(1 => 'TEXT', 2 => 'TAG', 3 => 'TAGBODY', 4 => 'LITERAL', 5 => 'DOUBLEQUOTEDSTRING',
+ 6 => 'CHILDBODY', 7 => 'CHILDBLOCK', 8 => 'CHILDLITERAL');
/**
* storage for assembled token patterns
*
- * @var sring
+ * @var string
*/
private $yy_global_pattern1 = null;
@@ -180,7 +181,15 @@ class Smarty_Internal_Templatelexer
* @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' => '" '"<", "==" ... logical operator', 'TLOGOP' => '"lt", "eq" ... logical operator; "is div by" ... if condition', 'SCOND' => '"is even" ... if condition',);
+ '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' => '" '"<", "==" ... logical operator',
+ 'TLOGOP' => '"lt", "eq" ... logical operator; "is div by" ... if condition',
+ 'SCOND' => '"is even" ... if condition',);
/**
* constructor
@@ -192,15 +201,15 @@ class Smarty_Internal_Templatelexer
{
$this->data = $data;
$this->counter = 0;
- if (preg_match('/^\xEF\xBB\xBF/', $this->data, $match)) {
+ if (preg_match('~^\xEF\xBB\xBF~i', $this->data, $match)) {
$this->counter += strlen($match[0]);
}
$this->line = 1;
$this->smarty = $compiler->smarty;
$this->compiler = $compiler;
- $this->ldel = preg_quote($this->smarty->left_delimiter, '/');
+ $this->ldel = preg_quote($this->smarty->left_delimiter, '~');
$this->ldel_length = strlen($this->smarty->left_delimiter);
- $this->rdel = preg_quote($this->smarty->right_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;
@@ -212,6 +221,14 @@ class Smarty_Internal_Templatelexer
$this->yyTracePrompt = '
';
}
+ /*
+ * Check if this tag is autoliteral
+ */
+ 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;
+ }
+
private $_yy_state = 1;
private $_yy_stack = array();
@@ -255,7 +272,7 @@ class Smarty_Internal_Templatelexer
public function yylex1()
{
if (!isset($this->yy_global_pattern1)) {
- $this->yy_global_pattern1 = "/\G(\\{\\})|\G(" . $this->ldel . "[*]((?:(?![*]" . $this->rdel . ")[\S\s][^*]*))*[*]" . $this->rdel . ")|\G(" . $this->ldel . "\\s*literal\\s*" . $this->rdel . ")|\G(" . $this->ldel . "\\s*)|\G(\\s*" . $this->rdel . ")|\G(<[?]xml\\s+([\S\s]*?)[?]>)|\G(<[%]((?:(?![%]>)[^\/][^%'\"\/]*)(([\/][*](?:(?![*][\/])[\S\s][^*]*)*[*][\/])|([\/][\/][^\n]*)|('[^'\\\\]*(?:\\\\.[^'\\\\]*)*')|(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"))*)*[%]>)|\G(<[?](?:php(?=[\s=]))?((?:(?![?]>)[^\/][^?'\"\/]*)(([\/][*](?:(?![*][\/])[\S\s][^*]*)*[*][\/])|([\/][\/][^\n]*)|('[^'\\\\]*(?:\\\\.[^'\\\\]*)*')|(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"))*)*[?]>)|\G(