mirror of
https://github.com/smarty-php/smarty.git
synced 2026-08-06 13:34:11 +02:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| cdee97d3f1 | |||
| 06d6a5efd9 | |||
| 0be92bc8a6 | |||
| 61db287b8f | |||
| 3293a873bd | |||
| 3232277bc5 | |||
| bbd09c7bfa | |||
| 52dc8adafb | |||
| 6f054ecc2f | |||
| 4fec27ccc2 | |||
| fea0d02d99 |
@@ -23,6 +23,7 @@ jobs:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
|
||||
php-version:
|
||||
- "7.2"
|
||||
@@ -32,6 +33,7 @@ jobs:
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
|
||||
compiler:
|
||||
- default
|
||||
@@ -49,10 +51,13 @@ jobs:
|
||||
- os: ubuntu-latest
|
||||
php-version: "8.3"
|
||||
compiler: jit
|
||||
- os: ubuntu-latest
|
||||
php-version: "8.4"
|
||||
compiler: jit
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Override PHP ini values for JIT compiler
|
||||
if: matrix.compiler == 'jit'
|
||||
@@ -68,7 +73,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 +81,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
|
||||
|
||||
+37
-2
@@ -6,6 +6,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [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)
|
||||
@@ -16,16 +51,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/).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
```
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
@@ -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);
|
||||
}
|
||||
});
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
+57
-18
@@ -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,
|
||||
@@ -1259,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;
|
||||
@@ -1470,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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+1016
-896
File diff suppressed because it is too large
Load Diff
+109
-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) .')';
|
||||
}
|
||||
|
||||
@@ -1282,7 +1360,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 +1372,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 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;
|
||||
|
||||
+25
-1
@@ -54,7 +54,7 @@ class Smarty extends \Smarty\TemplateBase {
|
||||
/**
|
||||
* smarty version
|
||||
*/
|
||||
const SMARTY_VERSION = '5.1.0';
|
||||
const SMARTY_VERSION = '5.4.3';
|
||||
|
||||
/**
|
||||
* 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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
*
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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