diff --git a/.gitignore b/.gitignore index 4de2ae04..d0d6b422 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,5 @@ phpunit* .phpunit.result.cache -/vendor/* -/composer.lock +vendor/* +composer.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index ed6193d5..ddbae7a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed `$smarty->_current_file` - Removed `$smarty->allow_ambiguous_resources` (ambiguous resources handlers should still work) +### Fixed +- `|strip_tags` does not work if the input is 0 [#890](https://github.com/smarty-php/smarty/issues/890) + +## [4.3.2] - 2023-07-19 + +### Fixed +- `$smarty->muteUndefinedOrNullWarnings()` now also mutes PHP8 warnings for undefined properties + +## [4.3.1] - 2023-03-28 + +### Security +- Fixed Cross site scripting vulnerability in Javascript escaping. This addresses CVE-2023-28447. + ### Fixed - `$smarty->muteUndefinedOrNullWarnings()` now also mutes PHP7 notices for undefined array indexes [#736](https://github.com/smarty-php/smarty/issues/736) - `$smarty->muteUndefinedOrNullWarnings()` now treats undefined vars and array access of a null or false variables diff --git a/SECURITY.md b/SECURITY.md index ae9d5dc8..80b5ef5c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,15 +5,16 @@ Smarty currently supports the latest minor version of Smarty 3 and Smarty 4. | Version | Supported | -| ------- | ------------------ | -| 4.0.x | :white_check_mark: | +|---------|--------------------| +| 4.3.x | :white_check_mark: | | 3.1.x | :white_check_mark: | | < 3.1 | :x: | ## Reporting a Vulnerability - If you have discovered a security issue with Smarty, please contact us at mail [at] simonwisselink.nl. Do not - disclose your findings publicly and PLEASE PLEASE do not file an Issue. +If you have discovered a security issue with Smarty, please contact us at mail [at] simonwisselink.nl. Do not +disclose your findings publicly and **PLEASE** do not file an Issue (because that would disclose your findings +publicly.) We will try to confirm the vulnerability and develop a fix if appropriate. When we release the fix, we will publish a security release. Please let us know if you want to be credited. diff --git a/docs/designers/language-builtin-functions/language-function-capture.md b/docs/designers/language-builtin-functions/language-function-capture.md index 4f7a6021..83f4d02d 100644 --- a/docs/designers/language-builtin-functions/language-function-capture.md +++ b/docs/designers/language-builtin-functions/language-function-capture.md @@ -28,6 +28,8 @@ is the value passed in the `name` attribute. If you do not supply the | nocache | Disables caching of this captured block | +## Examples + ```smarty {* we don't want to print a div tag unless content is displayed *} {capture name="banner"} diff --git a/src/Debug.php b/src/Debug.php index 946a0cde..d313a7a5 100644 --- a/src/Debug.php +++ b/src/Debug.php @@ -220,9 +220,12 @@ class Debug extends Data $_config_vars = $ptr->config_vars; ksort($_config_vars); $debugging = $smarty->debugging; + $templateName = $obj->getSource()->type . ':' . $obj->getSource()->name; + $displayMode = $debugging === 2 || !$full; + $offset = $this->offset * 50; $_template = $debObj->doCreateTemplate($debObj->debug_tpl); if ($obj instanceof \Smarty\Template) { - $_template->assign('template_name', $obj->getSource()->type . ':' . $obj->getSource()->name); + $_template->assign('template_name', $templateName); } elseif ($obj instanceof Smarty || $full) { $_template->assign('template_data', $this->template_data[$this->index]); } else { @@ -231,8 +234,8 @@ class Debug extends Data $_template->assign('assigned_vars', $_assigned_vars); $_template->assign('config_vars', $_config_vars); $_template->assign('execution_time', microtime(true) - $smarty->start_time); - $_template->assign('display_mode', $debugging === 2 || !$full); - $_template->assign('offset', $this->offset * 50); + $_template->assign('targetWindow', $displayMode ? md5("$offset$templateName") : '__Smarty__'); + $_template->assign('offset', $offset); echo $_template->fetch(); if (isset($full)) { $this->index--; diff --git a/src/ErrorHandler.php b/src/ErrorHandler.php index 7cb1f987..16ebbeaa 100644 --- a/src/ErrorHandler.php +++ b/src/ErrorHandler.php @@ -8,6 +8,12 @@ namespace Smarty; */ class ErrorHandler { + /** + * Allows {$foo->propName} where propName is undefined. + * @var bool + */ + public $allowUndefinedProperties = true; + /** * Allows {$foo.bar} where bar is unset and {$foo.bar1.bar2} where either bar1 or bar2 is unset. * @var bool @@ -63,6 +69,13 @@ class ErrorHandler */ public function handleError($errno, $errstr, $errfile, $errline, $errcontext = []) { + if ($this->allowUndefinedProperties && preg_match( + '/^(Undefined property)/', + $errstr + )) { + return; // suppresses this error + } + if ($this->allowUndefinedArrayKeys && preg_match( '/^(Undefined index|Undefined array key|Trying to access array offset on value of type)/', $errstr diff --git a/src/debug.tpl b/src/debug.tpl index 64add864..cd932566 100644 --- a/src/debug.tpl +++ b/src/debug.tpl @@ -166,10 +166,8 @@ {/capture} - diff --git a/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php b/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php index 4d08afcd..192cc531 100644 --- a/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php +++ b/tests/UnitTests/CacheResourceTests/File/CacheResourceFileTest.php @@ -101,7 +101,7 @@ class CacheResourceFileTest extends CacheResourceTestCommon $this->smarty->caching = true; $this->smarty->cache_lifetime = 1000; $this->cleanCacheDir(); - $this->smarty->setUseSubDirs(false); + $this->smarty->setUseSubDirs(true); $tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar'); $this->writeCachedContent($tpl); $tpl2 = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar2', 'blar'); diff --git a/tests/UnitTests/SmartyMethodsTests/CompileCheck/templates_c/.gitignore b/tests/UnitTests/SmartyMethodsTests/CompileCheck/templates_c/.gitignore new file mode 100644 index 00000000..d88cc144 --- /dev/null +++ b/tests/UnitTests/SmartyMethodsTests/CompileCheck/templates_c/.gitignore @@ -0,0 +1,2 @@ +# Ignore anything in here, but keep this directory +* diff --git a/tests/UnitTests/TemplateSource/TagTests/BockExtend/CompileBlockExtendsTest.php b/tests/UnitTests/TemplateSource/TagTests/BockExtend/CompileBlockExtendsTest.php index a10211c3..1b0ee50f 100644 --- a/tests/UnitTests/TemplateSource/TagTests/BockExtend/CompileBlockExtendsTest.php +++ b/tests/UnitTests/TemplateSource/TagTests/BockExtend/CompileBlockExtendsTest.php @@ -1193,4 +1193,8 @@ 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')); + } + } diff --git a/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/038_child.tpl b/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/038_child.tpl new file mode 100644 index 00000000..86132ef2 --- /dev/null +++ b/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/038_child.tpl @@ -0,0 +1,2 @@ +{extends file='038_parent.tpl'} +{block name=content assign=content}Content with lots of html here{/block} \ No newline at end of file diff --git a/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/038_parent.tpl b/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/038_parent.tpl new file mode 100644 index 00000000..f00073af --- /dev/null +++ b/tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/038_parent.tpl @@ -0,0 +1 @@ +{block name=content}{/block}Captured content is: {$content} \ No newline at end of file diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierEscapeTest.php b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierEscapeTest.php index 0b2133a7..5c0c2edf 100644 --- a/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierEscapeTest.php +++ b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierEscapeTest.php @@ -123,4 +123,24 @@ class PluginModifierEscapeTest extends PHPUnit_Smarty $this->assertEquals("sma'rty|»example«.com", $this->smarty->fetch($tpl)); } + public function testTemplateLiteralBackticks() + { + $tpl = $this->smarty->createTemplate('string:{"`Hello, World!`"|escape:"javascript"}'); + $this->assertEquals("\\`Hello, World!\\`", $this->smarty->fetch($tpl)); + } + + public function testTemplateLiteralInterpolation() + { + $tpl = $this->smarty->createTemplate('string:{$vector|escape:"javascript"}'); + $this->smarty->assign('vector', "`Hello, \${name}!`"); + $this->assertEquals("\\`Hello, \\\$\\{name}!\\`", $this->smarty->fetch($tpl)); + } + + public function testTemplateLiteralBackticksAndInterpolation() + { + $this->smarty->assign('vector', '`${alert(`Hello, ${name}!`)}${`\n`}`'); + $tpl = $this->smarty->createTemplate('string:{$vector|escape:"javascript"}'); + $this->assertEquals("\\`\\\$\\{alert(\\`Hello, \\\$\\{name}!\\`)}\\\$\\{\\`\\\\n\\`}\\`", $this->smarty->fetch($tpl)); + } + } diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierStripTagsTest.php b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierStripTagsTest.php new file mode 100644 index 00000000..c0860a27 --- /dev/null +++ b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierStripTagsTest.php @@ -0,0 +1,46 @@ +setUpSmarty(__DIR__); + } + + public function testDefault() { + $tpl = $this->smarty->createTemplate('string:{$x|strip_tags}'); + $tpl->assign('x', 'hi'); + $this->assertEquals(" hi ", $this->smarty->fetch($tpl)); + } + + public function testParam1() { + $tpl = $this->smarty->createTemplate('string:{$x|strip_tags:false}'); + $tpl->assign('x', 'hi'); + $this->assertEquals("hi", $this->smarty->fetch($tpl)); + } + + public function testInputIsFalsy0() { + $tpl = $this->smarty->createTemplate('string:{$x|strip_tags}'); + $tpl->assign('x', 0); + $this->assertEquals("0", $this->smarty->fetch($tpl)); + } + + public function testInputIsFalsy1() { + $tpl = $this->smarty->createTemplate('string:{$x|strip_tags}'); + $tpl->assign('x', ''); + $this->assertEquals("", $this->smarty->fetch($tpl)); + } + +} diff --git a/tests/UnitTests/TemplateSource/ValueTests/Operators/OperatorsTest.php b/tests/UnitTests/TemplateSource/ValueTests/Operators/OperatorsTest.php new file mode 100644 index 00000000..ea88e4bd --- /dev/null +++ b/tests/UnitTests/TemplateSource/ValueTests/Operators/OperatorsTest.php @@ -0,0 +1,23 @@ +setUpSmarty(__DIR__); + } + + public function testInit() + { + $this->cleanDirs(); + } + + /** + * @group issue861 + */ + public function testTernaries() { + $this->assertEquals('2 equals 2', $this->smarty->fetch("string:{(2 === 2) ? '2 equals 2' : '2 ain\'t 2'}")); + $this->assertEquals('3 equals 3', $this->smarty->fetch("string:{(3 == 3) ? '3 equals 3' : '3 ain\'t 3'}")); + $this->assertEquals('4 equals 4', $this->smarty->fetch("string:{(4 !== 4) ? '4 ain\'t 4' : '4 equals 4'}")); + } + +} \ No newline at end of file diff --git a/tests/UnitTests/TemplateSource/ValueTests/Operators/templates_c/.gitignore b/tests/UnitTests/TemplateSource/ValueTests/Operators/templates_c/.gitignore new file mode 100644 index 00000000..d88cc144 --- /dev/null +++ b/tests/UnitTests/TemplateSource/ValueTests/Operators/templates_c/.gitignore @@ -0,0 +1,2 @@ +# Ignore anything in here, but keep this directory +*