From 46b15e6365ce3df16c82bf4a29e4ee191c68e1d7 Mon Sep 17 00:00:00 2001 From: Shad Date: Wed, 3 Apr 2024 19:57:09 +0200 Subject: [PATCH 01/16] add is_array modifier doc (#984) --- .../language-modifiers/language-modifier-is_array.md | 9 +++++++++ mkdocs.yml | 1 + 2 files changed, 10 insertions(+) create mode 100644 docs/designers/language-modifiers/language-modifier-is_array.md diff --git a/docs/designers/language-modifiers/language-modifier-is_array.md b/docs/designers/language-modifiers/language-modifier-is_array.md new file mode 100644 index 00000000..f6cfffcd --- /dev/null +++ b/docs/designers/language-modifiers/language-modifier-is_array.md @@ -0,0 +1,9 @@ +# is_array + +Return true if the variable passed to it is an array. + +## Basic usage + +```smarty +{if $myVar|is_array}it's an array{/if} +``` diff --git a/mkdocs.yml b/mkdocs.yml index 223cab28..74ad349c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -60,6 +60,7 @@ nav: - 'escape': 'designers/language-modifiers/language-modifier-escape.md' - 'from_charset': 'designers/language-modifiers/language-modifier-from-charset.md' - 'indent': 'designers/language-modifiers/language-modifier-indent.md' + - 'is_array': 'designers/language-modifiers/language-modifier-is_array.md' - 'isset': 'designers/language-modifiers/language-modifier-isset.md' - 'join': 'designers/language-modifiers/language-modifier-join.md' - 'json_encode': 'designers/language-modifiers/language-modifier-json-encode.md' From 0972503aef38662bcd8e6f8d60d1d32215512288 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Wed, 27 Mar 2024 22:57:04 +0100 Subject: [PATCH 02/16] version bump --- changelog/966.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 changelog/966.md diff --git a/changelog/966.md b/changelog/966.md deleted file mode 100644 index 5332ce59..00000000 --- a/changelog/966.md +++ /dev/null @@ -1 +0,0 @@ -- Fix error in Smarty\Smarty::compileAllTemplates() by including missing FilesystemIterator class [#966](https://github.com/smarty-php/smarty/issues/966) \ No newline at end of file From 569cef71d0fc45aeed260170c4ad66626d791161 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Wed, 27 Mar 2024 23:05:16 +0100 Subject: [PATCH 03/16] fix release tooling to support/5 branch --- make-release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make-release.sh b/make-release.sh index 2b6db0d7..a5e9ffde 100755 --- a/make-release.sh +++ b/make-release.sh @@ -15,7 +15,7 @@ php utilities/update-smarty-version-number.php $1 git add changelog CHANGELOG.md src/Smarty.php git commit -m "version bump" -git checkout master +git checkout support/5 git pull git merge --no-ff "release/$1" git branch -d "release/$1" From 599bcee13ea7b305876191241be920a1c0fcf9b5 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Thu, 28 Mar 2024 11:22:29 +0100 Subject: [PATCH 04/16] Fix Smarty::assign() not returning when called with an array as first parameter. (#973) Fixes #972 --- changelog/972.md | 1 + src/Data.php | 2 +- .../SmartyMethodsTests/Assign/AssignTest.php | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 changelog/972.md diff --git a/changelog/972.md b/changelog/972.md new file mode 100644 index 00000000..e1e930a3 --- /dev/null +++ b/changelog/972.md @@ -0,0 +1 @@ +- Fix Smarty::assign() not returning $this when called with an array as first parameter [#972](https://github.com/smarty-php/smarty/pull/972) \ No newline at end of file diff --git a/src/Data.php b/src/Data.php index 3176c7f0..582ee660 100644 --- a/src/Data.php +++ b/src/Data.php @@ -109,7 +109,7 @@ class Data foreach ($tpl_var as $_key => $_val) { $this->assign($_key, $_val, $nocache, $scope); } - return; + return $this; } switch ($scope ?? $this->getDefaultScope()) { case self::SCOPE_GLOBAL: diff --git a/tests/UnitTests/SmartyMethodsTests/Assign/AssignTest.php b/tests/UnitTests/SmartyMethodsTests/Assign/AssignTest.php index ea5f3a4b..e8ae92b7 100644 --- a/tests/UnitTests/SmartyMethodsTests/Assign/AssignTest.php +++ b/tests/UnitTests/SmartyMethodsTests/Assign/AssignTest.php @@ -42,4 +42,15 @@ class AssignTest extends PHPUnit_Smarty $this->smarty->assign(array('foo' => 'bar', 'foo2' => 'bar2')); $this->assertEquals('bar bar2', $this->smarty->fetch('eval:{$foo} {$foo2}')); } + + /** + * Test that assign returns this. + */ + public function testAssignReturnsThis() + { + $this->assertEquals( + 'data', + $this->smarty->assign(['dummy' => 'data'])->fetch('eval:{$dummy}') + ); + } } From 5400b53edf17c8cb56b65852d6d077943aefc87e Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Fri, 5 Apr 2024 22:40:31 +0200 Subject: [PATCH 05/16] Revert "fix release tooling to support/5 branch" This reverts commit 569cef71d0fc45aeed260170c4ad66626d791161. --- make-release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make-release.sh b/make-release.sh index a5e9ffde..2b6db0d7 100755 --- a/make-release.sh +++ b/make-release.sh @@ -15,7 +15,7 @@ php utilities/update-smarty-version-number.php $1 git add changelog CHANGELOG.md src/Smarty.php git commit -m "version bump" -git checkout support/5 +git checkout master git pull git merge --no-ff "release/$1" git branch -d "release/$1" From 34adf4e54cae4a352d3b239f18aacc8d04861921 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Sat, 6 Apr 2024 23:41:20 +0200 Subject: [PATCH 06/16] Fixed unit tests to not rely on the existence of any domain or unavailability of internet access when running tests. (#987) --- src/BlockHandler/TextFormat.php | 3 - src/Compile/Modifier/CatModifierCompiler.php | 2 - .../CountCharactersModifierCompiler.php | 2 - .../CountParagraphsModifierCompiler.php | 2 - .../CountSentencesModifierCompiler.php | 2 - .../Modifier/CountWordsModifierCompiler.php | 1 - .../Modifier/DefaultModifierCompiler.php | 1 - .../Modifier/EscapeModifierCompiler.php | 1 - .../Modifier/IndentModifierCompiler.php | 1 - .../Modifier/LowerModifierCompiler.php | 1 - .../Modifier/Nl2brModifierCompiler.php | 1 - .../Modifier/RoundModifierCompiler.php | 1 - .../Modifier/StrRepeatModifierCompiler.php | 1 - .../Modifier/StringFormatModifierCompiler.php | 1 - .../Modifier/StripModifierCompiler.php | 1 - .../Modifier/StripTagsModifierCompiler.php | 1 - .../Modifier/StrlenModifierCompiler.php | 1 - .../Modifier/UpperModifierCompiler.php | 1 - .../Modifier/WordWrapModifierCompiler.php | 1 - src/Data.php | 8 - src/Extension/DefaultExtension.php | 7 - src/FunctionHandler/Counter.php | 2 - src/FunctionHandler/Cycle.php | 2 - src/FunctionHandler/Fetch.php | 2 - src/FunctionHandler/HtmlCheckboxes.php | 2 - src/FunctionHandler/HtmlImage.php | 2 - src/FunctionHandler/HtmlOptions.php | 2 - src/FunctionHandler/HtmlRadios.php | 2 - src/FunctionHandler/HtmlSelectDate.php | 2 - src/FunctionHandler/HtmlSelectTime.php | 2 - src/FunctionHandler/HtmlTable.php | 2 - src/FunctionHandler/Mailto.php | 2 - src/FunctionHandler/Math.php | 2 - src/Smarty.php | 15 - src/Template.php | 1 - src/TemplateBase.php | 7 - .../UnitTests/SecurityTests/SecurityTest.php | 710 +++++++++--------- .../PluginFunctionFetchTest.php | 132 ++-- .../TagTests/PluginFunction/testfile.txt | 1 + 39 files changed, 415 insertions(+), 515 deletions(-) create mode 100644 tests/UnitTests/TemplateSource/TagTests/PluginFunction/testfile.txt diff --git a/src/BlockHandler/TextFormat.php b/src/BlockHandler/TextFormat.php index 9cd804bb..b4fa5acd 100644 --- a/src/BlockHandler/TextFormat.php +++ b/src/BlockHandler/TextFormat.php @@ -20,9 +20,6 @@ use Smarty\Template; * - indent_char - string (" ") * - wrap_boundary - boolean (true) * - * @link https://www.smarty.net/manual/en/language.function.textformat.php {textformat} - * (Smarty online manual) - * * @param array $params parameters * @param string $content contents of the block * @param Template $template template object diff --git a/src/Compile/Modifier/CatModifierCompiler.php b/src/Compile/Modifier/CatModifierCompiler.php index f7cc2589..21005d5b 100644 --- a/src/Compile/Modifier/CatModifierCompiler.php +++ b/src/Compile/Modifier/CatModifierCompiler.php @@ -11,8 +11,6 @@ namespace Smarty\Compile\Modifier; * Input: string to catenate * Example: {$var|cat:"foo"} * - * @link https://www.smarty.net/manual/en/language.modifier.cat.php cat - * (Smarty online manual) * @author Uwe Tews */ diff --git a/src/Compile/Modifier/CountCharactersModifierCompiler.php b/src/Compile/Modifier/CountCharactersModifierCompiler.php index 0afad80b..fb5f5ca3 100644 --- a/src/Compile/Modifier/CountCharactersModifierCompiler.php +++ b/src/Compile/Modifier/CountCharactersModifierCompiler.php @@ -6,8 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: count_characters * Purpose: count the number of characters in a text * - * @link https://www.smarty.net/manual/en/language.modifier.count.characters.php count_characters (Smarty online - * manual) * @author Uwe Tews */ diff --git a/src/Compile/Modifier/CountParagraphsModifierCompiler.php b/src/Compile/Modifier/CountParagraphsModifierCompiler.php index f67e64a3..76552e07 100644 --- a/src/Compile/Modifier/CountParagraphsModifierCompiler.php +++ b/src/Compile/Modifier/CountParagraphsModifierCompiler.php @@ -6,8 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: count_paragraphs * Purpose: count the number of paragraphs in a text * - * @link https://www.smarty.net/manual/en/language.modifier.count.paragraphs.php - * count_paragraphs (Smarty online manual) * @author Uwe Tews */ diff --git a/src/Compile/Modifier/CountSentencesModifierCompiler.php b/src/Compile/Modifier/CountSentencesModifierCompiler.php index 503d63f1..bc7c43e1 100644 --- a/src/Compile/Modifier/CountSentencesModifierCompiler.php +++ b/src/Compile/Modifier/CountSentencesModifierCompiler.php @@ -6,8 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: count_sentences * Purpose: count the number of sentences in a text * - * @link https://www.smarty.net/manual/en/language.modifier.count.paragraphs.php - * count_sentences (Smarty online manual) * @author Uwe Tews */ diff --git a/src/Compile/Modifier/CountWordsModifierCompiler.php b/src/Compile/Modifier/CountWordsModifierCompiler.php index e1c648ab..c11d546d 100644 --- a/src/Compile/Modifier/CountWordsModifierCompiler.php +++ b/src/Compile/Modifier/CountWordsModifierCompiler.php @@ -6,7 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: count_words * Purpose: count the number of words in a text * - * @link https://www.smarty.net/manual/en/language.modifier.count.words.php count_words (Smarty online manual) * @author Uwe Tews */ diff --git a/src/Compile/Modifier/DefaultModifierCompiler.php b/src/Compile/Modifier/DefaultModifierCompiler.php index f802e4d5..3d82aa70 100644 --- a/src/Compile/Modifier/DefaultModifierCompiler.php +++ b/src/Compile/Modifier/DefaultModifierCompiler.php @@ -6,7 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: default * Purpose: designate default value for empty variables * - * @link https://www.smarty.net/manual/en/language.modifier.default.php default (Smarty online manual) * @author Uwe Tews */ diff --git a/src/Compile/Modifier/EscapeModifierCompiler.php b/src/Compile/Modifier/EscapeModifierCompiler.php index 54e6f34b..b600e08c 100644 --- a/src/Compile/Modifier/EscapeModifierCompiler.php +++ b/src/Compile/Modifier/EscapeModifierCompiler.php @@ -9,7 +9,6 @@ use Smarty\Exception; * Name: escape * Purpose: escape string for output * - * @link https://www.smarty.net/docsv2/en/language.modifier.escape count_characters (Smarty online manual) * @author Rodney Rehm */ diff --git a/src/Compile/Modifier/IndentModifierCompiler.php b/src/Compile/Modifier/IndentModifierCompiler.php index 401e24a1..353e757f 100644 --- a/src/Compile/Modifier/IndentModifierCompiler.php +++ b/src/Compile/Modifier/IndentModifierCompiler.php @@ -6,7 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: indent * Purpose: indent lines of text * - * @link https://www.smarty.net/manual/en/language.modifier.indent.php indent (Smarty online manual) * @author Uwe Tews */ diff --git a/src/Compile/Modifier/LowerModifierCompiler.php b/src/Compile/Modifier/LowerModifierCompiler.php index 4186b1ec..62fc87e9 100644 --- a/src/Compile/Modifier/LowerModifierCompiler.php +++ b/src/Compile/Modifier/LowerModifierCompiler.php @@ -6,7 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: lower * Purpose: convert string to lowercase * - * @link https://www.smarty.net/manual/en/language.modifier.lower.php lower (Smarty online manual) * @author Monte Ohrt * @author Uwe Tews */ diff --git a/src/Compile/Modifier/Nl2brModifierCompiler.php b/src/Compile/Modifier/Nl2brModifierCompiler.php index 074e6772..c3b1aa53 100644 --- a/src/Compile/Modifier/Nl2brModifierCompiler.php +++ b/src/Compile/Modifier/Nl2brModifierCompiler.php @@ -7,7 +7,6 @@ namespace Smarty\Compile\Modifier; * Name: nl2br * Purpose: insert HTML line breaks before all newlines in a string * - * @link https://www.smarty.net/docs/en/language.modifier.nl2br.tpl nl2br (Smarty online manual) */ class Nl2brModifierCompiler extends Base { diff --git a/src/Compile/Modifier/RoundModifierCompiler.php b/src/Compile/Modifier/RoundModifierCompiler.php index 33645ea0..82476833 100644 --- a/src/Compile/Modifier/RoundModifierCompiler.php +++ b/src/Compile/Modifier/RoundModifierCompiler.php @@ -7,7 +7,6 @@ namespace Smarty\Compile\Modifier; * Name: round * Purpose: Returns the rounded value of num to specified precision (number of digits after the decimal point) * - * @link https://www.smarty.net/docs/en/language.modifier.round.tpl round (Smarty online manual) */ class RoundModifierCompiler extends Base { diff --git a/src/Compile/Modifier/StrRepeatModifierCompiler.php b/src/Compile/Modifier/StrRepeatModifierCompiler.php index dbe4ba77..c33af329 100644 --- a/src/Compile/Modifier/StrRepeatModifierCompiler.php +++ b/src/Compile/Modifier/StrRepeatModifierCompiler.php @@ -6,7 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: str_repeat * Purpose: returns string repeated times times * - * @link https://www.smarty.net/docs/en/language.modifier.str_repeat.tpl str_repeat (Smarty online manual) */ class StrRepeatModifierCompiler extends Base { diff --git a/src/Compile/Modifier/StringFormatModifierCompiler.php b/src/Compile/Modifier/StringFormatModifierCompiler.php index a0c23ae5..e662f016 100644 --- a/src/Compile/Modifier/StringFormatModifierCompiler.php +++ b/src/Compile/Modifier/StringFormatModifierCompiler.php @@ -6,7 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: string_format * Purpose: format strings via sprintf * - * @link https://www.smarty.net/manual/en/language.modifier.string.format.php string_format (Smarty online manual) * @author Uwe Tews */ diff --git a/src/Compile/Modifier/StripModifierCompiler.php b/src/Compile/Modifier/StripModifierCompiler.php index 78871640..d85f83df 100644 --- a/src/Compile/Modifier/StripModifierCompiler.php +++ b/src/Compile/Modifier/StripModifierCompiler.php @@ -9,7 +9,6 @@ namespace Smarty\Compile\Modifier; * Example: {$var|strip} {$var|strip:" "} * Date: September 25th, 2002 * - * @link https://www.smarty.net/manual/en/language.modifier.strip.php strip (Smarty online manual) * @author Uwe Tews */ diff --git a/src/Compile/Modifier/StripTagsModifierCompiler.php b/src/Compile/Modifier/StripTagsModifierCompiler.php index e8885bc7..dfd09437 100644 --- a/src/Compile/Modifier/StripTagsModifierCompiler.php +++ b/src/Compile/Modifier/StripTagsModifierCompiler.php @@ -6,7 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: strip_tags * Purpose: strip html tags from text * - * @link https://www.smarty.net/docs/en/language.modifier.strip.tags.tpl strip_tags (Smarty online manual) * @author Uwe Tews */ diff --git a/src/Compile/Modifier/StrlenModifierCompiler.php b/src/Compile/Modifier/StrlenModifierCompiler.php index 07a44718..5cc666fd 100644 --- a/src/Compile/Modifier/StrlenModifierCompiler.php +++ b/src/Compile/Modifier/StrlenModifierCompiler.php @@ -7,7 +7,6 @@ namespace Smarty\Compile\Modifier; * Name: strlen * Purpose: return the length of the given string * - * @link https://www.smarty.net/docs/en/language.modifier.strlen.tpl strlen (Smarty online manual) */ class StrlenModifierCompiler extends Base { diff --git a/src/Compile/Modifier/UpperModifierCompiler.php b/src/Compile/Modifier/UpperModifierCompiler.php index 9bef41ff..74e9a702 100644 --- a/src/Compile/Modifier/UpperModifierCompiler.php +++ b/src/Compile/Modifier/UpperModifierCompiler.php @@ -6,7 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: lower * Purpose: convert string to uppercase * - * @link https://www.smarty.net/manual/en/language.modifier.upper.php lower (Smarty online manual) * @author Uwe Tews */ diff --git a/src/Compile/Modifier/WordWrapModifierCompiler.php b/src/Compile/Modifier/WordWrapModifierCompiler.php index 4a6d84b0..092b95a8 100644 --- a/src/Compile/Modifier/WordWrapModifierCompiler.php +++ b/src/Compile/Modifier/WordWrapModifierCompiler.php @@ -6,7 +6,6 @@ namespace Smarty\Compile\Modifier; * Name: wordwrap * Purpose: wrap a string of text at a given length * - * @link https://www.smarty.net/manual/en/language.modifier.wordwrap.php wordwrap (Smarty online manual) * @author Uwe Tews */ diff --git a/src/Data.php b/src/Data.php index 582ee660..64a4770e 100644 --- a/src/Data.php +++ b/src/Data.php @@ -163,8 +163,6 @@ class Data * be not cached * * @return Data - * @link https://www.smarty.net/docs/en/api.append.tpl - * * @api Smarty::append() */ public function append($tpl_var, $value = null, $merge = false, $nocache = false) @@ -218,7 +216,6 @@ class Data * * @return mixed variable value or or array of variables * @api Smarty::getTemplateVars() - * @link https://www.smarty.net/docs/en/api.get.template.vars.tpl * */ public function getTemplateVars($varName = null, $searchParents = true) @@ -351,7 +348,6 @@ class Data * @param string|array $tpl_var the template variable(s) to clear * * @return Data - * @link https://www.smarty.net/docs/en/api.clear.assign.tpl * * @api Smarty::clearAssign() */ @@ -371,7 +367,6 @@ class Data * clear all the assigned template variables. * * @return Data - * @link https://www.smarty.net/docs/en/api.clear.all.assign.tpl * * @api Smarty::clearAllAssign() */ @@ -387,7 +382,6 @@ class Data * @param string|null $name variable name or null * * @return Data - * @link https://www.smarty.net/docs/en/api.clear.config.tpl * * @api Smarty::clearConfig() */ @@ -440,7 +434,6 @@ class Data * * @return mixed variable value or or array of variables * @throws Exception - * @link https://www.smarty.net/docs/en/api.get.config.vars.tpl * * @api Smarty::getConfigVars() */ @@ -462,7 +455,6 @@ class Data * @returns $this * @throws \Exception - * @link https://www.smarty.net/docs/en/api.config.load.tpl * * @api Smarty::configLoad() */ diff --git a/src/Extension/DefaultExtension.php b/src/Extension/DefaultExtension.php index e400dddb..cecc4a46 100644 --- a/src/Extension/DefaultExtension.php +++ b/src/Extension/DefaultExtension.php @@ -113,7 +113,6 @@ class DefaultExtension extends Base { * Name: spacify * Purpose: add spaces between characters in a string * - * @link https://www.smarty.net/manual/en/language.modifier.spacify.php spacify (Smarty online manual) * @author Monte Ohrt * * @param string $string input string @@ -234,7 +233,6 @@ class DefaultExtension extends Base { * - format: strftime format for output * - default_date: default date if $string is empty * - * @link https://www.smarty.net/manual/en/language.modifier.date.format.php date_format (Smarty online manual) * @author Monte Ohrt * * @param string $string input date string @@ -386,7 +384,6 @@ class DefaultExtension extends Base { * Name: escape * Purpose: escape string for output * - * @link https://www.smarty.net/docs/en/language.modifier.escape * @author Monte Ohrt * * @param string $string input string @@ -654,8 +651,6 @@ class DefaultExtension extends Base { * Name: regex_replace * Purpose: regular expression search/replace * - * @link https://www.smarty.net/manual/en/language.modifier.regex.replace.php - * regex_replace (Smarty online manual) * @author Monte Ohrt * * @param string $string input string @@ -703,7 +698,6 @@ class DefaultExtension extends Base { * Name: replace * Purpose: simple search/replace * - * @link https://www.smarty.net/manual/en/language.modifier.replace.php replace (Smarty online manual) * @author Monte Ohrt * @author Uwe Tews * @@ -726,7 +720,6 @@ class DefaultExtension extends Base { * optionally splitting in the middle of a word, and * appending the $etc string or inserting $etc into the middle. * - * @link https://www.smarty.net/manual/en/language.modifier.truncate.php truncate (Smarty online manual) * @author Monte Ohrt * * @param string $string input string diff --git a/src/FunctionHandler/Counter.php b/src/FunctionHandler/Counter.php index c6f9fdbe..b447caf1 100644 --- a/src/FunctionHandler/Counter.php +++ b/src/FunctionHandler/Counter.php @@ -13,8 +13,6 @@ use Smarty\Template; * @param Template $template template object * * @return string|null - *@link https://www.smarty.net/manual/en/language.function.counter.php {counter} - * (Smarty online manual) * * @author Monte Ohrt */ diff --git a/src/FunctionHandler/Cycle.php b/src/FunctionHandler/Cycle.php index 756573fa..909a688b 100644 --- a/src/FunctionHandler/Cycle.php +++ b/src/FunctionHandler/Cycle.php @@ -26,8 +26,6 @@ use Smarty\Template; * {cycle name=row values="one,two,three" reset=true} * {cycle name=row} * - * @link https://www.smarty.net/manual/en/language.function.cycle.php {cycle} - * (Smarty online manual) * @author Monte Ohrt * @author credit to Mark Priatel * @author credit to Gerard diff --git a/src/FunctionHandler/Fetch.php b/src/FunctionHandler/Fetch.php index 3031ac88..d10ef668 100644 --- a/src/FunctionHandler/Fetch.php +++ b/src/FunctionHandler/Fetch.php @@ -10,8 +10,6 @@ use Smarty\Template; * Name: fetch * Purpose: fetch file, web or ftp data and display results * - * @link https://www.smarty.net/manual/en/language.function.fetch.php {fetch} - * (Smarty online manual) * @author Monte Ohrt * * @param array $params parameters diff --git a/src/FunctionHandler/HtmlCheckboxes.php b/src/FunctionHandler/HtmlCheckboxes.php index a32b48b2..45ecc40a 100644 --- a/src/FunctionHandler/HtmlCheckboxes.php +++ b/src/FunctionHandler/HtmlCheckboxes.php @@ -27,8 +27,6 @@ use Smarty\Template; * - assign (optional) - assign the output as an array to this variable * - escape (optional) - escape the content (not value), defaults to true * - * @link https://www.smarty.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} - * (Smarty online manual) * @author Christopher Kvarme * @author credits to Monte Ohrt * @version 1.0 diff --git a/src/FunctionHandler/HtmlImage.php b/src/FunctionHandler/HtmlImage.php index a524eef9..9cb08745 100644 --- a/src/FunctionHandler/HtmlImage.php +++ b/src/FunctionHandler/HtmlImage.php @@ -20,8 +20,6 @@ use Smarty\Template; * - basedir - (optional) - base directory for absolute paths, default is environment variable DOCUMENT_ROOT * - path_prefix - prefix for path output (optional, default empty) * - * @link https://www.smarty.net/manual/en/language.function.html.image.php {html_image} - * (Smarty online manual) * @author Monte Ohrt * @author credits to Duda * @version 1.0 diff --git a/src/FunctionHandler/HtmlOptions.php b/src/FunctionHandler/HtmlOptions.php index c008766d..5346738b 100644 --- a/src/FunctionHandler/HtmlOptions.php +++ b/src/FunctionHandler/HtmlOptions.php @@ -19,8 +19,6 @@ use Smarty\Template; * - id (optional) - string default not set * - class (optional) - string default not set * - * @link https://www.smarty.net/manual/en/language.function.html.options.php {html_image} - * (Smarty online manual) * @author Monte Ohrt * @author Ralf Strehle (minor optimization) * diff --git a/src/FunctionHandler/HtmlRadios.php b/src/FunctionHandler/HtmlRadios.php index 0cc95609..544c5c7d 100644 --- a/src/FunctionHandler/HtmlRadios.php +++ b/src/FunctionHandler/HtmlRadios.php @@ -27,8 +27,6 @@ use Smarty\Template; * {html_radios values=$ids name='box' separator='
' output=$names} * {html_radios values=$ids checked=$checked separator='
' output=$names} * - * @link https://www.smarty.net/manual/en/language.function.html.radios.php {html_radios} - * (Smarty online manual) * @author Christopher Kvarme * @author credits to Monte Ohrt * @version 1.0 diff --git a/src/FunctionHandler/HtmlSelectDate.php b/src/FunctionHandler/HtmlSelectDate.php index 55e36641..a6acfb7b 100644 --- a/src/FunctionHandler/HtmlSelectDate.php +++ b/src/FunctionHandler/HtmlSelectDate.php @@ -26,8 +26,6 @@ use Smarty\Template; * - 2.0 complete rewrite for performance, * added attributes month_names, *_id * - * @link https://www.smarty.net/manual/en/language.function.html.select.date.php {html_select_date} - * (Smarty online manual) * @version 2.0 * @author Andrei Zmievski * @author Monte Ohrt diff --git a/src/FunctionHandler/HtmlSelectTime.php b/src/FunctionHandler/HtmlSelectTime.php index 6e4f679d..40679c10 100644 --- a/src/FunctionHandler/HtmlSelectTime.php +++ b/src/FunctionHandler/HtmlSelectTime.php @@ -9,8 +9,6 @@ use Smarty\Template; * Name: html_select_time * Purpose: Prints the dropdowns for time selection * - * @link https://www.smarty.net/manual/en/language.function.html.select.time.php {html_select_time} - * (Smarty online manual) * @author Roberto Berto * @author Monte Ohrt * diff --git a/src/FunctionHandler/HtmlTable.php b/src/FunctionHandler/HtmlTable.php index 1dadc7f1..d5d14705 100644 --- a/src/FunctionHandler/HtmlTable.php +++ b/src/FunctionHandler/HtmlTable.php @@ -37,8 +37,6 @@ use Smarty\Template; * @return string *@author credit to boots * @version 1.1 - * @link https://www.smarty.net/manual/en/language.function.html.table.php {html_table} - * (Smarty online manual) * * @author Monte Ohrt * @author credit to Messju Mohr diff --git a/src/FunctionHandler/Mailto.php b/src/FunctionHandler/Mailto.php index 8f7b821a..eb35c48e 100644 --- a/src/FunctionHandler/Mailto.php +++ b/src/FunctionHandler/Mailto.php @@ -35,8 +35,6 @@ use Smarty\Template; * {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"} * {mailto address="me@domain.com" extra='class="mailto"'} * - * @link https://www.smarty.net/manual/en/language.function.mailto.php {mailto} - * (Smarty online manual) * @version 1.2 * @author Monte Ohrt * @author credits to Jason Sweat (added cc, bcc and subject functionality) diff --git a/src/FunctionHandler/Math.php b/src/FunctionHandler/Math.php index f8236ca9..23ef9253 100644 --- a/src/FunctionHandler/Math.php +++ b/src/FunctionHandler/Math.php @@ -10,8 +10,6 @@ use Smarty\Template; * Name: math * Purpose: handle math computations in template * - * @link https://www.smarty.net/manual/en/language.function.math.php {math} - * (Smarty online manual) * @author Monte Ohrt * * @param array $params parameters diff --git a/src/Smarty.php b/src/Smarty.php index bf1d3fad..18ff5262 100644 --- a/src/Smarty.php +++ b/src/Smarty.php @@ -40,7 +40,6 @@ use Smarty\Runtime\TplFunctionRuntime; * Smarty mailing list. Send a blank e-mail to * smarty-discussion-subscribe@googlegroups.com * - * @link https://www.smarty.net/ * @author Monte Ohrt * @author Uwe Tews * @author Rodney Rehm @@ -731,7 +730,6 @@ class Smarty extends \Smarty\TemplateBase { * * @return $this * @throws \Smarty\Exception - * @link https://www.smarty.net/docs/en/api.register.plugin.tpl * * @api Smarty::registerPlugin() */ @@ -758,7 +756,6 @@ class Smarty extends \Smarty\TemplateBase { * @param string $name name of template tag * * @return array|null - * @link https://www.smarty.net/docs/en/api.unregister.plugin.tpl * * @api Smarty::unregisterPlugin() */ @@ -776,7 +773,6 @@ class Smarty extends \Smarty\TemplateBase { * @param string $name name of template tag * * @return $this - * @link https://www.smarty.net/docs/en/api.unregister.plugin.tpl * * @api Smarty::unregisterPlugin() */ @@ -850,7 +846,6 @@ class Smarty extends \Smarty\TemplateBase { * * @return $this * @throws Exception if $callback is not callable - * @link https://www.smarty.net/docs/en/api.register.default.plugin.handler.tpl * * @api Smarty::registerDefaultPluginHandler() * @@ -1254,7 +1249,6 @@ class Smarty extends \Smarty\TemplateBase { * * @return int number of cache files deleted * @throws \Smarty\Exception - * @link https://www.smarty.net/docs/en/api.clear.cache.tpl * * @api Smarty::clearCache() */ @@ -1274,7 +1268,6 @@ class Smarty extends \Smarty\TemplateBase { * @param string $type resource type * * @return int number of cache files deleted - * @link https://www.smarty.net/docs/en/api.clear.all.cache.tpl * * @api Smarty::clearAllCache() */ @@ -1291,7 +1284,6 @@ class Smarty extends \Smarty\TemplateBase { * * @return int number of template files deleted * @throws \Smarty\Exception - * @link https://www.smarty.net/docs/en/api.clear.compiled.template.tpl * * @api Smarty::clearCompiledTemplate() */ @@ -1805,7 +1797,6 @@ class Smarty extends \Smarty\TemplateBase { * @return bool * @throws \Smarty\Exception * @api Smarty::loadFilter() - * @link https://www.smarty.net/docs/en/api.load.filter.tpl * * @deprecated since 5.0 */ @@ -1857,7 +1848,6 @@ class Smarty extends \Smarty\TemplateBase { * @throws \Smarty\Exception * @api Smarty::unloadFilter() * - * @link https://www.smarty.net/docs/en/api.unload.filter.tpl * * @deprecated since 5.0 */ @@ -1901,7 +1891,6 @@ class Smarty extends \Smarty\TemplateBase { * @param Base $resource_handler * * @return Smarty - * @link https://www.smarty.net/docs/en/api.register.cacheresource.tpl * * @api Smarty::registerCacheResource() * @@ -1924,7 +1913,6 @@ class Smarty extends \Smarty\TemplateBase { * * @return Smarty * @api Smarty::unregisterCacheResource() - * @link https://www.smarty.net/docs/en/api.unregister.cacheresource.tpl * * @deprecated since 5.0 * @@ -1958,7 +1946,6 @@ class Smarty extends \Smarty\TemplateBase { * * @return TemplateBase * @throws \Smarty\Exception - * @link https://www.smarty.net/docs/en/api.register.filter.tpl * * @api Smarty::registerFilter() */ @@ -2020,7 +2007,6 @@ class Smarty extends \Smarty\TemplateBase { * @throws \Smarty\Exception * @api Smarty::unregisterFilter() * - * @link https://www.smarty.net/docs/en/api.unregister.filter.tpl * */ public function unregisterFilter($type, $name) { @@ -2203,7 +2189,6 @@ class Smarty extends \Smarty\TemplateBase { * @return bool cache status * @throws \Exception * @throws \Smarty\Exception - * @link https://www.smarty.net/docs/en/api.is.cached.tpl * * @api Smarty::isCached() */ diff --git a/src/Template.php b/src/Template.php index 8bb5370f..fcb0f58d 100644 --- a/src/Template.php +++ b/src/Template.php @@ -604,7 +604,6 @@ class Template extends TemplateBase { * @return bool cache status * @throws \Exception * @throws \Smarty\Exception - * @link https://www.smarty.net/docs/en/api.is.cached.tpl * * @api Smarty::isCached() */ diff --git a/src/TemplateBase.php b/src/TemplateBase.php index 4dab470f..0b7f212c 100644 --- a/src/TemplateBase.php +++ b/src/TemplateBase.php @@ -75,7 +75,6 @@ abstract class TemplateBase extends Data { * * @return \Smarty|\Smarty\Template * @throws \Smarty\Exception - * @link https://www.smarty.net/docs/en/api.register.object.tpl * * @api Smarty::registerObject() */ @@ -116,7 +115,6 @@ abstract class TemplateBase extends Data { * * @return TemplateBase * @api Smarty::unregisterObject() - * @link https://www.smarty.net/docs/en/api.unregister.object.tpl * */ public function unregisterObject($object_name) { @@ -179,7 +177,6 @@ abstract class TemplateBase extends Data { * @return Data data object * @throws Exception * @api Smarty::createData() - * @link https://www.smarty.net/docs/en/api.create.data.tpl * */ public function createData(Data $parent = null, $name = null) { @@ -222,7 +219,6 @@ abstract class TemplateBase extends Data { * * @return object * @throws \Smarty\Exception if no such object is found - * @link https://www.smarty.net/docs/en/api.get.registered.object.tpl * * @api Smarty::getRegisteredObject() */ @@ -319,7 +315,6 @@ abstract class TemplateBase extends Data { * @return TemplateBase * @throws \Smarty\Exception * @api Smarty::registerClass() - * @link https://www.smarty.net/docs/en/api.register.class.tpl * */ public function registerClass($class_name, $class_impl) { @@ -380,7 +375,6 @@ abstract class TemplateBase extends Data { * @param \Smarty\Resource\BasePlugin $resource_handler instance of Smarty\Resource\BasePlugin * * @return \Smarty\Smarty|\Smarty\Template - * @link https://www.smarty.net/docs/en/api.register.resource.tpl * * @api Smarty::registerResource() */ @@ -397,7 +391,6 @@ abstract class TemplateBase extends Data { * * @return TemplateBase * @api Smarty::unregisterResource() - * @link https://www.smarty.net/docs/en/api.unregister.resource.tpl * */ public function unregisterResource($type) { diff --git a/tests/UnitTests/SecurityTests/SecurityTest.php b/tests/UnitTests/SecurityTests/SecurityTest.php index e2e66c96..9996f225 100644 --- a/tests/UnitTests/SecurityTests/SecurityTest.php +++ b/tests/UnitTests/SecurityTests/SecurityTest.php @@ -10,411 +10,411 @@ use Smarty\CompilerException; /** * class for security test - * - * - * - * */ class SecurityTest extends PHPUnit_Smarty { - public function setUp(): void - { - $this->setUpSmarty(__DIR__); + public function setUp(): void + { + $this->setUpSmarty(__DIR__); - $this->smarty->setForceCompile(true); - $this->smarty->enableSecurity(); - } - public function testInit() - { - $this->cleanDirs(); - } + $this->smarty->setForceCompile(true); + $this->smarty->enableSecurity(); + } + public function testInit() + { + $this->cleanDirs(); + } -/** -* test that security is loaded - */ - public function testSecurityLoaded() - { - $this->assertTrue(is_object($this->smarty->security_policy)); - } + /** + * test that security is loaded + */ + public function testSecurityLoaded() + { + $this->assertTrue(is_object($this->smarty->security_policy)); + } -/** - * test trusted PHP function - */ - public function testTrustedFunction() - { - $this->assertEquals("5", $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{count($foo)}')); - } + /** + * test trusted PHP function + */ + public function testTrustedFunction() + { + $this->assertEquals("5", $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{count($foo)}')); + } -/** - * test trusted modifier - * @deprecated - */ - public function testTrustedModifier() - { - $this->assertEquals("5", @$this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@count}')); - } + /** + * test trusted modifier + * @deprecated + */ + public function testTrustedModifier() + { + $this->assertEquals("5", @$this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@count}')); + } -/** - * test not trusted modifier - * - * - * @deprecated - */ - public function testNotTrustedModifier() - { - $this->smarty->security_policy->disabled_modifiers[] = 'escape'; - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('modifier \'escape\' disabled by security setting'); - @$this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|escape}'); - } + /** + * test not trusted modifier + * + * + * @deprecated + */ + public function testNotTrustedModifier() + { + $this->smarty->security_policy->disabled_modifiers[] = 'escape'; + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('modifier \'escape\' disabled by security setting'); + @$this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|escape}'); + } -/** - * test allowed tags - */ - public function testAllowedTags1() - { - $this->smarty->security_policy->allowed_tags = array('counter'); - $this->assertEquals("1", $this->smarty->fetch('string:{counter start=1}')); - } + /** + * test allowed tags + */ + public function testAllowedTags1() + { + $this->smarty->security_policy->allowed_tags = array('counter'); + $this->assertEquals("1", $this->smarty->fetch('string:{counter start=1}')); + } -/** - * test not allowed tag - * - * - */ - public function testNotAllowedTags2() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('tag \'cycle\' not allowed by security setting'); - $this->smarty->security_policy->allowed_tags = array('counter'); - $this->smarty->fetch('string:{counter}{cycle values="1,2"}'); - } + /** + * test not allowed tag + * + * + */ + public function testNotAllowedTags2() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('tag \'cycle\' not allowed by security setting'); + $this->smarty->security_policy->allowed_tags = array('counter'); + $this->smarty->fetch('string:{counter}{cycle values="1,2"}'); + } -/** - * test disabled tag - * - * - */ - public function testDisabledTags() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('tag \'cycle\' disabled by security setting'); - $this->smarty->security_policy->disabled_tags = array('cycle'); - $this->smarty->fetch('string:{counter}{cycle values="1,2"}'); - } + /** + * test disabled tag + * + * + */ + public function testDisabledTags() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('tag \'cycle\' disabled by security setting'); + $this->smarty->security_policy->disabled_tags = array('cycle'); + $this->smarty->fetch('string:{counter}{cycle values="1,2"}'); + } -/** - * test allowed modifier - */ - public function testAllowedModifier1() - { - error_reporting(E_ALL & E_STRICT); - $this->smarty->security_policy->allowed_modifiers = array('capitalize'); - $this->assertEquals("Hello World", $this->smarty->fetch('string:{"hello world"|capitalize}')); - error_reporting(E_ALL | E_STRICT); - } + /** + * test allowed modifier + */ + public function testAllowedModifier1() + { + error_reporting(E_ALL & E_STRICT); + $this->smarty->security_policy->allowed_modifiers = array('capitalize'); + $this->assertEquals("Hello World", $this->smarty->fetch('string:{"hello world"|capitalize}')); + error_reporting(E_ALL | E_STRICT); + } - public function testAllowedModifier2() - { - $this->smarty->security_policy->allowed_modifiers = array('upper'); - $this->assertEquals("HELLO WORLD", $this->smarty->fetch('string:{"hello world"|upper}')); - } + public function testAllowedModifier2() + { + $this->smarty->security_policy->allowed_modifiers = array('upper'); + $this->assertEquals("HELLO WORLD", $this->smarty->fetch('string:{"hello world"|upper}')); + } -/** - * test not allowed modifier - * - * - */ - public function testNotAllowedModifier() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('modifier \'lower\' not allowed by security setting'); - $this->smarty->security_policy->allowed_modifiers = array('upper'); - $this->smarty->fetch('string:{"hello"|upper}{"world"|lower}'); - } + /** + * test not allowed modifier + * + * + */ + public function testNotAllowedModifier() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('modifier \'lower\' not allowed by security setting'); + $this->smarty->security_policy->allowed_modifiers = array('upper'); + $this->smarty->fetch('string:{"hello"|upper}{"world"|lower}'); + } -/** - * test disabled modifier - * - * - */ - public function testDisabledModifier() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('modifier \'lower\' disabled by security setting'); - $this->smarty->security_policy->disabled_modifiers = array('lower'); - $this->smarty->fetch('string:{"hello"|upper}{"world"|lower}'); - } + /** + * test disabled modifier + * + * + */ + public function testDisabledModifier() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('modifier \'lower\' disabled by security setting'); + $this->smarty->security_policy->disabled_modifiers = array('lower'); + $this->smarty->fetch('string:{"hello"|upper}{"world"|lower}'); + } -/** - * test Smarty no longer handles embedded PHP - */ - public function testSmartyPhpAllow() - { - $this->assertEquals('', $this->smarty->fetch('string:')); - } + /** + * test Smarty no longer handles embedded PHP + */ + public function testSmartyPhpAllow() + { + $this->assertEquals('', $this->smarty->fetch('string:')); + } - public function testSmartyPhpAllow2() - { - $this->assertEquals('', $this->smarty->fetch('string:')); - } + public function testSmartyPhpAllow2() + { + $this->assertEquals('', $this->smarty->fetch('string:')); + } - public function testSmartyPhpAllow3() - { - $this->assertEquals('<% echo "hello world"; %>', $this->smarty->fetch('string:<% echo "hello world"; %>')); - } + public function testSmartyPhpAllow3() + { + $this->assertEquals('<% echo "hello world"; %>', $this->smarty->fetch('string:<% echo "hello world"; %>')); + } -/** - * test standard directory - */ - public function testStandardDirectory() - { - $content = $this->smarty->fetch('string:{include file="helloworld.tpl"}'); - $this->assertEquals("hello world", $content); - } + /** + * test standard directory + */ + public function testStandardDirectory() + { + $content = $this->smarty->fetch('string:{include file="helloworld.tpl"}'); + $this->assertEquals("hello world", $content); + } -/** - * test trusted directory - */ - public function testTrustedDirectory() - { - $this->smarty->security_policy->secure_dir = array('.' . DIRECTORY_SEPARATOR . 'templates_2' . DIRECTORY_SEPARATOR); - $this->assertEquals("hello world", $this->smarty->fetch('string:{include file="templates_2/hello.tpl"}')); - } + /** + * test trusted directory + */ + public function testTrustedDirectory() + { + $this->smarty->security_policy->secure_dir = array('.' . DIRECTORY_SEPARATOR . 'templates_2' . DIRECTORY_SEPARATOR); + $this->assertEquals("hello world", $this->smarty->fetch('string:{include file="templates_2/hello.tpl"}')); + } -/** - * test not trusted directory - * - * - * - */ - public function testNotTrustedDirectory() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('not trusted file path'); - $this->smarty->security_policy->secure_dir = array(str_replace('\\', '/', __DIR__ . '/templates_3/')); - $this->smarty->fetch('string:{include file="templates_2/hello.tpl"}'); - } + /** + * test not trusted directory + * + * + * + */ + public function testNotTrustedDirectory() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('not trusted file path'); + $this->smarty->security_policy->secure_dir = array(str_replace('\\', '/', __DIR__ . '/templates_3/')); + $this->smarty->fetch('string:{include file="templates_2/hello.tpl"}'); + } -/** - * test disabled security for not trusted dir - */ - public function testDisabledTrustedDirectory() - { - $this->smarty->disableSecurity(); - $this->assertEquals("hello world", $this->smarty->fetch('string:{include file="templates_2/hello.tpl"}')); - } + /** + * test disabled security for not trusted dir + */ + public function testDisabledTrustedDirectory() + { + $this->smarty->disableSecurity(); + $this->assertEquals("hello world", $this->smarty->fetch('string:{include file="templates_2/hello.tpl"}')); + } -/** - * test trusted static class - */ - public function testTrustedStaticClass() - { - $this->smarty->security_policy->static_classes = array('mysecuritystaticclass'); - $tpl = $this->smarty->createTemplate('string:{mysecuritystaticclass::square(5)}'); - $this->assertEquals('25', $this->smarty->fetch($tpl)); - } + /** + * test trusted static class + */ + public function testTrustedStaticClass() + { + $this->smarty->security_policy->static_classes = array('mysecuritystaticclass'); + $tpl = $this->smarty->createTemplate('string:{mysecuritystaticclass::square(5)}'); + $this->assertEquals('25', $this->smarty->fetch($tpl)); + } - /** - * test not trusted PHP function - * - * - */ - public function testNotTrustedStaticClass() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('access to static class \'mysecuritystaticclass\' not allowed by security setting'); - $this->smarty->security_policy->static_classes = array('null'); - $this->smarty->fetch('string:{mysecuritystaticclass::square(5)}'); - } + /** + * test not trusted PHP function + * + * + */ + public function testNotTrustedStaticClass() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('access to static class \'mysecuritystaticclass\' not allowed by security setting'); + $this->smarty->security_policy->static_classes = array('null'); + $this->smarty->fetch('string:{mysecuritystaticclass::square(5)}'); + } - /** - * test not trusted PHP function - */ - public function testNotTrustedStaticClassEval() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('dynamic static class not allowed by security setting'); - $this->smarty->security_policy->static_classes = array('null'); - $this->smarty->fetch('string:{$test = "mysecuritystaticclass"}{$test::square(5)}'); - } + /** + * test not trusted PHP function + */ + public function testNotTrustedStaticClassEval() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('dynamic static class not allowed by security setting'); + $this->smarty->security_policy->static_classes = array('null'); + $this->smarty->fetch('string:{$test = "mysecuritystaticclass"}{$test::square(5)}'); + } - /** - * test not trusted PHP function - */ - public function testNotTrustedStaticClassSmartyVar() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('dynamic static class not allowed by security setting'); - $this->smarty->security_policy->static_classes = array('null'); - $this->smarty->fetch('string:{$smarty.template_object::square(5)}'); - } + /** + * test not trusted PHP function + */ + public function testNotTrustedStaticClassSmartyVar() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('dynamic static class not allowed by security setting'); + $this->smarty->security_policy->static_classes = array('null'); + $this->smarty->fetch('string:{$smarty.template_object::square(5)}'); + } - public function testChangedTrustedDirectory() - { - $this->smarty->security_policy->secure_dir = array( - '.' . DIRECTORY_SEPARATOR . 'templates_2' . DIRECTORY_SEPARATOR, - ); - $this->assertEquals("hello world", $this->smarty->fetch('string:{include file="templates_2/hello.tpl"}')); + public function testChangedTrustedDirectory() + { + $this->smarty->security_policy->secure_dir = array( + '.' . DIRECTORY_SEPARATOR . 'templates_2' . DIRECTORY_SEPARATOR, + ); + $this->assertEquals("hello world", $this->smarty->fetch('string:{include file="templates_2/hello.tpl"}')); - $this->smarty->security_policy->secure_dir = array( - '.' . DIRECTORY_SEPARATOR . 'templates_2' . DIRECTORY_SEPARATOR, - '.' . DIRECTORY_SEPARATOR . 'templates_3' . DIRECTORY_SEPARATOR, - ); - $this->assertEquals("templates_3", $this->smarty->fetch('string:{include file="templates_3/dirname.tpl"}')); - } -/** - * test template file exits - * - * - * - */ - public function testTemplateTrustedStream() - { - stream_wrapper_register("global", ResourceStreamSecurity::class) - or die("Failed to register protocol"); - $fp = fopen("global://mytest", "r+"); - fwrite($fp, 'hello world {$foo}'); - fclose($fp); - $this->smarty->security_policy->streams= array('global'); - $tpl = $this->smarty->createTemplate('global:mytest'); - $this->assertTrue($tpl->getSource()->exists); - stream_wrapper_unregister("global"); - } -/** - * - * - * test template file exits - */ - public function testTemplateNotTrustedStream() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('stream \'global\' not allowed by security setting'); - stream_wrapper_register("global", ResourceStreamSecurity::class) - or die("Failed to register protocol"); - $fp = fopen("global://mytest", "r+"); - fwrite($fp, 'hello world {$foo}'); - fclose($fp); - $this->smarty->security_policy->streams= array('notrusted'); - $tpl = $this->smarty->createTemplate('global:mytest'); - $this->assertTrue($tpl->getSource()->exists); - stream_wrapper_unregister("global"); - } -/** - * - * @group slow -*/ - public function testTrustedUri() - { - $this->smarty->security_policy->trusted_uri = array( - '#https://www.smarty.net$#i' - ); - $this->assertStringContainsString('Preface | Smarty', $this->smarty->fetch('string:{fetch file="https://www.smarty.net/docs/en/preface.tpl"}')); - } + $this->smarty->security_policy->secure_dir = array( + '.' . DIRECTORY_SEPARATOR . 'templates_2' . DIRECTORY_SEPARATOR, + '.' . DIRECTORY_SEPARATOR . 'templates_3' . DIRECTORY_SEPARATOR, + ); + $this->assertEquals("templates_3", $this->smarty->fetch('string:{include file="templates_3/dirname.tpl"}')); + } + /** + * test template file exits + * + * + * + */ + public function testTemplateTrustedStream() + { + stream_wrapper_register("global", ResourceStreamSecurity::class) + or die("Failed to register protocol"); + $fp = fopen("global://mytest", "r+"); + fwrite($fp, 'hello world {$foo}'); + fclose($fp); + $this->smarty->security_policy->streams= array('global'); + $tpl = $this->smarty->createTemplate('global:mytest'); + $this->assertTrue($tpl->getSource()->exists); + stream_wrapper_unregister("global"); + } + /** + * + * + * test template file exits + */ + public function testTemplateNotTrustedStream() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('stream \'global\' not allowed by security setting'); + stream_wrapper_register("global", ResourceStreamSecurity::class) + or die("Failed to register protocol"); + $fp = fopen("global://mytest", "r+"); + fwrite($fp, 'hello world {$foo}'); + fclose($fp); + $this->smarty->security_policy->streams= array('notrusted'); + $tpl = $this->smarty->createTemplate('global:mytest'); + $this->assertTrue($tpl->getSource()->exists); + stream_wrapper_unregister("global"); + } -/** - * - * -*/ - public function testNotTrustedUri() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('URI \'https://www.smarty.net/docs/en/preface.tpl\' not allowed by security setting'); - $this->smarty->security_policy->trusted_uri = array(); - $this->assertStringContainsString('Preface | Smarty', $this->smarty->fetch('string:{fetch file="https://www.smarty.net/docs/en/preface.tpl"}')); - } + public function testTrustedUri() + { + $this->smarty->security_policy->trusted_uri = array( + '#https://s4otw4nhg.erteorteortert.nusuchtld$#i' + ); - /** - * In security mode, accessing $smarty.template_object should be illegal. - */ - public function testSmartyTemplateObject() { - $this->expectException(CompilerException::class); - $this->smarty->display('string:{$smarty.template_object}'); - } + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('{fetch} cannot read resource \'https://s4otw4nhg.erteorteortert.nusuchtld/docs/en/preface.tpl\''); + + $this->smarty->fetch('string:{fetch file="https://s4otw4nhg.erteorteortert.nusuchtld/docs/en/preface.tpl"}'); + } + + /** + * + * + */ + public function testNotTrustedUri() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('URI \'https://example.net\' not allowed by security setting'); + $this->smarty->security_policy->trusted_uri = []; + $this->assertStringContainsString( + 'Preface | Smarty', + $this->smarty->fetch('string:{fetch file="https://example.net"}') + ); + } + + /** + * In security mode, accessing $smarty.template_object should be illegal. + */ + public function testSmartyTemplateObject() { + $this->expectException(CompilerException::class); + $this->smarty->display('string:{$smarty.template_object}'); + } } class mysecuritystaticclass { - const STATIC_CONSTANT_VALUE = 3; - static $static_var = 5; + const STATIC_CONSTANT_VALUE = 3; + static $static_var = 5; - static function square($i) - { - return $i * $i; - } + static function square($i) + { + return $i * $i; + } } #[AllowDynamicProperties] class ResourceStreamSecurity { - private $position; - private $varname; + private $position; + private $varname; - public function stream_open($path, $mode, $options, &$opened_path) - { - $url = parse_url($path); - $this->varname = $url["host"]; - $this->position = 0; + public function stream_open($path, $mode, $options, &$opened_path) + { + $url = parse_url($path); + $this->varname = $url["host"]; + $this->position = 0; - return true; - } + return true; + } - public function stream_read($count) - { - $p = &$this->position; - $ret = substr($GLOBALS[$this->varname], $p, $count); - $p += strlen($ret); + public function stream_read($count) + { + $p = &$this->position; + $ret = substr($GLOBALS[$this->varname], $p, $count); + $p += strlen($ret); - return $ret; - } + return $ret; + } - public function stream_write($data) - { - $v = &$GLOBALS[$this->varname]; - $l = strlen($data); - $p = &$this->position; - $v = substr($v ?? '', 0, $p) . $data . substr($v ?? '', $p += $l); + public function stream_write($data) + { + $v = &$GLOBALS[$this->varname]; + $l = strlen($data); + $p = &$this->position; + $v = substr($v ?? '', 0, $p) . $data . substr($v ?? '', $p += $l); - return $l; - } + return $l; + } - public function stream_tell() - { - return $this->position; - } + public function stream_tell() + { + return $this->position; + } - public function stream_eof() - { - if (!isset($GLOBALS[$this->varname])) { - return true; - } + public function stream_eof() + { + if (!isset($GLOBALS[$this->varname])) { + return true; + } - return $this->position >= strlen($GLOBALS[$this->varname]); - } + return $this->position >= strlen($GLOBALS[$this->varname]); + } - public function stream_seek($offset, $whence) - { - $l = strlen($GLOBALS[$this->varname]); - $p = &$this->position; - switch ($whence) { - case SEEK_SET: - $newPos = $offset; - break; - case SEEK_CUR: - $newPos = $p + $offset; - break; - case SEEK_END: - $newPos = $l + $offset; - break; - default: - return false; - } - $ret = ($newPos >= 0 && $newPos <= $l); - if ($ret) { - $p = $newPos; - } - return $ret; - } + public function stream_seek($offset, $whence) + { + $l = strlen($GLOBALS[$this->varname]); + $p = &$this->position; + switch ($whence) { + case SEEK_SET: + $newPos = $offset; + break; + case SEEK_CUR: + $newPos = $p + $offset; + break; + case SEEK_END: + $newPos = $l + $offset; + break; + default: + return false; + } + $ret = ($newPos >= 0 && $newPos <= $l); + if ($ret) { + $p = $newPos; + } + return $ret; + } } diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginFunction/PluginFunctionFetchTest.php b/tests/UnitTests/TemplateSource/TagTests/PluginFunction/PluginFunctionFetchTest.php index d9899e3c..5c3aa45e 100644 --- a/tests/UnitTests/TemplateSource/TagTests/PluginFunction/PluginFunctionFetchTest.php +++ b/tests/UnitTests/TemplateSource/TagTests/PluginFunction/PluginFunctionFetchTest.php @@ -1,85 +1,71 @@ setUpSmarty(__DIR__); - } + public function setUp(): void + { + $this->setUpSmarty(__DIR__); + } - public function testInit() - { - $this->cleanDirs(); - } + public function testInit() + { + $this->cleanDirs(); + } + /** + * test {fetch} from local file + */ + public function testFetchFile() + { + $this->assertStringContainsString( + 'ct4hn8nzgm;cgzm;', + $this->smarty->fetch('string:{fetch file="./testfile.txt"}') + ); + } -/** -* test {fetch} from UIR -* -* -* @group slow -*/ - public function testFetchUri() - { - $this->assertStringContainsString('Preface | Smarty', $this->smarty->fetch('string:{fetch file="https://www.smarty.net/docs/en/preface.tpl"}')); - } + /** + * test {fetch} non-existing file + */ + public function testFetchNonExistingFile() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('{fetch} cannot read resource \'./no/such/file\''); + $this->smarty->fetch('string:{fetch file="./no/such/file"}'); + } -/** -* test {fetch} invalid uri -* -* -* -*/ - public function testFetchInvalidUri() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('{fetch} cannot read resource \'https://foo.smarty.net/foo.dat\''); - $this->smarty->fetch('string:{fetch file="https://foo.smarty.net/foo.dat"}'); - } - - /** - * test {fetch file=...} access to file from path not aloo/wed by security settings - * - * @run InSeparateProcess - * - */ - public function testFetchSecurity() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('not trusted file path'); - $this->cleanDirs(); - $dir=$this->smarty->getTemplateDir(); - $this->smarty->enableSecurity(); - $this->smarty->fetch('string:{fetch file=\''. $dir[0]. '../../../../../etc/passwd\'}'); - } - /** - * test {fetch file=...} access to file from path not aloo/wed by security settings - * - * @run InSeparateProcess - * - */ - public function testFetchSecurity2() - { - $this->expectException(\Smarty\Exception::class); - $this->expectExceptionMessage('not trusted file path'); - $this->cleanDirs(); - $this->smarty->getTemplateDir(); - $this->smarty->enableSecurity(); - $this->smarty->setTemplateDir('/templates'); - $this->smarty->fetch('string:{fetch file="/templates/../etc/passwd"}'); - } + /** + * test {fetch file=...} access to file from path not aloo/wed by security settings + * + * @run InSeparateProcess + * + */ + public function testFetchSecurity() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('not trusted file path'); + $this->cleanDirs(); + $dir=$this->smarty->getTemplateDir(); + $this->smarty->enableSecurity(); + $this->smarty->fetch('string:{fetch file=\''. $dir[0]. '../../../../../etc/passwd\'}'); + } + /** + * test {fetch file=...} access to file from path not aloo/wed by security settings + * + * @run InSeparateProcess + * + */ + public function testFetchSecurity2() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessage('not trusted file path'); + $this->cleanDirs(); + $this->smarty->getTemplateDir(); + $this->smarty->enableSecurity(); + $this->smarty->setTemplateDir('/templates'); + $this->smarty->fetch('string:{fetch file="/templates/../etc/passwd"}'); + } } diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginFunction/testfile.txt b/tests/UnitTests/TemplateSource/TagTests/PluginFunction/testfile.txt new file mode 100644 index 00000000..4efd4a71 --- /dev/null +++ b/tests/UnitTests/TemplateSource/TagTests/PluginFunction/testfile.txt @@ -0,0 +1 @@ +ct4hn8nzgm;cgzm; \ No newline at end of file From 77c0b74e3bbbcbe48ed425634150de2f6c1808e2 Mon Sep 17 00:00:00 2001 From: kynx Date: Thu, 11 Apr 2024 19:31:30 +0100 Subject: [PATCH 07/16] Fix docblock types (#992) --- src/Smarty.php | 38 ++++++++++++++++++-------------------- src/TemplateBase.php | 20 ++++++++++---------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/Smarty.php b/src/Smarty.php index 18ff5262..5a9654b6 100644 --- a/src/Smarty.php +++ b/src/Smarty.php @@ -535,8 +535,6 @@ class Smarty extends \Smarty\TemplateBase { /** * Load an additional extension. * - * @param Base $extension - * * @return void */ public function addExtension(ExtensionInterface $extension) { @@ -582,7 +580,7 @@ class Smarty extends \Smarty\TemplateBase { * * @param string|\Smarty\Security $security_class if a string is used, it must be class-name * - * @return Smarty current Smarty instance for chaining + * @return static current Smarty instance for chaining * @throws \Smarty\Exception */ public function enableSecurity($security_class = null) { @@ -593,7 +591,7 @@ class Smarty extends \Smarty\TemplateBase { /** * Disable security * - * @return Smarty current Smarty instance for chaining + * @return static current Smarty instance for chaining */ public function disableSecurity() { $this->security_policy = null; @@ -607,7 +605,7 @@ class Smarty extends \Smarty\TemplateBase { * @param string $key of the array element to assign the template dir to * @param bool $isConfig true for config_dir * - * @return Smarty current Smarty instance for chaining + * @return static current Smarty instance for chaining */ public function addTemplateDir($template_dir, $key = null, $isConfig = false) { if ($isConfig) { @@ -672,7 +670,7 @@ class Smarty extends \Smarty\TemplateBase { * @param string|array $template_dir directory(s) of template sources * @param bool $isConfig true for config_dir * - * @return Smarty current Smarty instance for chaining + * @return static current Smarty instance for chaining */ public function setTemplateDir($template_dir, $isConfig = false) { if ($isConfig) { @@ -692,7 +690,7 @@ class Smarty extends \Smarty\TemplateBase { * @param string|array $config_dir directory(s) of config sources * @param mixed $key key of the array element to assign the config dir to * - * @return Smarty current Smarty instance for chaining + * @return static current Smarty instance for chaining */ public function addConfigDir($config_dir, $key = null) { return $this->addTemplateDir($config_dir, $key, true); @@ -714,7 +712,7 @@ class Smarty extends \Smarty\TemplateBase { * * @param $config_dir * - * @return Smarty current Smarty instance for chaining + * @return static current Smarty instance for chaining */ public function setConfigDir($config_dir) { return $this->setTemplateDir($config_dir, true); @@ -788,7 +786,7 @@ class Smarty extends \Smarty\TemplateBase { * * @param null|array|string $plugins_dir * - * @return Smarty current Smarty instance for chaining + * @return static current Smarty instance for chaining * @deprecated since 5.0 */ public function addPluginsDir($plugins_dir) { @@ -821,7 +819,7 @@ class Smarty extends \Smarty\TemplateBase { * * @param string|array $plugins_dir directory(s) of plugins * - * @return Smarty current Smarty instance for chaining + * @return static current Smarty instance for chaining * @deprecated since 5.0 */ public function setPluginsDir($plugins_dir) { @@ -882,7 +880,7 @@ class Smarty extends \Smarty\TemplateBase { * * @param string $compile_dir directory to store compiled templates in * - * @return Smarty current Smarty instance for chaining + * @return static current Smarty instance for chaining */ public function setCompileDir($compile_dir) { $this->_normalizeDir('compile_dir', $compile_dir); @@ -908,7 +906,7 @@ class Smarty extends \Smarty\TemplateBase { * * @param string $cache_dir directory to store cached templates in * - * @return Smarty current Smarty instance for chaining + * @return static current Smarty instance for chaining */ public function setCacheDir($cache_dir) { $this->_normalizeDir('cache_dir', $cache_dir); @@ -1171,7 +1169,7 @@ class Smarty extends \Smarty\TemplateBase { /** * Get Smarty object * - * @return Smarty + * @return static */ public function getSmarty() { return $this; @@ -1844,7 +1842,7 @@ class Smarty extends \Smarty\TemplateBase { * @param string $type filter type * @param string $name filter name * - * @return TemplateBase + * @return static * @throws \Smarty\Exception * @api Smarty::unloadFilter() * @@ -1890,7 +1888,7 @@ class Smarty extends \Smarty\TemplateBase { * @param string $name name of resource type * @param Base $resource_handler * - * @return Smarty + * @return static * * @api Smarty::registerCacheResource() * @@ -1911,7 +1909,7 @@ class Smarty extends \Smarty\TemplateBase { * * @param $name * - * @return Smarty + * @return static * @api Smarty::unregisterCacheResource() * * @deprecated since 5.0 @@ -1944,7 +1942,7 @@ class Smarty extends \Smarty\TemplateBase { * @param callable $callback * @param string|null $name optional filter name * - * @return TemplateBase + * @return static * @throws \Smarty\Exception * * @api Smarty::registerFilter() @@ -2003,7 +2001,7 @@ class Smarty extends \Smarty\TemplateBase { * @param string $type filter type * @param callback|string $name the name previously used in ::registerFilter * - * @return TemplateBase + * @return static * @throws \Smarty\Exception * @api Smarty::unregisterFilter() * @@ -2040,7 +2038,7 @@ class Smarty extends \Smarty\TemplateBase { * @param array|string $modifiers modifier or list of modifiers * to add * - * @return Smarty + * @return static * @api Smarty::addDefaultModifiers() * */ @@ -2070,7 +2068,7 @@ class Smarty extends \Smarty\TemplateBase { * @param array|string $modifiers modifier or list of modifiers * to set * - * @return TemplateBase + * @return static * @api Smarty::setDefaultModifiers() * */ diff --git a/src/TemplateBase.php b/src/TemplateBase.php index 0b7f212c..3674edf7 100644 --- a/src/TemplateBase.php +++ b/src/TemplateBase.php @@ -73,7 +73,7 @@ abstract class TemplateBase extends Data { * @param bool $format smarty argument format, else traditional * @param array $block_methods list of block-methods * - * @return \Smarty|\Smarty\Template + * @return static * @throws \Smarty\Exception * * @api Smarty::registerObject() @@ -113,7 +113,7 @@ abstract class TemplateBase extends Data { * * @param string $object_name name of object * - * @return TemplateBase + * @return static * @api Smarty::unregisterObject() * */ @@ -251,7 +251,7 @@ abstract class TemplateBase extends Data { * @param array|string $literals literal or list of literals * to addto add * - * @return TemplateBase + * @return static * @throws \Smarty\Exception * @api Smarty::addLiterals() * @@ -269,7 +269,7 @@ abstract class TemplateBase extends Data { * @param array|string $literals literal or list of literals * to setto set * - * @return TemplateBase + * @return static * @throws \Smarty\Exception * @api Smarty::setLiterals() * @@ -312,7 +312,7 @@ abstract class TemplateBase extends Data { * @param string $class_impl the referenced PHP class to * register * - * @return TemplateBase + * @return static * @throws \Smarty\Exception * @api Smarty::registerClass() * @@ -333,7 +333,7 @@ abstract class TemplateBase extends Data { * * @param callable $callback class/method name * - * @return TemplateBase + * @return static * @throws Exception if $callback is not callable * @api Smarty::registerDefaultConfigHandler() * @@ -353,7 +353,7 @@ abstract class TemplateBase extends Data { * * @param callable $callback class/method name * - * @return TemplateBase + * @return static * @throws Exception if $callback is not callable * @api Smarty::registerDefaultTemplateHandler() * @@ -374,7 +374,7 @@ abstract class TemplateBase extends Data { * @param string $name name of resource type * @param \Smarty\Resource\BasePlugin $resource_handler instance of Smarty\Resource\BasePlugin * - * @return \Smarty\Smarty|\Smarty\Template + * @return static * * @api Smarty::registerResource() */ @@ -389,7 +389,7 @@ abstract class TemplateBase extends Data { * * @param string $type name of resource type * - * @return TemplateBase + * @return static * @api Smarty::unregisterResource() * */ @@ -406,7 +406,7 @@ abstract class TemplateBase extends Data { * * @param string $tpl_name * - * @return TemplateBase + * @return static * @throws Exception if file is not readable * @api Smarty::setDebugTemplate() * From 5ee4363000ce32bfa45be5156a665bb6132313b4 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Sat, 13 Apr 2024 16:53:05 +0200 Subject: [PATCH 08/16] Fix change in signature of getTemplateVars (#995) --- changelog/994.md | 1 + src/Data.php | 5 +- .../GetTemplateVars/GetTemplateVarsTest.php | 210 ++++++++++-------- 3 files changed, 117 insertions(+), 99 deletions(-) create mode 100644 changelog/994.md diff --git a/changelog/994.md b/changelog/994.md new file mode 100644 index 00000000..16c58c51 --- /dev/null +++ b/changelog/994.md @@ -0,0 +1 @@ +- Fix that getTemplateVars would return an array of objects instead of the assigned variables values [#994](https://github.com/smarty-php/smarty/issues/994) \ No newline at end of file diff --git a/src/Data.php b/src/Data.php index 64a4770e..f8abe0f6 100644 --- a/src/Data.php +++ b/src/Data.php @@ -224,7 +224,10 @@ class Data return $this->getValue($varName, $searchParents); } - return array_merge($this->parent && $searchParents ? $this->parent->getTemplateVars() : [], $this->tpl_vars); + return array_merge( + $this->parent && $searchParents ? $this->parent->getTemplateVars() : [], + array_map(function(Variable $var) { return $var->getValue(); }, $this->tpl_vars) + ); } /** diff --git a/tests/UnitTests/SmartyMethodsTests/GetTemplateVars/GetTemplateVarsTest.php b/tests/UnitTests/SmartyMethodsTests/GetTemplateVars/GetTemplateVarsTest.php index 4aab7c3b..db60b822 100644 --- a/tests/UnitTests/SmartyMethodsTests/GetTemplateVars/GetTemplateVarsTest.php +++ b/tests/UnitTests/SmartyMethodsTests/GetTemplateVars/GetTemplateVarsTest.php @@ -1,112 +1,126 @@ setUpSmarty(__DIR__); - } + public function setUp(): void + { + $this->setUpSmarty(__DIR__); + } + public function testInit() + { + $this->cleanDirs(); + } + /** + * test root getTemplateVars single value + */ + public function testGetSingleTemplateVarScopeRoot() + { + $this->smarty->assign('foo', 'bar'); + $this->smarty->assign('blar', 'buh'); + $this->assertEquals("bar", $this->smarty->getTemplateVars('foo')); + } - public function testInit() - { - $this->cleanDirs(); - } - /** - * test root getTemplateVars single value - */ - public function testGetSingleTemplateVarScopeRoot() - { - $this->smarty->assign('foo', 'bar'); - $this->smarty->assign('blar', 'buh'); - $this->assertEquals("bar", $this->smarty->getTemplateVars('foo')); - } + /** + * test root getTemplateVars all values + */ + public function testGetAllTemplateVarsScopeRoot() + { + $this->smarty->assign('foo', 'bar'); + $this->smarty->assign('blar', 'buh'); + $vars = $this->smarty->getTemplateVars(); + $this->assertTrue(is_array($vars)); + $this->assertEquals("bar", $vars['foo']); + $this->assertEquals("buh", $vars['blar']); + } - /** - * test root getTemplateVars all values - */ - public function testGetAllTemplateVarsScopeRoot() - { - $this->smarty->assign('foo', 'bar'); - $this->smarty->assign('blar', 'buh'); - $vars = $this->smarty->getTemplateVars(); - $this->assertTrue(is_array($vars)); - $this->assertEquals("bar", $vars['foo']); - $this->assertEquals("buh", $vars['blar']); - } + /** + * test single variable with data object chain + */ + public function testGetSingleTemplateVarScopeAll() + { + $data1 = $this->smarty->createData($this->smarty); + $data2 = $this->smarty->createData($data1); + $this->smarty->assign('foo', 'bar'); + $this->smarty->assign('blar', 'buh'); + $this->assertEquals("bar", $data2->getTemplateVars('foo')); + } - /** - * test single variable with data object chain - */ - public function testGetSingleTemplateVarScopeAll() - { - $data1 = $this->smarty->createData($this->smarty); - $data2 = $this->smarty->createData($data1); - $this->smarty->assign('foo', 'bar'); - $this->smarty->assign('blar', 'buh'); - $this->assertEquals("bar", $data2->getTemplateVars('foo')); - } + /** + * test get all variables with data object chain + */ + public function testGetAllTemplateVarsScopeAll() + { + $data1 = $this->smarty->createData($this->smarty); + $data2 = $this->smarty->createData($data1); + $this->smarty->assign('foo', 'bar'); + $data1->assign('blar', 'buh'); + $data2->assign('foo2', 'bar2'); + $vars = $data2->getTemplateVars(null); + $this->assertTrue(is_array($vars)); + $this->assertEquals("bar", $vars['foo']); + $this->assertEquals("bar2", $vars['foo2']); + $this->assertEquals("buh", $vars['blar']); + } - /** - * test get all variables with data object chain - */ - public function testGetAllTemplateVarsScopeAll() - { - $data1 = $this->smarty->createData($this->smarty); - $data2 = $this->smarty->createData($data1); - $this->smarty->assign('foo', 'bar'); - $data1->assign('blar', 'buh'); - $data2->assign('foo2', 'bar2'); - $vars = $data2->getTemplateVars(null); - $this->assertTrue(is_array($vars)); - $this->assertEquals("bar", $vars['foo']); - $this->assertEquals("bar2", $vars['foo2']); - $this->assertEquals("buh", $vars['blar']); - } + /** + * test get all variables with data object chain search parents disabled + */ + public function testGetAllTemplateVarsScopeAllNoParents() + { + $data1 = $this->smarty->createData($this->smarty); + $data2 = $this->smarty->createData($data1); + $this->smarty->assign('foo', 'bar'); + $data1->assign('blar', 'buh'); + $data2->assign('foo2', 'bar2'); + $vars = $data2->getTemplateVars(null, false); + $this->assertTrue(is_array($vars)); + $this->assertFalse(isset($vars['foo'])); + $this->assertEquals("bar2", $vars['foo2']); + $this->assertFalse(isset($vars['blar'])); + } - /** - * test get all variables with data object chain search parents disabled - */ - public function testGetAllTemplateVarsScopeAllNoParents() - { - $data1 = $this->smarty->createData($this->smarty); - $data2 = $this->smarty->createData($data1); - $this->smarty->assign('foo', 'bar'); - $data1->assign('blar', 'buh'); - $data2->assign('foo2', 'bar2'); - $vars = $data2->getTemplateVars(null, false); - $this->assertTrue(is_array($vars)); - $this->assertFalse(isset($vars['foo'])); - $this->assertEquals("bar2", $vars['foo2']); - $this->assertFalse(isset($vars['blar'])); - } + /** + * test get single variables with data object chain search parents disabled + */ + public function testGetSingleTemplateVarsScopeAllNoParents() + { + error_reporting(error_reporting() & ~(E_NOTICE | E_USER_NOTICE)); + $data1 = $this->smarty->createData($this->smarty); + $data2 = $this->smarty->createData($data1); + $this->smarty->assign('foo', 'bar'); + $data1->assign('blar', 'buh'); + $data2->assign('foo2', 'bar2'); + $this->assertEquals("", $data2->getTemplateVars('foo', false)); + $this->assertEquals("bar2", $data2->getTemplateVars('foo2', false)); + $this->assertEquals("", $data2->getTemplateVars('blar', false)); + } + + /** + * test that variable assigned by global assign in template is included in getTemplateVars + */ + public function testAssignedInTemplate() + { + $this->smarty->fetch('string:{assign var="b" value="x" scope="global"}'); + $this->assertEquals('x', $this->smarty->getTemplateVars('b')); + } + + /** + * test that getTemplateVars returns simple array of values + */ + public function testSimpleCallReturnsArrayWithAllValues() + { + $this->smarty->assign('foo', 'bar'); + $this->smarty->assign('i', 3); + + $vars = $this->smarty->getTemplateVars(); + + $this->assertArrayHasKey('foo', $vars); + $this->assertArrayHasKey('i', $vars); + $this->assertEquals('bar', $vars['foo']); + $this->assertEquals(3,$vars['i']); + } - /** - * test get single variables with data object chain search parents disabled - */ - public function testGetSingleTemplateVarsScopeAllNoParents() - { - error_reporting(error_reporting() & ~(E_NOTICE | E_USER_NOTICE)); - $data1 = $this->smarty->createData($this->smarty); - $data2 = $this->smarty->createData($data1); - $this->smarty->assign('foo', 'bar'); - $data1->assign('blar', 'buh'); - $data2->assign('foo2', 'bar2'); - $this->assertEquals("", $data2->getTemplateVars('foo', false)); - $this->assertEquals("bar2", $data2->getTemplateVars('foo2', false)); - $this->assertEquals("", $data2->getTemplateVars('blar', false)); - } } From 9a8702d9372b7e68b41303cd2182b7c30a688ec7 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Fri, 19 Apr 2024 10:42:54 +0200 Subject: [PATCH 09/16] Corrected invalid classnames in Runtime code for foreach (#1001) Fixes #1000 --- changelog/1000.md | 1 + src/Runtime/ForeachRuntime.php | 18 ++++++++---------- 2 files changed, 9 insertions(+), 10 deletions(-) create mode 100644 changelog/1000.md diff --git a/changelog/1000.md b/changelog/1000.md new file mode 100644 index 00000000..5aa31f8c --- /dev/null +++ b/changelog/1000.md @@ -0,0 +1 @@ +- Fix invalid classnames in Runtime code for foreach [#1000](https://github.com/smarty-php/smarty/issues/1000) \ No newline at end of file diff --git a/src/Runtime/ForeachRuntime.php b/src/Runtime/ForeachRuntime.php index fc311df0..06da7d54 100644 --- a/src/Runtime/ForeachRuntime.php +++ b/src/Runtime/ForeachRuntime.php @@ -116,22 +116,20 @@ class ForeachRuntime { * * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0 * for empty elements + * @throws \Exception */ - public function count($value) { - if ($value instanceof IteratorAggregate) { + public function count($value): int + { + if ($value instanceof \IteratorAggregate) { // Note: getIterator() returns a Traversable, not an Iterator // thus rewind() and valid() methods may not be present return iterator_count($value->getIterator()); - } elseif ($value instanceof Iterator) { - return $value instanceof Generator ? 1 : iterator_count($value); - } elseif ($value instanceof Countable) { + } elseif ($value instanceof \Iterator) { + return $value instanceof \Generator ? 1 : iterator_count($value); + } elseif ($value instanceof \Countable) { return count($value); - } elseif ($value instanceof PDOStatement) { - return $value->rowCount(); - } elseif ($value instanceof Traversable) { - return iterator_count($value); } - return count((array)$value); + return count((array) $value); } /** From f411247aa11e2a88455581128c9bb1e8895af890 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Fri, 19 Apr 2024 11:14:07 +0200 Subject: [PATCH 10/16] Prevent notices on null to string conversion in Template::appendCode (#1002) Fixes #996 --- changelog/996.md | 1 + src/Compiler/Template.php | 5 +++-- src/ParseTree/Dq.php | 6 +++--- src/ParseTree/Tag.php | 4 ++-- src/ParseTree/Template.php | 2 +- src/Parser/TemplateParser.php | 2 +- src/Parser/TemplateParser.y | 2 +- 7 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 changelog/996.md diff --git a/changelog/996.md b/changelog/996.md new file mode 100644 index 00000000..3735bcc7 --- /dev/null +++ b/changelog/996.md @@ -0,0 +1 @@ +- Prevent deprecation notices during compilation in PHP8.3 [#996](https://github.com/smarty-php/smarty/issues/996) diff --git a/src/Compiler/Template.php b/src/Compiler/Template.php index 23984151..b775abba 100644 --- a/src/Compiler/Template.php +++ b/src/Compiler/Template.php @@ -680,7 +680,8 @@ class Template extends BaseCompiler { * * @return string */ - public function appendCode($left, $right) { + public function appendCode(string $left, string $right): string + { if (preg_match('/\s*\?>\s?$/D', $left) && preg_match('/^<\?php\s+/', $right)) { $left = preg_replace('/\s*\?>\s?$/D', "\n", $left); $left .= preg_replace('/^<\?php\s+/', '', $right); @@ -1056,7 +1057,7 @@ class Template extends BaseCompiler { $prefixArray = array_merge($this->prefix_code, array_pop($this->prefixCodeStack)); $this->prefixCodeStack[] = []; foreach ($prefixArray as $c) { - $code = $this->appendCode($code, $c); + $code = $this->appendCode($code, (string) $c); } $this->prefix_code = []; return $code; diff --git a/src/ParseTree/Dq.php b/src/ParseTree/Dq.php index 27c3db9f..b5fca3b4 100644 --- a/src/ParseTree/Dq.php +++ b/src/ParseTree/Dq.php @@ -47,18 +47,18 @@ class Dq extends Base if ($subtree instanceof Code) { $this->subtrees[ $last_subtree ]->data = $parser->compiler->appendCode( - $this->subtrees[ $last_subtree ]->data, + (string) $this->subtrees[ $last_subtree ]->data, 'data . ';?>' ); } elseif ($subtree instanceof DqContent) { $this->subtrees[ $last_subtree ]->data = $parser->compiler->appendCode( - $this->subtrees[ $last_subtree ]->data, + (string) $this->subtrees[ $last_subtree ]->data, 'data . '";?>' ); } else { $this->subtrees[ $last_subtree ]->data = - $parser->compiler->appendCode($this->subtrees[ $last_subtree ]->data, $subtree->data); + $parser->compiler->appendCode((string) $this->subtrees[ $last_subtree ]->data, (string) $subtree->data); } } else { $this->subtrees[] = $subtree; diff --git a/src/ParseTree/Tag.php b/src/ParseTree/Tag.php index f4bdee25..05237f2d 100644 --- a/src/ParseTree/Tag.php +++ b/src/ParseTree/Tag.php @@ -62,9 +62,9 @@ class Tag extends Base public function assign_to_var(\Smarty\Parser\TemplateParser $parser) { $var = $parser->compiler->getNewPrefixVariable(); - $tmp = $parser->compiler->appendCode('', $this->data); + $tmp = $parser->compiler->appendCode('', (string) $this->data); $tmp = $parser->compiler->appendCode($tmp, ""); - $parser->compiler->appendPrefixCode((string) $tmp); + $parser->compiler->appendPrefixCode($tmp); return $var; } } diff --git a/src/ParseTree/Template.php b/src/ParseTree/Template.php index 47096392..ce802a0f 100644 --- a/src/ParseTree/Template.php +++ b/src/ParseTree/Template.php @@ -114,7 +114,7 @@ class Template extends Base break; case 'tag': foreach ($chunk['subtrees'] as $subtree) { - $text = $parser->compiler->appendCode($text, $subtree->to_smarty_php($parser)); + $text = $parser->compiler->appendCode($text, (string) $subtree->to_smarty_php($parser)); } $code .= $text; break; diff --git a/src/Parser/TemplateParser.php b/src/Parser/TemplateParser.php index 12d9b6c5..1e087c55 100644 --- a/src/Parser/TemplateParser.php +++ b/src/Parser/TemplateParser.php @@ -2536,7 +2536,7 @@ public static $yy_action = array( // line 806 "src/Parser/TemplateParser.y" public function yy_r101(){ $prefixVar = $this->compiler->getNewPrefixVariable(); - $tmp = $this->compiler->appendCode('', $this->yystack[$this->yyidx + 0]->minor); + $tmp = $this->compiler->appendCode('', (string) $this->yystack[$this->yyidx + 0]->minor); $this->compiler->appendPrefixCode($this->compiler->appendCode($tmp, "")); $this->_retvalue = $prefixVar; } diff --git a/src/Parser/TemplateParser.y b/src/Parser/TemplateParser.y index d01a42af..f1e3c35e 100644 --- a/src/Parser/TemplateParser.y +++ b/src/Parser/TemplateParser.y @@ -805,7 +805,7 @@ value(res) ::= varindexed(vi) DOUBLECOLON static_class_access(r). { // Smarty tag value(res) ::= smartytag(st). { $prefixVar = $this->compiler->getNewPrefixVariable(); - $tmp = $this->compiler->appendCode('', st); + $tmp = $this->compiler->appendCode('', (string) st); $this->compiler->appendPrefixCode($this->compiler->appendCode($tmp, "")); res = $prefixVar; } From 47c4864dd11f60038689763c0dfe8f706c0cbf42 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Tue, 23 Apr 2024 00:22:13 +0200 Subject: [PATCH 11/16] version bump --- CHANGELOG.md | 11 +++++++++++ changelog/1000.md | 1 - changelog/918.md | 1 - changelog/933.md | 1 - changelog/937.md | 2 -- changelog/972.md | 1 - changelog/994.md | 1 - changelog/996.md | 1 - src/Smarty.php | 2 +- 9 files changed, 12 insertions(+), 9 deletions(-) delete mode 100644 changelog/1000.md delete mode 100644 changelog/918.md delete mode 100644 changelog/933.md delete mode 100644 changelog/937.md delete mode 100644 changelog/972.md delete mode 100644 changelog/994.md delete mode 100644 changelog/996.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 274c3b74..e679aeb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [5.1.0] - 2024-04-22 +- Prevent deprecation notices during compilation in PHP8.3 [#996](https://github.com/smarty-php/smarty/issues/996) +- Fix that getTemplateVars would return an array of objects instead of the assigned variables values [#994](https://github.com/smarty-php/smarty/issues/994) +- Fix Smarty::assign() not returning $this when called with an array as first parameter [#972](https://github.com/smarty-php/smarty/pull/972) +- Documented support for `{if $element is in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937) +- Added support for `{if $element is not in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937) +- Using stream variables in templates now throws a deprecation notice [#933](https://github.com/smarty-php/smarty/pull/933) +- Internal compiler classes always return a string (the internal has_code flag has been removed for simplicity) [#918](https://github.com/smarty-php/smarty/pull/918) +- Fix invalid classnames in Runtime code for foreach [#1000](https://github.com/smarty-php/smarty/issues/1000) + + ## [5.0.1] - 2024-03-27 - Fix error in Smarty\Smarty::compileAllTemplates() by including missing FilesystemIterator class [#966](https://github.com/smarty-php/smarty/issues/966) diff --git a/changelog/1000.md b/changelog/1000.md deleted file mode 100644 index 5aa31f8c..00000000 --- a/changelog/1000.md +++ /dev/null @@ -1 +0,0 @@ -- Fix invalid classnames in Runtime code for foreach [#1000](https://github.com/smarty-php/smarty/issues/1000) \ No newline at end of file diff --git a/changelog/918.md b/changelog/918.md deleted file mode 100644 index 853fdd12..00000000 --- a/changelog/918.md +++ /dev/null @@ -1 +0,0 @@ -- Internal compiler classes always return a string (the internal has_code flag has been removed for simplicity) [#918](https://github.com/smarty-php/smarty/pull/918) diff --git a/changelog/933.md b/changelog/933.md deleted file mode 100644 index 7c6633cf..00000000 --- a/changelog/933.md +++ /dev/null @@ -1 +0,0 @@ -- Using stream variables in templates now throws a deprecation notice [#933](https://github.com/smarty-php/smarty/pull/933) diff --git a/changelog/937.md b/changelog/937.md deleted file mode 100644 index 37f80e99..00000000 --- a/changelog/937.md +++ /dev/null @@ -1,2 +0,0 @@ -- Documented support for `{if $element is in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937) -- Added support for `{if $element is not in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937) \ No newline at end of file diff --git a/changelog/972.md b/changelog/972.md deleted file mode 100644 index e1e930a3..00000000 --- a/changelog/972.md +++ /dev/null @@ -1 +0,0 @@ -- Fix Smarty::assign() not returning $this when called with an array as first parameter [#972](https://github.com/smarty-php/smarty/pull/972) \ No newline at end of file diff --git a/changelog/994.md b/changelog/994.md deleted file mode 100644 index 16c58c51..00000000 --- a/changelog/994.md +++ /dev/null @@ -1 +0,0 @@ -- Fix that getTemplateVars would return an array of objects instead of the assigned variables values [#994](https://github.com/smarty-php/smarty/issues/994) \ No newline at end of file diff --git a/changelog/996.md b/changelog/996.md deleted file mode 100644 index 3735bcc7..00000000 --- a/changelog/996.md +++ /dev/null @@ -1 +0,0 @@ -- Prevent deprecation notices during compilation in PHP8.3 [#996](https://github.com/smarty-php/smarty/issues/996) diff --git a/src/Smarty.php b/src/Smarty.php index 5a9654b6..dbb91726 100644 --- a/src/Smarty.php +++ b/src/Smarty.php @@ -54,7 +54,7 @@ class Smarty extends \Smarty\TemplateBase { /** * smarty version */ - const SMARTY_VERSION = '5.0.1'; + const SMARTY_VERSION = '5.1.0'; /** * define caching modes From 3293a873bdc64bf55e0e53fa5377b3ab8bd9b601 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Mon, 29 Apr 2024 10:01:40 +0200 Subject: [PATCH 12/16] Remove unused attributes from config_load (#1004) fixes #993 --- .../language-function-config-load.md | 1 - src/Compile/Tag/ConfigLoad.php | 8 +++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/designers/language-builtin-functions/language-function-config-load.md b/docs/designers/language-builtin-functions/language-function-config-load.md index e13c3083..1972179d 100644 --- a/docs/designers/language-builtin-functions/language-function-config-load.md +++ b/docs/designers/language-builtin-functions/language-function-config-load.md @@ -9,7 +9,6 @@ |----------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | file | Yes | The name of the config file to include | | section | No | The name of the section to load | -| scope | no | How the scope of the loaded variables are treated, which must be one of local, parent or global. local means variables are loaded into the local template context. parent means variables are loaded into both the local context and the parent template that called it. global means variables are available to all templates. | ## Examples diff --git a/src/Compile/Tag/ConfigLoad.php b/src/Compile/Tag/ConfigLoad.php index d9e67ec9..8b4cf46d 100644 --- a/src/Compile/Tag/ConfigLoad.php +++ b/src/Compile/Tag/ConfigLoad.php @@ -43,7 +43,7 @@ class ConfigLoad extends Base { * @var array * @see BasePlugin */ - protected $optional_attributes = ['section', 'scope']; + protected $optional_attributes = ['section']; /** * Attribute definition: Overwrites base class. @@ -51,7 +51,7 @@ class ConfigLoad extends Base { * @var array * @see BasePlugin */ - protected $option_flags = ['nocache', 'noscope']; + protected $option_flags = []; /** * Compiles code for the {config_load} tag @@ -66,9 +66,7 @@ class ConfigLoad extends Base { { // check and get attributes $_attr = $this->getAttributes($compiler, $args); - if ($_attr['nocache'] === true) { - $compiler->trigger_template_error('nocache option not allowed', null, true); - } + // save possible attributes $conf_file = $_attr['file']; $section = $_attr['section'] ?? 'null'; From 61db287b8fd58b2f0a714f1007bd71059b9e52a9 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Fri, 24 May 2024 00:21:02 +0200 Subject: [PATCH 13/16] Scottchiefbaker/master (#1019) * Add a PSR-4 loading script to allow Smarty to be used without Composer authored-by: Scott Baker --- changelog/1017.md | 1 + docs/getting-started.md | 8 ++++++++ libs/Smarty.class.php | 42 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 changelog/1017.md create mode 100644 libs/Smarty.class.php diff --git a/changelog/1017.md b/changelog/1017.md new file mode 100644 index 00000000..cb9dd555 --- /dev/null +++ b/changelog/1017.md @@ -0,0 +1 @@ +- Added a PSR-4 loading script to allow Smarty to be used without Composer [#1017](https://github.com/smarty-php/smarty/pull/1017) diff --git a/docs/getting-started.md b/docs/getting-started.md index 5b49fffd..3628fd20 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -25,9 +25,17 @@ Here's how you create an instance of Smarty in your PHP scripts: ```php testInstall(); // +///////////////////////////////////////////////////////////////////// + +define('__SMARTY_DIR', __DIR__ . '/../src/'); + +// Global function declarations +require_once(__SMARTY_DIR . "/functions.php"); + +spl_autoload_register(function ($class) { + // Class prefix + $prefix = 'Smarty\\'; + + // Does the class use the namespace prefix? + $len = strlen($prefix); + if (strncmp($prefix, $class, $len) !== 0) { + // If not, move to the next registered autoloader + return; + } + + // Hack off the prefix part + $relative_class = substr($class, $len); + + // Build a path to the include file + $file = __SMARTY_DIR . str_replace('\\', '/', $relative_class) . '.php'; + + // If the file exists, require it + if (file_exists($file)) { + require_once($file); + } +}); From 0be92bc8a6fb83e6e0d883946f7e7c09ba4e857a Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Tue, 28 May 2024 22:44:30 +0200 Subject: [PATCH 14/16] Merge pull request from GHSA-4rmg-292m-wg3w --- changelog/GHSA-4rmg-292m-wg3w.md | 2 + src/Compile/Tag/ExtendsTag.php | 64 +------------------ src/Compiler/Template.php | 38 +++++++---- src/Smarty.php | 9 +++ .../BockExtend/CompileBlockExtendsTest.php | 36 ++++++++++- .../BockExtend/templates/escaping.tpl | 1 + .../BockExtend/templates/escaping2.tpl | 1 + .../BockExtend/templates/escaping3.tpl | 1 + .../TagTests/Include/CompileIncludeTest.php | 12 ++++ .../templates/test_include_security.tpl | 1 + .../_Issues/419/ExtendsIssue419Test.php | 7 ++ 11 files changed, 96 insertions(+), 76 deletions(-) create mode 100644 changelog/GHSA-4rmg-292m-wg3w.md create mode 100644 tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping.tpl create mode 100644 tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping2.tpl create mode 100644 tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping3.tpl create mode 100644 tests/UnitTests/TemplateSource/TagTests/Include/templates/test_include_security.tpl diff --git a/changelog/GHSA-4rmg-292m-wg3w.md b/changelog/GHSA-4rmg-292m-wg3w.md new file mode 100644 index 00000000..c0e28bc1 --- /dev/null +++ b/changelog/GHSA-4rmg-292m-wg3w.md @@ -0,0 +1,2 @@ +- Fixed a code injection vulnerability in extends-tag. This addresses CVE-2024-35226. +- Added `$smarty->setCacheModifiedCheck()` setter for cache_modified_check \ No newline at end of file diff --git a/src/Compile/Tag/ExtendsTag.php b/src/Compile/Tag/ExtendsTag.php index dcdbbc97..0ec2cf2b 100644 --- a/src/Compile/Tag/ExtendsTag.php +++ b/src/Compile/Tag/ExtendsTag.php @@ -32,7 +32,7 @@ class ExtendsTag extends Inheritance { * * @var array */ - protected $optional_attributes = ['extends_resource']; + protected $optional_attributes = []; /** * Attribute definition: Overwrites base class. @@ -64,29 +64,7 @@ class ExtendsTag extends Inheritance { } // add code to initialize inheritance $this->registerInit($compiler, true); - $file = trim($_attr['file'], '\'"'); - if (strlen($file) > 8 && substr($file, 0, 8) === 'extends:') { - // generate code for each template - $files = array_reverse(explode('|', substr($file, 8))); - $i = 0; - foreach ($files as $file) { - if ($file[0] === '"') { - $file = trim($file, '".'); - } else { - $file = "'{$file}'"; - } - $i++; - if ($i === count($files) && isset($_attr['extends_resource'])) { - $this->compileEndChild($compiler); - } - $this->compileInclude($compiler, $file); - } - if (!isset($_attr['extends_resource'])) { - $this->compileEndChild($compiler); - } - } else { - $this->compileEndChild($compiler, $_attr['file']); - } + $this->compileEndChild($compiler, $_attr['file']); return ''; } @@ -106,42 +84,4 @@ class ExtendsTag extends Inheritance { (isset($template) ? ", {$template}, \$_smarty_current_dir" : '') . ");\n?>" ); } - - /** - * Add code for including subtemplate to end of template - * - * @param \Smarty\Compiler\Template $compiler - * @param string $template subtemplate name - * - * @throws \Smarty\CompilerException - * @throws \Smarty\Exception - */ - private function compileInclude(\Smarty\Compiler\Template $compiler, $template) { - $compiler->getParser()->template_postfix[] = new \Smarty\ParseTree\Tag( - $compiler->getParser(), - $compiler->compileTag( - 'include', - [ - $template, - ['scope' => 'parent'], - ] - ) - ); - } - - /** - * Create source code for {extends} from source components array - * - * @param \Smarty\Template $template - * - * @return string - */ - public static function extendsSourceArrayCode(\Smarty\Template $template) { - $resources = []; - foreach ($template->getSource()->components as $source) { - $resources[] = $source->resource; - } - return $template->getLeftDelimiter() . 'extends file=\'extends:' . join('|', $resources) . - '\' extends_resource=true' . $template->getRightDelimiter(); - } } diff --git a/src/Compiler/Template.php b/src/Compiler/Template.php index b775abba..1d4aa244 100644 --- a/src/Compiler/Template.php +++ b/src/Compiler/Template.php @@ -403,21 +403,37 @@ class Template extends BaseCompiler { } // get template source if (!empty($this->template->getSource()->components)) { - // we have array of inheritance templates by extends: resource - // generate corresponding source code sequence - $_content = - ExtendsTag::extendsSourceArrayCode($this->template); + + $_compiled_code = 'getInheritance()->init($_smarty_tpl, true); ?>'; + + $i = 0; + $reversed_components = array_reverse($this->template->getSource()->components); + foreach ($reversed_components as $source) { + $i++; + if ($i === count($reversed_components)) { + $_compiled_code .= 'getInheritance()->endChild($_smarty_tpl); ?>'; + } + $_compiled_code .= $this->compileTag( + 'include', + [ + var_export($source->resource, true), + ['scope' => 'parent'], + ] + ); + } + $_compiled_code = $this->smarty->runPostFilters($_compiled_code, $this->template); } else { // get template source $_content = $this->template->getSource()->getContent(); + $_compiled_code = $this->smarty->runPostFilters( + $this->doCompile( + $this->smarty->runPreFilters($_content, $this->template), + true + ), + $this->template + ); } - $_compiled_code = $this->smarty->runPostFilters( - $this->doCompile( - $this->smarty->runPreFilters($_content, $this->template), - true - ), - $this->template - ); + } catch (\Exception $e) { if ($this->smarty->debugging) { $this->smarty->getDebug()->end_compile($this->template); diff --git a/src/Smarty.php b/src/Smarty.php index dbb91726..9c27d7a8 100644 --- a/src/Smarty.php +++ b/src/Smarty.php @@ -2211,5 +2211,14 @@ class Smarty extends \Smarty\TemplateBase { return $template; } + /** + * Sets if Smarty should check If-Modified-Since headers to determine cache validity. + * @param bool $cache_modified_check + * @return void + */ + public function setCacheModifiedCheck($cache_modified_check): void { + $this->cache_modified_check = (bool) $cache_modified_check; + } + } diff --git a/tests/UnitTests/TemplateSource/TagTests/BockExtend/CompileBlockExtendsTest.php b/tests/UnitTests/TemplateSource/TagTests/BockExtend/CompileBlockExtendsTest.php index 1b0ee50f..6f0a798f 100644 --- a/tests/UnitTests/TemplateSource/TagTests/BockExtend/CompileBlockExtendsTest.php +++ b/tests/UnitTests/TemplateSource/TagTests/BockExtend/CompileBlockExtendsTest.php @@ -1193,8 +1193,38 @@ class CompileBlockExtendsTest extends PHPUnit_Smarty ); } - public function testBlockWithAssign() { - $this->assertEquals('Captured content is: Content with lots of html here', $this->smarty->fetch('038_child.tpl')); - } + public function testBlockWithAssign() { + $this->assertEquals('Captured content is: Content with lots of html here', $this->smarty->fetch('038_child.tpl')); + } + + /** + * Test escaping of file parameter + */ + public function testEscaping() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessageMatches('/Unable to load.*/'); + $this->assertEquals('hello world', $this->smarty->fetch('escaping.tpl')); + } + + /** + * Test escaping of file parameter 2 + */ + public function testEscaping2() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessageMatches('/Unable to load.*/'); + $this->assertEquals('hello world', $this->smarty->fetch('escaping2.tpl')); + } + + /** + * Test escaping of file parameter 3 + */ + public function testEscaping3() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessageMatches('/Unable to load.*/'); + $this->assertEquals('hello world', $this->smarty->fetch('escaping3.tpl')); + } } diff --git a/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping.tpl b/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping.tpl new file mode 100644 index 00000000..79c52e0a --- /dev/null +++ b/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping.tpl @@ -0,0 +1 @@ +{extends "extends:helloworld.tpl', var_dump(shell_exec('ls')), 1, 2, 3);}}?>"} \ No newline at end of file diff --git a/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping2.tpl b/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping2.tpl new file mode 100644 index 00000000..d72a5718 --- /dev/null +++ b/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping2.tpl @@ -0,0 +1 @@ +{extends 'extends:"helloworld.tpl\', var_dump(shell_exec(\'ls\')), 1, 2, 3);}}?>'} \ No newline at end of file diff --git a/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping3.tpl b/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping3.tpl new file mode 100644 index 00000000..96372c82 --- /dev/null +++ b/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping3.tpl @@ -0,0 +1 @@ +{extends file='extends:"helloworld.tpl'|cat:"', var_dump(shell_exec('ls')), 1, 2, 3);}}?>"} \ No newline at end of file diff --git a/tests/UnitTests/TemplateSource/TagTests/Include/CompileIncludeTest.php b/tests/UnitTests/TemplateSource/TagTests/Include/CompileIncludeTest.php index 8a7cb78e..bd6eeaf4 100644 --- a/tests/UnitTests/TemplateSource/TagTests/Include/CompileIncludeTest.php +++ b/tests/UnitTests/TemplateSource/TagTests/Include/CompileIncludeTest.php @@ -82,6 +82,18 @@ class CompileIncludeTest extends PHPUnit_Smarty $this->assertEquals('I1I2I3', $content, $text); } + /** + * test template name escaping + */ + public function testIncludeFilenameEscaping() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessageMatches('/Unable to load.*/'); + $tpl = $this->smarty->createTemplate('test_include_security.tpl'); + $content = $this->smarty->fetch($tpl); + $this->assertEquals("hello world", $content); + } + /** * test standard output * diff --git a/tests/UnitTests/TemplateSource/TagTests/Include/templates/test_include_security.tpl b/tests/UnitTests/TemplateSource/TagTests/Include/templates/test_include_security.tpl new file mode 100644 index 00000000..47d83bc1 --- /dev/null +++ b/tests/UnitTests/TemplateSource/TagTests/Include/templates/test_include_security.tpl @@ -0,0 +1 @@ +{include file="helloworld.tpl', var_dump(shell_exec('ls')), 1, 2, 3);}}?>"} diff --git a/tests/UnitTests/TemplateSource/_Issues/419/ExtendsIssue419Test.php b/tests/UnitTests/TemplateSource/_Issues/419/ExtendsIssue419Test.php index 2079fc0a..9f6d8164 100644 --- a/tests/UnitTests/TemplateSource/_Issues/419/ExtendsIssue419Test.php +++ b/tests/UnitTests/TemplateSource/_Issues/419/ExtendsIssue419Test.php @@ -32,4 +32,11 @@ class ExtendsIssue419Test extends PHPUnit_Smarty $this->assertEquals('child', $this->smarty->fetch('extends:001_parent.tpl|001_child.tpl')); } + public function testextendsSecurity() + { + $this->expectException(\Smarty\Exception::class); + $this->expectExceptionMessageMatches('/Unable to load.*/'); + $this->assertEquals('child', $this->smarty->fetch('string:{include "001_parent.tpl\', var_dump(shell_exec(\'ls\')), 1, 2, 3);}}?>"}')); + } + } From 06d6a5efd936221e5220805c9d07fba72254be80 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Tue, 28 May 2024 23:45:14 +0200 Subject: [PATCH 15/16] version bump --- CHANGELOG.md | 6 ++++++ changelog/1017.md | 1 - changelog/GHSA-4rmg-292m-wg3w.md | 2 -- src/Smarty.php | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) delete mode 100644 changelog/1017.md delete mode 100644 changelog/GHSA-4rmg-292m-wg3w.md diff --git a/CHANGELOG.md b/CHANGELOG.md index e679aeb7..f359cec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [5.2.0] - 2024-05-28 +- Fixed a code injection vulnerability in extends-tag. This addresses CVE-2024-35226. +- Added `$smarty->setCacheModifiedCheck()` setter for cache_modified_check +- Added a PSR-4 loading script to allow Smarty to be used without Composer [#1017](https://github.com/smarty-php/smarty/pull/1017) + + ## [5.1.0] - 2024-04-22 - Prevent deprecation notices during compilation in PHP8.3 [#996](https://github.com/smarty-php/smarty/issues/996) - Fix that getTemplateVars would return an array of objects instead of the assigned variables values [#994](https://github.com/smarty-php/smarty/issues/994) diff --git a/changelog/1017.md b/changelog/1017.md deleted file mode 100644 index cb9dd555..00000000 --- a/changelog/1017.md +++ /dev/null @@ -1 +0,0 @@ -- Added a PSR-4 loading script to allow Smarty to be used without Composer [#1017](https://github.com/smarty-php/smarty/pull/1017) diff --git a/changelog/GHSA-4rmg-292m-wg3w.md b/changelog/GHSA-4rmg-292m-wg3w.md deleted file mode 100644 index c0e28bc1..00000000 --- a/changelog/GHSA-4rmg-292m-wg3w.md +++ /dev/null @@ -1,2 +0,0 @@ -- Fixed a code injection vulnerability in extends-tag. This addresses CVE-2024-35226. -- Added `$smarty->setCacheModifiedCheck()` setter for cache_modified_check \ No newline at end of file diff --git a/src/Smarty.php b/src/Smarty.php index 9c27d7a8..5af9c9b3 100644 --- a/src/Smarty.php +++ b/src/Smarty.php @@ -54,7 +54,7 @@ class Smarty extends \Smarty\TemplateBase { /** * smarty version */ - const SMARTY_VERSION = '5.1.0'; + const SMARTY_VERSION = '5.2.0'; /** * define caching modes From 2a87c65994811a1eb26a59f58ecbf663445e8739 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Wed, 29 May 2024 15:32:47 +0200 Subject: [PATCH 16/16] implemented and documented prependTemplateDir. (#1025) --- changelog/1022.md | 1 + docs/api/configuring.md | 23 +++++++++++-------- src/Smarty.php | 15 ++++++++++++ .../FileIndexed/FileResourceIndexedTest.php | 9 ++++++++ 4 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 changelog/1022.md diff --git a/changelog/1022.md b/changelog/1022.md new file mode 100644 index 00000000..5833ce02 --- /dev/null +++ b/changelog/1022.md @@ -0,0 +1 @@ +- Added `$smarty->prependTemplateDir()` method [#1022](https://github.com/smarty-php/smarty/issues/1022) \ No newline at end of file diff --git a/docs/api/configuring.md b/docs/api/configuring.md index 4c1c91fa..ee2ebf7e 100644 --- a/docs/api/configuring.md +++ b/docs/api/configuring.md @@ -12,24 +12,27 @@ Use `getTemplateDir()` to retrieve the configured paths. setTemplateDir('./config'); +$smarty->setTemplateDir('./templates'); -// set multiple directories where config files are stored -$smarty->setTemplateDir(['./config', './config_2', './config_3']); +// set multiple directories where templates are stored +$smarty->setTemplateDir(['./templates', './templates_2', './templates_3']); -// add directory where config files are stored to the current list of dirs -$smarty->addTemplateDir('./config_1'); +// add directory where templates files are stored to the current list of dirs +$smarty->addTemplateDir('./templates_1'); // add multiple directories to the current list of dirs $smarty->addTemplateDir([ - './config_2', - './config_3', + './templates_2', + './templates_3', ]); // chaining of method calls -$smarty->setTemplateDir('./config') - ->addTemplateDir('./config_1') - ->addTemplateDir('./config_2'); +$smarty->setTemplateDir('./templates') + ->addTemplateDir('./templates_1') + ->addTemplateDir('./templates_2'); + +// insert a template dir before exising template dirs +$smarty->prependTemplateDir('./more_important_templates') // get all directories where config files are stored $template_dirs = $smarty->getTemplateDir(); diff --git a/src/Smarty.php b/src/Smarty.php index 5af9c9b3..4f1bf425 100644 --- a/src/Smarty.php +++ b/src/Smarty.php @@ -684,6 +684,21 @@ class Smarty extends \Smarty\TemplateBase { return $this; } + /** + * Adds a template directory before any existing directoires + * + * @param string $new_template_dir directory of template sources + * @param bool $is_config true for config_dir + * + * @return static current Smarty instance for chaining + */ + public function prependTemplateDir($new_template_dir, $is_config = false) { + $current_template_dirs = $is_config ? $this->config_dir : $this->template_dir; + array_unshift($current_template_dirs, $new_template_dir); + $this->setTemplateDir($current_template_dirs, $is_config); + return $this; + } + /** * Add config directory(s) * diff --git a/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php b/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php index 9065c10d..4bba6a27 100644 --- a/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php +++ b/tests/UnitTests/ResourceTests/FileIndexed/FileResourceIndexedTest.php @@ -91,4 +91,13 @@ class FileResourceIndexedTest extends PHPUnit_Smarty $this->assertNotEquals($tpl->getCached()->filepath, $tpl2->getCached()->filepath); } + + public function testPrependTemplatePath() + { + $this->smarty->setTemplateDir(__DIR__ . '/templates'); + $this->smarty->prependTemplateDir(__DIR__ . '/templates_4'); + $tpl = $this->smarty->createTemplate('dirname.tpl'); + $this->assertEquals('templates_4', $this->smarty->fetch($tpl)); + } + }