Removed PHP functions and checks for the already removed php modifiers. Re-implemented functions as regular functions. Probably should compile these directly.

This commit is contained in:
Simon Wisselink
2023-01-07 23:06:47 +01:00
parent e595cd2a5d
commit fd64cc688a
21 changed files with 393 additions and 217 deletions

View File

@@ -8,10 +8,6 @@ template engine. Every `{if}` must be paired with a matching `{/if}`.
functions are recognized, such as *\|\|*, *or*, *&&*, *and*, functions are recognized, such as *\|\|*, *or*, *&&*, *and*,
*is\_array()*, etc. *is\_array()*, etc.
If securty is enabled, only PHP functions from `$php_functions` property
of the securty policy are allowed. See the
[Security](#advanced.features.security) section for details.
The following is a list of recognized qualifiers, which must be The following is a list of recognized qualifiers, which must be
separated from surrounding elements by spaces. Note that items listed in separated from surrounding elements by spaces. Note that items listed in
\[brackets\] are optional. PHP equivalents are shown where applicable. \[brackets\] are optional. PHP equivalents are shown where applicable.

View File

@@ -53,19 +53,6 @@ instance of the Smarty\_Security class. These are the possible settings:
static classes. To disable access to all static classes set static classes. To disable access to all static classes set
\$static\_classes = null. \$static\_classes = null.
- `$php_functions` is an array of PHP functions that are considered
trusted and can be used from within template. To disable access to
all PHP functions set \$php\_functions = null. An empty array (
\$php\_functions = array() ) will allow all PHP functions. The
default is array(\'isset\', \'empty\', \'count\', \'sizeof\',
\'in\_array\', \'is\_array\',\'time\',\'nl2br\').
- `$php_modifiers` is an array of PHP functions that are considered
trusted and can be used from within template as modifier. To disable
access to all PHP modifier set \$php\_modifier = null. An empty
array ( \$php\_modifier = array() ) will allow all PHP functions.
The default is array(\'escape\',\'count\').
- `$streams` is an array of streams that are considered trusted and - `$streams` is an array of streams that are considered trusted and
can be used from within template. To disable access to all streams can be used from within template. To disable access to all streams
set \$streams = null. An empty array ( \$streams = array() ) will set \$streams = null. An empty array ( \$streams = array() ) will
@@ -105,10 +92,7 @@ Smarty\_Security class or create an instance of it.
<?php <?php
class My_Security_Policy extends \Smarty\Security { class My_Security_Policy extends \Smarty\Security {
// disable all PHP functions public $allow_constants = false;
public $php_functions = null;
// allow everthing as modifier
public $php_modifiers = array();
} }
$smarty = new Smarty(); $smarty = new Smarty();
// enable security // enable security
@@ -119,10 +103,7 @@ Smarty\_Security class or create an instance of it.
<?php <?php
$smarty = new Smarty(); $smarty = new Smarty();
$my_security_policy = new \Smarty\Security($smarty); $my_security_policy = new \Smarty\Security($smarty);
// disable all PHP functions $my_security_policy->allow_constants = false;
$my_security_policy->php_functions = null;
// allow everthing as modifier
$my_security_policy->php_modifiers = array();
// enable security // enable security
$smarty->enableSecurity($my_security_policy); $smarty->enableSecurity($my_security_policy);
?> ?>

View File

@@ -11,6 +11,7 @@
namespace Smarty\Compile; namespace Smarty\Compile;
use Smarty\Compiler\Template; use Smarty\Compiler\Template;
use Smarty\CompilerException;
/** /**
* Smarty Internal Plugin Compile Registered Function Class * Smarty Internal Plugin Compile Registered Function Class
@@ -28,6 +29,13 @@ class FunctionCallCompiler extends Base {
*/ */
public $optional_attributes = ['_any']; public $optional_attributes = ['_any'];
/**
* Shorttag attribute order defined by its names
*
* @var array
*/
protected $shorttag_order = ['var1', 'var2', 'var3'];
/** /**
* Compiles code for the execution of a registered function * Compiles code for the execution of a registered function
* *
@@ -42,12 +50,14 @@ class FunctionCallCompiler extends Base {
* @throws \Smarty\Exception * @throws \Smarty\Exception
*/ */
public function compile($args, Template $compiler, $parameter = [], $tag = null, $function = null) { public function compile($args, Template $compiler, $parameter = [], $tag = null, $function = null) {
// check and get attributes // check and get attributes
$_attr = $this->getAttributes($compiler, $args); $_attr = $this->getAttributes($compiler, $args);
unset($_attr['nocache']); unset($_attr['nocache']);
if (!$functionHandler = $compiler->smarty->getFunctionHandler($function)) {
$functionHandler = $compiler->smarty->getFunctionHandler($function); throw new CompilerException("Cannot compile unknown function $function.");
}
// not cacheable? // not cacheable?
$compiler->tag_nocache = $compiler->tag_nocache || !$functionHandler->isCacheable(); $compiler->tag_nocache = $compiler->tag_nocache || !$functionHandler->isCacheable();
@@ -65,6 +75,6 @@ class FunctionCallCompiler extends Base {
if (!empty($parameter['modifierlist'])) { if (!empty($parameter['modifierlist'])) {
$output = $compiler->compileModifier($parameter['modifierlist'], $output); $output = $compiler->compileModifier($parameter['modifierlist'], $output);
} }
return "<?php echo {$output};?>\n"; return $output;
} }
} }

View File

@@ -529,77 +529,6 @@ class Template extends BaseCompiler {
return '$_smarty_tpl->getConfigVariable(' . $variable . ')'; return '$_smarty_tpl->getConfigVariable(' . $variable . ')';
} }
/**
* compile PHP function call
*
* @param string $name
* @param array $parameter
*
* @return string
* @throws \Smarty\CompilerException
*/
public function compilePHPFunctionCall($name, $parameter) {
if (!$this->smarty->security_policy || $this->smarty->security_policy->isTrustedPhpFunction($name, $this)) {
if (strcasecmp($name, 'isset') === 0 || strcasecmp($name, 'empty') === 0
|| strcasecmp($name, 'array') === 0 || is_callable($name)
) {
$func_name = smarty_strtolower_ascii($name);
if ($func_name === 'isset') {
if (count($parameter) === 0) {
$this->trigger_template_error('Illegal number of parameter in "isset()"');
}
$pa = [];
foreach ($parameter as $p) {
$pa[] = $this->syntaxMatchesVariable($p) ? 'isset(' . $p . ')' : '(' . $p . ' !== null )';
}
return '(' . implode(' && ', $pa) . ')';
} elseif (in_array(
$func_name,
[
'empty',
'reset',
'current',
'end',
'prev',
'next',
]
)
) {
if (count($parameter) !== 1) {
$this->trigger_template_error("Illegal number of parameter in '{$func_name()}'");
}
if ($func_name === 'empty') {
return $func_name . '(' .
str_replace("')->value", "',null,true,false)->value", $parameter[0]) . ')';
} else {
return $func_name . '(' . $parameter[0] . ')';
}
} else {
return $name . '(' . implode(',', $parameter) . ')';
}
} else {
$this->trigger_template_error("unknown function '{$name}'");
}
}
}
/**
* Determines whether the passed string represents a valid (PHP) variable.
* This is important, because `isset()` only works on variables and `empty()` can only be passed
* a variable prior to php5.5
*
* @param $string
*
* @return bool
*/
private 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));
}
/** /**
* This method is called from parser to process a text content section if strip is enabled * This method is called from parser to process a text content section if strip is enabled
* - remove text from inheritance child templates as they may generate output * - remove text from inheritance child templates as they may generate output
@@ -1278,7 +1207,11 @@ class Template extends BaseCompiler {
// check if tag is a function // check if tag is a function
if ($this->smarty->getFunctionHandler($base_tag)) { if ($this->smarty->getFunctionHandler($base_tag)) {
if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($base_tag, $this)) { if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($base_tag, $this)) {
return $this->functionCallCompiler->compile($args, $this, $parameter, $tag, $base_tag); return (new \Smarty\Compile\PrintExpressionCompiler())->compile(
[],
$this,
['value' => $this->compileFunctionCall($base_tag, $args, $parameter)]
);
} }
} }
@@ -1483,4 +1416,8 @@ class Template extends BaseCompiler {
); );
} }
public function compileFunctionCall(string $base_tag, array $args, array $parameter = []) {
return $this->functionCallCompiler->compile($args, $this, $parameter, $base_tag, $base_tag);
}
} }

View File

@@ -69,8 +69,10 @@ class DefaultExtension extends Base {
} }
switch ($functionName) { switch ($functionName) {
case 'count': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Count(); break;
case 'counter': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Counter(); break; case 'counter': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Counter(); break;
case 'cycle': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Cycle(); break; case 'cycle': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Cycle(); break;
case 'empty': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\EmptyHandler(); break;
case 'fetch': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Fetch(); break; case 'fetch': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Fetch(); break;
case 'html_checkboxes': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlCheckboxes(); break; case 'html_checkboxes': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlCheckboxes(); break;
case 'html_image': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlImage(); break; case 'html_image': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlImage(); break;
@@ -79,8 +81,12 @@ class DefaultExtension extends Base {
case 'html_select_date': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlSelectDate(); break; 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_select_time': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlSelectTime(); break;
case 'html_table': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlTable(); 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 'isset': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\IssetHandler(); break;
case 'mailto': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Mailto(); break; case 'mailto': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Mailto(); break;
case 'math': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Math(); break; case 'math': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Math(); break;
case 'time': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Time(); break;
} }
return $this->functionHandlers[$functionName] ?? null; return $this->functionHandlers[$functionName] ?? null;

View File

@@ -0,0 +1,36 @@
<?php
namespace Smarty\FunctionHandler;
use Smarty\Exception;
use Smarty\Template;
/**
* count(Countable|array $value, int $mode = COUNT_NORMAL): int
* If the optional mode parameter is set to COUNT_RECURSIVE (or 1), count() will recursively count the array.
* This is particularly useful for counting all the elements of a multidimensional array.
*
* Returns the number of elements in value. Prior to PHP 8.0.0, if the parameter was neither an array nor an object that
* implements the Countable interface, 1 would be returned, unless value was null, in which case 0 would be returned.
*/
class Count extends Base {
public function handle($params, Template $template) {
$params = array_values($params ?? []);
if (count($params) < 1 || count($params) > 2) {
throw new Exception("Invalid number of arguments for in_array. in_arrays expects 2 or 3 parameters.");
}
$value = $params[0];
if ($value instanceof \Countable) {
return $value->count();
}
$mode = count($params) == 2 ? (int) $params[1] : COUNT_NORMAL;
return count((array) $value, $mode);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Smarty\FunctionHandler;
use Smarty\Exception;
use Smarty\Template;
/**
* empty(mixed $var): bool
*
* Returns true if var does not exist or has a value that is empty or equal to zero, aka falsey, see conversion to
* boolean. Otherwise returns false.
*
* No warning is generated if the variable does not exist. That means empty() is essentially the concise equivalent
* to !isset($var) || $var == false.
*/
class EmptyHandler extends Base {
public function handle($params, Template $template) {
if (count($params) !== 1) {
throw new Exception("Invalid number of arguments for empty. empty expects exactly 1 parameter.");
}
return empty(reset($params));
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Smarty\FunctionHandler;
use Smarty\Exception;
use Smarty\Template;
/**
* in_array(mixed $needle, array $haystack, bool $strict = false): bool
* Returns true if needle is found in the array, false otherwise
*/
class InArray extends Base {
public function handle($params, Template $template) {
$params = array_values($params ?? []);
if (count($params) < 2 || count($params) > 3) {
throw new Exception("Invalid number of arguments for in_array. in_arrays expects 2 or 3 parameters.");
}
// default to false, true if param 3 is set to true
$needle = $params[0];
$haystack = (array) $params[1];
$strict = count($params) == 3 && $params[2];
return in_array($needle, $haystack, $strict);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Smarty\FunctionHandler;
use Smarty\Exception;
use Smarty\Template;
/**
* is_array(mixed $value): bool
* Returns true if value is an array, false otherwise.
*/
class IsArray extends Base {
public function handle($params, Template $template) {
if (count($params) !== 1) {
throw new Exception("Invalid number of arguments for is_array. is_array expects exactly 1 parameter.");
}
return is_array(reset($params));
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Smarty\FunctionHandler;
use Smarty\Exception;
use Smarty\Template;
/**
* Determines if a variable is declared and is different than null
* `isset(mixed $var, mixed ...$vars): bool`
*
* Returns true if var exists and has any value other than null. false otherwise.
*/
class IssetHandler extends Base {
public function handle($params, Template $template) {
if (count($params) === 0) {
throw new Exception("Invalid number of arguments for isset. isset expects at least 1 parameter.");
}
foreach ($params as $param) {
if (!isset($param)) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Smarty\FunctionHandler;
use Smarty\Exception;
use Smarty\Template;
/**
* is_array(mixed $value): bool
* Returns true if value is an array, false otherwise.
*/
class Time extends Base {
public function handle($params, Template $template) {
if (count($params) > 0) {
throw new Exception("Invalid number of arguments for time. time expects no parameters.");
}
return time();
}
}

View File

@@ -1037,7 +1037,7 @@ objectelement(res)::= PTR method(f). {
// function // function
// //
function(res) ::= ns1(f) OPENP params(p) CLOSEP. { function(res) ::= ns1(f) OPENP params(p) CLOSEP. {
res = $this->compiler->compilePHPFunctionCall(f, p); res = $this->compiler->compileFunctionCall(f, p);
} }
@@ -1071,7 +1071,7 @@ params(res) ::= expr(e). {
res = array(e); res = array(e);
} }
// kein parameter // no parameter
params(res) ::= . { params(res) ::= . {
res = array(); res = array();
} }

View File

@@ -94,24 +94,6 @@ class Security {
*/ */
public $trusted_static_properties = []; public $trusted_static_properties = [];
/**
* This is an array of trusted PHP functions.
* If empty all functions are allowed.
* To disable all PHP functions set $php_functions = null.
*
* @var array
*/
public $php_functions = ['isset', 'empty', 'count', 'sizeof', 'in_array', 'is_array', 'time',];
/**
* This is an array of trusted PHP modifiers.
* If empty all modifiers are allowed.
* To disable all modifier set $php_modifiers = null.
*
* @var array
*/
public $php_modifiers = ['escape', 'count', 'sizeof', 'nl2br',];
/** /**
* This is an array of allowed tags. * This is an array of allowed tags.
* If empty no restriction by allowed_tags. * If empty no restriction by allowed_tags.
@@ -216,27 +198,6 @@ class Security {
*/ */
protected $_secure_dir = []; protected $_secure_dir = [];
/**
* Cache for $php_resource_dir lookup
*
* @var array
*/
protected $_php_resource_dir = null;
/**
* Cache for $trusted_dir lookup
*
* @var array
*/
protected $_trusted_dir = null;
/**
* Cache for $_include_array lookup
*
* @var array
*/
protected $_include_dir = [];
/** /**
* @param Smarty $smarty * @param Smarty $smarty
*/ */
@@ -244,24 +205,6 @@ class Security {
$this->smarty = $smarty; $this->smarty = $smarty;
} }
/**
* Check if PHP function is trusted.
*
* @param string $function_name
* @param object $compiler compiler object
*
* @return boolean true if function is trusted
*/
public function isTrustedPhpFunction($function_name, $compiler) {
if (isset($this->php_functions)
&& (empty($this->php_functions) || in_array($function_name, $this->php_functions))
) {
return true;
}
$compiler->trigger_template_error("PHP function '{$function_name}' not allowed by security setting");
return false; // should not, but who knows what happens to the compiler in the future?
}
/** /**
* Check if static class is trusted. * Check if static class is trusted.
* *
@@ -317,25 +260,6 @@ class Security {
return false; // should not, but who knows what happens to the compiler in the future? return false; // should not, but who knows what happens to the compiler in the future?
} }
/**
* Check if PHP modifier is trusted.
*
* @param string $modifier_name
* @param object $compiler compiler object
*
* @return boolean true if modifier is trusted
* @deprecated
*/
public function isTrustedPhpModifier($modifier_name, $compiler) {
if (isset($this->php_modifiers)
&& (empty($this->php_modifiers) || in_array($modifier_name, $this->php_modifiers))
) {
return true;
}
$compiler->trigger_template_error("modifier '{$modifier_name}' not allowed by security setting");
return false; // should not, but who knows what happens to the compiler in the future?
}
/** /**
* Check if tag is trusted. * Check if tag is trusted.
* *

View File

@@ -64,7 +64,7 @@ class PHPUnit_Smarty extends PHPUnit\Framework\TestCase
*/ */
public static function setUpBeforeClass(): void public static function setUpBeforeClass(): void
{ {
error_reporting(E_ALL & ~E_STRICT); error_reporting(E_ALL & ~E_STRICT & ~E_DEPRECATED & ~E_USER_DEPRECATED);
self::$init = true; self::$init = true;
self::$pluginsdir =self::getSmartyPluginsDir(); self::$pluginsdir =self::getSmartyPluginsDir();
} }

View File

@@ -40,32 +40,9 @@ class SecurityTest extends PHPUnit_Smarty
/** /**
* test trusted PHP function * test trusted PHP function
*/ */
public function testTrustedPHPFunction() public function testTrustedFunction()
{ {
$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)}'));
}
/**
* test not trusted PHP function
*
*
*/
public function testNotTrustedPHPFunction()
{
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessage('PHP function \'sizeof\' not allowed by security setting');
$this->smarty->security_policy->php_functions = array('null');
$this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{sizeof($foo)}');
}
/**
* test not trusted PHP function at disabled security
*/
public function testDisabledTrustedPHPFunction()
{
$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)}'));
} }
/** /**
@@ -74,7 +51,7 @@ class SecurityTest extends PHPUnit_Smarty
*/ */
public function testTrustedModifier() public function testTrustedModifier()
{ {
$this->assertEquals("5", @$this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@sizeof}')); $this->assertEquals("5", @$this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@count}'));
} }
/** /**
@@ -87,21 +64,9 @@ class SecurityTest extends PHPUnit_Smarty
{ {
$this->expectException(\Smarty\Exception::class); $this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessage('modifier \'sizeof\' not allowed by security setting'); $this->expectExceptionMessage('modifier \'sizeof\' not allowed by security setting');
$this->smarty->security_policy->php_modifiers = array('null');
@$this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@sizeof}'); @$this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@sizeof}');
} }
/**
* test not trusted modifier at disabled security
* @deprecated
*/
public function testDisabledTrustedModifier()
{
$this->smarty->security_policy->php_modifiers = array('null');
$this->smarty->disableSecurity();
@$this->assertEquals("5", $this->smarty->fetch('string:{assign var=foo value=[1,2,3,4,5]}{$foo|@sizeof}'));
}
/** /**
* test allowed tags * test allowed tags
*/ */

View File

@@ -0,0 +1,28 @@
<?php
namespace UnitTests\TemplateSource\TagTests\PluginFunction;
class CountTest extends \PHPUnit_Smarty {
public function setUp(): void {
$this->setUpSmarty(__DIR__);
}
public function testBasicSyntax() {
$this->assertEquals('3', $this->smarty->fetch("string:{count([1,2,3])}"));
}
public function testNonRecursive() {
$this->assertEquals('3', $this->smarty->fetch("string:{count([1,2,[3,4]])}"));
}
public function testRecursive() {
$this->assertEquals('5', $this->smarty->fetch("string:{count([1,2,[3,4]], 1)}"));
}
public function testInvalidParameters() {
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessage('Invalid number of arguments');
$this->assertEquals("", $this->smarty->fetch("string:{count()}"));
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace UnitTests\TemplateSource\TagTests\PluginFunction;
class EmptyTest extends \PHPUnit_Smarty {
public function setUp(): void {
$this->setUpSmarty(__DIR__);
}
public function testBasicSyntax() {
$this->assertEquals("yay", $this->smarty->fetch("string:{if empty(\$noSuch)}yay{/if}"));
}
public function testEmptyStringIsEmpty() {
$this->assertEquals("yay", $this->smarty->fetch("string:{if empty('')}yay{/if}"));
}
public function testFalseIsEmpty() {
$this->smarty->assign('test', false);
$this->assertEquals("yay", $this->smarty->fetch("string:{if empty(\$test)}yay{/if}"));
}
public function testIntZeroIsEmpty() {
$this->smarty->assign('test', 0);
$this->assertEquals("yay", $this->smarty->fetch("string:{if empty(\$test)}yay{/if}"));
}
public function testStringZeroIsEmpty() {
$this->smarty->assign('test', '0');
$this->assertEquals("yay", $this->smarty->fetch("string:{if empty(\$test)}yay{/if}"));
}
public function testIntThreeIsNotEmpty() {
$this->smarty->assign('test', 3);
$this->assertEquals("nay", $this->smarty->fetch("string:{if empty(\$test)}yay{else}nay{/if}"));
}
public function testInvalidParameters() {
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessage('Invalid number of arguments');
$this->assertEquals("", $this->smarty->fetch("string:{empty(3, 'foo')}"));
}
}

View File

@@ -0,0 +1,27 @@
<?php
class InArrayTest extends \PHPUnit_Smarty {
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
}
public function testBasicSyntax()
{
$this->assertEquals("yay", $this->smarty->fetch("string:{if in_array(3,[3])}yay{/if}"));
}
public function testNotInArray()
{
$this->assertEquals("nay", $this->smarty->fetch("string:{if in_array(2,[3])}yay{else}nay{/if}"));
}
public function testInvalidParameters()
{
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessage('Invalid number of arguments');
$this->assertEquals("", $this->smarty->fetch("string:{in_array('foo')}"));
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace UnitTests\TemplateSource\TagTests\PluginFunction;
class IsArrayTest extends \PHPUnit_Smarty {
public function setUp(): void {
$this->setUpSmarty(__DIR__);
}
public function testBasicSyntax() {
$this->assertEquals("yay", $this->smarty->fetch("string:{if is_array([3])}yay{/if}"));
}
public function testIntNotIsArray() {
$this->assertEquals("nay", $this->smarty->fetch("string:{if is_array(2)}yay{else}nay{/if}"));
}
public function testStringNotIsArray() {
$this->assertEquals("nay", $this->smarty->fetch("string:{if is_array('foo')}yay{else}nay{/if}"));
}
public function testInvalidParameters() {
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessage('Invalid number of arguments');
$this->assertEquals("", $this->smarty->fetch("string:{is_array(3, 'foo')}"));
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace UnitTests\TemplateSource\TagTests\PluginFunction;
class IssetTest extends \PHPUnit_Smarty {
public function setUp(): void {
$this->setUpSmarty(__DIR__);
}
public function testBasicSyntax() {
$this->assertEquals("nay", $this->smarty->fetch("string:{if isset(\$noSuch)}yay{else}nay{/if}"));
}
public function testEmptyStringIsset() {
$this->assertEquals("yay", $this->smarty->fetch("string:{if isset('')}yay{/if}"));
}
public function testFalseIsset() {
$this->smarty->assign('test', false);
$this->assertEquals("yay", $this->smarty->fetch("string:{if isset(\$test)}yay{/if}"));
}
public function testIntZeroIsset() {
$this->smarty->assign('test', 0);
$this->assertEquals("yay", $this->smarty->fetch("string:{if isset(\$test)}yay{/if}"));
}
public function testMultivar() {
$this->smarty->assign('test', 0);
$this->smarty->assign('test2', 'pizza');
$this->assertEquals("yay", $this->smarty->fetch("string:{if isset(\$test, \$test2)}yay{/if}"));
}
public function testMultivarOneNotset() {
$this->smarty->assign('test', 0);
$this->assertEquals("nay", $this->smarty->fetch("string:{if isset(\$test, \$test2)}yay{else}nay{/if}"));
}
public function testInvalidParameters() {
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessage('Invalid number of arguments');
$this->assertEquals("", $this->smarty->fetch("string:{empty(3, 'foo')}"));
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace UnitTests\TemplateSource\TagTests\PluginFunction;
class TimeTest extends \PHPUnit_Smarty {
public function setUp(): void {
$this->setUpSmarty(__DIR__);
}
public function testBasicSyntax() {
$this->assertStringMatchesFormat('%d', $this->smarty->fetch("string:{time()}"));
}
public function testInvalidParameters() {
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessage('Invalid number of arguments');
$this->assertEquals("", $this->smarty->fetch("string:{time(3, 'foo')}"));
}
}