mirror of
https://github.com/smarty-php/smarty.git
synced 2026-08-04 12:34:33 +02:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 76428d1121 | |||
| 0a84d52bc2 | |||
| b3ade90dec | |||
| 4bcca1a2b4 | |||
| 0f7037d7ee | |||
| 459bd4adbd | |||
| 71c063d0b2 | |||
| c7c2d476aa | |||
| a2713ab89e | |||
| 28ea4f078c | |||
| b96c3060d5 | |||
| 3606c4717e | |||
| 8a8cf58c5a | |||
| 4eb86a6770 | |||
| 5f59e14fc1 | |||
| ed14f5269a | |||
| 9f47b059ed | |||
| 99085d8dc6 | |||
| eed1e07128 | |||
| 208f881d06 | |||
| 273f7e00fe | |||
| ce1ff003d7 | |||
| 28519ca00f | |||
| b674cba13d | |||
| a52a5b72ba | |||
| 7ad97ad030 | |||
| d8fa8c982f | |||
| de7e15d423 | |||
| 1b6919da85 | |||
| 457284283a | |||
| 9ffca4a093 | |||
| 0c8a549603 |
@@ -6,6 +6,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixes
|
||||
- Fixed use of `rand()` without a parameter in math function [#794](https://github.com/smarty-php/smarty/issues/794)
|
||||
|
||||
## [3.1.46] - 2022-08-01
|
||||
|
||||
### Fixed
|
||||
- Fixed problems with smarty_mb_str_replace [#549](https://github.com/smarty-php/smarty/issues/549)
|
||||
- Fixed second parameter of unescape modifier not working [#777](https://github.com/smarty-php/smarty/issues/777)
|
||||
|
||||
## [3.1.45] - 2022-05-17
|
||||
|
||||
### Security
|
||||
- Prevent PHP injection through malicious block name or include file name. This addresses CVE-2022-29221
|
||||
|
||||
### Fixed
|
||||
- Math equation `max(x, y)` didn't work anymore [#721](https://github.com/smarty-php/smarty/issues/721)
|
||||
|
||||
## [3.1.44] - 2022-01-18
|
||||
|
||||
### 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
|
||||
|
||||
@@ -758,6 +758,9 @@ 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']).';?>');
|
||||
|
||||
@@ -111,7 +111,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
/**
|
||||
* smarty version
|
||||
*/
|
||||
const SMARTY_VERSION = '3.1.40';
|
||||
const SMARTY_VERSION = '3.1.46';
|
||||
/**
|
||||
* define variable scopes
|
||||
*/
|
||||
|
||||
@@ -94,22 +94,19 @@ function smarty_function_mailto($params)
|
||||
);
|
||||
return;
|
||||
}
|
||||
// FIXME: (rodneyrehm) document.write() excues me what? 1998 has passed!
|
||||
if ($encode === 'javascript') {
|
||||
$string = 'document.write(\'<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>\');';
|
||||
$string = '<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">eval(unescape(\'' . $js_encode . '\'))</script>';
|
||||
return '<script type="text/javascript">document.write(unescape(\'' . $js_encode . '\'))</script>';
|
||||
} elseif ($encode === 'javascript_charcode') {
|
||||
$string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
|
||||
for ($x = 0, $y = strlen($string); $x < $y; $x++) {
|
||||
for ($x = 0, $_length = strlen($string); $x < $_length; $x++) {
|
||||
$ord[] = ord($string[ $x ]);
|
||||
}
|
||||
$_ret = "<script type=\"text/javascript\" language=\"javascript\">\n" . "{document.write(String.fromCharCode(" .
|
||||
implode(',', $ord) . "))" . "}\n" . "</script>\n";
|
||||
return $_ret;
|
||||
return '<script type="text/javascript">document.write(String.fromCharCode(' . implode(',', $ord) . '))</script>';
|
||||
} elseif ($encode === 'hex') {
|
||||
preg_match('!^(.*)(\?.*)$!', $address, $match);
|
||||
if (!empty($match[ 2 ])) {
|
||||
|
||||
@@ -28,7 +28,12 @@ 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,
|
||||
@@ -39,27 +44,51 @@ function smarty_function_math($params, $template)
|
||||
'pow' => true,
|
||||
'rand' => true,
|
||||
'round' => true,
|
||||
'asin' => true,
|
||||
'asinh' => true,
|
||||
'sin' => true,
|
||||
'sinh' => true,
|
||||
'sqrt' => true,
|
||||
'srand' => true,
|
||||
'tan' => true
|
||||
'atan' => true,
|
||||
'atanh' => true,
|
||||
'tan' => true,
|
||||
'tanh' => 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);
|
||||
@@ -96,6 +125,7 @@ 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;
|
||||
|
||||
@@ -14,20 +14,28 @@
|
||||
* @author Rodney Rehm
|
||||
*
|
||||
* @param array $params parameters
|
||||
* @param Smarty_Internal_TemplateCompilerBase $compiler
|
||||
*
|
||||
* @return string with compiled code
|
||||
*/
|
||||
function smarty_modifiercompiler_unescape($params)
|
||||
function smarty_modifiercompiler_unescape($params, Smarty_Internal_TemplateCompilerBase $compiler)
|
||||
{
|
||||
if (!isset($params[ 1 ])) {
|
||||
$params[ 1 ] = 'html';
|
||||
}
|
||||
$compiler->template->_checkPlugins(
|
||||
array(
|
||||
array(
|
||||
'function' => 'smarty_literal_compiler_param',
|
||||
'file' => SMARTY_PLUGINS_DIR . 'shared.literal_compiler_param.php'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$esc_type = smarty_literal_compiler_param($params, 1, 'html');
|
||||
|
||||
if (!isset($params[ 2 ])) {
|
||||
$params[ 2 ] = '\'' . addslashes(Smarty::$_CHARSET) . '\'';
|
||||
} else {
|
||||
$params[ 2 ] = "'{$params[ 2 ]}'";
|
||||
}
|
||||
switch (trim($params[ 1 ], '"\'')) {
|
||||
|
||||
switch ($esc_type) {
|
||||
case 'entity':
|
||||
case 'htmlall':
|
||||
if (Smarty::$_MBSTRING) {
|
||||
|
||||
@@ -44,9 +44,43 @@ if (!function_exists('smarty_mb_str_replace')) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$mb_reg_charset = mb_regex_encoding();
|
||||
// Check if mbstring regex is using UTF-8
|
||||
$reg_is_unicode = !strcasecmp($mb_reg_charset, "UTF-8");
|
||||
if(!$reg_is_unicode) {
|
||||
// ...and set to UTF-8 if not
|
||||
mb_regex_encoding("UTF-8");
|
||||
}
|
||||
|
||||
// See if charset used by Smarty is matching one used by regex...
|
||||
$current_charset = mb_regex_encoding();
|
||||
$convert_result = (bool)strcasecmp(Smarty::$_CHARSET, $current_charset);
|
||||
if($convert_result) {
|
||||
// ...convert to it if not.
|
||||
$subject = mb_convert_encoding($subject, $current_charset, Smarty::$_CHARSET);
|
||||
$search = mb_convert_encoding($search, $current_charset, Smarty::$_CHARSET);
|
||||
$replace = mb_convert_encoding($replace, $current_charset, Smarty::$_CHARSET);
|
||||
}
|
||||
|
||||
$parts = mb_split(preg_quote($search), $subject);
|
||||
// If original regex encoding was not unicode...
|
||||
if(!$reg_is_unicode) {
|
||||
// ...restore original regex encoding to avoid breaking the system.
|
||||
mb_regex_encoding($mb_reg_charset);
|
||||
}
|
||||
if($parts === false) {
|
||||
// This exception is thrown if call to mb_split failed.
|
||||
// Usually it happens, when $search or $replace are not valid for given mb_regex_encoding().
|
||||
// There may be other cases for it to fail, please file an issue if you find a reproducible one.
|
||||
throw new SmartyException("Source string is not a valid $current_charset sequence (probably)");
|
||||
}
|
||||
|
||||
$count = count($parts) - 1;
|
||||
$subject = implode($replace, $parts);
|
||||
// Convert results back to charset used by Smarty, if needed.
|
||||
if($convert_result) {
|
||||
$subject = mb_convert_encoding($subject, Smarty::$_CHARSET, $current_charset);
|
||||
}
|
||||
}
|
||||
return $subject;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_
|
||||
// setup buffer for template function code
|
||||
$compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template();
|
||||
$output = "<?php\n";
|
||||
$output .= "/* {block {$_name}} */\n";
|
||||
$output .= $compiler->cStyleComment(" {block {$_name}} ") . "\n";
|
||||
$output .= "class {$_className} extends Smarty_Internal_Block\n";
|
||||
$output .= "{\n";
|
||||
foreach ($_block as $property => $value) {
|
||||
@@ -155,7 +155,7 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_
|
||||
}
|
||||
$output .= "}\n";
|
||||
$output .= "}\n";
|
||||
$output .= "/* {/block {$_name}} */\n\n";
|
||||
$output .= $compiler->cStyleComment(" {/block {$_name}} ") . "\n\n";
|
||||
$output .= "?>\n";
|
||||
$compiler->parser->current_buffer->append_subtree(
|
||||
$compiler->parser,
|
||||
|
||||
@@ -134,7 +134,7 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase
|
||||
if ($compiler->template->compiled->has_nocache_code) {
|
||||
$compiler->parent_compiler->tpl_function[ $_name ][ 'call_name_caching' ] = $_funcNameCaching;
|
||||
$output = "<?php\n";
|
||||
$output .= "/* {$_funcNameCaching} */\n";
|
||||
$output .= $compiler->cStyleComment(" {$_funcNameCaching} ") . "\n";
|
||||
$output .= "if (!function_exists('{$_funcNameCaching}')) {\n";
|
||||
$output .= "function {$_funcNameCaching} (Smarty_Internal_Template \$_smarty_tpl,\$params) {\n";
|
||||
$output .= "ob_start();\n";
|
||||
@@ -159,7 +159,7 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase
|
||||
$output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";\n?>";
|
||||
$output .= "<?php echo str_replace('{$compiler->template->compiled->nocache_hash}', \$_smarty_tpl->compiled->nocache_hash, ob_get_clean());\n";
|
||||
$output .= "}\n}\n";
|
||||
$output .= "/*/ {$_funcName}_nocache */\n\n";
|
||||
$output .= $compiler->cStyleComment("/ {$_funcName}_nocache ") . "\n\n";
|
||||
$output .= "?>\n";
|
||||
$compiler->parser->current_buffer->append_subtree(
|
||||
$compiler->parser,
|
||||
@@ -179,7 +179,7 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase
|
||||
}
|
||||
$compiler->parent_compiler->tpl_function[ $_name ][ 'call_name' ] = $_funcName;
|
||||
$output = "<?php\n";
|
||||
$output .= "/* {$_funcName} */\n";
|
||||
$output .= $compiler->cStyleComment(" {$_funcName} ") . "\n";
|
||||
$output .= "if (!function_exists('{$_funcName}')) {\n";
|
||||
$output .= "function {$_funcName}(Smarty_Internal_Template \$_smarty_tpl,\$params) {\n";
|
||||
$output .= $_paramsCode;
|
||||
@@ -196,7 +196,7 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase
|
||||
);
|
||||
$compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode);
|
||||
$output = "<?php\n}}\n";
|
||||
$output .= "/*/ {$_funcName} */\n\n";
|
||||
$output .= $compiler->cStyleComment("/ {$_funcName} ") . "\n\n";
|
||||
$output .= "?>\n";
|
||||
$compiler->parser->current_buffer->append_subtree(
|
||||
$compiler->parser,
|
||||
|
||||
@@ -318,14 +318,14 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
|
||||
}
|
||||
// get compiled code
|
||||
$compiled_code = "<?php\n\n";
|
||||
$compiled_code .= "/* Start inline template \"{$sourceInfo}\" =============================*/\n";
|
||||
$compiled_code .= $compiler->cStyleComment(" Start inline template \"{$sourceInfo}\" =============================") . "\n";
|
||||
$compiled_code .= "function {$tpl->compiled->unifunc} (Smarty_Internal_Template \$_smarty_tpl) {\n";
|
||||
$compiled_code .= "?>\n" . $tpl->compiler->compileTemplateSource($tpl, null, $compiler->parent_compiler);
|
||||
$compiled_code .= "<?php\n";
|
||||
$compiled_code .= "}\n?>\n";
|
||||
$compiled_code .= $tpl->compiler->postFilter($tpl->compiler->blockOrFunctionCode);
|
||||
$compiled_code .= "<?php\n\n";
|
||||
$compiled_code .= "/* End inline template \"{$sourceInfo}\" =============================*/\n";
|
||||
$compiled_code .= $compiler->cStyleComment(" End inline template \"{$sourceInfo}\" =============================") . "\n";
|
||||
$compiled_code .= '?>';
|
||||
unset($tpl->compiler);
|
||||
if ($tpl->compiled->has_nocache_code) {
|
||||
|
||||
@@ -157,10 +157,12 @@ class Smarty_Internal_Config_File_Compiler
|
||||
$this->smarty->_debug->end_compile($this->template);
|
||||
}
|
||||
// template header code
|
||||
$template_header =
|
||||
"<?php /* Smarty version " . Smarty::SMARTY_VERSION . ", created on " . strftime("%Y-%m-%d %H:%M:%S") .
|
||||
"\n";
|
||||
$template_header .= " compiled from '{$this->template->source->filepath}' */ ?>\n";
|
||||
$template_header = sprintf(
|
||||
"<?php /* Smarty version %s, created on %s\n compiled from '%s' */ ?>\n",
|
||||
Smarty::SMARTY_VERSION,
|
||||
date("Y-m-d H:i:s"),
|
||||
str_replace('*/', '* /' , $this->template->source->filepath)
|
||||
);
|
||||
$code = '<?php $_smarty_tpl->smarty->ext->configLoad->_loadConfigVars($_smarty_tpl, ' .
|
||||
var_export($this->config_data, true) . '); ?>';
|
||||
return $template_header . $this->template->smarty->ext->_codeFrame->create($this->template, $code);
|
||||
|
||||
@@ -44,9 +44,12 @@ class Smarty_Internal_Runtime_CodeFrame
|
||||
$properties[ 'file_dependency' ] = $_template->cached->file_dependency;
|
||||
$properties[ 'cache_lifetime' ] = $_template->cache_lifetime;
|
||||
}
|
||||
$output = "<?php\n";
|
||||
$output .= "/* Smarty version {$properties[ 'version' ]}, created on " . strftime("%Y-%m-%d %H:%M:%S") .
|
||||
"\n from '" . str_replace('*/', '* /', $_template->source->filepath) . "' */\n\n";
|
||||
$output = sprintf(
|
||||
"<?php\n/* Smarty version %s, created on %s\n from '%s' */\n\n",
|
||||
$properties[ 'version' ],
|
||||
date("Y-m-d H:i:s"),
|
||||
str_replace('*/', '* /', $_template->source->filepath)
|
||||
);
|
||||
$output .= "/* @var Smarty_Internal_Template \$_smarty_tpl */\n";
|
||||
$dec = "\$_smarty_tpl->_decodeProperties(\$_smarty_tpl, " . var_export($properties, true) . ',' .
|
||||
($cache ? 'true' : 'false') . ')';
|
||||
|
||||
@@ -1455,6 +1455,10 @@ abstract class Smarty_Internal_TemplateCompilerBase
|
||||
*/
|
||||
abstract protected function doCompile($_content, $isTemplateSource = false);
|
||||
|
||||
public function cStyleComment($string) {
|
||||
return '/*' . str_replace('*/', '* /' , $string) . '*/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile Tag
|
||||
*
|
||||
|
||||
@@ -2837,6 +2837,10 @@ 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} = " .
|
||||
|
||||
+9
-2
@@ -1,6 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
printf 'Creating release %s\n' "$1"
|
||||
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
|
||||
|
||||
git checkout -b "release/$1"
|
||||
sed -i "s/## \\[Unreleased\\]/## \\[Unreleased\\]\\n\\n## \\[$1\\] - $(date +%Y-%m-%d)/" CHANGELOG.md
|
||||
@@ -9,11 +14,13 @@ 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 master
|
||||
git checkout support/3.1
|
||||
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'
|
||||
|
||||
@@ -298,18 +298,38 @@ 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
|
||||
* @runInSeparateProcess
|
||||
* @preserveGlobalState disabled
|
||||
*/
|
||||
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 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)}');
|
||||
}
|
||||
|
||||
public function testChangedTrustedDirectory()
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@ class PluginFunctionMailtoTest extends PHPUnit_Smarty
|
||||
|
||||
public function testEncodeJavascript()
|
||||
{
|
||||
$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>';
|
||||
$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>';
|
||||
$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">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>';
|
||||
$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>';
|
||||
$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\" 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";
|
||||
$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>';
|
||||
$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\" 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";
|
||||
$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>';
|
||||
$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;
|
||||
|
||||
+7
-2
@@ -63,6 +63,11 @@ class PluginModifierUnescapeTest extends PHPUnit_Smarty
|
||||
$tpl = $this->smarty->createTemplate('string:{"' . $encoded . '"|unescape:"url"}');
|
||||
$this->assertEquals($result, $this->smarty->fetch($tpl));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
public function testCharset()
|
||||
{
|
||||
$tpl = $this->smarty->createTemplate("string:{''Stiff Opposition Expected to Casketless Funeral Plan''|unescape:'htmlall':'utf-8'}");
|
||||
$this->assertEquals("'Stiff Opposition Expected to Casketless Funeral Plan'", $this->smarty->fetch($tpl));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,6 +44,30 @@ 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 testMathMaxFunctionParameters()
|
||||
{
|
||||
$this->smarty->disableSecurity();
|
||||
$expected = max(0, 2) . ' -- ' . max(0, 2, 3);
|
||||
$tpl = $this->smarty->createTemplate('eval:{$x = 0}{$y = 2}{$z = 3}{math equation="max(x, y)" x=$x y=$y} -- {math equation="max(x, y, z)" x=$x y=$y z=$z}');
|
||||
$this->assertEquals($expected, $this->smarty->fetch($tpl));
|
||||
}
|
||||
|
||||
public function testMathMinFunctionParameters()
|
||||
{
|
||||
$this->smarty->disableSecurity();
|
||||
$expected = min(1, 2) . ' -- ' . min(1, 2, 0);
|
||||
$tpl = $this->smarty->createTemplate('eval:{$x = 1}{$y = 2}{$z = 0}{math equation="min(x, y)" x=$x y=$y} -- {math equation="min(x, y, z)" x=$x y=$y z=$z}');
|
||||
$this->assertEquals($expected, $this->smarty->fetch($tpl));
|
||||
}
|
||||
|
||||
public function testSyntaxSin()
|
||||
{
|
||||
$this->smarty->disableSecurity();
|
||||
@@ -107,4 +131,43 @@ 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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* Smarty PHPunit tests - issue #549 regression tests
|
||||
*
|
||||
* @package PHPunit
|
||||
* @author Andrey Repin <anrdaemon@yandex.ru>
|
||||
*/
|
||||
|
||||
/**
|
||||
* class for compiler tests
|
||||
*
|
||||
* @runTestsInSeparateProcess
|
||||
* @preserveGlobalState disabled
|
||||
* @backupStaticAttributes enabled
|
||||
*
|
||||
* mb_split breaks if Smarty encoding is not the same as mbstring regex encoding.
|
||||
*/
|
||||
class MbSplitEncodingIssue549Test extends PHPUnit_Smarty
|
||||
{
|
||||
/** @var string Saved Smarty charset */
|
||||
private $charset;
|
||||
|
||||
/** @var array Source data for tests, hexed to protect from accidental reencoding */
|
||||
private $data = array(
|
||||
"subject" => '4772c3bc6e6577616c64', // "Grünewald"
|
||||
"pattern" => '77616c64', // "wald"
|
||||
"replacement" => '7374c3bc726d', // "stürm"
|
||||
"result" => '4772c3bc6e657374c3bc726d', // "Grünestürm"
|
||||
);
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if(!\Smarty::$_MBSTRING)
|
||||
{
|
||||
return $this->markTestSkipped("mbstring extension is not in use by Smarty");
|
||||
}
|
||||
|
||||
$this->charset = \Smarty::$_CHARSET;
|
||||
$this->setUpSmarty(dirname(__FILE__));
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
\Smarty::$_CHARSET = $this->charset ?: \Smarty::$_CHARSET;
|
||||
$this->cleanDirs();
|
||||
}
|
||||
|
||||
/** Provider for testReplaceModifier
|
||||
*/
|
||||
public function encodingPairsProvider()
|
||||
{
|
||||
return array(
|
||||
"with non-UNICODE src/non-UNICODE regex (PHP < 5.6 default)" => array("Windows-1252", "EUC-JP"),
|
||||
"with UTF-8 src/non-UNICODE regex (PHP < 5.6 default)" => array("UTF-8", "EUC-JP"),
|
||||
"with UTF-8 src/UTF-8 regex (PHP >= 5.6)" => array("UTF-8", "UTF-8"),
|
||||
"with non-UNICODE src/UTF-8 regex" => array("Windows-1252", "UTF-8"),
|
||||
);
|
||||
}
|
||||
|
||||
/** Test behavior of `replace` modifier with different source and regex encodings
|
||||
*
|
||||
* @dataProvider encodingPairsProvider
|
||||
*/
|
||||
public function testReplaceModifier($mb_int_encoding, $mb_regex_encoding)
|
||||
{
|
||||
$data = $this->data;
|
||||
\array_walk($data, function(&$value, $key) use($mb_int_encoding) {
|
||||
$value = \mb_convert_encoding(pack("H*", $value), $mb_int_encoding, "UTF-8");
|
||||
});
|
||||
\extract($data, \EXTR_SKIP);
|
||||
|
||||
\mb_regex_encoding($mb_regex_encoding);
|
||||
\Smarty::$_CHARSET = $mb_int_encoding;
|
||||
$this->assertEquals($result, $this->smarty->fetch("string:{\"$subject\"|replace:\"$pattern\":\"$replacement\"}"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
# Ignore anything in here, but keep this directory
|
||||
*
|
||||
@@ -0,0 +1,2 @@
|
||||
# Ignore anything in here, but keep this directory
|
||||
*
|
||||
Reference in New Issue
Block a user