From d0d1698963ddd111d8d75eea10c2cb74da48808f Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Tue, 25 Apr 2023 22:15:55 +0200 Subject: [PATCH] Using PHP functions in expressions now also triggers a deprecation notice because we will drop support for this in the next major release Fixes #813 --- CHANGELOG.md | 3 ++ ...arty_internal_compile_private_modifier.php | 2 +- .../smarty_internal_templatecompilerbase.php | 12 +++++- libs/sysplugins/smarty_security.php | 2 +- .../UnitTests/SecurityTests/SecurityTest.php | 4 +- .../PHPfunctions/PhpFunctionTest.php | 37 ++++++++++++++++++- 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 899cfd7e..0c0d1f04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed +- Using PHP functions in expressions now also 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) + ## [4.3.1] - 2023-03-28 ### Security diff --git a/libs/sysplugins/smarty_internal_compile_private_modifier.php b/libs/sysplugins/smarty_internal_compile_private_modifier.php index aea082f0..1e7cd42d 100644 --- a/libs/sysplugins/smarty_internal_compile_private_modifier.php +++ b/libs/sysplugins/smarty_internal_compile_private_modifier.php @@ -109,7 +109,7 @@ class Smarty_Internal_Compile_Private_Modifier extends Smarty_Internal_CompileBa if (!is_object($compiler->smarty->security_policy) || $compiler->smarty->security_policy->isTrustedPhpModifier($modifier, $compiler) ) { - trigger_error('Using php-function "' . $modifier . '" as a modifier is deprecated and will be ' . + trigger_error('Using unregistered function "' . $modifier . '" in a template 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})"; diff --git a/libs/sysplugins/smarty_internal_templatecompilerbase.php b/libs/sysplugins/smarty_internal_templatecompilerbase.php index d5c18d31..10caf590 100644 --- a/libs/sysplugins/smarty_internal_templatecompilerbase.php +++ b/libs/sysplugins/smarty_internal_templatecompilerbase.php @@ -640,7 +640,17 @@ abstract class Smarty_Internal_TemplateCompilerBase return $func_name . '(' . $parameter[ 0 ] . ')'; } } else { - return $name . '(' . implode(',', $parameter) . ')'; + $first_param = array_shift($parameter); + $modifier = array_merge(array($name), $parameter); + // Now, compile the function call as a modifier + return $this->compileTag( + 'private_modifier', + array(), + array( + 'modifierlist' => array($modifier), + 'value' => $first_param + ) + ); } } else { $this->trigger_template_error("unknown function '{$name}'"); diff --git a/libs/sysplugins/smarty_security.php b/libs/sysplugins/smarty_security.php index 97cd0521..49ae2a38 100644 --- a/libs/sysplugins/smarty_security.php +++ b/libs/sysplugins/smarty_security.php @@ -253,7 +253,7 @@ class Smarty_Security * * @param string $function_name * @param object $compiler compiler object - * + * @deprecated * @return boolean true if function is trusted */ public function isTrustedPhpFunction($function_name, $compiler) diff --git a/tests/UnitTests/SecurityTests/SecurityTest.php b/tests/UnitTests/SecurityTests/SecurityTest.php index 7631a0a6..c3398f95 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]}{sizeof($foo)}')); + $this->assertEquals("5", $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{count($foo)}')); } /** @@ -75,7 +75,7 @@ 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]}{sizeof($foo)}')); + $this->assertEquals("5", $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{count($foo)}')); } /** diff --git a/tests/UnitTests/TemplateSource/ValueTests/PHPfunctions/PhpFunctionTest.php b/tests/UnitTests/TemplateSource/ValueTests/PHPfunctions/PhpFunctionTest.php index cf8970c5..24b2a62e 100644 --- a/tests/UnitTests/TemplateSource/ValueTests/PHPfunctions/PhpFunctionTest.php +++ b/tests/UnitTests/TemplateSource/ValueTests/PHPfunctions/PhpFunctionTest.php @@ -57,6 +57,7 @@ class PhpFunctionTest extends PHPUnit_Smarty public function testEmpty2() { $this->smarty->disableSecurity(); + $this->smarty->registerPlugin('modifier', 'pass', 'pass'); $this->smarty->assign('var', array(null, false, (int) 0, @@ -78,6 +79,7 @@ class PhpFunctionTest extends PHPUnit_Smarty public function testEmpty3() { $this->smarty->disableSecurity(); + $this->smarty->registerPlugin('modifier', 'pass', 'pass'); $this->smarty->assign('var', array(true, (int) 1, (float) 0.1, @@ -114,6 +116,7 @@ class PhpFunctionTest extends PHPUnit_Smarty public function testIsset1() { $this->smarty->disableSecurity(); + $this->smarty->registerPlugin('modifier', 'pass', 'pass'); $this->smarty->assign('isNull', null); $this->smarty->assign('isSet', 1); $this->smarty->assign('arr', array('isNull' => null, 'isSet' => 1)); @@ -155,7 +158,7 @@ class PhpFunctionTest extends PHPUnit_Smarty public function testIsset3($strTemplate, $result) { $this->smarty->disableSecurity(); - + $this->smarty->registerPlugin('modifier', 'intval', 'intval'); $this->smarty->assign('varobject', new TestIsset()); $this->smarty->assign('vararray', $vararray = array( 'keythatexists' => false, @@ -196,6 +199,38 @@ class PhpFunctionTest extends PHPUnit_Smarty array('{if isset($_varsimple{$key})}true{else}false{/if}', 'true'), ); } + + /** + * Tests various PHP functions (deprecated) + * @dataProvider dataVariousPHPFunctions + */ + public function testVariousPHPFunctions($strTemplate, $value, $expected) { + $this->smarty->disableSecurity(); + $this->cleanDirs(); + $this->smarty->assign('value', $value); + $this->assertEquals($expected, $this->smarty->fetch('string:' . $strTemplate)); + } + + /** + * Data provider for testIsset3 + */ + public function dataVariousPHPFunctions() + { + return array( + array('{$a = count($value)}{$a}', array(1,2,3), '3'), + array('{$a = in_array("b", $value)}{$a}', array(1,'b',3), true), + array('{$a = strlen(uniqid())}{$a}', '', 13), + array('{$a = date("Y", $value)}{$a}', strtotime("01-01-2030"), 2030), + array('{$a = PhpFunctionTest::sayHi($value)}{$a}', 'mario', 'hi mario'), + array('{$a = pass($value)}{$a}', 'mario', 'mario'), + ); + } + + public static function sayHi($value) { + return 'hi ' . $value; + } + + } /**