Compare commits

...

71 Commits

Author SHA1 Message Date
Simon Wisselink cbcd66e1de Merge branch 'release/5.5.1' 2025-05-19 11:29:42 +02:00
Simon Wisselink 46cd224efb version bump 2025-05-19 11:29:40 +02:00
Simon Wisselink d3b716a0b9 changelog 2025-05-19 11:29:30 +02:00
pharixces 693502c341 Bugfix/bcpluginsadapter support modifiercompiler (#1132)
* Add support for modifiercompiler in the BCPluginsAdapter class.

---------

Co-authored-by: Anne Zijlstra <a.zijlstra@iwink.nl>
2025-05-19 11:28:10 +02:00
Shad bb968469fa add empty and in_array modifier doc (#1113) 2025-05-06 14:23:46 +02:00
Simon Wisselink 372f7cf41a Merge branch 'release/5.5.0' 2025-05-03 23:36:46 +02:00
Simon Wisselink f659193c94 version bump 2025-05-03 23:36:44 +02:00
Simon Wisselink 0b6166482a changelog 2025-05-03 23:36:27 +02:00
hirosan 4ff25bbe59 Support trailing comma in array (#1128) 2025-05-03 23:34:15 +02:00
hirosan afbd71b868 Update getting-started.md (#1111)
Indicate support for php8.4 in docs.
2025-04-16 08:11:00 +02:00
Simon Wisselink e26f82d02c Merge branch 'release/5.4.5' 2025-04-15 13:20:08 +02:00
Simon Wisselink 6ad6a35824 version bump 2025-04-15 13:20:06 +02:00
Simon Wisselink baa53399f5 changelog 2025-04-15 13:19:54 +02:00
gherosh 37bea77ea7 Update StringEval.php (#1126)
Fix: Implicitly marking parameter $_template as nullable is deprecated, the explicit nullable type must be used instead
2025-04-15 13:19:00 +02:00
Simon Wisselink 0d33f3acde Added sponsor 2025-04-13 22:34:16 +02:00
Simon Wisselink 05adbf45f3 Drop jit runs from CI unit tests.
Fixes #1125
2025-04-13 22:20:14 +02:00
Simon Wisselink df4795b803 Merge branch 'release/5.4.4' 2025-04-13 22:12:10 +02:00
Simon Wisselink 5401418258 version bump 2025-04-13 22:12:08 +02:00
Simon Wisselink a5bbba3f05 Fix syntax error occurring when registering a function plugin that ends with the string 'close' (#1124)
Fixes #1122
2025-04-10 23:47:44 +02:00
Simon Wisselink a0664a4ab2 Added funding options 2025-04-10 22:39:35 +02:00
Simon Wisselink a4b8466205 Added unit tests to prevent regressions of issue #1100 that was fixed in v4 2025-02-13 23:20:05 +01:00
Simon Wisselink 5d1ea5806a change SMARTY_VERSION to $smarty.version.
Fixes #1073
2024-12-28 17:40:25 +01:00
Simon Wisselink ab247c723b Add upgrading remarks on magic APi methods.
Fixes #979
2024-12-27 23:37:21 +01:00
Simon Wisselink fb997111f4 Add note to docs about plugins that expect parameters by reference 2024-12-27 23:08:17 +01:00
Simon Wisselink c6bff57950 Merge branch 'release/5.4.3' 2024-12-23 01:38:44 +01:00
Simon Wisselink 07faafe4da version bump 2024-12-23 01:38:41 +01:00
Simon Wisselink 295b7fb582 move to official php8.4 image for unit testing in CI 2024-12-23 01:34:55 +01:00
Simon Wisselink cf9de567c1 Restore special handling of isset and empty as it was in v4. Fixes #1063 (#1093)
* Restore special handling of isset and empty as it was in v4. Fixes #1063
2024-12-23 01:29:07 +01:00
Simon Wisselink f47ac761af replace/qualify call_user_func_array. (#1083)
Fixes #1074
2024-11-20 23:05:14 +01:00
Simon Wisselink 642a97adcc Merge branch 'release/5.4.2' 2024-11-20 22:18:16 +01:00
Simon Wisselink 3bba3ff5e9 version bump 2024-11-20 22:18:13 +01:00
Simon Wisselink b3b43af816 Add to changelog 2024-11-20 22:18:03 +01:00
Wim Wisselink 1b06b37db2 Add PHP 8.4 support to Smarty (#1043) 2024-11-20 15:59:26 +01:00
Simon Wisselink a1b4c9c551 Add unit tests for short hand template function definition and shorthand template function calls. 2024-10-06 22:06:39 +02:00
Simon Wisselink cd58df7a26 Merge branch 'release/5.4.1' 2024-08-30 01:10:45 +02:00
Simon Wisselink 70ed68ff5b version bump 2024-08-30 01:10:42 +02:00
Simon Wisselink 598ccde435 Changelog 2024-08-29 00:09:43 +02:00
Atsushi Matsuo cb09fda90d Update a workflow file for GitHub Actions to test on Windows (#1046) 2024-08-28 23:56:51 +02:00
Atsushi Matsuo c8f1853bfe Modify NullCoalescingTest.php and TernaryTest.php to prevent test failure on Windows (#1059) 2024-08-28 23:16:04 +02:00
Atsushi Matsuo 2f781e2e65 Fix unit tests to enable to run CacheResourceFileTest.php on Windows (#1055) 2024-08-28 23:15:57 +02:00
Atsushi Matsuo 30c6ee64ab Fix an issue that preventing the use of "extends:" to define the inheritance tree on Windows (#1056) 2024-08-28 23:09:34 +02:00
Simon Wisselink fd90f7eac9 Merge branch 'release/5.4.0' 2024-08-14 22:00:44 +02:00
Simon Wisselink 77b91a072b version bump 2024-08-14 22:00:42 +02:00
Simon Wisselink 9ede0e40fa changelog 2024-08-14 22:00:15 +02:00
Stephan Lueckl 1ccfca17d6 Fixing forced OpCache invalidation on every template include, which is resulting in fast raising wasted OpCache memory #1007 (#1047)
* Fixing forced OpCache Invalidation on every call, which is resulting in fast raising wasted memory
* Fix undefined $path variable warning
---------

Co-authored-by: Daniel Metzner <daniel.metzner@niceshops.com>
2024-08-14 21:58:51 +02:00
Shad d6153d4d4d add missing closing tr tag (#1039) 2024-07-01 16:38:18 +02:00
Amaury Bouchard 2289fa69f1 Improvement of auto-escaping (#1030)
* Evolution of auto-escaping: no double-escaping when using the 'escape' modifier; add the 'force' mode to the 'escape' modifier; add the 'raw' modifier.
* Add 'raw' modifier's documentation
---------

Co-authored-by: Simon Wisselink <s.wisselink@iwink.nl>
2024-06-30 13:25:30 +02:00
Simon Wisselink 3cb3585432 Merge branch 'release/5.3.1' 2024-06-16 21:51:13 +02:00
Simon Wisselink a2193eb4cf version bump 2024-06-16 21:51:11 +02:00
Simon Wisselink 8ecde47203 fixed error when using section with nocache.
Fixes #1034
2024-06-16 21:48:14 +02:00
Simon Wisselink b978cb348e add smarty logo svg for future use 2024-06-16 21:36:57 +02:00
Simon Wisselink 353ca06d07 Merge branch 'release/5.3.0' 2024-05-30 13:14:56 +02:00
Simon Wisselink 20c08ac40d version bump 2024-05-30 13:14:54 +02:00
Simon Wisselink 4aa1273a80 Merge branch 'support/5' 2024-05-30 13:11:33 +02:00
Simon Wisselink 2a87c65994 implemented and documented prependTemplateDir. (#1025) 2024-05-29 15:32:47 +02:00
Simon Wisselink cdee97d3f1 Merge branch 'release/5.2.0' 2024-05-28 23:45:16 +02:00
Simon Wisselink 06d6a5efd9 version bump 2024-05-28 23:45:14 +02:00
Simon Wisselink 0be92bc8a6 Merge pull request from GHSA-4rmg-292m-wg3w 2024-05-28 22:44:30 +02:00
Simon Wisselink 61db287b8f Scottchiefbaker/master (#1019)
* Add a PSR-4 loading script to allow Smarty to be used without Composer
authored-by: Scott Baker <scott@perturb.org>
2024-05-24 00:21:02 +02:00
Simon Wisselink 3293a873bd Remove unused attributes from config_load (#1004)
fixes #993
2024-04-29 10:01:40 +02:00
Simon Wisselink 8d53d3cbf2 Merge branch 'release/5.1.0' 2024-04-23 00:22:15 +02:00
Simon Wisselink 47c4864dd1 version bump 2024-04-23 00:22:13 +02:00
Simon Wisselink f411247aa1 Prevent notices on null to string conversion in Template::appendCode (#1002)
Fixes #996
2024-04-19 11:14:07 +02:00
Simon Wisselink 9a8702d937 Corrected invalid classnames in Runtime code for foreach (#1001)
Fixes #1000
2024-04-19 10:42:54 +02:00
Simon Wisselink 5ee4363000 Fix change in signature of getTemplateVars (#995) 2024-04-13 16:53:05 +02:00
Simon Wisselink 3232277bc5 Fix warning when calling hasVariable for an undefined variable (#978)
Fixes #977
2024-03-29 23:32:49 +01:00
Simon Wisselink bbd09c7bfa Merge branch 'release/5.0.2' into support/5 2024-03-28 11:23:18 +01:00
Simon Wisselink 52dc8adafb version bump 2024-03-28 11:23:16 +01:00
Simon Wisselink 6f054ecc2f Fix Smarty::assign() not returning when called with an array as first parameter. (#973)
Fixes #972
2024-03-28 11:22:29 +01:00
Simon Wisselink 4fec27ccc2 fix release tooling to support/5 branch 2024-03-27 23:05:16 +01:00
Simon Wisselink fea0d02d99 version bump 2024-03-27 23:03:40 +01:00
101 changed files with 2081 additions and 1291 deletions
+1
View File
@@ -0,0 +1 @@
github: [wisskid]
+5 -21
View File
@@ -23,6 +23,7 @@ jobs:
matrix:
os:
- ubuntu-latest
- windows-latest
php-version:
- "7.2"
@@ -32,31 +33,14 @@ jobs:
- "8.1"
- "8.2"
- "8.3"
- "8.4"
compiler:
- default
include:
- os: ubuntu-latest
php-version: "8.0"
compiler: jit
- os: ubuntu-latest
php-version: "8.1"
compiler: jit
- os: ubuntu-latest
php-version: "8.2"
compiler: jit
- os: ubuntu-latest
php-version: "8.3"
compiler: jit
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Override PHP ini values for JIT compiler
if: matrix.compiler == 'jit'
run: echo "PHP_INI_VALUES::assert.exception=1, zend.assertions=1, opcache.enable=1, opcache.enable_cli=1, opcache.optimization_level=-1, opcache.jit=1255, opcache.jit_buffer_size=32M" >> $GITHUB_ENV
uses: actions/checkout@v4
- name: Install PHP with extensions
uses: shivammathur/setup-php@v2
@@ -68,7 +52,7 @@ jobs:
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: vendor
key: v5r2-${{ runner.os }}-php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}
@@ -76,7 +60,7 @@ jobs:
v5r1-${{ runner.os }}-php-${{ matrix.php-version }}-
- name: Install dependencies
uses: php-actions/composer@v6
run: composer install
- name: Run make
run: make -B
+65 -2
View File
@@ -6,15 +6,78 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [5.5.1] - 2025-05-19
- Fix missing support for loading modifiercompilers from plugin dir in BCPluginsAdapter [#1132](https://github.com/smarty-php/smarty/pull/1132)
## [5.5.0] - 2025-05-03
- Support trailing comma in array [#1013](https://github.com/smarty-php/smarty/issues/1013)
## [5.4.5] - 2025-04-15
- Fixed deprecation notice in StringEval in PHP8.4 [#1119](https://github.com/smarty-php/smarty/issues/1119)
## [5.4.4] - 2025-04-13
- Fix syntax error occurring when registering a function plugin that ends with the string 'close' [#1122](https://github.com/smarty-php/smarty/issues/1122)
- Replace SMARTY_VERSION constant with $smarty.version in debug.tpl [#1073](https://github.com/smarty-php/smarty/issues/1073)
## [5.4.3] - 2024-12-23
- Fix PHP backtraces by qualifying/replacing `call_user_func_array` calls [#1074](https://github.com/smarty-php/smarty/issues/1074)
## [5.4.2] - 2024-11-20
- Support the deprecations introduced in PHP 8.4 and added tests for PHP 8.4 [#1043](https://github.com/smarty-php/smarty/pull/1043)
## [5.4.1] - 2024-08-29
- Enable (and fix) unit tests for Windows [#1046](https://github.com/smarty-php/smarty/pull/1046)
- Fix the use of "extends:" to define the inheritance tree on Windows [#1018](https://github.com/smarty-php/smarty/issues/1018)
## [5.4.0] - 2024-08-14
- Fixing forced OpCache invalidation on every template include, which is resulting in fast raising wasted OpCache memory [#1007](https://github.com/smarty-php/smarty/issues/1007)
- Improvement of auto-escaping [#1030](https://github.com/smarty-php/smarty/pull/1030)
## [5.3.1] - 2024-06-16
- Fixed error when using section with nocache [#1034](https://github.com/smarty-php/smarty/issues/1034)
## [5.3.0] - 2024-05-30
- Fix warning when calling hasVariable for an undefined variable [#977](https://github.com/smarty-php/smarty/issues/977)
- Added `$smarty->prependTemplateDir()` method [#1022](https://github.com/smarty-php/smarty/issues/1022)
## [5.2.0] - 2024-05-28
- Fixed a code injection vulnerability in extends-tag. This addresses CVE-2024-35226.
- Added `$smarty->setCacheModifiedCheck()` setter for cache_modified_check
- Added a PSR-4 loading script to allow Smarty to be used without Composer [#1017](https://github.com/smarty-php/smarty/pull/1017)
## [5.1.0] - 2024-04-22
- Prevent deprecation notices during compilation in PHP8.3 [#996](https://github.com/smarty-php/smarty/issues/996)
- Fix that getTemplateVars would return an array of objects instead of the assigned variables values [#994](https://github.com/smarty-php/smarty/issues/994)
- Fix Smarty::assign() not returning $this when called with an array as first parameter [#972](https://github.com/smarty-php/smarty/pull/972)
- Documented support for `{if $element is in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937)
- Added support for `{if $element is not in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937)
- Using stream variables in templates now throws a deprecation notice [#933](https://github.com/smarty-php/smarty/pull/933)
- Internal compiler classes always return a string (the internal has_code flag has been removed for simplicity) [#918](https://github.com/smarty-php/smarty/pull/918)
- Fix invalid classnames in Runtime code for foreach [#1000](https://github.com/smarty-php/smarty/issues/1000)
## [5.0.2] - 2024-03-28
- Fix Smarty::assign() not returning $this when called with an array as first parameter [#972](https://github.com/smarty-php/smarty/pull/972)
## [5.0.1] - 2024-03-27
- Fix error in Smarty\Smarty::compileAllTemplates() by including missing FilesystemIterator class [#966](https://github.com/smarty-php/smarty/issues/966)
## [5.0.0] - 2024-03-25
- Fixed that scoped variables would overwrite parent scope [#952](https://github.com/smarty-php/smarty/issues/952)
- Removed publicly accessible `$tpl->_var_stack` variable
### 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)
+8 -1
View File
@@ -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.
## Requirements
Smarty v5 can be run with PHP 7.2 to PHP 8.3.
Smarty v5 can be run with PHP 7.2 to PHP 8.4.
## Installation
Smarty versions 3.1.11 or later can be installed with [Composer](https://getcomposer.org/).
@@ -18,3 +18,10 @@ composer require smarty/smarty
````
More in the [Getting Started](./docs/getting-started.md) section of the docs.
## Sponsors
Smarty is sponsored by:
- Marc Laporte [@marclaporte](https://github.com/marclaporte)
Thank you!
-1
View File
@@ -1 +0,0 @@
- Internal compiler classes always return a string (the internal has_code flag has been removed for simplicity) [#918](https://github.com/smarty-php/smarty/pull/918)
-1
View File
@@ -1 +0,0 @@
- Using stream variables in templates now throws a deprecation notice [#933](https://github.com/smarty-php/smarty/pull/933)
-2
View File
@@ -1,2 +0,0 @@
- Documented support for `{if $element is in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937)
- Added support for `{if $element is not in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937)
-1
View File
@@ -1 +0,0 @@
- Fix Smarty::assign() not returning $this when called with an array as first parameter [#972](https://github.com/smarty-php/smarty/pull/972)
+5
View File
@@ -42,6 +42,11 @@ services:
service: base
build:
dockerfile: ./utilities/testrunners/php83/Dockerfile
php84:
extends:
service: base
build:
dockerfile: ./utilities/testrunners/php84/Dockerfile
volumes:
smarty-code:
+42 -10
View File
@@ -12,24 +12,27 @@ Use `getTemplateDir()` to retrieve the configured paths.
<?php
// set a single directory where the config files are stored
$smarty->setTemplateDir('./config');
$smarty->setTemplateDir('./templates');
// set multiple directories where config files are stored
$smarty->setTemplateDir(['./config', './config_2', './config_3']);
// set multiple directories where templates are stored
$smarty->setTemplateDir(['./templates', './templates_2', './templates_3']);
// add directory where config files are stored to the current list of dirs
$smarty->addTemplateDir('./config_1');
// add directory where templates files are stored to the current list of dirs
$smarty->addTemplateDir('./templates_1');
// add multiple directories to the current list of dirs
$smarty->addTemplateDir([
'./config_2',
'./config_3',
'./templates_2',
'./templates_3',
]);
// chaining of method calls
$smarty->setTemplateDir('./config')
->addTemplateDir('./config_1')
->addTemplateDir('./config_2');
$smarty->setTemplateDir('./templates')
->addTemplateDir('./templates_1')
->addTemplateDir('./templates_2');
// insert a template dir before exising template dirs
$smarty->prependTemplateDir('./more_important_templates')
// get all directories where config files are stored
$template_dirs = $smarty->getTemplateDir();
@@ -140,6 +143,35 @@ Enable auto-escaping for HTML as follows:
$smarty->setEscapeHtml(true);
```
When auto-escaping is enabled, the `|escape` modifier's default mode (`html`) has no effect,
to avoid double-escaping. It is possible to force it with the `force` mode.
Other modes (`htmlall`, `url`, `urlpathinfo`, `quotes`, `javascript`) may be used
with the result you might expect, without double-escaping.
Even when auto-escaping is enabled, you might want to display the content of a variable without
escaping it. To do so, use the `|raw` modifier.
Examples (with auto-escaping enabled):
```smarty
{* these three statements are identical *}
{$myVar}
{$myVar|escape}
{$myVar|escape:'html'}
{* no double-escaping on these statements *}
{$var|escape:'htmlall'}
{$myVar|escape:'url'}
{$myVar|escape:'urlpathinfo'}
{$myVar|escape:'quotes'}
{$myVar|escape:'javascript'}
{* no escaping at all *}
{$myVar|raw}
{* force double-escaping *}
{$myVar|escape:'force'}
```
## Disabling compile check
By default, Smarty tests to see if the
current template has changed since the last time
@@ -9,7 +9,6 @@
|----------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| file | Yes | The name of the config file to include |
| section | No | The name of the section to load |
| scope | no | How the scope of the loaded variables are treated, which must be one of local, parent or global. local means variables are loaded into the local template context. parent means variables are loaded into both the local context and the parent template that called it. global means variables are available to all templates. |
## Examples
@@ -0,0 +1,10 @@
# empty
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.
## Basic usage
```smarty
{if $myVar|empty}it's an empty variable{/if}
{if empty($myVar)}it's an empty variable{/if}
```
@@ -73,6 +73,6 @@ This snippet is useful for emails, but see also
<a href="mailto:{$EmailAddress|escape:'hex'}">{$EmailAddress|escape:'mail'}</a>
```
See also [escaping smarty parsing](../language-basic-syntax/language-escaping.md),
See also [auto-escaping](../../api/configuring.md#enabling-auto-escaping), [escaping smarty parsing](../language-basic-syntax/language-escaping.md),
[`{mailto}`](../language-custom-functions/language-function-mailto.md) and the [obfuscating email
addresses](../../appendixes/tips.md#obfuscating-e-mail-addresses) page.
addresses](../../appendixes/tips.md#obfuscating-e-mail-addresses) pages.
@@ -0,0 +1,17 @@
# in_array
test if value is contained in an array
## Basic usage
```smarty
{if in_array('value2', $myarray)} value2 is in myarray{/if}
```
Can be replaced by operator *is in*
```smarty
{if 'value2' is in $myarray}value2 is in myarray{/if}
```
See Also [operators](../language-basic-syntax/language-syntax-operators.md)
@@ -0,0 +1,8 @@
# raw
Prevents variable escaping when [auto-escaping](../../api/configuring.md#enabling-auto-escaping) is activated.
## Basic usage
```smarty
{$myVar|raw}
```
+9 -1
View File
@@ -1,7 +1,7 @@
# Getting started
## Requirements
Smarty can be run with PHP 7.2 to PHP 8.3.
Smarty can be run with PHP 7.2 to PHP 8.4.
## Installation
Smarty can be installed with [Composer](https://getcomposer.org/).
@@ -25,9 +25,17 @@ Here's how you create an instance of Smarty in your PHP scripts:
```php
<?php
// Instantiated via composer
require 'vendor/autoload.php';
use Smarty\Smarty;
$smarty = new Smarty();
// or ...
// Instantiated directly
require("/path/to/smarty/libs/Smarty.class.php");
use Smarty\Smarty;
$smarty = new Smarty();
```
Now that the library files are in place, it's time to set up the Smarty
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generator: Adobe Illustrator 25.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F5E0B4;}
.st1{fill:#383535;}
.st2{fill:#FBDE3D;}
.st3{fill:#8C919F;}
.st4{fill:#CACED5;}
.st5{fill:#FFFFFF;}
</style>
<g>
<polygon class="st0" points="782.2,925.8 733.4,643.2 996.4,532.7 745.7,396.4 823.6,120.2 560.7,232.2 391.6,0 313.7,274.7 26.5,260.1 194.4,491.3 3.6,705.5 289.4,721.3 340.5,1000 529.1,787 "/>
<path class="st1" d="M706.9,493.4c0-126-102.2-228.2-228.2-228.2c-126,0-228.2,102.2-228.2,228.2c0,81.8,43.1,153.6,107.8,193.8 v202.6l43.5,43.5l0.2-0.2h150.6l0.2,0.2l43.5-43.5V689C662.6,649,706.9,576.4,706.9,493.4z"/>
<path class="st2" d="M682.2,492.9c0-112.7-91.3-204-204-204s-204,91.3-204,204c0,78,43.8,145.8,108.1,180.1v93.6h191.7V673 C638.4,638.7,682.2,571,682.2,492.9z"/>
<g>
<polygon class="st3" points="382.7,790.4 382.7,881.1 412,910.3 544.9,910.3 574.1,881.1 574.1,790.4 "/>
<polygon class="st4" points="540,813.2 540,866.5 527,879.5 540.4,892.9 558.7,874.6 558.9,874.6 558.9,813.2 "/>
</g>
<path class="st5" d="M478.3,310.4c-5,0-9.1,4.1-9.1,9.1c0,5,4.1,9.1,9.1,9.1c90.7,0,164.3,73.5,164.3,164.3c0,5,4.1,9.1,9.1,9.1 s9.1-4.1,9.1-9.1C660.8,392.1,579.1,310.4,478.3,310.4z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+14
View File
@@ -49,6 +49,11 @@ $smarty->registerPlugin('modifier', 'my_special_func', 'my_special_func');
But you may want to consider writing a proper [extension](api/extending/extensions.md).
#### Passing parameters by reference
You cannot use plugins that expect a parameter by reference anymore. PHP-function such as `reset()`, `prev()`,
`next()` and `end()` can be registered as plugin, but they won't work because they expect a parameter by
reference and Smarty will try to pass it by value.
### Removed undocumented tags
Smarty 4 still supported some tags that have been carried over from previous version, but have never been documented.
@@ -102,6 +107,15 @@ Search your code for the following changes:
- `$smarty->assignByRef()` should be replaced with `$smarty->assign()`
- `$smarty->loadPlugin()` should be replaced with `$smarty->registerPlugin()`
### Removed undocumented magic API methods
Smarty v4 allowed setting (internal) properties for which no setter existed by using magic methods
that start with either `set` or `get`. This has been removed in Smarty 5.
For example, `$smarty->setErrorUnassigned(true);` would set the `error_unassigned` property.
Every setter of getter that was ever documented or unit tested has been kept.
### Removed PHP constants
The following constants have been removed to prevent global side effects.
+42
View File
@@ -0,0 +1,42 @@
<?php
/////////////////////////////////////////////////////////////////////
// This is a stub PSR-4 loading script that gets all the pieces of //
// Smarty 5.x loaded without requiring the use of composer. It's //
// not really a 'class' file, but the name is used so we're //
// backwards compatible with previous versions of Smarty. //
// //
// Example: //
// require_once("/path/to/smarty/libs/Smarty.class.php"); //
// //
// $smarty = new Smarty\Smarty; //
// $smarty->testInstall(); //
/////////////////////////////////////////////////////////////////////
define('__SMARTY_DIR', __DIR__ . '/../src/');
// Global function declarations
require_once(__SMARTY_DIR . "/functions.php");
spl_autoload_register(function ($class) {
// Class prefix
$prefix = 'Smarty\\';
// Does the class use the namespace prefix?
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
// If not, move to the next registered autoloader
return;
}
// Hack off the prefix part
$relative_class = substr($class, $len);
// Build a path to the include file
$file = __SMARTY_DIR . str_replace('\\', '/', $relative_class) . '.php';
// If the file exists, require it
if (file_exists($file)) {
require_once($file);
}
});
+3
View File
@@ -57,9 +57,11 @@ nav:
- 'date_format': 'designers/language-modifiers/language-modifier-date-format.md'
- 'debug_print_var': 'designers/language-modifiers/language-modifier-debug-print-var.md'
- 'default': 'designers/language-modifiers/language-modifier-default.md'
- 'empty': "designers/language-modifiers/language-modifier-empty.md"
- 'escape': 'designers/language-modifiers/language-modifier-escape.md'
- 'from_charset': 'designers/language-modifiers/language-modifier-from-charset.md'
- 'indent': 'designers/language-modifiers/language-modifier-indent.md'
- 'in_array': 'designers/language-modifiers/language-modifier-in_array.md'
- 'is_array': 'designers/language-modifiers/language-modifier-is_array.md'
- 'isset': 'designers/language-modifiers/language-modifier-isset.md'
- 'join': 'designers/language-modifiers/language-modifier-join.md'
@@ -68,6 +70,7 @@ nav:
- 'noprint': 'designers/language-modifiers/language-modifier-noprint.md'
- 'number_format': 'designers/language-modifiers/language-modifier-number-format.md'
- 'nl2br': 'designers/language-modifiers/language-modifier-nl2br.md'
- 'raw': 'designers/language-modifiers/language-modifier-raw.md'
- 'regex_replace': 'designers/language-modifiers/language-modifier-regex-replace.md'
- 'replace': 'designers/language-modifiers/language-modifier-replace.md'
- 'round': 'designers/language-modifiers/language-modifier-round.md'
+1
View File
@@ -14,3 +14,4 @@ $COMPOSE_CMD run --rm php80 ./run-tests.sh $@ && \
$COMPOSE_CMD run --rm php81 ./run-tests.sh $@ && \
$COMPOSE_CMD run --rm php82 ./run-tests.sh $@
$COMPOSE_CMD run --rm php83 ./run-tests.sh $@
$COMPOSE_CMD run --rm php84 ./run-tests.sh $@
+1 -1
View File
@@ -14,6 +14,6 @@ class BlockPluginWrapper extends Base {
}
public function handle($params, $content, Template $template, &$repeat) {
return call_user_func_array($this->callback, [$params, $content, &$template, &$repeat]);
return \call_user_func_array($this->callback, [$params, $content, &$template, &$repeat]);
}
}
+1 -1
View File
@@ -44,7 +44,7 @@ abstract class Base
*/
abstract public function process(
Template $_template,
Cached $cached = null,
?Cached $cached = null,
$update = false
);
+1 -1
View File
@@ -139,7 +139,7 @@ abstract class Custom extends Base
*/
public function process(
Template $_smarty_tpl,
\Smarty\Template\Cached $cached = null,
?\Smarty\Template\Cached $cached = null,
$update = false
) {
if (!$cached) {
+1 -1
View File
@@ -99,7 +99,7 @@ class File extends Base
*/
public function process(
Template $_smarty_tpl,
Cached $cached = null,
?Cached $cached = null,
$update = false
) {
$_smarty_tpl->getCached()->setValid(false);
+1 -1
View File
@@ -103,7 +103,7 @@ abstract class KeyValueStore extends Base
*/
public function process(
Template $_smarty_tpl,
Cached $cached = null,
?Cached $cached = null,
$update = false
) {
if (!$cached) {
@@ -24,22 +24,32 @@ class EscapeModifierCompiler extends Base {
}
switch ($esc_type) {
case 'html':
case 'force':
// in case of auto-escaping, and without the 'force' option, no double-escaping
if ($compiler->getSmarty()->escape_html && $esc_type != 'force')
return $params[0];
// otherwise, escape the variable
return 'htmlspecialchars((string)' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ', ' .
var_export($double_encode, true) . ')';
// no break
case 'htmlall':
$compiler->setRawOutput(true);
return 'htmlentities(mb_convert_encoding((string)' . $params[ 0 ] . ', \'UTF-8\', ' .
var_export($char_set, true) . '), ENT_QUOTES, \'UTF-8\', ' .
var_export($double_encode, true) . ')';
// no break
case 'url':
$compiler->setRawOutput(true);
return 'rawurlencode((string)' . $params[ 0 ] . ')';
case 'urlpathinfo':
$compiler->setRawOutput(true);
return 'str_replace("%2F", "/", rawurlencode((string)' . $params[ 0 ] . '))';
case 'quotes':
$compiler->setRawOutput(true);
// escape unescaped single quotes
return 'preg_replace("%(?<!\\\\\\\\)\'%", "\\\'", (string)' . $params[ 0 ] . ')';
case 'javascript':
$compiler->setRawOutput(true);
// escape quotes and backslashes, newlines, etc.
// see https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements
return 'strtr((string)' .
@@ -53,4 +63,4 @@ class EscapeModifierCompiler extends Base {
}
return '$_smarty_tpl->getSmarty()->getModifierCallback(\'escape\')(' . join(', ', $params) . ')';
}
}
}
@@ -0,0 +1,21 @@
<?php
namespace Smarty\Compile\Modifier;
use Smarty\Exception;
/**
* Smarty raw modifier plugin
* Type: modifier
* Name: raw
* Purpose: when escaping is enabled by default, generates a raw output of a variable
*
* @author Amaury Bouchard
*/
class RawModifierCompiler extends Base {
public function compile($params, \Smarty\Compiler\Template $compiler) {
$compiler->setRawOutput(true);
return ($params[0]);
}
}
+1 -1
View File
@@ -75,7 +75,7 @@ class ModifierCompiler extends Base {
}
}
}
return $output;
return (string)$output;
}
/**
+2 -1
View File
@@ -82,12 +82,13 @@ class PrintExpressionCompiler extends Base {
$output = $compiler->compileModifier($modifierlist, $output);
}
if ($compiler->getTemplate()->getSmarty()->escape_html) {
if ($compiler->getTemplate()->getSmarty()->escape_html && !$compiler->isRawOutput()) {
$output = "htmlspecialchars((string) ({$output}), ENT_QUOTES, '" . addslashes(\Smarty\Smarty::$_CHARSET) . "')";
}
}
$output = "<?php echo {$output};?>\n";
$compiler->setRawOutput(false);
}
return $output;
}
+3 -5
View File
@@ -43,7 +43,7 @@ class ConfigLoad extends Base {
* @var array
* @see BasePlugin
*/
protected $optional_attributes = ['section', 'scope'];
protected $optional_attributes = ['section'];
/**
* Attribute definition: Overwrites base class.
@@ -51,7 +51,7 @@ class ConfigLoad extends Base {
* @var array
* @see BasePlugin
*/
protected $option_flags = ['nocache', 'noscope'];
protected $option_flags = [];
/**
* Compiles code for the {config_load} tag
@@ -66,9 +66,7 @@ class ConfigLoad extends Base {
{
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache'] === true) {
$compiler->trigger_template_error('nocache option not allowed', null, true);
}
// save possible attributes
$conf_file = $_attr['file'];
$section = $_attr['section'] ?? 'null';
+2 -62
View File
@@ -32,7 +32,7 @@ class ExtendsTag extends Inheritance {
*
* @var array
*/
protected $optional_attributes = ['extends_resource'];
protected $optional_attributes = [];
/**
* Attribute definition: Overwrites base class.
@@ -64,29 +64,7 @@ class ExtendsTag extends Inheritance {
}
// add code to initialize inheritance
$this->registerInit($compiler, true);
$file = trim($_attr['file'], '\'"');
if (strlen($file) > 8 && substr($file, 0, 8) === 'extends:') {
// generate code for each template
$files = array_reverse(explode('|', substr($file, 8)));
$i = 0;
foreach ($files as $file) {
if ($file[0] === '"') {
$file = trim($file, '".');
} else {
$file = "'{$file}'";
}
$i++;
if ($i === count($files) && isset($_attr['extends_resource'])) {
$this->compileEndChild($compiler);
}
$this->compileInclude($compiler, $file);
}
if (!isset($_attr['extends_resource'])) {
$this->compileEndChild($compiler);
}
} else {
$this->compileEndChild($compiler, $_attr['file']);
}
$this->compileEndChild($compiler, $_attr['file']);
return '';
}
@@ -106,42 +84,4 @@ class ExtendsTag extends Inheritance {
(isset($template) ? ", {$template}, \$_smarty_current_dir" : '') . ");\n?>"
);
}
/**
* Add code for including subtemplate to end of template
*
* @param \Smarty\Compiler\Template $compiler
* @param string $template subtemplate name
*
* @throws \Smarty\CompilerException
* @throws \Smarty\Exception
*/
private function compileInclude(\Smarty\Compiler\Template $compiler, $template) {
$compiler->getParser()->template_postfix[] = new \Smarty\ParseTree\Tag(
$compiler->getParser(),
$compiler->compileTag(
'include',
[
$template,
['scope' => 'parent'],
]
)
);
}
/**
* Create source code for {extends} from source components array
*
* @param \Smarty\Template $template
*
* @return string
*/
public static function extendsSourceArrayCode(\Smarty\Template $template) {
$resources = [];
foreach ($template->getSource()->components as $source) {
$resources[] = $source->resource;
}
return $template->getLeftDelimiter() . 'extends file=\'extends:' . join('|', $resources) .
'\' extends_resource=true' . $template->getRightDelimiter();
}
}
+1 -1
View File
@@ -99,7 +99,7 @@ class Section extends ForeachSection {
if ($compiler->tag_nocache) {
// push a {nocache} tag onto the stack to prevent caching of this block
$this->openTag('nocache');
$this->openTag($compiler, 'nocache');
}
$this->openTag($compiler, 'section', ['section', $compiler->tag_nocache]);
+1 -1
View File
@@ -33,7 +33,7 @@ class SectionClose extends Base {
if ($nocache_pushed) {
// pop the pushed virtual nocache tag
$this->closeTag('nocache');
$this->closeTag($compiler, 'nocache');
}
$output = "<?php\n";
+1 -1
View File
@@ -41,7 +41,7 @@ class CodeFrame
$content = '',
$functions = '',
$cache = false,
\Smarty\Compiler\Template $compiler = null
?\Smarty\Compiler\Template $compiler = null
) {
// build property code
$properties[ 'version' ] = \Smarty\Smarty::SMARTY_VERSION;
+66 -26
View File
@@ -313,6 +313,12 @@ class Template extends BaseCompiler {
*/
private $noCacheStackDepth = 0;
/**
* disabled auto-escape (when set to true, the next variable output is not auto-escaped)
*
* @var boolean
*/
private $raw_output = false;
/**
* Initialize compiler
@@ -368,7 +374,7 @@ class Template extends BaseCompiler {
* @throws CompilerException
* @throws Exception
*/
public function compileTemplateSource(\Smarty\Template $template, \Smarty\Compiler\Template $parent_compiler = null) {
public function compileTemplateSource(\Smarty\Template $template, ?\Smarty\Compiler\Template $parent_compiler = null) {
try {
// save template object in compiler class
$this->template = $template;
@@ -403,21 +409,37 @@ class Template extends BaseCompiler {
}
// get template source
if (!empty($this->template->getSource()->components)) {
// we have array of inheritance templates by extends: resource
// generate corresponding source code sequence
$_content =
ExtendsTag::extendsSourceArrayCode($this->template);
$_compiled_code = '<?php $_smarty_tpl->getInheritance()->init($_smarty_tpl, true); ?>';
$i = 0;
$reversed_components = array_reverse($this->template->getSource()->components);
foreach ($reversed_components as $source) {
$i++;
if ($i === count($reversed_components)) {
$_compiled_code .= '<?php $_smarty_tpl->getInheritance()->endChild($_smarty_tpl); ?>';
}
$_compiled_code .= $this->compileTag(
'include',
[
var_export($source->resource, true),
['scope' => 'parent'],
]
);
}
$_compiled_code = $this->smarty->runPostFilters($_compiled_code, $this->template);
} else {
// get template source
$_content = $this->template->getSource()->getContent();
$_compiled_code = $this->smarty->runPostFilters(
$this->doCompile(
$this->smarty->runPreFilters($_content, $this->template),
true
),
$this->template
);
}
$_compiled_code = $this->smarty->runPostFilters(
$this->doCompile(
$this->smarty->runPreFilters($_content, $this->template),
true
),
$this->template
);
} catch (\Exception $e) {
if ($this->smarty->debugging) {
$this->smarty->getDebug()->end_compile($this->template);
@@ -483,7 +505,7 @@ class Template extends BaseCompiler {
*
* @return string
*/
public function compileVariable($variable) {
public function triggerTagNoCache($variable): void {
if (!strpos($variable, '(')) {
// not a variable variable
$var = trim($variable, '\'');
@@ -494,7 +516,6 @@ class Template extends BaseCompiler {
false
)->isNocache();
}
return '$_smarty_tpl->getValue(' . $variable . ')';
}
/**
@@ -643,7 +664,7 @@ class Template extends BaseCompiler {
$script = null;
$cacheable = true;
$result = call_user_func_array(
$result = \call_user_func_array(
$defaultPluginHandlerFunc,
[
$tag,
@@ -680,7 +701,8 @@ class Template extends BaseCompiler {
*
* @return string
*/
public function appendCode($left, $right) {
public function appendCode(string $left, string $right): string
{
if (preg_match('/\s*\?>\s?$/D', $left) && preg_match('/^<\?php\s+/', $right)) {
$left = preg_replace('/\s*\?>\s?$/D', "\n", $left);
$left .= preg_replace('/^<\?php\s+/', '', $right);
@@ -1056,7 +1078,7 @@ class Template extends BaseCompiler {
$prefixArray = array_merge($this->prefix_code, array_pop($this->prefixCodeStack));
$this->prefixCodeStack[] = [];
foreach ($prefixArray as $c) {
$code = $this->appendCode($code, $c);
$code = $this->appendCode($code, (string) $c);
}
$this->prefix_code = [];
return $code;
@@ -1124,12 +1146,12 @@ class Template extends BaseCompiler {
}
// check if tag is a function
if ($this->smarty->getFunctionHandler($base_tag)) {
if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($base_tag, $this)) {
if ($this->smarty->getFunctionHandler($tag)) {
if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) {
return (new \Smarty\Compile\PrintExpressionCompiler())->compile(
['nofilter'], // functions are never auto-escaped
$this,
['value' => $this->compileFunctionCall($base_tag, $args, $parameter)]
['value' => $this->compileFunctionCall($tag, $args, $parameter)]
);
}
}
@@ -1142,16 +1164,16 @@ class Template extends BaseCompiler {
}
// the default plugin handler is a handler of last resort, it may also handle not specifically registered tags.
if ($callback = $this->getPluginFromDefaultHandler($base_tag, Smarty::PLUGIN_COMPILER)) {
if ($callback = $this->getPluginFromDefaultHandler($tag, Smarty::PLUGIN_COMPILER)) {
if (!empty($parameter['modifierlist'])) {
throw new CompilerException('No modifiers allowed on ' . $base_tag);
throw new CompilerException('No modifiers allowed on ' . $tag);
}
$tagCompiler = new \Smarty\Compile\Tag\BCPluginWrapper($callback);
return $tagCompiler->compile($args, $this, $parameter);
}
if ($this->getPluginFromDefaultHandler($base_tag, Smarty::PLUGIN_FUNCTION)) {
return $this->defaultHandlerFunctionCallCompiler->compile($args, $this, $parameter, $tag, $base_tag);
return $this->defaultHandlerFunctionCallCompiler->compile($args, $this, $parameter, $tag, $tag);
}
if ($this->getPluginFromDefaultHandler($base_tag, Smarty::PLUGIN_BLOCK)) {
@@ -1258,9 +1280,10 @@ class Template extends BaseCompiler {
}
// call post compile callbacks
foreach ($this->postCompileCallbacks as $cb) {
$parameter = $cb;
$parameter[0] = $this;
call_user_func_array($cb[0], $parameter);
$callbackFunction = $cb[0];
$parameters = $cb;
$parameters[0] = $this;
$callbackFunction(...$parameters);
}
// return compiled code
return $this->prefixCompiledCode . $this->parser->retvalue . $this->postfixCompiledCode;
@@ -1469,4 +1492,21 @@ class Template extends BaseCompiler {
public function getTagStack(): array {
return $this->_tag_stack;
}
/**
* Should the next variable output be raw (true) or auto-escaped (false)
* @return bool
*/
public function isRawOutput(): bool {
return $this->raw_output;
}
/**
* Should the next variable output be raw (true) or auto-escaped (false)
* @param bool $raw_output
* @return void
*/
public function setRawOutput(bool $raw_output): void {
$this->raw_output = $raw_output;
}
}
+2 -2
View File
@@ -16,14 +16,14 @@ class CompilerException extends Exception {
* @param int $code The Exception code.
* @param string|null $filename The filename where the exception is thrown.
* @param int|null $line The line number where the exception is thrown.
* @param Throwable|null $previous The previous exception used for the exception chaining.
* @param \Throwable|null $previous The previous exception used for the exception chaining.
*/
public function __construct(
string $message = "",
int $code = 0,
?string $filename = null,
?int $line = null,
Throwable $previous = null
?\Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
+5 -2
View File
@@ -224,7 +224,10 @@ class Data
return $this->getValue($varName, $searchParents);
}
return array_merge($this->parent && $searchParents ? $this->parent->getTemplateVars() : [], $this->tpl_vars);
return array_merge(
$this->parent && $searchParents ? $this->parent->getTemplateVars() : [],
array_map(function(Variable $var) { return $var->getValue(); }, $this->tpl_vars)
);
}
/**
@@ -287,7 +290,7 @@ class Data
* @return bool
*/
public function hasVariable($varName): bool {
return !($this->getVariable($varName) instanceof UndefinedVariable);
return !($this->getVariable($varName, true, false) instanceof UndefinedVariable);
}
/**
+2 -2
View File
@@ -168,7 +168,6 @@ class BCPluginsAdapter extends Base {
}
public function loadPluginsFromDir(string $path) {
foreach([
'function',
'modifier',
@@ -177,6 +176,7 @@ class BCPluginsAdapter extends Base {
'prefilter',
'postfilter',
'outputfilter',
'modifiercompiler',
] as $type) {
foreach (glob($path . $type . '.?*.php') as $filename) {
$pluginName = $this->getPluginNameFromFilename($filename);
@@ -226,4 +226,4 @@ class BCPluginsAdapter extends Base {
return $matches[1];
}
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ class CallbackWrapper {
public function handle(...$params) {
try {
return call_user_func_array($this->callback, $params);
return ($this->callback)(...$params);
} catch (\ArgumentCountError $e) {
throw new Exception("Invalid number of arguments to modifier " . $this->modifierName);
}
+2 -1
View File
@@ -35,6 +35,7 @@ class DefaultExtension extends Base {
case 'lower': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\LowerModifierCompiler(); break;
case 'nl2br': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\Nl2brModifierCompiler(); break;
case 'noprint': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\NoPrintModifierCompiler(); break;
case 'raw': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\RawModifierCompiler(); break;
case 'round': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\RoundModifierCompiler(); break;
case 'str_repeat': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\StrRepeatModifierCompiler(); break;
case 'string_format': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\StringFormatModifierCompiler(); break;
@@ -753,4 +754,4 @@ class DefaultExtension extends Base {
return $string;
}
}
}
+3 -3
View File
@@ -47,18 +47,18 @@ class Dq extends Base
if ($subtree instanceof Code) {
$this->subtrees[ $last_subtree ]->data =
$parser->compiler->appendCode(
$this->subtrees[ $last_subtree ]->data,
(string) $this->subtrees[ $last_subtree ]->data,
'<?php echo ' . $subtree->data . ';?>'
);
} elseif ($subtree instanceof DqContent) {
$this->subtrees[ $last_subtree ]->data =
$parser->compiler->appendCode(
$this->subtrees[ $last_subtree ]->data,
(string) $this->subtrees[ $last_subtree ]->data,
'<?php echo "' . $subtree->data . '";?>'
);
} else {
$this->subtrees[ $last_subtree ]->data =
$parser->compiler->appendCode($this->subtrees[ $last_subtree ]->data, $subtree->data);
$parser->compiler->appendCode((string) $this->subtrees[ $last_subtree ]->data, (string) $subtree->data);
}
} else {
$this->subtrees[] = $subtree;
+2 -2
View File
@@ -62,9 +62,9 @@ class Tag extends Base
public function assign_to_var(\Smarty\Parser\TemplateParser $parser)
{
$var = $parser->compiler->getNewPrefixVariable();
$tmp = $parser->compiler->appendCode('<?php ob_start();?>', $this->data);
$tmp = $parser->compiler->appendCode('<?php ob_start();?>', (string) $this->data);
$tmp = $parser->compiler->appendCode($tmp, "<?php {$var}=ob_get_clean();?>");
$parser->compiler->appendPrefixCode((string) $tmp);
$parser->compiler->appendPrefixCode($tmp);
return $var;
}
}
+1 -1
View File
@@ -114,7 +114,7 @@ class Template extends Base
break;
case 'tag':
foreach ($chunk['subtrees'] as $subtree) {
$text = $parser->compiler->appendCode($text, $subtree->to_smarty_php($parser));
$text = $parser->compiler->appendCode($text, (string) $subtree->to_smarty_php($parser));
}
$code .= $text;
break;
File diff suppressed because it is too large Load Diff
+114 -32
View File
@@ -19,7 +19,7 @@ use \Smarty\ParseTree\Code;
use \Smarty\ParseTree\Dq;
use \Smarty\ParseTree\DqContent;
use \Smarty\ParseTree\Tag;
use \Smarty\CompilerException;
/**
* Smarty Template Parser Class
@@ -306,7 +306,8 @@ smartytag(A) ::= SIMPELOUTPUT(B). {
$attributes[] = 'nocache';
$var = $match[1];
}
A = $this->compiler->compilePrintExpression($this->compiler->compileVariable('\''.$var.'\''), $attributes);
$this->compiler->triggerTagNoCache($var);
A = $this->compiler->compilePrintExpression('$_smarty_tpl->getValue(\''.$var.'\')', $attributes);
}
// simple tag like {name}
@@ -375,7 +376,7 @@ outattr(A) ::= output(B) attributes(C). {
A = array(B,C);
}
output(A) ::= variable(B). {
output(A) ::= variablevalue(B). {
A = B;
}
output(A) ::= value(B). {
@@ -689,7 +690,8 @@ nullcoalescing(res) ::= expr(v) QMARK QMARK expr(e2). {
// ternary
//
ternary(res) ::= expr(v) QMARK DOLLARID(e1) COLON expr(e2). {
res = v.' ? '. $this->compiler->compileVariable('\''.substr(e1,1).'\'') . ' : '.e2;
$this->compiler->triggerTagNoCache(substr(e1,1));
res = v.' ? $_smarty_tpl->getValue(\''.substr(e1,1).'\') : '.e2;
}
ternary(res) ::= expr(v) QMARK value(e1) COLON expr(e2). {
@@ -706,7 +708,7 @@ ternary(res) ::= expr(v) QMARK COLON expr(e2). {
}
// value
value(res) ::= variable(v). {
value(res) ::= variablevalue(v). {
res = v;
}
@@ -724,7 +726,7 @@ value(res) ::= TYPECAST(t) value(v). {
res = t.v;
}
value(res) ::= variable(v) INCDEC(o). {
value(res) ::= variablevalue(v) INCDEC(o). {
res = v.o;
}
@@ -771,10 +773,10 @@ value(res) ::= OPENP expr(e) CLOSEP. {
res = '('. e .')';
}
value(res) ::= variable(v1) INSTANCEOF(i) ns1(v2). {
value(res) ::= variablevalue(v1) INSTANCEOF(i) ns1(v2). {
res = v1.i.v2;
}
value(res) ::= variable(v1) INSTANCEOF(i) variable(v2). {
value(res) ::= variablevalue(v1) INSTANCEOF(i) variablevalue(v2). {
res = v1.i.v2;
}
@@ -797,7 +799,8 @@ value(res) ::= varindexed(vi) DOUBLECOLON static_class_access(r). {
if (vi['var'] === '\'smarty\'') {
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ". (new \Smarty\Compile\SpecialVariableCompiler())->compile(array(),$this->compiler,vi['smarty_internal_index']).';?>');
} else {
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ". $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'].';?>');
$this->compiler->triggerTagNoCache(vi['var']);
$this->compiler->appendPrefixCode("<?php {$prefixVar} = \$_smarty_tpl->getValue(" . vi['var'] . ')'.vi['smarty_internal_index'].';?>');
}
res = $prefixVar .'::'.r[0].r[1];
}
@@ -805,7 +808,7 @@ value(res) ::= varindexed(vi) DOUBLECOLON static_class_access(r). {
// Smarty tag
value(res) ::= smartytag(st). {
$prefixVar = $this->compiler->getNewPrefixVariable();
$tmp = $this->compiler->appendCode('<?php ob_start();?>', st);
$tmp = $this->compiler->appendCode('<?php ob_start();?>', (string) st);
$this->compiler->appendPrefixCode($this->compiler->appendCode($tmp, "<?php {$prefixVar} = ob_get_clean();?>"));
res = $prefixVar;
}
@@ -847,54 +850,88 @@ ns1(res) ::= NAMESPACE(i). {
}
// variable lists
// multiple variables
variablelist(res) ::= variablelist(l) COMMA variable(v). {
res = array_merge(l,array(v));
}
variablelist(res) ::= variablelist(l) COMMA expr(e). {
res = array_merge(l,array(e));
}
// single variable
variablelist(res) ::= variable(v). {
res = array(v);
}
// single expression
variablelist(res) ::= expr(e). {
res = array(e);
}
// no variable
variablelist(res) ::= . {
res = array();
}
//
// variables
//
// Smarty variable (optional array)
variable(res) ::= DOLLARID(i). {
res = $this->compiler->compileVariable('\''.substr(i,1).'\'');
$this->compiler->triggerTagNoCache(substr(i,1));
res = array('$_smarty_tpl->hasVariable(\''.substr(i,1).'\')','$_smarty_tpl->getValue(\''.substr(i,1).'\')');
}
variable(res) ::= varindexed(vi). {
if (vi['var'] === '\'smarty\'') {
$smarty_var = (new \Smarty\Compile\SpecialVariableCompiler())->compile(array(),$this->compiler,vi['smarty_internal_index']);
res = $smarty_var;
res = array('true', $smarty_var);
} else {
// used for array reset,next,prev,end,current
$this->last_variable = vi['var'];
$this->last_index = vi['smarty_internal_index'];
res = $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'];
$this->compiler->triggerTagNoCache(vi['var']);
res = array('true', '$_smarty_tpl->getValue(' . vi['var'] . ')'.vi['smarty_internal_index']);
}
}
// variable with property
variable(res) ::= varvar(v) AT ID(p). {
res = '$_smarty_tpl->getVariable('. v .')->'.p;
res = array('true', '$_smarty_tpl->getVariable('. v .')->'.p);
}
// object
variable(res) ::= object(o). {
res = o;
res = array('true', o);
}
// config variable
variable(res) ::= HATCH ID(i) HATCH. {
configvariable(res) ::= HATCH ID(i) HATCH. {
res = $this->compiler->compileConfigVariable('\'' . i . '\'');
}
variable(res) ::= HATCH ID(i) HATCH arrayindex(a). {
configvariable(res) ::= HATCH ID(i) HATCH arrayindex(a). {
res = '(is_array($tmp = ' . $this->compiler->compileConfigVariable('\'' . i . '\'') . ') ? $tmp'.a.' :null)';
}
variable(res) ::= HATCH variable(v) HATCH. {
configvariable(res) ::= HATCH variablevalue(v) HATCH. {
res = $this->compiler->compileConfigVariable(v);
}
variable(res) ::= HATCH variable(v) HATCH arrayindex(a). {
configvariable(res) ::= HATCH variablevalue(v) HATCH arrayindex(a). {
res = '(is_array($tmp = ' . $this->compiler->compileConfigVariable(v) . ') ? $tmp'.a.' : null)';
}
variablevalue(res) ::= variable(v). {
res = v[1];
}
variablevalue(res) ::= configvariable(v). {
res = v;
}
varindexed(res) ::= DOLLARID(i) arrayindex(a). {
res = array('var'=>'\''.substr(i,1).'\'', 'smarty_internal_index'=>a);
}
@@ -918,14 +955,17 @@ arrayindex ::= . {
// single index definition
// Smarty2 style index
indexdef(res) ::= DOT DOLLARID(i). {
res = '['.$this->compiler->compileVariable('\''.substr(i,1).'\'').']';
$this->compiler->triggerTagNoCache(substr(i,1));
res = '[$_smarty_tpl->getValue(\''.substr(i,1).'\')]';
}
indexdef(res) ::= DOT varvar(v). {
res = '['.$this->compiler->compileVariable(v).']';
$this->compiler->triggerTagNoCache(v);
res = '[$_smarty_tpl->getValue(' . v . ')]';
}
indexdef(res) ::= DOT varvar(v) AT ID(p). {
res = '['.$this->compiler->compileVariable(v).'->'.p.']';
$this->compiler->triggerTagNoCache(v);
res = '[$_smarty_tpl->getValue(' . v . ')->'.p.']';
}
indexdef(res) ::= DOT ID(i). {
@@ -956,9 +996,10 @@ indexdef(res) ::= OPENB INTEGER(n) CLOSEB. {
res = '['.n.']';
}
indexdef(res) ::= OPENB DOLLARID(i) CLOSEB. {
res = '['.$this->compiler->compileVariable('\''.substr(i,1).'\'').']';
$this->compiler->triggerTagNoCache(substr(i,1));
res = '[$_smarty_tpl->getValue(\''.substr(i,1).'\')]';
}
indexdef(res) ::= OPENB variable(v) CLOSEB. {
indexdef(res) ::= OPENB variablevalue(v) CLOSEB. {
res = '['.v.']';
}
indexdef(res) ::= OPENB value(v) CLOSEB. {
@@ -1000,7 +1041,8 @@ varvarele(res) ::= ID(s). {
}
varvarele(res) ::= SIMPELOUTPUT(i). {
$var = trim(substr(i, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' $');
res = $this->compiler->compileVariable('\''.$var.'\'');
$this->compiler->triggerTagNoCache($var);
res = '$_smarty_tpl->getValue(\''.$var.'\')';
}
// variable sections of element
@@ -1015,7 +1057,8 @@ object(res) ::= varindexed(vi) objectchain(oc). {
if (vi['var'] === '\'smarty\'') {
res = (new \Smarty\Compile\SpecialVariableCompiler())->compile(array(),$this->compiler,vi['smarty_internal_index']).oc;
} else {
res = $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'].oc;
$this->compiler->triggerTagNoCache(vi['var']);
res = '$_smarty_tpl->getValue(' . vi['var'] . ')'.vi['smarty_internal_index'].oc;
}
}
@@ -1041,7 +1084,8 @@ objectelement(res)::= PTR varvar(v) arrayindex(a). {
if ($this->security) {
$this->compiler->trigger_template_error (self::ERR2);
}
res = '->{'.$this->compiler->compileVariable(v).a.'}';
$this->compiler->triggerTagNoCache(v);
res = '->{$_smarty_tpl->getValue(' . v . ')'.a.'}';
}
objectelement(res)::= PTR LDEL expr(e) RDEL arrayindex(a). {
@@ -1067,8 +1111,41 @@ objectelement(res)::= PTR method(f). {
//
// function
//
function(res) ::= ns1(f) OPENP params(p) CLOSEP. {
res = $this->compiler->compileModifierInExpression(f, p);
function(res) ::= ns1(f) OPENP variablelist(v) CLOSEP. {
if (f == 'isset') {
res = '(true';
if (count(v) == 0) {
throw new CompilerException("Invalid number of arguments for isset. isset expects at least one parameter.");
}
foreach (v as $value) {
if (is_array($value)) {
res .= ' && (' . $value[0] . ' && null !== (' . $value[1] . ' ?? null))';
} else {
res .= ' && (' . $value . ' !== null)';
}
}
res .= ')';
} elseif (f == 'empty') {
if (count(v) != 1) {
throw new CompilerException("Invalid number of arguments for empty. empty expects at exactly one parameter.");
}
if (is_array(v[0])) {
res .= '( !' . v[0][0] . ' || empty(' . v[0][1] . '))';
} else {
res = 'false == ' . v[0];
}
} else {
$p = array();
foreach (v as $value) {
if (is_array($value)) {
$p[] = $value[1];
} else {
$p[] = $value;
}
}
res = $this->compiler->compileModifierInExpression(f, $p);
}
}
@@ -1087,7 +1164,8 @@ method(res) ::= DOLLARID(f) OPENP params(p) CLOSEP. {
$this->compiler->trigger_template_error (self::ERR2);
}
$prefixVar = $this->compiler->getNewPrefixVariable();
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ".$this->compiler->compileVariable('\''.substr(f,1).'\'').';?>');
$this->compiler->triggerTagNoCache(substr(f,1));
$this->compiler->appendPrefixCode("<?php {$prefixVar} = \$_smarty_tpl->getValue('".substr(f,1).'\')'.';?>');
res = $prefixVar .'('. implode(',',p) .')';
}
@@ -1243,6 +1321,10 @@ arrayelements(res) ::= arrayelements(a1) COMMA arrayelement(a). {
res = a1.','.a;
}
arrayelements(res) ::= arrayelements(a) COMMA. {
res = a.',';
}
arrayelements ::= . {
return;
}
@@ -1282,7 +1364,7 @@ doublequoted(res) ::= doublequotedcontent(o). {
res = new Dq($this, o);
}
doublequotedcontent(res) ::= BACKTICK variable(v) BACKTICK. {
doublequotedcontent(res) ::= BACKTICK variablevalue(v) BACKTICK. {
res = new Code('(string)'.v);
}
@@ -1294,7 +1376,7 @@ doublequotedcontent(res) ::= DOLLARID(i). {
res = new Code('(string)$_smarty_tpl->getValue(\''. substr(i,1) .'\')');
}
doublequotedcontent(res) ::= LDEL variable(v) RDEL. {
doublequotedcontent(res) ::= LDEL variablevalue(v) RDEL. {
res = new Code('(string)'.v);
}
+1 -1
View File
@@ -112,7 +112,7 @@ abstract class BasePlugin
* @param Source $source source object
* @param Template|null $_template template object
*/
abstract public function populate(Source $source, \Smarty\Template $_template = null);
abstract public function populate(Source $source, ?\Smarty\Template $_template = null);
/**
* populate Source Object with timestamp and exists from Resource
+1 -1
View File
@@ -50,7 +50,7 @@ abstract class CustomPlugin extends BasePlugin {
* @param Source $source source object
* @param Template|null $_template template object
*/
public function populate(Source $source, Template $_template = null) {
public function populate(Source $source, ?Template $_template = null) {
$source->uid = sha1($source->type . ':' . $source->name);
$mtime = $this->fetchTimestamp($source->name);
if ($mtime !== null) {
+6 -2
View File
@@ -23,7 +23,7 @@ class ExtendsPlugin extends BasePlugin
*
* @throws Exception
*/
public function populate(Source $source, Template $_template = null)
public function populate(Source $source, ?Template $_template = null)
{
$uid = '';
$sources = array();
@@ -93,7 +93,11 @@ class ExtendsPlugin extends BasePlugin
*/
public function getBasename(Source $source)
{
return str_replace(':', '.', basename($source->getResourceName()));
$search = array(':');
if (\Smarty\Smarty::$_IS_WINDOWS) {
$search = array(':', '|');
}
return str_replace($search, '.', basename($source->getResourceName()));
}
/*
+7 -4
View File
@@ -32,7 +32,7 @@ class FilePlugin extends BasePlugin {
*
* @throws Exception
*/
public function populate(Source $source, Template $_template = null) {
public function populate(Source $source, ?Template $_template = null) {
$source->uid = sha1(
$source->name . ($source->isConfig ? $source->getSmarty()->_joined_config_dir :
@@ -56,11 +56,14 @@ class FilePlugin extends BasePlugin {
* @param Source $source source object
*/
public function populateTimestamp(Source $source) {
if (!$source->exists && $path = $this->getFilePath($source->name, $source->getSmarty(), $source->isConfig)) {
$source->timestamp = $source->exists = is_file($path);
$path = $this->getFilePath($source->name, $source->getSmarty(), $source->isConfig);
if (!$source->exists) {
$source->exists = ($path !== false && is_file($path));
}
if ($source->exists && $path) {
if ($source->exists && $path !== false) {
$source->timestamp = filemtime($path);
} else {
$source->timestamp = 0;
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ class StreamPlugin extends RecompiledPlugin {
*
* @return void
*/
public function populate(Source $source, Template $_template = null) {
public function populate(Source $source, ?Template $_template = null) {
$source->uid = false;
$source->content = $this->getContent($source);
$source->timestamp = $source->exists = !!$source->content;
+1 -1
View File
@@ -31,7 +31,7 @@ class StringEval extends RecompiledPlugin
*
* @return void
*/
public function populate(\Smarty\Template\Source $source, \Smarty\Template $_template = null)
public function populate(\Smarty\Template\Source $source, ?\Smarty\Template $_template = null)
{
$source->uid = sha1($source->name);
$source->timestamp = $source->exists = true;
+1 -1
View File
@@ -31,7 +31,7 @@ class StringPlugin extends BasePlugin {
*
* @return void
*/
public function populate(Source $source, Template $_template = null) {
public function populate(Source $source, ?Template $_template = null) {
$source->uid = sha1($source->name);
$source->timestamp = $source->exists = true;
}
+2 -2
View File
@@ -26,7 +26,7 @@ class DefaultPluginHandlerRuntime {
$script = null;
$cacheable = null;
return (call_user_func_array(
return (\call_user_func_array(
$this->defaultPluginHandler,
[
$tag,
@@ -54,7 +54,7 @@ class DefaultPluginHandlerRuntime {
$script = null;
$cacheable = null;
if (call_user_func_array(
if (\call_user_func_array(
$this->defaultPluginHandler,
[
$tag,
+8 -10
View File
@@ -116,22 +116,20 @@ class ForeachRuntime {
*
* @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0
* for empty elements
* @throws \Exception
*/
public function count($value) {
if ($value instanceof IteratorAggregate) {
public function count($value): int
{
if ($value instanceof \IteratorAggregate) {
// Note: getIterator() returns a Traversable, not an Iterator
// thus rewind() and valid() methods may not be present
return iterator_count($value->getIterator());
} elseif ($value instanceof Iterator) {
return $value instanceof Generator ? 1 : iterator_count($value);
} elseif ($value instanceof Countable) {
} elseif ($value instanceof \Iterator) {
return $value instanceof \Generator ? 1 : iterator_count($value);
} elseif ($value instanceof \Countable) {
return count($value);
} elseif ($value instanceof PDOStatement) {
return $value->rowCount();
} elseif ($value instanceof Traversable) {
return iterator_count($value);
}
return count((array)$value);
return count((array) $value);
}
/**
+1 -1
View File
@@ -162,7 +162,7 @@ class InheritanceRuntime {
private function processBlock(
Template $tpl,
\Smarty\Runtime\Block $block,
\Smarty\Runtime\Block $parent = null
?\Smarty\Runtime\Block $parent = null
) {
if ($block->hide && !isset($block->child)) {
return;
+25 -1
View File
@@ -54,7 +54,7 @@ class Smarty extends \Smarty\TemplateBase {
/**
* smarty version
*/
const SMARTY_VERSION = '5.0.1';
const SMARTY_VERSION = '5.5.1';
/**
* define caching modes
@@ -684,6 +684,21 @@ class Smarty extends \Smarty\TemplateBase {
return $this;
}
/**
* Adds a template directory before any existing directoires
*
* @param string $new_template_dir directory of template sources
* @param bool $is_config true for config_dir
*
* @return static current Smarty instance for chaining
*/
public function prependTemplateDir($new_template_dir, $is_config = false) {
$current_template_dirs = $is_config ? $this->config_dir : $this->template_dir;
array_unshift($current_template_dirs, $new_template_dir);
$this->setTemplateDir($current_template_dirs, $is_config);
return $this;
}
/**
* Add config directory(s)
*
@@ -2211,5 +2226,14 @@ class Smarty extends \Smarty\TemplateBase {
return $template;
}
/**
* Sets if Smarty should check If-Modified-Since headers to determine cache validity.
* @param bool $cache_modified_check
* @return void
*/
public function setCacheModifiedCheck($cache_modified_check): void {
$this->cache_modified_check = (bool) $cache_modified_check;
}
}
+3 -3
View File
@@ -115,7 +115,7 @@ class Template extends TemplateBase {
public function __construct(
$template_resource,
Smarty $smarty,
\Smarty\Data $_parent = null,
?\Smarty\Data $_parent = null,
$_cache_id = null,
$_compile_id = null,
$_caching = null,
@@ -248,7 +248,7 @@ class Template extends TemplateBase {
$caching,
$cache_lifetime,
array $extra_vars = [],
int $scope = null,
?int $scope = null,
?string $currentDir = null
) {
@@ -462,7 +462,7 @@ class Template extends TemplateBase {
* @return string
* @throws Exception
*/
public function createCodeFrame($content = '', $functions = '', $cache = false, \Smarty\Compiler\Template $compiler = null) {
public function createCodeFrame($content = '', $functions = '', $cache = false, ?\Smarty\Compiler\Template $compiler = null) {
return $this->getCodeFrameCompiler()->create($content, $functions, $cache, $compiler);
}
+12 -9
View File
@@ -136,7 +136,7 @@ class Compiled extends GeneratedPhpFile {
if ($this->exists && !$_smarty_tpl->getSmarty()->force_compile
&& !($_smarty_tpl->compile_check && $_smarty_tpl->getSource()->getTimeStamp() > $this->getTimeStamp())
) {
$this->loadCompiledTemplate($_smarty_tpl);
$this->loadCompiledTemplate($_smarty_tpl, false);
}
if (!$this->isValid) {
@@ -241,16 +241,19 @@ class Compiled extends GeneratedPhpFile {
* HHVM requires a workaround because of a PHP incompatibility
*
* @param Template $_smarty_tpl do not change/remove variable name, is used by compiled template
* @param bool $invalidateCachedFiles forces a revalidation of the file in opcache or apc cache (if available)
*
*/
private function loadCompiledTemplate(Template $_smarty_tpl) {
if (function_exists('opcache_invalidate')
&& (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api")) < 1)
) {
opcache_invalidate($this->filepath, true);
} elseif (function_exists('apc_compile_file')) {
apc_compile_file($this->filepath);
private function loadCompiledTemplate(Template $_smarty_tpl, bool $invalidateCachedFiles = true) {
if ($invalidateCachedFiles) {
if (function_exists('opcache_invalidate')
&& (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api")) < 1)
) {
opcache_invalidate($this->filepath, true);
} elseif (function_exists('apc_compile_file')) {
apc_compile_file($this->filepath);
}
}
if (defined('HHVM_VERSION')) {
eval('?>' . file_get_contents($this->filepath));
+4 -4
View File
@@ -134,9 +134,9 @@ class Source {
* @throws Exception
*/
public static function load(
Template $_template = null,
Smarty $smarty = null,
$template_resource = null
?Template $_template = null,
?Smarty $smarty = null,
$template_resource = null
) {
if ($_template) {
$smarty = $_template->getSmarty();
@@ -203,7 +203,7 @@ class Source {
*/
public function _getDefaultTemplate($default_handler) {
$_content = $_timestamp = null;
$_return = call_user_func_array(
$_return = \call_user_func_array(
$default_handler,
[$this->type, $this->name, &$_content, &$_timestamp, $this->smarty]
);
+1 -1
View File
@@ -179,7 +179,7 @@ abstract class TemplateBase extends Data {
* @api Smarty::createData()
*
*/
public function createData(Data $parent = null, $name = null) {
public function createData(?Data $parent = null, $name = null) {
/* @var Smarty $smarty */
$smarty = $this->getSmarty();
$dataObj = new Data($parent, $smarty, $name);
+2 -1
View File
@@ -108,7 +108,7 @@
</head>
<body>
<h1>Smarty {\Smarty\Smarty::SMARTY_VERSION} Debug Console
<h1>Smarty {$smarty.version} Debug Console
- {if isset($template_name)}{$template_name|debug_print_var nofilter} {/if}{if !empty($template_data)}Total Time {$execution_time|string_format:"%.5f"}{/if}</h1>
{if !empty($template_data)}
@@ -144,6 +144,7 @@
{$vars['attributes']|debug_print_var nofilter}
{/if}
</td>
</tr>
{/foreach}
</table>
+1 -1
View File
@@ -64,7 +64,7 @@ class PHPUnit_Smarty extends PHPUnit\Framework\TestCase
*/
public static function setUpBeforeClass(): void
{
error_reporting(E_ALL & ~E_STRICT & ~E_DEPRECATED & ~E_USER_DEPRECATED);
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
self::$init = true;
self::$pluginsdir =self::getSmartyPluginsDir();
}
@@ -65,15 +65,34 @@ class UndefinedTemplateVarTest extends PHPUnit_Smarty
*/
public function testError()
{
$this->smarty->error_unassigned = true;
$this->smarty->error_unassigned = true;
$this->expectException(PHPUnit\Framework\Error\Error::class);
$this->expectExceptionMessage('Undefined ');
$this->expectExceptionMessage('Undefined ');
$e1 = error_reporting();
$this->assertEquals('undefined = ', $this->smarty->fetch('001_main.tpl'));
$e2 = error_reporting();
$this->assertEquals($e1, $e2);
}
public function testNoError()
{
$this->smarty->error_unassigned = false;
$e1 = error_reporting();
$this->assertEquals('undefined = ', $this->smarty->fetch('001_main.tpl'));
$e2 = error_reporting();
$this->assertEquals($e1, $e2);
}
public function testNoErrorForIssetOrEmpty()
{
$this->smarty->error_unassigned = true;
$e1 = error_reporting();
$this->assertEquals('undefined = ', $this->smarty->fetch('001_isset.tpl'));
$this->assertEquals('undefined = ', $this->smarty->fetch('001_empty.tpl'));
$e2 = error_reporting();
$this->assertEquals($e1, $e2);
}
public function testUndefinedSimpleVar() {
$this->smarty->muteUndefinedOrNullWarnings();
$tpl = $this->smarty->createTemplate('string:a{if $undef}def{/if}b');
@@ -133,30 +152,30 @@ class UndefinedTemplateVarTest extends PHPUnit_Smarty
}
public function testDereferenceOnNull() {
$this->smarty->setErrorReporting(E_ALL & ~E_WARNING & ~E_NOTICE);
$this->smarty->muteUndefinedOrNullWarnings();
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
$this->smarty->assign('object', null);
$this->assertEquals("ab", $this->smarty->fetch($tpl));
}
public function testDereferenceOnNull() {
$this->smarty->setErrorReporting(E_ALL & ~E_WARNING & ~E_NOTICE);
$this->smarty->muteUndefinedOrNullWarnings();
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
$this->smarty->assign('object', null);
$this->assertEquals("ab", $this->smarty->fetch($tpl));
}
public function testDereferenceOnBool() {
$this->smarty->setErrorReporting(E_ALL & ~E_NOTICE);
$this->smarty->muteUndefinedOrNullWarnings();
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
$this->smarty->assign('object', false);
$this->assertEquals("ab", $this->smarty->fetch($tpl));
}
public function testDereferenceOnBool() {
$this->smarty->setErrorReporting(E_ALL & ~E_NOTICE);
$this->smarty->muteUndefinedOrNullWarnings();
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
$this->smarty->assign('object', false);
$this->assertEquals("ab", $this->smarty->fetch($tpl));
}
public function testDereferenceOnString() {
$this->smarty->setErrorReporting(E_ALL & ~E_NOTICE);
$this->smarty->muteUndefinedOrNullWarnings();
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
$this->smarty->assign('object', 'xyz');
$this->assertEquals("ab", $this->smarty->fetch($tpl));
}
public function testDereferenceOnString() {
$this->smarty->setErrorReporting(E_ALL & ~E_NOTICE);
$this->smarty->muteUndefinedOrNullWarnings();
$tpl = $this->smarty->createTemplate('string:a{if $object->myprop}def{/if}b');
$this->smarty->assign('object', 'xyz');
$this->assertEquals("ab", $this->smarty->fetch($tpl));
}
}
@@ -0,0 +1 @@
undefined = {if empty($foo)}{/if}
@@ -0,0 +1 @@
undefined = {if isset($foo)}{/if}
@@ -61,4 +61,68 @@ class AutoEscapeTest extends PHPUnit_Smarty
$this->assertEquals("<p>hi</p>", $this->smarty->fetch($tpl));
}
/**
* test autoescape + raw modifier
*/
public function testAutoEscapeRaw() {
$tpl = $this->smarty->createTemplate('eval:{$foo|raw}');
$tpl->assign('foo', '<a@b.c>');
$this->assertEquals("<a@b.c>", $this->smarty->fetch($tpl));
}
/**
* test autoescape + escape modifier = no double-escaping
*/
public function testAutoEscapeNoDoubleEscape() {
$tpl = $this->smarty->createTemplate('eval:{$foo|escape}');
$tpl->assign('foo', '<a@b.c>');
$this->assertEquals("&lt;a@b.c&gt;", $this->smarty->fetch($tpl));
}
/**
* test autoescape + escape modifier = force double-escaping
*/
public function testAutoEscapeForceDoubleEscape() {
$tpl = $this->smarty->createTemplate('eval:{$foo|escape:\'force\'}');
$tpl->assign('foo', '<a@b.c>');
$this->assertEquals("&amp;lt;a@b.c&amp;gt;", $this->smarty->fetch($tpl));
}
/**
* test autoescape + escape modifier = special escape
*/
public function testAutoEscapeSpecialEscape() {
$tpl = $this->smarty->createTemplate('eval:{$foo|escape:\'url\'}');
$tpl->assign('foo', 'aa bb');
$this->assertEquals("aa%20bb", $this->smarty->fetch($tpl));
}
/**
* test autoescape + escape modifier = special escape
*/
public function testAutoEscapeSpecialEscape2() {
$tpl = $this->smarty->createTemplate('eval:{$foo|escape:\'url\'}');
$tpl->assign('foo', '<BR>');
$this->assertEquals("%3CBR%3E", $this->smarty->fetch($tpl));
}
/**
* test autoescape + escape modifier = special escape
*/
public function testAutoEscapeSpecialEscape3() {
$tpl = $this->smarty->createTemplate('eval:{$foo|escape:\'htmlall\'}');
$tpl->assign('foo', '<BR>');
$this->assertEquals("&lt;BR&gt;", $this->smarty->fetch($tpl));
}
/**
* test autoescape + escape modifier = special escape
*/
public function testAutoEscapeSpecialEscape4() {
$tpl = $this->smarty->createTemplate('eval:{$foo|escape:\'javascript\'}');
$tpl->assign('foo', '<\'');
$this->assertEquals("<\\'", $this->smarty->fetch($tpl));
}
}
@@ -14,10 +14,13 @@ include_once __DIR__ . '/../_shared/CacheResourceTestCommon.php';
class CacheResourceFileTest extends CacheResourceTestCommon
{
private $directorySeparator;
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
parent::setUp();
$this->directorySeparator = preg_quote(DIRECTORY_SEPARATOR, '/');
$this->smarty->setCachingType('filetest');
}
@@ -38,7 +41,8 @@ class CacheResourceFileTest extends CacheResourceTestCommon
$this->smarty->setUseSubDirs(true);
$tpl = $this->smarty->createTemplate('helloworld.tpl');
$this->assertRegExp('/.*\/([a-f0-9]{2}\/){3}.*.php/', $tpl->getCached()->filepath);
$pattern = '/.*' . $this->directorySeparator . '([a-f0-9]{2}' . $this->directorySeparator . '){3}.*\.php/';
$this->assertRegExp($pattern, $tpl->getCached()->filepath);
}
/**
@@ -51,7 +55,8 @@ class CacheResourceFileTest extends CacheResourceTestCommon
$this->smarty->setUseSubDirs(true);
$tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar');
$this->assertRegExp('/.*\/foo\/bar\/([a-f0-9]{2}\/){3}.*.php/', $tpl->getCached()->filepath);
$pattern = '/.*' . $this->directorySeparator . 'foo' . $this->directorySeparator . 'bar' . $this->directorySeparator . '([a-f0-9]{2}' . $this->directorySeparator . '){3}.*\.php/';
$this->assertRegExp($pattern, $tpl->getCached()->filepath);
}
/**
@@ -63,7 +68,9 @@ class CacheResourceFileTest extends CacheResourceTestCommon
$this->smarty->cache_lifetime = 1000;
$this->smarty->setUseSubDirs(true);
$tpl = $this->smarty->createTemplate('helloworld.tpl', null, 'blar');
$this->assertRegExp('/.*\/blar\/([a-f0-9]{2}\/){3}.*.php/', $tpl->getCached()->filepath);
$pattern = '/.*' . $this->directorySeparator . 'blar' . $this->directorySeparator . '([a-f0-9]{2}' . $this->directorySeparator . '){3}.*\.php/';
$this->assertRegExp($pattern, $tpl->getCached()->filepath);
}
/**
@@ -75,7 +82,9 @@ class CacheResourceFileTest extends CacheResourceTestCommon
$this->smarty->cache_lifetime = 1000;
$this->smarty->setUseSubDirs(true);
$tpl = $this->smarty->createTemplate('helloworld.tpl', 'foo|bar', 'blar');
$this->assertRegExp('/.*\/foo\/bar\/blar\\/([a-f0-9]{2}\/){3}.*.php/', $tpl->getCached()->filepath);
$pattern = '/.*' . $this->directorySeparator . 'foo' . $this->directorySeparator . 'bar' . $this->directorySeparator . 'blar' . $this->directorySeparator . '([a-f0-9]{2}' . $this->directorySeparator . '){3}.*\.php/';
$this->assertRegExp($pattern, $tpl->getCached()->filepath);
}
/**
@@ -12,7 +12,7 @@ class Smarty_Resource_FiletestPlugin extends FilePlugin
* @param Source $source source object
* @param Template $_template template object
*/
public function populate(Source $source, Template $_template = null)
public function populate(Source $source, ?Template $_template = null)
{
parent::populate($source, $_template);
if ($source->exists) {
@@ -34,7 +34,7 @@ class Smarty_Resource_AmbiguousPlugin extends FilePlugin
* @param Source $source source object
* @param Template $_template template object
*/
public function populate(Source $source, Template $_template = null)
public function populate(Source $source, ?Template $_template = null)
{
$segment = '';
if ($this->segment) {
@@ -91,4 +91,13 @@ class FileResourceIndexedTest extends PHPUnit_Smarty
$this->assertNotEquals($tpl->getCached()->filepath, $tpl2->getCached()->filepath);
}
public function testPrependTemplatePath()
{
$this->smarty->setTemplateDir(__DIR__ . '/templates');
$this->smarty->prependTemplateDir(__DIR__ . '/templates_4');
$tpl = $this->smarty->createTemplate('dirname.tpl');
$this->assertEquals('templates_4', $this->smarty->fetch($tpl));
}
}
@@ -16,7 +16,7 @@ use Smarty\Template\Source;
class Smarty_Resource_Db extends RecompiledPlugin {
public function populate(Source $source, Template $_template = null) {
public function populate(Source $source, ?Template $_template = null) {
$source->uid = sha1($source->resource);
$source->timestamp = 1000000000;
$source->exists = true;
@@ -16,7 +16,7 @@ use Smarty\Template\Source;
class Smarty_Resource_Db2 extends RecompiledPlugin
{
public function populate(Source $source, Template $_template = null)
public function populate(Source $source, ?Template $_template = null)
{
$source->uid = sha1($source->resource);
$source->timestamp = 0;
@@ -15,7 +15,7 @@ use Smarty\Template\Source;
class Smarty_Resource_Db3 extends Smarty\Resource\BasePlugin
{
public function populate(Source $source, Template $_template = null)
public function populate(Source $source, ?Template $_template = null)
{
$source->uid = sha1($source->resource);
$source->timestamp = 0;
@@ -16,7 +16,7 @@ use Smarty\Template\Source;
class Smarty_Resource_Db4 extends Smarty\Resource\BasePlugin
{
public function populate(Source $source, Template $_template = null)
public function populate(Source $source, ?Template $_template = null)
{
$source->uid = sha1($source->resource);
$source->timestamp = 0;
@@ -1,112 +0,0 @@
<?php
/**
* Smarty PHPunit tests getTemplateVars method
*
* @author Uwe Tews
*/
/**
* class for getTemplateVars method test
*
*
*
*
*/
class GetTemplateVarsTest extends PHPUnit_Smarty
{
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
}
public function testInit()
{
$this->cleanDirs();
}
/**
* test root getTemplateVars single value
*/
public function testGetSingleTemplateVarScopeRoot()
{
$this->smarty->assign('foo', 'bar');
$this->smarty->assign('blar', 'buh');
$this->assertEquals("bar", $this->smarty->getTemplateVars('foo'));
}
/**
* test root getTemplateVars all values
*/
public function testGetAllTemplateVarsScopeRoot()
{
$this->smarty->assign('foo', 'bar');
$this->smarty->assign('blar', 'buh');
$vars = $this->smarty->getTemplateVars();
$this->assertTrue(is_array($vars));
$this->assertEquals("bar", $vars['foo']);
$this->assertEquals("buh", $vars['blar']);
}
/**
* test single variable with data object chain
*/
public function testGetSingleTemplateVarScopeAll()
{
$data1 = $this->smarty->createData($this->smarty);
$data2 = $this->smarty->createData($data1);
$this->smarty->assign('foo', 'bar');
$this->smarty->assign('blar', 'buh');
$this->assertEquals("bar", $data2->getTemplateVars('foo'));
}
/**
* test get all variables with data object chain
*/
public function testGetAllTemplateVarsScopeAll()
{
$data1 = $this->smarty->createData($this->smarty);
$data2 = $this->smarty->createData($data1);
$this->smarty->assign('foo', 'bar');
$data1->assign('blar', 'buh');
$data2->assign('foo2', 'bar2');
$vars = $data2->getTemplateVars(null);
$this->assertTrue(is_array($vars));
$this->assertEquals("bar", $vars['foo']);
$this->assertEquals("bar2", $vars['foo2']);
$this->assertEquals("buh", $vars['blar']);
}
/**
* test get all variables with data object chain search parents disabled
*/
public function testGetAllTemplateVarsScopeAllNoParents()
{
$data1 = $this->smarty->createData($this->smarty);
$data2 = $this->smarty->createData($data1);
$this->smarty->assign('foo', 'bar');
$data1->assign('blar', 'buh');
$data2->assign('foo2', 'bar2');
$vars = $data2->getTemplateVars(null, false);
$this->assertTrue(is_array($vars));
$this->assertFalse(isset($vars['foo']));
$this->assertEquals("bar2", $vars['foo2']);
$this->assertFalse(isset($vars['blar']));
}
/**
* test get single variables with data object chain search parents disabled
*/
public function testGetSingleTemplateVarsScopeAllNoParents()
{
error_reporting(error_reporting() & ~(E_NOTICE | E_USER_NOTICE));
$data1 = $this->smarty->createData($this->smarty);
$data2 = $this->smarty->createData($data1);
$this->smarty->assign('foo', 'bar');
$data1->assign('blar', 'buh');
$data2->assign('foo2', 'bar2');
$this->assertEquals("", $data2->getTemplateVars('foo', false));
$this->assertEquals("bar2", $data2->getTemplateVars('foo2', false));
$this->assertEquals("", $data2->getTemplateVars('blar', false));
}
}
@@ -1,2 +0,0 @@
# Ignore anything in here, but keep this directory
*
@@ -1,2 +0,0 @@
# Ignore anything in here, but keep this directory
*
@@ -192,6 +192,15 @@ class RegisterFunctionTest extends PHPUnit_Smarty
];
}
/**
* test registerPlugin for function name ending in 'close' #1122
*/
public function testRegisterFunctionEndingInClose()
{
$this->smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'window_close', 'myfunction');
$this->assertEquals('hello world 1', $this->smarty->fetch('eval:{window_close value=1}'));
}
}
function myfunction($params, $smarty)
@@ -0,0 +1,55 @@
<?php
// first class callables where introduced in PHP 8.1
if (PHP_VERSION_ID >= 80100) {
/**
* class for register modifier with (first class) callables tests
*
* @runTestsInSeparateProcess
* @preserveGlobalState disabled
* @backupStaticAttributes enabled
*/
class RegisterModifierFirstClassCallablesTest extends PHPUnit_Smarty
{
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
}
public function testInit()
{
$this->cleanDirs();
}
public function testRegisterFirstClassCallable()
{
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'testmodifier', eval('return strrev(...);'));
$this->assertEquals('mosredna', $this->smarty->fetch('string:{"andersom"|testmodifier}'));
}
public function testRegisterFirstClassCallableSameName()
{
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'mymodifier', eval('return strrev(...);'));
$this->assertEquals('mosredna', $this->smarty->fetch('string:{"andersom"|mymodifier}'));
}
public function testRegisterFirstClassCallableAsFunc()
{
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'kprint_r_out', eval('return strrev(...);'));
$this->smarty->assign('myVar', 'andersom');
$this->assertEquals('mosredna', $this->smarty->fetch('string:{kprint_r_out($myVar)}'));
}
public function testRegisterFirstClassCallableSameNameAsPhpFunc()
{
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'mymodifierfcc', eval('return strrev(...);'));
$this->assertEquals('mosredna', $this->smarty->fetch('string:{mymodifierfcc("andersom")}'));
}
}
}
function mymodifierfcc($a, $b, $c)
{
return "$a function $b $c";
}
@@ -135,6 +135,20 @@ class RegisterModifierTest extends PHPUnit_Smarty
$this->assertEquals($expectedValue, $this->smarty->fetch('string:' . $template));
}
public function testRegisterNativePhpFuncAsString()
{
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'strrev', 'strrev');
$this->smarty->assign('myVar', 'andersom');
$this->assertEquals('mosredna', $this->smarty->fetch('string:{strrev($myVar)}'));
}
public function testRegisterNativePhpFuncUnderDifferentName()
{
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'k_xyz_a', 'strrev');
$this->smarty->assign('myVar', 'andersom');
$this->assertEquals('mosredna', $this->smarty->fetch('string:{k_xyz_a($myVar)}'));
}
}
class WildcardExtension extends \Smarty\Extension\Base {
@@ -0,0 +1,126 @@
<?php
/**
* Smarty PHPunit tests getTemplateVars method
*/
class GetTemplateVarsTest extends PHPUnit_Smarty
{
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
}
public function testInit()
{
$this->cleanDirs();
}
/**
* test root getTemplateVars single value
*/
public function testGetSingleTemplateVarScopeRoot()
{
$this->smarty->assign('foo', 'bar');
$this->smarty->assign('blar', 'buh');
$this->assertEquals("bar", $this->smarty->getTemplateVars('foo'));
}
/**
* test root getTemplateVars all values
*/
public function testGetAllTemplateVarsScopeRoot()
{
$this->smarty->assign('foo', 'bar');
$this->smarty->assign('blar', 'buh');
$vars = $this->smarty->getTemplateVars();
$this->assertTrue(is_array($vars));
$this->assertEquals("bar", $vars['foo']);
$this->assertEquals("buh", $vars['blar']);
}
/**
* test single variable with data object chain
*/
public function testGetSingleTemplateVarScopeAll()
{
$data1 = $this->smarty->createData($this->smarty);
$data2 = $this->smarty->createData($data1);
$this->smarty->assign('foo', 'bar');
$this->smarty->assign('blar', 'buh');
$this->assertEquals("bar", $data2->getTemplateVars('foo'));
}
/**
* test get all variables with data object chain
*/
public function testGetAllTemplateVarsScopeAll()
{
$data1 = $this->smarty->createData($this->smarty);
$data2 = $this->smarty->createData($data1);
$this->smarty->assign('foo', 'bar');
$data1->assign('blar', 'buh');
$data2->assign('foo2', 'bar2');
$vars = $data2->getTemplateVars(null);
$this->assertTrue(is_array($vars));
$this->assertEquals("bar", $vars['foo']);
$this->assertEquals("bar2", $vars['foo2']);
$this->assertEquals("buh", $vars['blar']);
}
/**
* test get all variables with data object chain search parents disabled
*/
public function testGetAllTemplateVarsScopeAllNoParents()
{
$data1 = $this->smarty->createData($this->smarty);
$data2 = $this->smarty->createData($data1);
$this->smarty->assign('foo', 'bar');
$data1->assign('blar', 'buh');
$data2->assign('foo2', 'bar2');
$vars = $data2->getTemplateVars(null, false);
$this->assertTrue(is_array($vars));
$this->assertFalse(isset($vars['foo']));
$this->assertEquals("bar2", $vars['foo2']);
$this->assertFalse(isset($vars['blar']));
}
/**
* test get single variables with data object chain search parents disabled
*/
public function testGetSingleTemplateVarsScopeAllNoParents()
{
error_reporting(error_reporting() & ~(E_NOTICE | E_USER_NOTICE));
$data1 = $this->smarty->createData($this->smarty);
$data2 = $this->smarty->createData($data1);
$this->smarty->assign('foo', 'bar');
$data1->assign('blar', 'buh');
$data2->assign('foo2', 'bar2');
$this->assertEquals("", $data2->getTemplateVars('foo', false));
$this->assertEquals("bar2", $data2->getTemplateVars('foo2', false));
$this->assertEquals("", $data2->getTemplateVars('blar', false));
}
/**
* test that variable assigned by global assign in template is included in getTemplateVars
*/
public function testAssignedInTemplate()
{
$this->smarty->fetch('string:{assign var="b" value="x" scope="global"}');
$this->assertEquals('x', $this->smarty->getTemplateVars('b'));
}
/**
* test that getTemplateVars returns simple array of values
*/
public function testSimpleCallReturnsArrayWithAllValues()
{
$this->smarty->assign('foo', 'bar');
$this->smarty->assign('i', 3);
$vars = $this->smarty->getTemplateVars();
$this->assertArrayHasKey('foo', $vars);
$this->assertArrayHasKey('i', $vars);
$this->assertEquals('bar', $vars['foo']);
$this->assertEquals(3,$vars['i']);
}
}
@@ -0,0 +1,32 @@
<?php
/**
* Tests the ::hasVariable method
*/
class HasVariableTest extends PHPUnit_Smarty
{
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
}
public function testInit()
{
$this->cleanDirs();
}
public function testSimpleTrue()
{
$this->smarty->assign('foo', 'bar');
$this->assertTrue($this->smarty->hasVariable('foo'));
}
public function testSimpleFalse()
{
$this->smarty->assign('foo', 'bar');
$this->assertFalse($this->smarty->hasVariable('foox'));
}
}
@@ -4,7 +4,7 @@ class NullCoalescingTest extends PHPUnit_Smarty {
public function setUp(): void
{
$this->setUpSmarty('/tmp');
$this->setUpSmarty(sys_get_temp_dir());
$this->cleanDirs();
}
@@ -1193,8 +1193,38 @@ class CompileBlockExtendsTest extends PHPUnit_Smarty
);
}
public function testBlockWithAssign() {
$this->assertEquals('Captured content is: Content with lots of html here', $this->smarty->fetch('038_child.tpl'));
}
public function testBlockWithAssign() {
$this->assertEquals('Captured content is: Content with lots of html here', $this->smarty->fetch('038_child.tpl'));
}
/**
* Test escaping of file parameter
*/
public function testEscaping()
{
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessageMatches('/Unable to load.*/');
$this->assertEquals('hello world', $this->smarty->fetch('escaping.tpl'));
}
/**
* Test escaping of file parameter 2
*/
public function testEscaping2()
{
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessageMatches('/Unable to load.*/');
$this->assertEquals('hello world', $this->smarty->fetch('escaping2.tpl'));
}
/**
* Test escaping of file parameter 3
*/
public function testEscaping3()
{
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessageMatches('/Unable to load.*/');
$this->assertEquals('hello world', $this->smarty->fetch('escaping3.tpl'));
}
}
@@ -0,0 +1 @@
{extends "extends:helloworld.tpl', var_dump(shell_exec('ls')), 1, 2, 3);}}?>"}
@@ -0,0 +1 @@
{extends 'extends:"helloworld.tpl\', var_dump(shell_exec(\'ls\')), 1, 2, 3);}}?>'}
@@ -0,0 +1 @@
{extends file='extends:"helloworld.tpl'|cat:"', var_dump(shell_exec('ls')), 1, 2, 3);}}?>"}
@@ -41,10 +41,9 @@ class CompileIfTest extends PHPUnit_Smarty
$name = empty($testName) ? $testNumber : $testName;
$file = "testIf_{$name}.tpl";
$this->makeTemplateFile($file, $code);
$this->smarty->assignGlobal('file', $file);
$this->smarty->assign('file', $file);
$this->smarty->assign('bar', 'buh');
$this->assertEquals($result, $this->smarty->fetch($file),
"testIf - {$code} - {$name}");
$this->assertEquals($result, $this->smarty->fetch($file), "testIf - {$code} - {$name}");
}
/*
@@ -82,6 +82,18 @@ class CompileIncludeTest extends PHPUnit_Smarty
$this->assertEquals('I1I2I3', $content, $text);
}
/**
* test template name escaping
*/
public function testIncludeFilenameEscaping()
{
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessageMatches('/Unable to load.*/');
$tpl = $this->smarty->createTemplate('test_include_security.tpl');
$content = $this->smarty->fetch($tpl);
$this->assertEquals("hello world", $content);
}
/**
* test standard output
*
@@ -0,0 +1 @@
{include file="helloworld.tpl', var_dump(shell_exec('ls')), 1, 2, 3);}}?>"}
@@ -148,4 +148,10 @@ class CompileSectionTest extends PHPUnit_Smarty
);
}
public function testSectionWithNocache()
{
$source = 'string:{section name=module start=0 loop=1 nocache}{/section}';
$this->assertEquals('', $this->smarty->fetch($source));
}
}
@@ -442,4 +442,28 @@ class CompileFunctionTest extends PHPUnit_Smarty
$this->smarty->fetch('string:{function name=\'rce(){};echo "hi";function \'}{/function}');
}
/**
* test shorthand function definition with regular call
*/
public function testShorthand1()
{
$this->assertEquals("gribus", $this->smarty->fetch('shorthand1.tpl'));
}
/**
* test normal function definition with shorthand call
*/
public function testShorthand2()
{
$this->assertEquals("gribus", $this->smarty->fetch('shorthand2.tpl'));
}
/**
* test shorthand function definition with shorthand call
*/
public function testShorthand3()
{
$this->assertEquals("gribus", $this->smarty->fetch('shorthand3.tpl'));
}
}
@@ -0,0 +1,2 @@
{function blah}gribus{/function}
{call name=blah}
@@ -0,0 +1,2 @@
{function name=blah}gribus{/function}
{blah}
@@ -0,0 +1,2 @@
{function blah}gribus{/function}
{blah}
@@ -4,7 +4,7 @@ class TernaryTest extends PHPUnit_Smarty {
public function setUp(): void
{
$this->setUpSmarty('/tmp');
$this->setUpSmarty(sys_get_temp_dir());
$this->cleanDirs();
}
@@ -70,6 +70,8 @@ class ArrayTest extends PHPUnit_Smarty
array('{$foo=[1,2,[7,8,9],4,5]}{$x=2}{$foo.$x.0}', '7', 'T13', $i++),
array('{$foo=[1,2,[7,8,9],4,5]}{$x=0}{$foo.2.$x}', '7', 'T14', $i++),
array('{$foo=[1,2,[7,8,9],4,5]}{$x=[1,0]}{$foo.2.{$x.1}}', '7', 'T15', $i++),
array('{$foo=[1,2,3,4,5,]}{foreach $foo as $bar}{$bar}{/foreach}', '12345', 'T16', $i++),
array('{$foo=[1,2,3,4,5,[6,7,8,],]}{$foo[5][2]}', '8', 'T17', $i++),
);
}
}
@@ -32,4 +32,11 @@ class ExtendsIssue419Test extends PHPUnit_Smarty
$this->assertEquals('child', $this->smarty->fetch('extends:001_parent.tpl|001_child.tpl'));
}
public function testextendsSecurity()
{
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessageMatches('/Unable to load.*/');
$this->assertEquals('child', $this->smarty->fetch('string:{include "001_parent.tpl\', var_dump(shell_exec(\'ls\')), 1, 2, 3);}}?>"}'));
}
}
@@ -22,7 +22,7 @@ class My_Resource_Extendsall extends \Smarty\Resource\ExtendsPlugin
*
* @return void
*/
public function populate(Source $source, Template $_template = null)
public function populate(Source $source, ?Template $_template = null)
{
$uid = '';
$sources = array();

Some files were not shown because too many files have changed in this diff Show More