From 64e5609d0e7d03c6bb554f1749c09c776d25f4bf Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Thu, 28 Jul 2022 10:10:14 -0400 Subject: [PATCH] Throw syntax exception for unclosed tags. Fixes #395 --- src/Mustache/Tokenizer.php | 31 ++++++++++++++++++++++ test/Mustache/Test/TokenizerTest.php | 39 ++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/src/Mustache/Tokenizer.php b/src/Mustache/Tokenizer.php index 2a172c3..e59d30b 100644 --- a/src/Mustache/Tokenizer.php +++ b/src/Mustache/Tokenizer.php @@ -215,6 +215,10 @@ class Mustache_Tokenizer } } + if ($this->state !== self::IN_TEXT) { + $this->throwUnclosedTagException(); + } + $this->flushBuffer(); // Restore the user's encoding... @@ -279,6 +283,10 @@ class Mustache_Tokenizer $close = '=' . $this->ctag; $closeIndex = strpos($text, $close, $index); + if ($closeIndex === false) { + $this->throwUnclosedTagException(); + } + $token = array( self::TYPE => self::T_DELIM_CHANGE, self::LINE => $this->line, @@ -333,6 +341,10 @@ class Mustache_Tokenizer private function addPragma($text, $index) { $end = strpos($text, $this->ctag, $index); + if ($end === false) { + $this->throwUnclosedTagException(); + } + $pragma = trim(substr($text, $index + 2, $end - $index - 2)); // Pragmas are hoisted to the front of the template. @@ -344,4 +356,23 @@ class Mustache_Tokenizer return $end + $this->ctagLen - 1; } + + private function throwUnclosedTagException() + { + $name = trim($this->buffer); + if ($name !== '') { + $msg = sprintf('Unclosed tag: %s on line %d', $name, $this->line); + } else { + $msg = sprintf('Unclosed tag on line %d', $this->line); + } + + throw new Mustache_Exception_SyntaxException($msg, array( + self::TYPE => $this->tagType, + self::NAME => $name, + self::OTAG => $this->otag, + self::CTAG => $this->ctag, + self::LINE => $this->line, + self::INDEX => $this->seenTag - $this->otagLen, + )); + } } diff --git a/test/Mustache/Test/TokenizerTest.php b/test/Mustache/Test/TokenizerTest.php index 29568e0..3cdc42a 100644 --- a/test/Mustache/Test/TokenizerTest.php +++ b/test/Mustache/Test/TokenizerTest.php @@ -351,4 +351,43 @@ class Mustache_Test_TokenizerTest extends PHPUnit_Framework_TestCase ), ); } + + /** + * @dataProvider getUnclosedTags + * @expectedException Mustache_Exception_SyntaxException + */ + public function testUnclosedTagsThrowExceptions($text) + { + $tokenizer = new Mustache_Tokenizer(); + $tokenizer->scan($text, null); + } + + public function getUnclosedTags() + { + return array( + array('{{ name'), + array('{{ name }'), + array('{{{ name'), + array('{{{ name }'), + array('{{& name'), + array('{{& name }'), + array('{{# name'), + array('{{# name }'), + array('{{^ name'), + array('{{^ name }'), + array('{{/ name'), + array('{{/ name }'), + array('{{> name'), + array('{{< name'), + array('{{> name }'), + array('{{< name }'), + array('{{$ name'), + array('{{$ name }'), + array('{{= <% %>'), + array('{{= <% %>='), + array('{{= <% %>=}'), + array('{{% name'), + array('{{% name }'), + ); + } }