mirror of
https://github.com/smarty-php/smarty.git
synced 2026-08-07 14:04:13 +02:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e0536de18 | |||
| 265cf4f3bc | |||
| 47f95ad324 | |||
| 6786623afb | |||
| 2d97169086 | |||
| 0f098802c6 | |||
| bbcd5817f6 | |||
| 612094d763 | |||
| 0ef0dda825 | |||
| cef8951100 | |||
| 323aefa89f | |||
| 277648b81c | |||
| 8d3a7af308 | |||
| cdf0f2b164 | |||
| 995b7eb36f | |||
| 059bea274c | |||
| f707dadecb | |||
| ace1c8e90f | |||
| 19ae410bf5 | |||
| baad3115cd |
@@ -28,6 +28,7 @@ jobs:
|
|||||||
- "7.3"
|
- "7.3"
|
||||||
- "7.4"
|
- "7.4"
|
||||||
- "8.0"
|
- "8.0"
|
||||||
|
- "8.1"
|
||||||
|
|
||||||
compiler:
|
compiler:
|
||||||
- default
|
- default
|
||||||
@@ -36,6 +37,9 @@ jobs:
|
|||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
php-version: "8.0"
|
php-version: "8.0"
|
||||||
compiler: jit
|
compiler: jit
|
||||||
|
- os: ubuntu-latest
|
||||||
|
php-version: "8.1"
|
||||||
|
compiler: jit
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|||||||
@@ -6,6 +6,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [4.1.0] - 2022-02-06
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- PHP8.1 compatibility [#713](https://github.com/smarty-php/smarty/pull/713)
|
||||||
|
|
||||||
|
## [4.0.4] - 2022-01-18
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed illegal characters bug in math function security check [#702](https://github.com/smarty-php/smarty/issues/702)
|
||||||
|
|
||||||
|
## [4.0.3] - 2022-01-10
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Prevent evasion of the `static_classes` security policy. This addresses CVE-2021-21408
|
||||||
|
|
||||||
## [4.0.2] - 2022-01-10
|
## [4.0.2] - 2022-01-10
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Smarty is a template engine for PHP, facilitating the separation of presentation
|
|||||||
Read the [documentation](https://smarty-php.github.io/smarty/) to find out how to use it.
|
Read the [documentation](https://smarty-php.github.io/smarty/) to find out how to use it.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
Smarty can be run with PHP 7.1 to PHP 8.0.
|
Smarty can be run with PHP 7.1 to PHP 8.1.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
Smarty versions 3.1.11 or later can be installed with [Composer](https://getcomposer.org/).
|
Smarty versions 3.1.11 or later can be installed with [Composer](https://getcomposer.org/).
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ What is Smarty?
|
|||||||
==============
|
==============
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
Smarty can be run with PHP 7.1 to PHP 8.0.
|
Smarty can be run with PHP 7.1 to PHP 8.1.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
Smarty versions 3.1.11 or later can be installed with [Composer](https://getcomposer.org/).
|
Smarty versions 3.1.11 or later can be installed with [Composer](https://getcomposer.org/).
|
||||||
|
|||||||
@@ -747,6 +747,9 @@ value(res) ::= doublequoted_with_quotes(s). {
|
|||||||
|
|
||||||
|
|
||||||
value(res) ::= varindexed(vi) DOUBLECOLON static_class_access(r). {
|
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();
|
$prefixVar = $this->compiler->getNewPrefixVariable();
|
||||||
if (vi['var'] === '\'smarty\'') {
|
if (vi['var'] === '\'smarty\'') {
|
||||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ". $this->compiler->compileTag('private_special_variable',array(),vi['smarty_internal_index']).';?>');
|
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ". $this->compiler->compileTag('private_special_variable',array(),vi['smarty_internal_index']).';?>');
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
/**
|
/**
|
||||||
* smarty version
|
* smarty version
|
||||||
*/
|
*/
|
||||||
const SMARTY_VERSION = '4.0.2';
|
const SMARTY_VERSION = '4.1.0';
|
||||||
/**
|
/**
|
||||||
* define variable scopes
|
* define variable scopes
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ function smarty_function_math($params, $template)
|
|||||||
$number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
|
$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]*))';
|
$functionsOrVars = '((?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*))';
|
||||||
$operators = '[+\/*\^%-]'; // Allowed math operators
|
$operators = '[+\/*\^%-]'; // Allowed math operators
|
||||||
$regexp = '/^(('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*\((?1)+\)|\((?1)+\)))(?:'.$operators.'(?2))?)+$/';
|
$regexp = '/^(('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*\((?1)+\)|\((?1)+\)))(?:'.$operators.'(?1))?)+$/';
|
||||||
|
|
||||||
if (!preg_match($regexp, $equation)) {
|
if (!preg_match($regexp, $equation)) {
|
||||||
trigger_error("math: illegal characters", E_USER_WARNING);
|
trigger_error("math: illegal characters", E_USER_WARNING);
|
||||||
|
|||||||
@@ -196,8 +196,8 @@ class Smarty_Internal_CacheResource_File extends Smarty_CacheResource
|
|||||||
*/
|
*/
|
||||||
public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached)
|
public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached)
|
||||||
{
|
{
|
||||||
clearstatcache(true, $cached->lock_id);
|
clearstatcache(true, $cached->lock_id ?? '');
|
||||||
if (is_file($cached->lock_id)) {
|
if (null !== $cached->lock_id && is_file($cached->lock_id)) {
|
||||||
$t = filemtime($cached->lock_id);
|
$t = filemtime($cached->lock_id);
|
||||||
return $t && (time() - $t < $smarty->locking_timeout);
|
return $t && (time() - $t < $smarty->locking_timeout);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase
|
|||||||
$output = "<?php echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php ";
|
$output = "<?php echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php ";
|
||||||
$output .= "\\\$_smarty_tpl->smarty->ext->_tplFunction->restoreTemplateVariables(\\\$_smarty_tpl, '{$_name}');?>\n";
|
$output .= "\\\$_smarty_tpl->smarty->ext->_tplFunction->restoreTemplateVariables(\\\$_smarty_tpl, '{$_name}');?>\n";
|
||||||
$output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";\n?>";
|
$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 .= "<?php echo str_replace('{$compiler->template->compiled->nocache_hash}', \$_smarty_tpl->compiled->nocache_hash ?? '', ob_get_clean());\n";
|
||||||
$output .= "}\n}\n";
|
$output .= "}\n}\n";
|
||||||
$output .= "/*/ {$_funcName}_nocache */\n\n";
|
$output .= "/*/ {$_funcName}_nocache */\n\n";
|
||||||
$output .= "?>\n";
|
$output .= "?>\n";
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ class Smarty_Internal_Config_File_Compiler
|
|||||||
}
|
}
|
||||||
// template header code
|
// template header code
|
||||||
$template_header =
|
$template_header =
|
||||||
"<?php /* Smarty version " . Smarty::SMARTY_VERSION . ", created on " . strftime("%Y-%m-%d %H:%M:%S") .
|
"<?php /* Smarty version " . Smarty::SMARTY_VERSION . ", created on " . date("Y-m-d H:i:s") .
|
||||||
"\n";
|
"\n";
|
||||||
$template_header .= " compiled from '{$this->template->source->filepath}' */ ?>\n";
|
$template_header .= " compiled from '{$this->template->source->filepath}' */ ?>\n";
|
||||||
$code = '<?php $_smarty_tpl->smarty->ext->configLoad->_loadConfigVars($_smarty_tpl, ' .
|
$code = '<?php $_smarty_tpl->smarty->ext->configLoad->_loadConfigVars($_smarty_tpl, ' .
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class Smarty_Internal_Runtime_CodeFrame
|
|||||||
$properties[ 'cache_lifetime' ] = $_template->cache_lifetime;
|
$properties[ 'cache_lifetime' ] = $_template->cache_lifetime;
|
||||||
}
|
}
|
||||||
$output = "<?php\n";
|
$output = "<?php\n";
|
||||||
$output .= "/* Smarty version {$properties[ 'version' ]}, created on " . strftime("%Y-%m-%d %H:%M:%S") .
|
$output .= "/* Smarty version {$properties[ 'version' ]}, created on " . date("Y-m-d H:i:s") .
|
||||||
"\n from '" . str_replace('*/', '* /', $_template->source->filepath) . "' */\n\n";
|
"\n from '" . str_replace('*/', '* /', $_template->source->filepath) . "' */\n\n";
|
||||||
$output .= "/* @var Smarty_Internal_Template \$_smarty_tpl */\n";
|
$output .= "/* @var Smarty_Internal_Template \$_smarty_tpl */\n";
|
||||||
$dec = "\$_smarty_tpl->_decodeProperties(\$_smarty_tpl, " . var_export($properties, true) . ',' .
|
$dec = "\$_smarty_tpl->_decodeProperties(\$_smarty_tpl, " . var_export($properties, true) . ',' .
|
||||||
|
|||||||
@@ -1135,7 +1135,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
|
|||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
$e = new SmartyCompilerException($error_text);
|
$e = new SmartyCompilerException($error_text);
|
||||||
$e->line = $line;
|
$e->setLine($line);
|
||||||
$e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ]));
|
$e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ]));
|
||||||
$e->desc = $args;
|
$e->desc = $args;
|
||||||
$e->template = $this->template->source->filepath;
|
$e->template = $this->template->source->filepath;
|
||||||
|
|||||||
@@ -2397,6 +2397,9 @@ public static $yy_action = array(
|
|||||||
}
|
}
|
||||||
// line 749 "../smarty/lexer/smarty_internal_templateparser.y"
|
// line 749 "../smarty/lexer/smarty_internal_templateparser.y"
|
||||||
public function yy_r94(){
|
public function yy_r94(){
|
||||||
|
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();
|
$prefixVar = $this->compiler->getNewPrefixVariable();
|
||||||
if ($this->yystack[$this->yyidx + -2]->minor['var'] === '\'smarty\'') {
|
if ($this->yystack[$this->yyidx + -2]->minor['var'] === '\'smarty\'') {
|
||||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ". $this->compiler->compileTag('private_special_variable',array(),$this->yystack[$this->yyidx + -2]->minor['smarty_internal_index']).';?>');
|
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ". $this->compiler->compileTag('private_special_variable',array(),$this->yystack[$this->yyidx + -2]->minor['smarty_internal_index']).';?>');
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ class SmartyCompilerException extends SmartyException
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The line number of the template error
|
* @param int $line
|
||||||
*
|
|
||||||
* @type int|null
|
|
||||||
*/
|
*/
|
||||||
public $line = null;
|
public function setLine($line)
|
||||||
|
{
|
||||||
|
$this->line = $line;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* The template source snippet relating to the error
|
* The template source snippet relating to the error
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ class CacheResourceTestCommon extends PHPUnit_Smarty
|
|||||||
|
|
||||||
public function compiledPrefilter($text, Smarty_Internal_Template $tpl)
|
public function compiledPrefilter($text, Smarty_Internal_Template $tpl)
|
||||||
{
|
{
|
||||||
return str_replace('#', $tpl->getTemplateVars('test'), $text);
|
$replace = $tpl->getTemplateVars('test');
|
||||||
|
return str_replace('#', $replace ?? '', $text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ class ResourceStream
|
|||||||
$v = &$GLOBALS[$this->varname];
|
$v = &$GLOBALS[$this->varname];
|
||||||
$l = strlen($data);
|
$l = strlen($data);
|
||||||
$p = &$this->position;
|
$p = &$this->position;
|
||||||
$v = substr($v, 0, $p) . $data . substr($v, $p += $l);
|
$v = substr($v ?? '', 0, $p) . $data . substr($v ?? '', $p += $l);
|
||||||
|
|
||||||
return $l;
|
return $l;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -257,19 +257,41 @@ class SecurityTest extends PHPUnit_Smarty
|
|||||||
$this->assertEquals('25', $this->smarty->fetch($tpl));
|
$this->assertEquals('25', $this->smarty->fetch($tpl));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test not trusted PHP function
|
* test not trusted PHP function
|
||||||
* @runInSeparateProcess
|
* @runInSeparateProcess
|
||||||
* @preserveGlobalState disabled
|
* @preserveGlobalState disabled
|
||||||
*/
|
*/
|
||||||
public function testNotTrustedStaticClass()
|
public function testNotTrustedStaticClass()
|
||||||
{
|
{
|
||||||
$this->expectException('SmartyException');
|
$this->expectException('SmartyException');
|
||||||
$this->expectExceptionMessage('access to static class \'mysecuritystaticclass\' not allowed by security setting');
|
$this->expectExceptionMessage('access to static class \'mysecuritystaticclass\' not allowed by security setting');
|
||||||
$this->smarty->security_policy->static_classes = array('null');
|
$this->smarty->security_policy->static_classes = array('null');
|
||||||
$this->smarty->fetch('string:{mysecuritystaticclass::square(5)}');
|
$this->smarty->fetch('string:{mysecuritystaticclass::square(5)}');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test not trusted PHP function
|
||||||
|
*/
|
||||||
|
public function testNotTrustedStaticClassEval()
|
||||||
|
{
|
||||||
|
$this->expectException('SmartyException');
|
||||||
|
$this->expectExceptionMessage('dynamic static class not allowed by security setting');
|
||||||
|
$this->smarty->security_policy->static_classes = array('null');
|
||||||
|
$this->smarty->fetch('string:{$test = "mysecuritystaticclass"}{$test::square(5)}');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test not trusted PHP function
|
||||||
|
*/
|
||||||
|
public function testNotTrustedStaticClassSmartyVar()
|
||||||
|
{
|
||||||
|
$this->expectException('SmartyException');
|
||||||
|
$this->expectExceptionMessage('dynamic static class not allowed by security setting');
|
||||||
|
$this->smarty->security_policy->static_classes = array('null');
|
||||||
|
$this->smarty->fetch('string:{$smarty.template_object::square(5)}');
|
||||||
|
}
|
||||||
|
|
||||||
public function testChangedTrustedDirectory()
|
public function testChangedTrustedDirectory()
|
||||||
{
|
{
|
||||||
$this->smarty->security_policy->secure_dir = array(
|
$this->smarty->security_policy->secure_dir = array(
|
||||||
@@ -344,9 +366,9 @@ class SecurityTest extends PHPUnit_Smarty
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* In security mode, accessing $smarty.template_object should be illegal.
|
* In security mode, accessing $smarty.template_object should be illegal.
|
||||||
* @expectedException SmartyCompilerException
|
|
||||||
*/
|
*/
|
||||||
public function testSmartyTemplateObject() {
|
public function testSmartyTemplateObject() {
|
||||||
|
$this->expectException(SmartyCompilerException::class);
|
||||||
$this->smarty->display('string:{$smarty.template_object}');
|
$this->smarty->display('string:{$smarty.template_object}');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,7 +416,7 @@ class ResourceStreamSecurity
|
|||||||
$v = &$GLOBALS[$this->varname];
|
$v = &$GLOBALS[$this->varname];
|
||||||
$l = strlen($data);
|
$l = strlen($data);
|
||||||
$p = &$this->position;
|
$p = &$this->position;
|
||||||
$v = substr($v, 0, $p) . $data . substr($v, $p += $l);
|
$v = substr($v ?? '', 0, $p) . $data . substr($v ?? '', $p += $l);
|
||||||
|
|
||||||
return $l;
|
return $l;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -435,9 +435,9 @@ class CompileFunctionTest extends PHPUnit_Smarty
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test handling of function names that are a security risk
|
* Test handling of function names that are a security risk
|
||||||
* @expectedException SmartyCompilerException
|
|
||||||
*/
|
*/
|
||||||
public function testIllegalFunctionName() {
|
public function testIllegalFunctionName() {
|
||||||
|
$this->expectException(SmartyCompilerException::class);
|
||||||
$this->smarty->fetch('string:{function name=\'rce(){};echo "hi";function \'}{/function}');
|
$this->smarty->fetch('string:{function name=\'rce(){};echo "hi";function \'}{/function}');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,14 @@ class MathTest extends PHPUnit_Smarty
|
|||||||
$this->assertEquals($expected, $this->smarty->fetch($tpl));
|
$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()
|
public function testSyntaxSin()
|
||||||
{
|
{
|
||||||
$this->smarty->disableSecurity();
|
$this->smarty->disableSecurity();
|
||||||
@@ -108,31 +116,25 @@ class MathTest extends PHPUnit_Smarty
|
|||||||
$this->assertEquals($expected, $this->smarty->fetch($tpl));
|
$this->assertEquals($expected, $this->smarty->fetch($tpl));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException PHPUnit_Framework_Error_Warning
|
|
||||||
*/
|
|
||||||
public function testBackticksIllegal()
|
public function testBackticksIllegal()
|
||||||
{
|
{
|
||||||
|
$this->expectException(PHPUnit\Framework\Error\Warning::class);
|
||||||
$expected = "22.00";
|
$expected = "22.00";
|
||||||
$tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="`ls` x * y" x=$x y=$y}');
|
$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));
|
$this->assertEquals($expected, $this->smarty->fetch($tpl));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException PHPUnit_Framework_Error_Warning
|
|
||||||
*/
|
|
||||||
public function testDollarSignsIllegal()
|
public function testDollarSignsIllegal()
|
||||||
{
|
{
|
||||||
|
$this->expectException(PHPUnit\Framework\Error\Warning::class);
|
||||||
$expected = "22.00";
|
$expected = "22.00";
|
||||||
$tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="$" x=$x y=$y}');
|
$tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="$" x=$x y=$y}');
|
||||||
$this->assertEquals($expected, $this->smarty->fetch($tpl));
|
$this->assertEquals($expected, $this->smarty->fetch($tpl));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException PHPUnit_Framework_Error_Warning
|
|
||||||
*/
|
|
||||||
public function testBracketsIllegal()
|
public function testBracketsIllegal()
|
||||||
{
|
{
|
||||||
|
$this->expectException(PHPUnit\Framework\Error\Warning::class);
|
||||||
$expected = "I";
|
$expected = "I";
|
||||||
$tpl = $this->smarty->createTemplate('eval:{$x = "0"}{$y = "1"}{math equation="((y/x).(x))[x]" x=$x y=$y}');
|
$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));
|
$this->assertEquals($expected, $this->smarty->fetch($tpl));
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ class VariableStream
|
|||||||
$v = &$GLOBALS[$this->varname];
|
$v = &$GLOBALS[$this->varname];
|
||||||
$l = strlen($data);
|
$l = strlen($data);
|
||||||
$p = &$this->position;
|
$p = &$this->position;
|
||||||
$v = substr($v, 0, $p) . $data . substr($v, $p += $l);
|
$v = substr($v ?? '', 0, $p) . $data . substr($v ?? '', $p += $l);
|
||||||
|
|
||||||
return $l;
|
return $l;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user