Compare commits

..
38 changed files with 261 additions and 167 deletions
+1
View File
@@ -11,3 +11,4 @@ utilies/*.php
phpunit*
vendor/*
composer.lock
/composer.phar
+1 -23
View File
@@ -6,32 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Fixed
- Fixed illegal characters bug in math function security check [#702](https://github.com/smarty-php/smarty/issues/702)
## [3.1.43] - 2022-01-10
### Security
- Prevent evasion of the `static_classes` security policy. This addresses CVE-2021-21408
## [3.1.42] - 2022-01-10
### Security
- Prevent arbitrary PHP code execution through maliciously crafted expression for the math function. This addresses CVE-2021-29454
## [3.1.41] - 2022-01-09
### Security
- Rewrote the mailto function to not use `eval` when encoding with javascript
## [3.1.40] - 2021-10-13
### Changed
- default modifier uses empty instead of @ error suppression modifier when testing a variable https://github.com/smarty-php/smarty/issues/336
- modifier escape now triggers a E_USER_NOTICE when an unsupported escape type is used https://github.com/smarty-php/smarty/pull/649
### Security
- More advanced javascript escaping to handle https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements thanks to m-haritonov
## [3.1.39] - 2021-02-17
### Security
+1 -1
View File
@@ -18,7 +18,7 @@ Smarty can be run with PHP 5.2 to PHP 7.4.
> Read the NEW_FEATURES and INHERITANCE_RELEASE_NOTES file for recent extensions to Smarty 3.1 functionality
Smarty versions 3.1.11 or later are now on GitHub and can be installed with Composer.
Smarty versions 3.1.11 or later are now on github and can be installed with Composer.
The "smarty/smarty" package will start at libs/.... subfolder.
View File
-3
View File
@@ -758,9 +758,6 @@ value(res) ::= doublequoted_with_quotes(s). {
value(res) ::= varindexed(vi) DOUBLECOLON static_class_access(r). {
if ($this->security && $this->security->static_classes !== array()) {
$this->compiler->trigger_template_error('dynamic static class not allowed by security setting');
}
$prefixVar = $this->compiler->getNewPrefixVariable();
if (vi['var'] === '\'smarty\'') {
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ". $this->compiler->compileTag('private_special_variable',array(),vi['smarty_internal_index']).';?>');
+1 -1
View File
@@ -111,7 +111,7 @@ class Smarty extends Smarty_Internal_TemplateBase
/**
* smarty version
*/
const SMARTY_VERSION = '3.1.43';
const SMARTY_VERSION = '3.1.39';
/**
* define variable scopes
*/
+7 -4
View File
@@ -94,19 +94,22 @@ function smarty_function_mailto($params)
);
return;
}
// FIXME: (rodneyrehm) document.write() excues me what? 1998 has passed!
if ($encode === 'javascript') {
$string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
$string = 'document.write(\'<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>\');';
$js_encode = '';
for ($x = 0, $_length = strlen($string); $x < $_length; $x++) {
$js_encode .= '%' . bin2hex($string[ $x ]);
}
return '<script type="text/javascript">document.write(unescape(\'' . $js_encode . '\'))</script>';
return '<script type="text/javascript">eval(unescape(\'' . $js_encode . '\'))</script>';
} elseif ($encode === 'javascript_charcode') {
$string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
for ($x = 0, $_length = strlen($string); $x < $_length; $x++) {
for ($x = 0, $y = strlen($string); $x < $y; $x++) {
$ord[] = ord($string[ $x ]);
}
return '<script type="text/javascript">document.write(String.fromCharCode(' . implode(',', $ord) . '))</script>';
$_ret = "<script type=\"text/javascript\" language=\"javascript\">\n" . "{document.write(String.fromCharCode(" .
implode(',', $ord) . "))" . "}\n" . "</script>\n";
return $_ret;
} elseif ($encode === 'hex') {
preg_match('!^(.*)(\?.*)$!', $address, $match);
if (!empty($match[ 2 ])) {
+1 -31
View File
@@ -28,12 +28,7 @@ function smarty_function_math($params, $template)
'int' => true,
'abs' => true,
'ceil' => true,
'acos' => true,
'acosh' => true,
'cos' => true,
'cosh' => true,
'deg2rad' => true,
'rad2deg' => true,
'exp' => true,
'floor' => true,
'log' => true,
@@ -44,51 +39,27 @@ function smarty_function_math($params, $template)
'pow' => true,
'rand' => true,
'round' => true,
'asin' => true,
'asinh' => true,
'sin' => true,
'sinh' => true,
'sqrt' => true,
'srand' => true,
'atan' => true,
'atanh' => true,
'tan' => true,
'tanh' => true
'tan' => true
);
// be sure equation parameter is present
if (empty($params[ 'equation' ])) {
trigger_error("math: missing equation parameter", E_USER_WARNING);
return;
}
$equation = $params[ 'equation' ];
// Remove whitespaces
$equation = preg_replace('/\s+/', '', $equation);
// Adapted from https://www.php.net/manual/en/function.eval.php#107377
$number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
$functionsOrVars = '((?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*))';
$operators = '[+\/*\^%-]'; // Allowed math operators
$regexp = '/^(('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*\((?1)+\)|\((?1)+\)))(?:'.$operators.'(?1))?)+$/';
if (!preg_match($regexp, $equation)) {
trigger_error("math: illegal characters", E_USER_WARNING);
return;
}
// make sure parenthesis are balanced
if (substr_count($equation, '(') !== substr_count($equation, ')')) {
trigger_error("math: unbalanced parenthesis", E_USER_WARNING);
return;
}
// disallow backticks
if (strpos($equation, '`') !== false) {
trigger_error("math: backtick character not allowed in equation", E_USER_WARNING);
return;
}
// also disallow dollar signs
if (strpos($equation, '$') !== false) {
trigger_error("math: dollar signs not allowed in equation", E_USER_WARNING);
@@ -125,7 +96,6 @@ function smarty_function_math($params, $template)
}
$smarty_math_result = null;
eval("\$smarty_math_result = " . $equation . ";");
if (empty($params[ 'format' ])) {
if (empty($params[ 'assign' ])) {
return $smarty_math_result;
+1 -5
View File
@@ -184,11 +184,7 @@ function smarty_modifier_escape($string, $esc_type = 'html', $char_set = null, $
'"' => '\\"',
"\r" => '\\r',
"\n" => '\\n',
'</' => '<\/',
// see https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements
'<!--' => '<\!--',
'<s' => '<\s',
'<S' => '<\S'
'</' => '<\/'
)
);
case 'mail':
+8 -2
View File
@@ -18,7 +18,7 @@
*
* @return string with compiled code
*/
function smarty_modifiercompiler_default($params)
function smarty_modifiercompiler_default($params, Smarty_Internal_TemplateCompilerBase $compiler)
{
$output = $params[ 0 ];
if (!isset($params[ 1 ])) {
@@ -26,7 +26,13 @@ function smarty_modifiercompiler_default($params)
}
array_shift($params);
foreach ($params as $param) {
$output = '(($tmp = @' . $output . ')===null||$tmp===\'\' ? ' . $param . ' : $tmp)';
if ($compiler->syntaxMatchesVariable($output)) {
$output = '(!isset(' . $output . ') || ' . $output . ' === \'\' ? ' . $param . ' : ' . $output . ')';
} else {
$output = '(($tmp = ' . $output . ')===null||$tmp===\'\' ? ' . $param . ' : $tmp)';
}
}
return $output;
}
+1 -2
View File
@@ -89,10 +89,9 @@ function smarty_modifiercompiler_escape($params, Smarty_Internal_TemplateCompile
return 'preg_replace("%(?<!\\\\\\\\)\'%", "\\\'",' . $params[ 0 ] . ')';
case 'javascript':
// escape quotes and backslashes, newlines, etc.
// see https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements
return 'strtr(' .
$params[ 0 ] .
', array("\\\\" => "\\\\\\\\", "\'" => "\\\\\'", "\"" => "\\\\\"", "\\r" => "\\\\r", "\\n" => "\\\n", "</" => "<\/", "<!--" => "<\!--", "<s" => "<\s", "<S" => "<\S" ))';
', array("\\\\" => "\\\\\\\\", "\'" => "\\\\\'", "\"" => "\\\\\"", "\\r" => "\\\\r", "\\n" => "\\\n", "</" => "<\/" ))';
}
} catch (SmartyException $e) {
// pass through to regular plugin fallback
@@ -674,7 +674,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
* @param $string
* @return bool
*/
private function syntaxMatchesVariable($string) {
public function syntaxMatchesVariable($string) {
static $regex_pattern = '/^\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*((->)[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*|\[.*]*\])*$/';
return 1 === preg_match($regex_pattern, trim($string));
}
@@ -2837,10 +2837,6 @@ class Smarty_Internal_Templateparser
// line 765 "../smarty/lexer/smarty_internal_templateparser.y"
public function yy_r95()
{
if ($this->security && $this->security->static_classes !== array()) {
$this->compiler->trigger_template_error('dynamic static class not allowed by security setting');
}
$prefixVar = $this->compiler->getNewPrefixVariable();
if ($this->yystack[ $this->yyidx + -2 ]->minor[ 'var' ] === '\'smarty\'') {
$this->compiler->appendPrefixCode("<?php {$prefixVar} = " .
+2 -9
View File
@@ -1,11 +1,6 @@
#!/bin/bash
if [[ "$1" =~ ^3\.[0-9\.-rc]+$ ]]; then
printf 'Creating release %s\n' "$1"
else
echo "Invalid version number: $1. This script can only make v3.x.x releases."
exit 1;
fi
printf 'Creating release %s\n' "$1"
git checkout -b "release/$1"
sed -i "s/## \\[Unreleased\\]/## \\[Unreleased\\]\\n\\n## \\[$1\\] - $(date +%Y-%m-%d)/" CHANGELOG.md
@@ -14,13 +9,11 @@ sed -i "s/const SMARTY_VERSION = '[^']\+';/const SMARTY_VERSION = '$1';/" libs/S
git add CHANGELOG.md libs/Smarty.class.php
git commit -m "version bump"
git checkout support/3.1
git checkout master
git pull
git merge --no-ff "release/$1"
git branch -d "release/$1"
git tag -a "v$1" -m "Release $1"
printf 'Done creating release %s\n' "$1"
# shellcheck disable=SC2016
printf 'Run `git push --follow-tags origin` to publish it.\n'
-1
View File
@@ -177,7 +177,6 @@ class PHPUnit_Smarty extends PHPUnit_Framework_TestCase
$this->smartyBC->setCacheDir(dirname(__FILE__) . '/cache');
}
}
$smarty = $this->getSmartyObj();
}
/**
@@ -64,10 +64,10 @@ class MuteExpectedErrorsTest extends PHPUnit_Smarty
$this->smarty->clearCompiledTemplate('default.tpl');
$this->smarty->fetch('default.tpl');
$this->assertEquals(Smarty::$_IS_WINDOWS ? 2 : 2, count($this->_errors));
$this->assertEquals(0, count($this->_errors));
@filemtime('ckxladanwijicajscaslyxck');
$this->assertEquals(Smarty::$_IS_WINDOWS ? 3 : 3, count($this->_errors));
$this->assertEquals(1, count($this->_errors));
restore_error_handler();
}
@@ -112,11 +112,11 @@ class MuteExpectedErrorsTest extends PHPUnit_Smarty
$this->smarty->clearCompiledTemplate('default.tpl');
$this->smarty->fetch('default.tpl');
$this->assertEquals(Smarty::$_IS_WINDOWS ? 2 : 2, count($this->_errors));
$this->assertEquals(0, count($this->_errors));
@filemtime('ckxladanwijicajscaslyxck');
$error = array(__FILE__ . ' line ' . (__LINE__ - 1));
$this->assertEquals(Smarty::$_IS_WINDOWS ? 3 : 3, count($this->_errors));
$this->assertEquals(1, count($this->_errors));
restore_error_handler();
}
@@ -110,6 +110,9 @@ class FileResourceTest extends PHPUnit_Smarty
);
}
/**
* @doesNotPerformAssertions
*/
public function testGetCompiledTimestampPrepare()
{
$tpl = $this->smarty->createTemplate('helloworld.tpl');
@@ -142,6 +145,9 @@ class FileResourceTest extends PHPUnit_Smarty
$this->assertTrue($tpl->mustCompile());
}
/**
* @doesNotPerformAssertions
*/
public function testMustCompileTouchedSourcePrepare()
{
// touch to prepare next test
@@ -161,7 +161,7 @@ class PhpResourceTest extends PHPUnit_Smarty
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
* @doesNotPerformAssertions
*/
public function testIsCachedTouchedSourcePrepare()
{
@@ -212,6 +212,7 @@ class PhpResourceTest extends PHPUnit_Smarty
/**
* test $smarty->is_cached
* @doesNotPerformAssertions
*/
public function testSmartyIsCachedPrepare()
{
+12 -32
View File
@@ -298,38 +298,18 @@ class SecurityTest extends PHPUnit_Smarty
$this->assertEquals('25', $this->smarty->fetch($tpl));
}
/**
* test not trusted PHP function
* @expectedException SmartyException
* @expectedExceptionMessage access to static class 'mysecuritystaticclass' not allowed by security setting
*/
public function testNotTrustedStaticClass()
{
$this->smarty->security_policy->static_classes = array('null');
$this->smarty->fetch('string:{mysecuritystaticclass::square(5)}');
}
/**
* test not trusted PHP function
* @expectedException SmartyException
* @expectedExceptionMessage dynamic static class not allowed by security setting
*/
public function testNotTrustedStaticClassEval()
{
$this->smarty->security_policy->static_classes = array('null');
$this->smarty->fetch('string:{$test = "mysecuritystaticclass"}{$test::square(5)}');
}
/**
* test not trusted PHP function
* @expectedException SmartyException
* @expectedExceptionMessage dynamic static class not allowed by security setting
*/
public function testNotTrustedStaticClassSmartyVar()
{
$this->smarty->security_policy->static_classes = array('null');
$this->smarty->fetch('string:{$smarty.template_object::square(5)}');
}
/**
* test not trusted PHP function
* @expectedException SmartyException
* @expectedExceptionMessage access to static class 'mysecuritystaticclass' not allowed by security setting
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testNotTrustedStaticClass()
{
$this->smarty->security_policy->static_classes = array('null');
$this->smarty->fetch('string:{mysecuritystaticclass::square(5)}');
}
public function testChangedTrustedDirectory()
{
@@ -0,0 +1 @@
{* this is a comment *}
@@ -0,0 +1,7 @@
=
{* comment *}
{* comment *}
b
{* comment *}
{* comment *}
=
@@ -0,0 +1,7 @@
=
a
{* comment 1 *}
{* comment 2 *}
{* comment 3 *}
b
=
@@ -0,0 +1,7 @@
=
a
{* comment 1 *}
{* comment 2 *}
{* comment 3 *}
b
=
@@ -0,0 +1,7 @@
=
a
{* comment 1 *}
{* comment 2 *}
{* comment 3 *}
b
=
@@ -0,0 +1,7 @@
=
a
{* comment 1 *}
{* comment 2 *}
{* comment 3 *}
b
=
@@ -0,0 +1 @@
{* another $foo comment *}
@@ -0,0 +1 @@
{* another comment *}some in between{* another comment *}
@@ -0,0 +1,2 @@
{* multi line
comment *}
@@ -0,0 +1 @@
{* /* foo * / *}
@@ -0,0 +1,2 @@
A{* comment *}B
C
@@ -0,0 +1,3 @@
D{* comment *}
{* comment *}E
F
@@ -0,0 +1,2 @@
G{* multi
line *}H
@@ -0,0 +1,3 @@
I{* multi
line *}
J
@@ -20,6 +20,9 @@ class PluginFunctionHtmlImageTest extends PHPUnit_Smarty
$this->setUpSmarty(dirname(__FILE__));
}
/**
* @doesNotPerformAssertions
*/
public function testFoo()
{
// TODO: UnitTests for {html_image}
@@ -54,7 +54,7 @@ class PluginFunctionMailtoTest extends PHPUnit_Smarty
public function testEncodeJavascript()
{
$result = '<script type="text/javascript">document.write(unescape(\'%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%22%20%3e%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%3c%2f%61%3e\'))</script>';
$result = '<script type="text/javascript">eval(unescape(\'%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%22%20%3e%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%3c%2f%61%3e%27%29%3b\'))</script>';
$tpl = $this->smarty->createTemplate('eval:{mailto address="me@example.com" encode="javascript"}');
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
}
@@ -62,7 +62,7 @@ class PluginFunctionMailtoTest extends PHPUnit_Smarty
public function testEncodeJavascriptWithoutMbstring()
{
Smarty::$_MBSTRING = false;
$result = '<script type="text/javascript">document.write(unescape(\'%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%22%20%3e%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%3c%2f%61%3e\'))</script>';
$result = '<script type="text/javascript">eval(unescape(\'%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%22%20%3e%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%3c%2f%61%3e%27%29%3b\'))</script>';
$tpl = $this->smarty->createTemplate('eval:{mailto address="me@example.com" encode="javascript"}');
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
Smarty::$_MBSTRING = true;
@@ -70,7 +70,7 @@ class PluginFunctionMailtoTest extends PHPUnit_Smarty
public function testEncodeJavascriptCharcode()
{
$result = '<script type="text/javascript">document.write(String.fromCharCode(60,97,32,104,114,101,102,61,34,109,97,105,108,116,111,58,109,101,64,101,120,97,109,112,108,101,46,99,111,109,34,32,62,109,101,64,101,120,97,109,112,108,101,46,99,111,109,60,47,97,62))</script>';
$result = "<script type=\"text/javascript\" language=\"javascript\">\n{document.write(String.fromCharCode(60,97,32,104,114,101,102,61,34,109,97,105,108,116,111,58,109,101,64,101,120,97,109,112,108,101,46,99,111,109,34,32,62,109,101,64,101,120,97,109,112,108,101,46,99,111,109,60,47,97,62))}\n</script>\n";
$tpl = $this->smarty->createTemplate('eval:{mailto address="me@example.com" encode="javascript_charcode"}');
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
}
@@ -78,7 +78,7 @@ class PluginFunctionMailtoTest extends PHPUnit_Smarty
public function testEncodeJavascriptCharcodeWithoutMbstring()
{
Smarty::$_MBSTRING = false;
$result = '<script type="text/javascript">document.write(String.fromCharCode(60,97,32,104,114,101,102,61,34,109,97,105,108,116,111,58,109,101,64,101,120,97,109,112,108,101,46,99,111,109,34,32,62,109,101,64,101,120,97,109,112,108,101,46,99,111,109,60,47,97,62))</script>';
$result = "<script type=\"text/javascript\" language=\"javascript\">\n{document.write(String.fromCharCode(60,97,32,104,114,101,102,61,34,109,97,105,108,116,111,58,109,101,64,101,120,97,109,112,108,101,46,99,111,109,34,32,62,109,101,64,101,120,97,109,112,108,101,46,99,111,109,60,47,97,62))}\n</script>\n";
$tpl = $this->smarty->createTemplate('eval:{mailto address="me@example.com" encode="javascript_charcode"}');
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
Smarty::$_MBSTRING = true;
@@ -0,0 +1,151 @@
<?php
/**
* Smarty PHPunit tests of modifier
*
* @package PHPunit
*/
/**
* class for modifier tests
*/
class PluginModifierDefaultTest extends PHPUnit_Smarty
{
public function setUp()
{
$this->setUpSmarty(dirname(__FILE__));
$this->smarty->setErrorReporting(E_ALL ^ E_NOTICE);
}
/**
* @dataProvider dataTestSimpleVars
*/
public function testSimpleVars($template, $expected)
{
$tpl = $this->smarty->createTemplate($template);
$this->smarty->assign('s', 'v0');
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}
/**
* Generates test data for ::testSimpleVars
*/
public function dataTestSimpleVars() {
return array(
array('string:{$s|default:"B"}', 'v0'), // simple set variable
array('string:{$u|default:"B"}', 'B'), // simple unset variable
);
}
/**
* @dataProvider dataTestSimpleVarsNoDefaultValue
*/
public function testSimpleVarsNoDefaultValue($template, $expected)
{
$tpl = $this->smarty->createTemplate($template);
$this->smarty->assign('s', 'v0');
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}
/**
* Generates test data for ::testSimpleVarsNoDefaultValue
*/
public function dataTestSimpleVarsNoDefaultValue() {
return array(
array('string:{$s|default}', 'v0'), // simple set variable
array('string:{$u|default}', ''), // simple unset variable
);
}
public function testEmptyString()
{
$tpl = $this->smarty->createTemplate('string:{$s|default:"B"}');
$this->smarty->assign('s', '');
$this->assertEquals('B', $this->smarty->fetch($tpl));
}
/**
* @dataProvider dataFalsyValues
*/
public function testFalsyValues($falsyvalue, $expected)
{
$tpl = $this->smarty->createTemplate('string:{$s|default:"B"}');
$this->smarty->assign('s', $falsyvalue);
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}
/**
* Data for ::testFalsyValues
*/
public function dataFalsyValues() {
return array(
array(false, false),
array(0, 0),
array('0', '0'),
array(array(), 'Array'),
array(null, 'B'),
array('', 'B'),
);
}
public function testFunctionCall()
{
$tpl = $this->smarty->createTemplate('string:{strlen("a")|default:"B"}');
$this->assertEquals('1', $this->smarty->fetch($tpl));
}
public function testFunctionCallEmptyString()
{
$tpl = $this->smarty->createTemplate('string:{trim("")|default:"B"}');
$this->assertEquals('B', $this->smarty->fetch($tpl));
}
/**
* @dataProvider dataTestArrayObjectCombinations
*/
public function testArrayObjectCombinations($template, $expected)
{
$tpl = $this->smarty->createTemplate($template);
$this->smarty->assign('a', array(
'k' => (object) array ('v' => 'v3'),
'v' => 'v1'
));
$this->smarty->assign('o', (object) array (
'p' => array('v' => 'v4'),
'v' => 'v2'
));
$this->smarty->assign('k', 'k');
$this->smarty->assign('nk', 'nk');
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}
/**
* Generates test data for ::testArrayObjectCombinations
*/
public function dataTestArrayObjectCombinations() {
return array(
array('string:{$a.v|default:"B"}', 'v1'), // array key set
array('string:{$o->v|default:"B"}', 'v2'), // object property set
array('string:{$a.k->v|default:"B"}', 'v3'), // complex combi of array and key access
array('string:{$a["k"]->v|default:"B"}', 'v3'), // complex combi of array and key access
array('string:{$a[$k]->v|default:"B"}', 'v3'), // complex combi of array and key access
array('string:{$a[$nk]->v|default:"B"}', 'B'), // complex combi of array and key access
array('string:{$a[$u]->v|default:"B"}', 'B'), // complex combi of array and key access
array('string:{$o->p.v|default:"B"}', 'v4'), // complex combi of array and key access
array('string:{$a.c|default:"B"}', 'B'), // array key not set
array('string:{$u.c|default:"B"}', 'B'), // array not set, referencing key
array('string:{$o->u|default:"B"}', 'B'), // object property not set
array('string:{$u->u|default:"B"}', 'B'), // object not set
array('string:{$a.k->u|default:"B"}', 'B'), // complex combi of array and key access with something unset
array('string:{$a["k"]->u|default:"B"}', 'B'), // complex combi of array and key access with something unset
array('string:{$a[$k]->u|default:"B"}', 'B'), // complex combi of array and key access with something unset
array('string:{$a[$nk]->u|default:"B"}', 'B'), // complex combi of array and key access with something unset
array('string:{$a[$u]->u|default:"B"}', 'B'), // complex combi of array and key access with something unset
array('string:{$a.u->u|default:"B"}', 'B'), // complex combi of array and key access with something unset
array('string:{$o->p.u|default:"B"}', 'B'), // complex combi of array and key access with something unset
array('string:{$o->u.u|default:"B"}', 'B'), // complex combi of array and key access with something unset
);
}
}
@@ -44,14 +44,6 @@ class MathTest extends PHPUnit_Smarty
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}
public function testMultipleOperators()
{
$this->smarty->disableSecurity();
$expected = "2 -- 2";
$tpl = $this->smarty->createTemplate('eval:{$x = 5}{$y = 4}{math equation="x - y + 1" x=$x y=$y} -- {math equation="5 - 4 + 1"}');
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}
public function testSyntaxSin()
{
$this->smarty->disableSecurity();
@@ -115,35 +107,4 @@ class MathTest extends PHPUnit_Smarty
$tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="x * y" x=$x y=$y format="%0.2f"} -- {math equation="20.5 / 5" format="%0.2f"}');
$this->assertEquals($expected, $this->smarty->fetch($tpl));
}
/**
* @expectedException PHPUnit_Framework_Error_Warning
*/
public function testBackticksIllegal()
{
$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));
}
/**
* @expectedException PHPUnit_Framework_Error_Warning
*/
public function testDollarSignsIllegal()
{
$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));
}
/**
* @expectedException PHPUnit_Framework_Error_Warning
*/
public function testBracketsIllegal()
{
$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));
}
}
@@ -291,6 +291,9 @@ class ScopeTest extends PHPUnit_Smarty
'no smarty', $i ++,),);
}
/**
* @doesNotPerformAssertions
*/
public function testFunctionScope()
{
$this->smarty->assign('scope', 'none');