diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8a924ca3..80367524 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Include docs and demo in the releases [#799](https://github.com/smarty-php/smarty/issues/799)
+- Using PHP functions as modifiers now triggers a deprecation notice because we will drop support for this in the next major release [#813](https://github.com/smarty-php/smarty/issues/813)
### Fixed
- Output buffer is now cleaned for internal PHP errors as well, not just for Exceptions [#514](https://github.com/smarty-php/smarty/issues/514)
diff --git a/libs/plugins/modifier.count.php b/libs/plugins/modifier.count.php
new file mode 100644
index 00000000..ca35fc11
--- /dev/null
+++ b/libs/plugins/modifier.count.php
@@ -0,0 +1,36 @@
+ Prior to PHP 8.0.0, if the parameter was neither an array nor an object that implements the Countable interface,
+ * > 1 would be returned, unless value was null, in which case 0 would be returned.
+ */
+
+ if ($arrayOrObject instanceof Countable || is_array($arrayOrObject)) {
+ return count($arrayOrObject, (int) $mode);
+ } elseif ($arrayOrObject === null) {
+ return 0;
+ }
+ return 1;
+}
diff --git a/libs/plugins/modifiercompiler.nl2br.php b/libs/plugins/modifiercompiler.nl2br.php
new file mode 100644
index 00000000..308c00e4
--- /dev/null
+++ b/libs/plugins/modifiercompiler.nl2br.php
@@ -0,0 +1,23 @@
+smarty->security_policy)
|| $compiler->smarty->security_policy->isTrustedPhpModifier($modifier, $compiler)
) {
+ trigger_error('Using php-function "' . $modifier . '" as a modifier is deprecated and will be ' .
+ 'removed in a future release. Use Smarty::registerPlugin to explicitly register ' .
+ 'a custom modifier.', E_USER_DEPRECATED);
$output = "{$modifier}({$params})";
}
$compiler->known_modifier_type[ $modifier ] = $type;
diff --git a/libs/sysplugins/smarty_security.php b/libs/sysplugins/smarty_security.php
index 3c29c813..42c2a766 100644
--- a/libs/sysplugins/smarty_security.php
+++ b/libs/sysplugins/smarty_security.php
@@ -105,7 +105,7 @@ class Smarty_Security
*
* @var array
*/
- public $php_modifiers = array('escape', 'count', 'nl2br',);
+ public $php_modifiers = array('escape', 'count', 'sizeof', 'nl2br',);
/**
* This is an array of allowed tags.
@@ -328,7 +328,7 @@ class Smarty_Security
*
* @param string $modifier_name
* @param object $compiler compiler object
- *
+ * @deprecated
* @return boolean true if modifier is trusted
*/
public function isTrustedPhpModifier($modifier_name, $compiler)
diff --git a/tests/UnitTests/SecurityTests/SecurityTest.php b/tests/UnitTests/SecurityTests/SecurityTest.php
index d68ac3d4..60d80d67 100644
--- a/tests/UnitTests/SecurityTests/SecurityTest.php
+++ b/tests/UnitTests/SecurityTests/SecurityTest.php
@@ -52,7 +52,7 @@ class SecurityTest extends PHPUnit_Smarty
*/
public function testTrustedPHPFunction()
{
- $this->assertEquals("5", $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{count($foo)}'));
+ $this->assertEquals("5", $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{sizeof($foo)}'));
}
/**
@@ -63,9 +63,9 @@ class SecurityTest extends PHPUnit_Smarty
public function testNotTrustedPHPFunction()
{
$this->expectException('SmartyException');
- $this->expectExceptionMessage('PHP function \'count\' not allowed by security setting');
+ $this->expectExceptionMessage('PHP function \'sizeof\' not allowed by security setting');
$this->smarty->security_policy->php_functions = array('null');
- $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{count($foo)}');
+ $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{sizeof($foo)}');
}
/**
@@ -75,38 +75,41 @@ class SecurityTest extends PHPUnit_Smarty
{
$this->smarty->security_policy->php_functions = array('null');
$this->smarty->disableSecurity();
- $this->assertEquals("5", $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{count($foo)}'));
+ $this->assertEquals("5", $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{sizeof($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}'));
+ $this->assertEquals("5", @$this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@sizeof}'));
}
/**
* test not trusted modifier
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @deprecated
*/
public function testNotTrustedModifier()
{
$this->expectException('SmartyException');
- $this->expectExceptionMessage('modifier \'count\' not allowed by security setting');
+ $this->expectExceptionMessage('modifier \'sizeof\' not allowed by security setting');
$this->smarty->security_policy->php_modifiers = array('null');
- $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@count}');
+ @$this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@sizeof}');
}
/**
* test not trusted modifier at disabled security
+ * @deprecated
*/
public function testDisabledTrustedModifier()
{
$this->smarty->security_policy->php_modifiers = array('null');
$this->smarty->disableSecurity();
- $this->assertEquals("5", $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@count}'));
+ @$this->assertEquals("5", $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@sizeof}'));
}
/**
diff --git a/tests/UnitTests/SmartyMethodsTests/RegisterBlock/RegisterBlockTest.php b/tests/UnitTests/SmartyMethodsTests/RegisterBlock/RegisterBlockTest.php
index 7d72c73d..b79ce9fa 100644
--- a/tests/UnitTests/SmartyMethodsTests/RegisterBlock/RegisterBlockTest.php
+++ b/tests/UnitTests/SmartyMethodsTests/RegisterBlock/RegisterBlockTest.php
@@ -40,14 +40,14 @@ class RegisterBlockTest extends PHPUnit_Smarty
{
$this->smarty->registerPlugin(Smarty::PLUGIN_BLOCK, 'testblock', 'myblock');
$this->smarty->assign('value', 1);
- $this->assertEquals(strtoupper('function hello world 1 1 function hello world 1 2 function hello world 1 3 '), $this->smarty->fetch('eval:{testblock}hello world {$value}{/testblock|strtoupper}'));
+ $this->assertEquals(strtoupper('function hello world 1 1 function hello world 1 2 function hello world 1 3 '), $this->smarty->fetch('eval:{testblock}hello world {$value}{/testblock|upper}'));
}
public function testRegisterBlockFunctionModifier2()
{
$this->smarty->registerPlugin(Smarty::PLUGIN_BLOCK, 'testblock', 'myblock');
$this->smarty->assign('value', 1);
- $this->assertEquals(strtoupper('function hello world 1 1 function hello world 1 2 function hello world 1 3 '), $this->smarty->fetch('eval:{testblock}hello world {$value}{/testblock|default:""|strtoupper}'));
+ $this->assertEquals(strtoupper('function hello world 1 1 function hello world 1 2 function hello world 1 3 '), $this->smarty->fetch('eval:{testblock}hello world {$value}{/testblock|default:""|upper}'));
}
public function testRegisterBlockFunctionWrapper()
diff --git a/tests/UnitTests/SmartyMethodsTests/RegisterObject/CompileRegisteredObjectFunctionTest.php b/tests/UnitTests/SmartyMethodsTests/RegisterObject/CompileRegisteredObjectFunctionTest.php
index 59bd3cb8..94a8ef55 100644
--- a/tests/UnitTests/SmartyMethodsTests/RegisterObject/CompileRegisteredObjectFunctionTest.php
+++ b/tests/UnitTests/SmartyMethodsTests/RegisterObject/CompileRegisteredObjectFunctionTest.php
@@ -60,13 +60,13 @@ class CompileRegisteredObjectFunctionTest extends PHPUnit_Smarty
public function testRegisteredObjectBlockFunctionModifier1()
{
- $tpl = $this->smarty->createTemplate('eval:{objecttest->myblock}hello world{/objecttest->myblock|strtoupper}');
+ $tpl = $this->smarty->createTemplate('eval:{objecttest->myblock}hello world{/objecttest->myblock|upper}');
$this->assertEquals(strtoupper('block test'), $this->smarty->fetch($tpl));
}
public function testRegisteredObjectBlockFunctionModifier2()
{
- $tpl = $this->smarty->createTemplate('eval:{objecttest->myblock}hello world{/objecttest->myblock|default:""|strtoupper}');
+ $tpl = $this->smarty->createTemplate('eval:{objecttest->myblock}hello world{/objecttest->myblock|default:""|upper}');
$this->assertEquals(strtoupper('block test'), $this->smarty->fetch($tpl));
}
// TODO
diff --git a/tests/UnitTests/TemplateSource/TagTests/Append/CompileAppendTest.php b/tests/UnitTests/TemplateSource/TagTests/Append/CompileAppendTest.php
index 76b11052..9fab4fae 100644
--- a/tests/UnitTests/TemplateSource/TagTests/Append/CompileAppendTest.php
+++ b/tests/UnitTests/TemplateSource/TagTests/Append/CompileAppendTest.php
@@ -21,6 +21,7 @@ class CompileAppendTest extends PHPUnit_Smarty
$this->smarty->addPluginsDir("../../../__shared/PHPunitplugins/");
$this->smarty->addTemplateDir("../../../__shared/templates/");
$this->smarty->addTemplateDir("./templates_tmp");
+ $this->smarty->registerPlugin('modifier', 'var_export', 'var_export');
}
public function testInit()
diff --git a/tests/UnitTests/TemplateSource/TagTests/Assign/CompileAssignTest.php b/tests/UnitTests/TemplateSource/TagTests/Assign/CompileAssignTest.php
index fefdd72d..fb02564f 100644
--- a/tests/UnitTests/TemplateSource/TagTests/Assign/CompileAssignTest.php
+++ b/tests/UnitTests/TemplateSource/TagTests/Assign/CompileAssignTest.php
@@ -21,6 +21,7 @@ class CompileAssignTest extends PHPUnit_Smarty
$this->smarty->addPluginsDir("../../../__shared/PHPunitplugins/");
$this->smarty->addTemplateDir("../../../__shared/templates/");
$this->smarty->addTemplateDir("./templates_tmp");
+ $this->smarty->registerPlugin('modifier', 'var_export', 'var_export');
}
public function testInit()
diff --git a/tests/UnitTests/TemplateSource/TagTests/If/CompileIfTest.php b/tests/UnitTests/TemplateSource/TagTests/If/CompileIfTest.php
index 595ff55c..addd9999 100644
--- a/tests/UnitTests/TemplateSource/TagTests/If/CompileIfTest.php
+++ b/tests/UnitTests/TemplateSource/TagTests/If/CompileIfTest.php
@@ -21,6 +21,7 @@ class CompileIfTest extends PHPUnit_Smarty
$this->smarty->addPluginsDir("../../../__shared/PHPunitplugins/");
$this->smarty->addTemplateDir("../../../__shared/templates/");
$this->smarty->addTemplateDir("./templates_tmp");
+ $this->smarty->registerPlugin('modifier', 'var_export', 'var_export');
}
public function testInit()
diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierCountTest.php b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierCountTest.php
new file mode 100644
index 00000000..c736356e
--- /dev/null
+++ b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierCountTest.php
@@ -0,0 +1,48 @@
+setUpSmarty(dirname(__FILE__));
+ }
+
+ public function testArray()
+ {
+ $tpl = $this->smarty->createTemplate('string:count:{$v|count}');
+ $tpl->assign("v", array(1, 2, 3));
+ $this->assertEquals("count:3", $this->smarty->fetch($tpl));
+ }
+
+ public function testEmptyArray()
+ {
+ $tpl = $this->smarty->createTemplate('string:count:{$v|count}');
+ $tpl->assign("v", array());
+ $this->assertEquals("count:0", $this->smarty->fetch($tpl));
+ }
+
+ public function testNull()
+ {
+ $tpl = $this->smarty->createTemplate('string:count:{$v|count}');
+ $tpl->assign("v", null);
+ $this->assertEquals("count:0", $this->smarty->fetch($tpl));
+ }
+
+ public function testString()
+ {
+ $tpl = $this->smarty->createTemplate('string:count:{$v|count}');
+ $tpl->assign("v", "string");
+ $this->assertEquals("count:1", $this->smarty->fetch($tpl));
+ }
+
+}
diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierExplodeTest.php b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierExplodeTest.php
index b3b9d50e..5cd13dd3 100644
--- a/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierExplodeTest.php
+++ b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierExplodeTest.php
@@ -14,6 +14,7 @@ class PluginModifierExplodeTest extends \PHPUnit_Smarty
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
+ $this->smarty->registerPlugin('modifier', 'json_encode', 'json_encode');
}
/**
diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierNl2brTest.php b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierNl2brTest.php
new file mode 100644
index 00000000..ed263019
--- /dev/null
+++ b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierNl2brTest.php
@@ -0,0 +1,33 @@
+setUpSmarty(dirname(__FILE__));
+ }
+
+ public function testDefault()
+ {
+ $tpl = $this->smarty->createTemplate('string:{$v|nl2br}');
+ $tpl->assign("v", "Line1\nLine2");
+ $this->assertEquals("Line1
\nLine2", $this->smarty->fetch($tpl));
+ }
+
+ public function testNoXHTML()
+ {
+ $tpl = $this->smarty->createTemplate('string:{$v|nl2br:false}');
+ $tpl->assign("v", "Line1\nLine2");
+ $this->assertEquals("Line1
\nLine2", $this->smarty->fetch($tpl));
+ }
+}
diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierStrRepeatTest.php b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierStrRepeatTest.php
new file mode 100644
index 00000000..ef5bcfde
--- /dev/null
+++ b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierStrRepeatTest.php
@@ -0,0 +1,33 @@
+setUpSmarty(dirname(__FILE__));
+ }
+
+ public function testDefault()
+ {
+ $tpl = $this->smarty->createTemplate('string:{$v|str_repeat:2}');
+ $tpl->assign("v", "foo");
+ $this->assertEquals("foofoo", $this->smarty->fetch($tpl));
+ }
+
+ public function testZeroTimes()
+ {
+ $tpl = $this->smarty->createTemplate('string:{$v|str_repeat:0}');
+ $tpl->assign("v", "foo");
+ $this->assertEquals("", $this->smarty->fetch($tpl));
+ }
+}
diff --git a/tests/UnitTests/TemplateSource/ValueTests/Math/MathTest.php b/tests/UnitTests/TemplateSource/ValueTests/Math/MathTest.php
index 3be6ad2e..b29d5beb 100644
--- a/tests/UnitTests/TemplateSource/ValueTests/Math/MathTest.php
+++ b/tests/UnitTests/TemplateSource/ValueTests/Math/MathTest.php
@@ -18,6 +18,7 @@ class MathTest extends PHPUnit_Smarty
public function setUp(): void
{
$this->setUpSmarty(dirname(__FILE__));
+ $this->smarty->registerPlugin('modifier', 'sin', 'sin');
}
public function testInit()
@@ -104,7 +105,7 @@ class MathTest extends PHPUnit_Smarty
{
$this->smarty->disableSecurity();
$expected = "22.00 -- 4.10";
- $tpl = $this->smarty->createTemplate('eval:{$x = 4}{$y = 5.5}{$z = $x * $y}{"%0.2f"|sprintf:$z} -- {$x = 20.5}{$y = 5}{$z = $x / $y}{"%0.2f"|sprintf:$z}');
+ $tpl = $this->smarty->createTemplate('eval:{$x = 4}{$y = 5.5}{$z = $x * $y}{$z|string_format:"%0.2f"} -- {$x = 20.5}{$y = 5}{$z = $x / $y}{$z|string_format:"%0.2f"}');
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}
@@ -120,7 +121,7 @@ class MathTest extends PHPUnit_Smarty
{
$this->smarty->disableSecurity();
$expected = "22.00 -- 4.10";
- $tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{$z = $x * $y}{"%0.2f"|sprintf:$z} -- {$x = "20.5"}{$y = "5"}{$z = $x / $y}{"%0.2f"|sprintf:$z}');
+ $tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{$z = $x * $y}{$z|string_format:"%0.2f"} -- {$x = "20.5"}{$y = "5"}{$z = $x / $y}{$z|string_format:"%0.2f"}');
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}
@@ -132,36 +133,36 @@ class MathTest extends PHPUnit_Smarty
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}
- public function testBackticksIllegal()
- {
- $this->expectException(PHPUnit\Framework\Error\Warning::class);
- $expected = "22.00";
- $tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="`ls` x * y" x=$x y=$y}');
- $this->assertEquals($expected, $this->smarty->fetch($tpl));
- }
+ public function testBackticksIllegal()
+ {
+ $this->expectException(PHPUnit\Framework\Error\Warning::class);
+ $expected = "22.00";
+ $tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="`ls` x * y" x=$x y=$y}');
+ $this->assertEquals($expected, $this->smarty->fetch($tpl));
+ }
- public function testDollarSignsIllegal()
- {
- $this->expectException(PHPUnit\Framework\Error\Warning::class);
- $expected = "22.00";
- $tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="$" x=$x y=$y}');
- $this->assertEquals($expected, $this->smarty->fetch($tpl));
- }
+ public function testDollarSignsIllegal()
+ {
+ $this->expectException(PHPUnit\Framework\Error\Warning::class);
+ $expected = "22.00";
+ $tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="$" x=$x y=$y}');
+ $this->assertEquals($expected, $this->smarty->fetch($tpl));
+ }
- public function testBracketsIllegal()
- {
- $this->expectException(PHPUnit\Framework\Error\Warning::class);
- $expected = "I";
- $tpl = $this->smarty->createTemplate('eval:{$x = "0"}{$y = "1"}{math equation="((y/x).(x))[x]" x=$x y=$y}');
- $this->assertEquals($expected, $this->smarty->fetch($tpl));
- }
+ public function testBracketsIllegal()
+ {
+ $this->expectException(PHPUnit\Framework\Error\Warning::class);
+ $expected = "I";
+ $tpl = $this->smarty->createTemplate('eval:{$x = "0"}{$y = "1"}{math equation="((y/x).(x))[x]" x=$x y=$y}');
+ $this->assertEquals($expected, $this->smarty->fetch($tpl));
+ }
- public function testRand()
- {
- $tpl = $this->smarty->createTemplate('eval:{$x = "0"}{math equation="x * rand()" x=$x}');
- // this assertion may seem silly, but it serves to prove that using rand() without a parameter
- // will not trigger a security error (see https://github.com/smarty-php/smarty/issues/794)
- $this->assertEquals("0", $this->smarty->fetch($tpl));
- }
+ public function testRand()
+ {
+ $tpl = $this->smarty->createTemplate('eval:{$x = "0"}{math equation="x * rand()" x=$x}');
+ // this assertion may seem silly, but it serves to prove that using rand() without a parameter
+ // will not trigger a security error (see https://github.com/smarty-php/smarty/issues/794)
+ $this->assertEquals("0", $this->smarty->fetch($tpl));
+ }
}
diff --git a/tests/UnitTests/TemplateSource/_Issues/327/ModifierIssue327Test.php b/tests/UnitTests/TemplateSource/_Issues/327/ModifierIssue327Test.php
index 8418ea3e..0634907b 100644
--- a/tests/UnitTests/TemplateSource/_Issues/327/ModifierIssue327Test.php
+++ b/tests/UnitTests/TemplateSource/_Issues/327/ModifierIssue327Test.php
@@ -18,6 +18,7 @@ class ModifierIssue327Test extends PHPUnit_Smarty
public function setUp(): void
{
$this->setUpSmarty(dirname(__FILE__));
+ $this->smarty->registerPlugin('modifier', 'substr', 'substr');
}
public function testInit()