mirror of
https://github.com/smarty-php/smarty.git
synced 2026-08-04 04:24:18 +02:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 372f7cf41a | |||
| f659193c94 | |||
| 0b6166482a | |||
| 4ff25bbe59 | |||
| afbd71b868 | |||
| e26f82d02c | |||
| 6ad6a35824 | |||
| baa53399f5 | |||
| 37bea77ea7 | |||
| 0d33f3acde | |||
| 05adbf45f3 | |||
| df4795b803 | |||
| 5401418258 | |||
| a5bbba3f05 | |||
| a0664a4ab2 | |||
| a4b8466205 | |||
| 5d1ea5806a | |||
| ab247c723b | |||
| fb997111f4 | |||
| c6bff57950 | |||
| 07faafe4da | |||
| 295b7fb582 | |||
| cf9de567c1 | |||
| f47ac761af | |||
| 642a97adcc | |||
| 3bba3ff5e9 | |||
| b3b43af816 | |||
| 1b06b37db2 | |||
| a1b4c9c551 | |||
| cd58df7a26 | |||
| 70ed68ff5b | |||
| 598ccde435 | |||
| cb09fda90d | |||
| c8f1853bfe | |||
| 2f781e2e65 | |||
| 30c6ee64ab | |||
| fd90f7eac9 | |||
| 77b91a072b | |||
| 9ede0e40fa | |||
| 1ccfca17d6 | |||
| d6153d4d4d | |||
| 2289fa69f1 | |||
| 3cb3585432 | |||
| a2193eb4cf | |||
| 8ecde47203 | |||
| b978cb348e | |||
| 353ca06d07 | |||
| 20c08ac40d | |||
| 4aa1273a80 | |||
| 2a87c65994 | |||
| 3232277bc5 | |||
| bbd09c7bfa | |||
| 52dc8adafb | |||
| 6f054ecc2f | |||
| 4fec27ccc2 | |||
| fea0d02d99 |
@@ -0,0 +1 @@
|
||||
github: [wisskid]
|
||||
@@ -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
|
||||
|
||||
+44
-2
@@ -6,6 +6,48 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [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
|
||||
@@ -22,16 +64,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.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)
|
||||
- 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)
|
||||
|
||||
|
||||
@@ -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!
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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,8 @@
|
||||
# raw
|
||||
|
||||
Prevents variable escaping when [auto-escaping](../../api/configuring.md#enabling-auto-escaping) is activated.
|
||||
|
||||
## Basic usage
|
||||
```smarty
|
||||
{$myVar|raw}
|
||||
```
|
||||
@@ -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/).
|
||||
|
||||
@@ -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 |
@@ -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.
|
||||
|
||||
@@ -68,6 +68,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'
|
||||
|
||||
@@ -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 $@
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ abstract class Base
|
||||
*/
|
||||
abstract public function process(
|
||||
Template $_template,
|
||||
Cached $cached = null,
|
||||
?Cached $cached = null,
|
||||
$update = false
|
||||
);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ class ModifierCompiler extends Base {
|
||||
}
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
return (string)$output;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
+36
-13
@@ -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;
|
||||
@@ -499,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, '\'');
|
||||
@@ -510,7 +516,6 @@ class Template extends BaseCompiler {
|
||||
false
|
||||
)->isNocache();
|
||||
}
|
||||
return '$_smarty_tpl->getValue(' . $variable . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -659,7 +664,7 @@ class Template extends BaseCompiler {
|
||||
$script = null;
|
||||
$cacheable = true;
|
||||
|
||||
$result = call_user_func_array(
|
||||
$result = \call_user_func_array(
|
||||
$defaultPluginHandlerFunc,
|
||||
[
|
||||
$tag,
|
||||
@@ -1141,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)]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1159,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)) {
|
||||
@@ -1275,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;
|
||||
@@ -1486,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+1
-1
@@ -290,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+1022
-895
File diff suppressed because it is too large
Load Diff
+113
-31
@@ -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];
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
+16
-1
@@ -54,7 +54,7 @@ class Smarty extends \Smarty\TemplateBase {
|
||||
/**
|
||||
* smarty version
|
||||
*/
|
||||
const SMARTY_VERSION = '5.2.0';
|
||||
const SMARTY_VERSION = '5.5.0';
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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]
|
||||
);
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
|
||||
@@ -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("<a@b.c>", $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("&lt;a@b.c&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("<BR>", $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) {
|
||||
|
||||
+1
-1
@@ -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,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)
|
||||
|
||||
+55
@@ -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,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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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++),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
FROM php:8.4-cli-bullseye
|
||||
|
||||
## Basic utilities
|
||||
RUN apt-get update -yqq && apt-get install -y curl apt-utils git zip unzip
|
||||
|
||||
## Composer
|
||||
COPY ./utilities/testrunners/shared/install-composer.sh /root/install-composer.sh
|
||||
WORKDIR /root
|
||||
RUN sh ./install-composer.sh
|
||||
RUN mv ./composer.phar /usr/local/bin/composer
|
||||
Reference in New Issue
Block a user