Skip to content

Commit

Permalink
Fix Too many shorthand attributes error when using a modifier as a fu…
Browse files Browse the repository at this point in the history
…nction with more than 3 parameters in an expression (#953)

Fixes #949
  • Loading branch information
wisskid committed Mar 15, 2024
1 parent 293bc20 commit 17da1f5
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 145 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Expand Up @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed
- Too many shorthand attributes error when using a modifier as a function with more than 3 parameters in an expression [#949](https://github.com/smarty-php/smarty/issues/949)

### Removed
- Dropped support for undocumented `{time()}` added in v5.0.0 since we already have the documented `{$smarty.now}`

## [5.0.0-rc3] - 2024-02-26

### Added
Expand Down
Expand Up @@ -88,9 +88,6 @@ Object chaining:
{$object->method1($x)->method2($y)}
Direct PHP function access:
{time()}
```

> **Note**
Expand Down
24 changes: 10 additions & 14 deletions src/Compile/FunctionCallCompiler.php
Expand Up @@ -34,7 +34,7 @@ class FunctionCallCompiler extends Base {
*
* @var array
*/
protected $shorttag_order = ['var1', 'var2', 'var3'];
protected $shorttag_order = [];

/**
* Compiles code for the execution of a registered function
Expand All @@ -58,19 +58,15 @@ public function compile($args, Template $compiler, $parameter = [], $tag = null,
$_paramsArray = $this->formatParamsArray($_attr);
$_params = 'array(' . implode(',', $_paramsArray) . ')';

try {
$value = array_shift($_attr);
$output = $compiler->compileModifier([array_merge([$function], $_attr)], $value);
} catch (\Smarty\CompilerException $e) {
if ($functionHandler = $compiler->getSmarty()->getFunctionHandler($function)) {

// not cacheable?
$compiler->tag_nocache = $compiler->tag_nocache || !$functionHandler->isCacheable();
$output = "\$_smarty_tpl->getSmarty()->getFunctionHandler(" . var_export($function, true) . ")";
$output .= "->handle($_params, \$_smarty_tpl)";
} else {
throw $e;
}

if ($functionHandler = $compiler->getSmarty()->getFunctionHandler($function)) {

// not cacheable?
$compiler->tag_nocache = $compiler->tag_nocache || !$functionHandler->isCacheable();
$output = "\$_smarty_tpl->getSmarty()->getFunctionHandler(" . var_export($function, true) . ")";
$output .= "->handle($_params, \$_smarty_tpl)";
} else {
$compiler->trigger_template_error("unknown function '{$function}'", null, true);
}

if (!empty($parameter['modifierlist'])) {
Expand Down
19 changes: 19 additions & 0 deletions src/Compile/Modifier/IsArrayModifierCompiler.php
@@ -0,0 +1,19 @@
<?php
namespace Smarty\Compile\Modifier;
use Smarty\CompilerException;

/**
* Smarty is_array modifier plugin
*/
class IsArrayModifierCompiler extends Base {

public function compile($params, \Smarty\Compiler\Template $compiler) {

if (count($params) !== 1) {
throw new CompilerException("Invalid number of arguments for is_array. is_array expects exactly 1 parameter.");
}

return 'is_array(' . $params[0] . ')';
}

}
5 changes: 5 additions & 0 deletions src/Compiler/Template.php
Expand Up @@ -1369,6 +1369,11 @@ public function compileFunctionCall(string $base_tag, array $args, array $parame
return $this->functionCallCompiler->compile($args, $this, $parameter, $base_tag, $base_tag);
}

public function compileModifierInExpression(string $function, array $_attr) {
$value = array_shift($_attr);
return $this->compileModifier([array_merge([$function], $_attr)], $value);
}

/**
* @return TemplateParser|null
*/
Expand Down
25 changes: 21 additions & 4 deletions src/Extension/DefaultExtension.php
Expand Up @@ -2,6 +2,8 @@

namespace Smarty\Extension;

use Smarty\Exception;

class DefaultExtension extends Base {

private $modifiers = [];
Expand All @@ -27,6 +29,7 @@ public function getModifierCompiler(string $modifier): ?\Smarty\Compile\Modifier
case 'escape': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\EscapeModifierCompiler(); break;
case 'from_charset': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\FromCharsetModifierCompiler(); break;
case 'indent': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\IndentModifierCompiler(); break;
case 'is_array': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\IsArrayModifierCompiler(); break;
case 'isset': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\IssetModifierCompiler(); break;
case 'json_encode': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\JsonEncodeModifierCompiler(); break;
case 'lower': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\LowerModifierCompiler(); break;
Expand Down Expand Up @@ -57,6 +60,7 @@ public function getModifierCallback(string $modifierName) {
case 'escape': return [$this, 'smarty_modifier_escape'];
case 'explode': return [$this, 'smarty_modifier_explode'];
case 'implode': return [$this, 'smarty_modifier_implode'];
case 'in_array': return [$this, 'smarty_modifier_in_array'];
case 'join': return [$this, 'smarty_modifier_join'];
case 'mb_wordwrap': return [$this, 'smarty_modifier_mb_wordwrap'];
case 'number_format': return [$this, 'smarty_modifier_number_format'];
Expand Down Expand Up @@ -87,12 +91,8 @@ public function getFunctionHandler(string $functionName): ?\Smarty\FunctionHandl
case 'html_select_date': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlSelectDate(); break;
case 'html_select_time': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlSelectTime(); break;
case 'html_table': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlTable(); break;
case 'in_array': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\InArray(); break;
case 'is_array': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\IsArray(); break;
case 'mailto': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Mailto(); break;
case 'math': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Math(); break;
case 'strlen': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Strlen(); break;
case 'time': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Time(); break;
}

return $this->functionHandlers[$functionName] ?? null;
Expand Down Expand Up @@ -570,6 +570,23 @@ public function smarty_modifier_implode($values, $separator = '')
return implode((string) ($separator ?? ''), (array) $values);
}

/**
* Smarty in_array modifier plugin
* Type: modifier
* Name: in_array
* Purpose: test if value is contained in an array
*
* @param mixed $needle
* @param array $array
* @param bool $strict
*
* @return bool
*/
public function smarty_modifier_in_array($needle, $array, $strict = false)
{
return in_array($needle, (array) $array, (bool) $strict);
}

/**
* Smarty join modifier plugin
* Type: modifier
Expand Down
30 changes: 0 additions & 30 deletions src/FunctionHandler/InArray.php

This file was deleted.

21 changes: 0 additions & 21 deletions src/FunctionHandler/IsArray.php

This file was deleted.

28 changes: 0 additions & 28 deletions src/FunctionHandler/Strlen.php

This file was deleted.

21 changes: 0 additions & 21 deletions src/FunctionHandler/Time.php

This file was deleted.

2 changes: 1 addition & 1 deletion src/Parser/TemplateParser.php
Expand Up @@ -2675,7 +2675,7 @@ public function yy_r147(){
}
// line 1063 "src/Parser/TemplateParser.y"
public function yy_r148(){
$this->_retvalue = $this->compiler->compileFunctionCall($this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor);
$this->_retvalue = $this->compiler->compileModifierInExpression($this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor);
}
// line 1071 "src/Parser/TemplateParser.y"
public function yy_r149(){
Expand Down
2 changes: 1 addition & 1 deletion src/Parser/TemplateParser.y
Expand Up @@ -1061,7 +1061,7 @@ objectelement(res)::= PTR method(f). {
// function
//
function(res) ::= ns1(f) OPENP params(p) CLOSEP. {
res = $this->compiler->compileFunctionCall(f, p);
res = $this->compiler->compileModifierInExpression(f, p);
}


Expand Down

This file was deleted.

Expand Up @@ -79,7 +79,7 @@ public function testEmpty2()
public function testEmpty3()
{
$this->smarty->disableSecurity();
$this->getSmarty()->registerPlugin(\Smarty\Smarty::PLUGIN_FUNCTION, 'pass', function ($v) { return $v; });
$this->getSmarty()->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'pass', function ($v) { return $v; });
$this->smarty->assign('var', array(true,
(int) 1,
(float) 0.1,
Expand All @@ -99,7 +99,7 @@ public function testEmpty3()
public function testEmpty4()
{
$this->smarty->disableSecurity();
$this->getSmarty()->registerPlugin(\Smarty\Smarty::PLUGIN_FUNCTION, 'pass', function ($v) { return $v; });
$this->getSmarty()->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'pass', function ($v) { return $v; });
$this->smarty->assign('var', new TestIsset());
$expected = ' true , false , false , true , true , true , false ';
$this->assertEquals($expected, $this->smarty->fetch('string:{strip}{if empty($var->isNull)} true {else} false {/IF}
Expand Down
@@ -0,0 +1,16 @@
<?php

class TooManyShorthandAttributes949Test extends PHPUnit_Smarty
{

public function testPregMatchAll() {
$smarty = new \Smarty\Smarty();
$smarty->registerPlugin('modifier', 'var_dump', 'var_dump');
$templateStr = "eval:{\$a = 'blah'}{\$b = array()}{if var_dump('', \$a, \$b, 2)|noprint}blah{else}nah{/if}";
$this->assertEquals(
'nah',
$smarty->fetch($templateStr)
);
}

}

0 comments on commit 17da1f5

Please sign in to comment.