mirror of
https://github.com/smarty-php/smarty.git
synced 2026-08-10 23:41:23 +02:00
Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2272e4d819 | ||
|
|
f3c991962b | ||
|
|
f8f97b4e2d | ||
|
|
1bc7c722a3 | ||
|
|
02968a82b5 | ||
|
|
97aeb14c6f | ||
|
|
ed454551a3 | ||
|
|
f4b26a3cbf | ||
|
|
20a8026ccd | ||
|
|
27910bf2c1 | ||
|
|
cb95216671 | ||
|
|
d6ac3297df | ||
|
|
560475a2f2 | ||
|
|
382d66305d | ||
|
|
44bac8d58c | ||
|
|
f8e1ba76f7 | ||
|
|
629504485f | ||
|
|
71036be8be | ||
|
|
78f0cf5f65 | ||
|
|
64ad6442ca | ||
|
|
dff1955cd5 |
+1
-1
@@ -10,8 +10,8 @@
|
|||||||
/demo export-ignore
|
/demo export-ignore
|
||||||
/docs export-ignore
|
/docs export-ignore
|
||||||
/utilities export-ignore
|
/utilities export-ignore
|
||||||
|
/docker-compose.yml export-ignore
|
||||||
/.github export-ignore
|
/.github export-ignore
|
||||||
|
|
||||||
/.gitattributes export-ignore
|
/.gitattributes export-ignore
|
||||||
/.gitignore export-ignore
|
/.gitignore export-ignore
|
||||||
/make-release.sh export-ignore
|
/make-release.sh export-ignore
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
lexer/*.php
|
lexer/*.php
|
||||||
lexer/*.php.bak
|
lexer/*.php.bak
|
||||||
lexer/*.out
|
lexer/*.out
|
||||||
utilies/*.php
|
|
||||||
|
|
||||||
# Dev
|
# Dev
|
||||||
phpunit*
|
phpunit*
|
||||||
|
|||||||
+16
-1
@@ -6,8 +6,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed PHP8.1 deprecation errors in modifiers (upper, explode, number_format and replace) [#755](https://github.com/smarty-php/smarty/pull/755) and [#788](https://github.com/smarty-php/smarty/pull/788)
|
||||||
|
- Fixed use of `rand()` without a parameter in math function [#794](https://github.com/smarty-php/smarty/issues/794)
|
||||||
|
|
||||||
|
## [4.2.0] - 2022-08-01
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed problems with smarty_mb_str_replace [#549](https://github.com/smarty-php/smarty/issues/549)
|
||||||
|
- Fixed second parameter of unescape modifier not working [#777](https://github.com/smarty-php/smarty/issues/777)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Updated HTML of the debug template [#599](https://github.com/smarty-php/smarty/pull/599)
|
||||||
|
|
||||||
|
## [4.1.1] - 2022-05-17
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
- Prevent PHP injection through malicious block name or include file name. This addresses CVE-2022-
|
- Prevent PHP injection through malicious block name or include file name. This addresses CVE-2022-29221
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Exclude docs and demo from export and composer [#751](https://github.com/smarty-php/smarty/pull/751)
|
- Exclude docs and demo from export and composer [#751](https://github.com/smarty-php/smarty/pull/751)
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
Smarty currently supports the latest minor version of Smarty 3 and Smarty 4. (Smarty 4 has not been released yet.)
|
Smarty currently supports the latest minor version of Smarty 3 and Smarty 4.
|
||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
| ------- | ------------------ |
|
| ------- | ------------------ |
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
version: "2"
|
||||||
|
services:
|
||||||
|
base:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
working_dir: /app
|
||||||
|
entrypoint: sh ./utilities/testrunners/run-test.sh
|
||||||
|
php71:
|
||||||
|
extends:
|
||||||
|
service: base
|
||||||
|
build:
|
||||||
|
dockerfile: ./utilities/testrunners/php71/Dockerfile
|
||||||
|
php72:
|
||||||
|
extends:
|
||||||
|
service: base
|
||||||
|
build:
|
||||||
|
dockerfile: ./utilities/testrunners/php72/Dockerfile
|
||||||
|
php73:
|
||||||
|
extends:
|
||||||
|
service: base
|
||||||
|
build:
|
||||||
|
dockerfile: ./utilities/testrunners/php73/Dockerfile
|
||||||
|
php74:
|
||||||
|
extends:
|
||||||
|
service: base
|
||||||
|
build:
|
||||||
|
dockerfile: ./utilities/testrunners/php74/Dockerfile
|
||||||
|
php80:
|
||||||
|
extends:
|
||||||
|
service: base
|
||||||
|
build:
|
||||||
|
dockerfile: ./utilities/testrunners/php80/Dockerfile
|
||||||
|
php81:
|
||||||
|
extends:
|
||||||
|
service: base
|
||||||
|
build:
|
||||||
|
dockerfile: ./utilities/testrunners/php81/Dockerfile
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
Setting `$escape_html` to TRUE will escape all template variable output
|
Setting `$escape_html` to TRUE will escape all template variable output
|
||||||
by wrapping it in
|
by wrapping it in
|
||||||
`htmlspecialchars({$output}, ENT_QUOTES, SMARTY_RESOURCE_CHAR_SET);`,
|
`htmlspecialchars({$output}, ENT_QUOTES, $char_set);`,
|
||||||
which is the same as `{$variable|escape:"html"}`.
|
which is the same as `{$variable|escape:"html"}`.
|
||||||
|
|
||||||
Template designers can choose to selectively disable this feature by
|
Template designers can choose to selectively disable this feature by
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ Charset Encoding {#charset.encoding}
|
|||||||
================
|
================
|
||||||
|
|
||||||
There are a variety of encodings for textual data, ISO-8859-1 (Latin1)
|
There are a variety of encodings for textual data, ISO-8859-1 (Latin1)
|
||||||
and UTF-8 being the most popular. Unless specified otherwise with the
|
and UTF-8 being the most popular. Unless you change `Smarty::$_CHARSET`,
|
||||||
`SMARTY_RESOURCE_CHAR_SET` constant, Smarty recognizes `UTF-8` as the
|
Smarty recognizes `UTF-8` as the internal charset if
|
||||||
internal charset if [Multibyte String](https://www.php.net/mbstring) is
|
[Multibyte String](https://www.php.net/mbstring) is available,
|
||||||
available, `ISO-8859-1` if not.
|
`ISO-8859-1` if not.
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
@@ -36,8 +36,9 @@ available, `ISO-8859-1` if not.
|
|||||||
if (function_exists('mb_internal_charset')) {
|
if (function_exists('mb_internal_charset')) {
|
||||||
mb_internal_charset('EUC-JP');
|
mb_internal_charset('EUC-JP');
|
||||||
}
|
}
|
||||||
define('SMARTY_RESOURCE_CHAR_SET', 'EUC-JP');
|
|
||||||
require_once 'libs/Smarty.class.php';
|
require_once 'libs/Smarty.class.php';
|
||||||
|
Smarty::$_CHARSET = 'EUC-JP';
|
||||||
$smarty = new Smarty();
|
$smarty = new Smarty();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
/**
|
/**
|
||||||
* smarty version
|
* smarty version
|
||||||
*/
|
*/
|
||||||
const SMARTY_VERSION = '4.1.0';
|
const SMARTY_VERSION = '4.2.0';
|
||||||
/**
|
/**
|
||||||
* define variable scopes
|
* define variable scopes
|
||||||
*/
|
*/
|
||||||
|
|||||||
+34
-19
@@ -1,9 +1,9 @@
|
|||||||
{capture name='_smarty_debug' assign=debug_output}
|
{capture name='_smarty_debug' assign=debug_output}
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
<!DOCTYPE html>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Smarty Debug Console</title>
|
<title>Smarty Debug Console</title>
|
||||||
<style type="text/css">
|
<style>
|
||||||
{literal}
|
{literal}
|
||||||
body, h1, h2, h3, td, th, p {
|
body, h1, h2, h3, td, th, p {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
padding: 2px;
|
padding: 2px;
|
||||||
border-top: 1px solid black;
|
border-top: 1px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -67,11 +68,11 @@
|
|||||||
color: green;
|
color: green;
|
||||||
}
|
}
|
||||||
|
|
||||||
.odd {
|
tr:nth-child(odd) {
|
||||||
background-color: #eeeeee;
|
background-color: #eeeeee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.even {
|
tr:nth-child(even) {
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,13 +85,16 @@
|
|||||||
color: black;
|
color: black;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
#blue h3 {
|
#blue h3 {
|
||||||
color: blue;
|
color: blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#normal div {
|
#normal div {
|
||||||
color: black;
|
color: black;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
#table_assigned_vars th {
|
#table_assigned_vars th {
|
||||||
color: blue;
|
color: blue;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -99,7 +103,6 @@
|
|||||||
#table_config_vars th {
|
#table_config_vars th {
|
||||||
color: maroon;
|
color: maroon;
|
||||||
}
|
}
|
||||||
|
|
||||||
{/literal}
|
{/literal}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@@ -112,11 +115,11 @@
|
|||||||
<h2>included templates & config files (load time in seconds)</h2>
|
<h2>included templates & config files (load time in seconds)</h2>
|
||||||
<div>
|
<div>
|
||||||
{foreach $template_data as $template}
|
{foreach $template_data as $template}
|
||||||
<font color=brown>{$template.name}</font>
|
<span style="color: brown;">{$template.name}</span>
|
||||||
<br /> <span class="exectime">
|
<br> <span class="exectime">
|
||||||
(compile {$template['compile_time']|string_format:"%.5f"}) (render {$template['render_time']|string_format:"%.5f"}) (cache {$template['cache_time']|string_format:"%.5f"})
|
(compile {$template['compile_time']|string_format:"%.5f"}) (render {$template['render_time']|string_format:"%.5f"}) (cache {$template['cache_time']|string_format:"%.5f"})
|
||||||
</span>
|
</span>
|
||||||
<br />
|
<br>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -125,13 +128,22 @@
|
|||||||
|
|
||||||
<table id="table_assigned_vars">
|
<table id="table_assigned_vars">
|
||||||
{foreach $assigned_vars as $vars}
|
{foreach $assigned_vars as $vars}
|
||||||
<tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">
|
<tr>
|
||||||
<td><h3><font color=blue>${$vars@key}</font></h3>
|
<td>
|
||||||
{if isset($vars['nocache'])}<b>Nocache</b><br />{/if}
|
<h3 style="color: blue;">${$vars@key}</h3>
|
||||||
{if isset($vars['scope'])}<b>Origin:</b> {$vars['scope']|debug_print_var nofilter}{/if}
|
{if isset($vars['nocache'])}<strong>Nocache</strong><br>{/if}
|
||||||
|
{if isset($vars['scope'])}<strong>Origin:</strong> {$vars['scope']|debug_print_var nofilter}{/if}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<h3>Value</h3>
|
||||||
|
{$vars['value']|debug_print_var:10:80 nofilter}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{if isset($vars['attributes'])}
|
||||||
|
<h3>Attributes</h3>
|
||||||
|
{$vars['attributes']|debug_print_var nofilter}
|
||||||
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
<td><h3>Value</h3>{$vars['value']|debug_print_var:10:80 nofilter}</td>
|
|
||||||
<td>{if isset($vars['attributes'])}<h3>Attributes</h3>{$vars['attributes']|debug_print_var nofilter} {/if}</td>
|
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@@ -139,11 +151,14 @@
|
|||||||
|
|
||||||
<table id="table_config_vars">
|
<table id="table_config_vars">
|
||||||
{foreach $config_vars as $vars}
|
{foreach $config_vars as $vars}
|
||||||
<tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">
|
<tr>
|
||||||
<td><h3><font color=blue>#{$vars@key}#</font></h3>
|
<td>
|
||||||
{if isset($vars['scope'])}<b>Origin:</b> {$vars['scope']|debug_print_var nofilter}{/if}
|
<h3 style="color: blue;">#{$vars@key}#</h3>
|
||||||
|
{if isset($vars['scope'])}<strong>Origin:</strong> {$vars['scope']|debug_print_var nofilter}{/if}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{$vars['value']|debug_print_var:10:80 nofilter}
|
||||||
</td>
|
</td>
|
||||||
<td>{$vars['value']|debug_print_var:10:80 nofilter}</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ function smarty_function_math($params, $template)
|
|||||||
$number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
|
$number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
|
||||||
$functionsOrVars = '((?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*))';
|
$functionsOrVars = '((?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*))';
|
||||||
$operators = '[,+\/*\^%-]'; // Allowed math operators
|
$operators = '[,+\/*\^%-]'; // Allowed math operators
|
||||||
$regexp = '/^(('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*\((?1)+\)|\((?1)+\)))(?:'.$operators.'(?1))?)+$/';
|
$regexp = '/^(('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*\((?1)*\)|\((?1)*\)))(?:'.$operators.'(?1))?)+$/';
|
||||||
|
|
||||||
if (!preg_match($regexp, $equation)) {
|
if (!preg_match($regexp, $equation)) {
|
||||||
trigger_error("math: illegal characters", E_USER_WARNING);
|
trigger_error("math: illegal characters", E_USER_WARNING);
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Smarty plugin
|
||||||
|
*
|
||||||
|
* @package Smarty
|
||||||
|
* @subpackage PluginsModifier
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smarty explode modifier plugin
|
||||||
|
* Type: modifier
|
||||||
|
* Name: explode
|
||||||
|
* Purpose: split a string by a string
|
||||||
|
*
|
||||||
|
* @param string $separator
|
||||||
|
* @param string $string
|
||||||
|
* @param int|null $limit
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function smarty_modifier_explode($separator, $string, ?int $limit = null)
|
||||||
|
{
|
||||||
|
// provide $string default to prevent deprecation errors in PHP >=8.1
|
||||||
|
return explode($separator, $string ?? '', $limit ?? PHP_INT_MAX);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Smarty plugin
|
||||||
|
*
|
||||||
|
* @package Smarty
|
||||||
|
* @subpackage PluginsModifier
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smarty number_format modifier plugin
|
||||||
|
* Type: modifier
|
||||||
|
* Name: number_format
|
||||||
|
* Purpose: Format a number with grouped thousands
|
||||||
|
*
|
||||||
|
* @param float|null $num
|
||||||
|
* @param int $decimals
|
||||||
|
* @param string|null $decimal_separator
|
||||||
|
* @param string|null $thousands_separator
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function smarty_modifier_number_format(?float $num, int $decimals = 0, ?string $decimal_separator = ".", ?string $thousands_separator = ",")
|
||||||
|
{
|
||||||
|
// provide $num default to prevent deprecation errors in PHP >=8.1
|
||||||
|
return number_format($num ?? 0.0, $decimals, $decimal_separator, $thousands_separator);
|
||||||
|
}
|
||||||
@@ -14,20 +14,28 @@
|
|||||||
* @author Rodney Rehm
|
* @author Rodney Rehm
|
||||||
*
|
*
|
||||||
* @param array $params parameters
|
* @param array $params parameters
|
||||||
|
* @param Smarty_Internal_TemplateCompilerBase $compiler
|
||||||
*
|
*
|
||||||
* @return string with compiled code
|
* @return string with compiled code
|
||||||
*/
|
*/
|
||||||
function smarty_modifiercompiler_unescape($params)
|
function smarty_modifiercompiler_unescape($params, Smarty_Internal_TemplateCompilerBase $compiler)
|
||||||
{
|
{
|
||||||
if (!isset($params[ 1 ])) {
|
$compiler->template->_checkPlugins(
|
||||||
$params[ 1 ] = 'html';
|
array(
|
||||||
}
|
array(
|
||||||
|
'function' => 'smarty_literal_compiler_param',
|
||||||
|
'file' => SMARTY_PLUGINS_DIR . 'shared.literal_compiler_param.php'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$esc_type = smarty_literal_compiler_param($params, 1, 'html');
|
||||||
|
|
||||||
if (!isset($params[ 2 ])) {
|
if (!isset($params[ 2 ])) {
|
||||||
$params[ 2 ] = '\'' . addslashes(Smarty::$_CHARSET) . '\'';
|
$params[ 2 ] = '\'' . addslashes(Smarty::$_CHARSET) . '\'';
|
||||||
} else {
|
|
||||||
$params[ 2 ] = "'{$params[ 2 ]}'";
|
|
||||||
}
|
}
|
||||||
switch (trim($params[ 1 ], '"\'')) {
|
|
||||||
|
switch ($esc_type) {
|
||||||
case 'entity':
|
case 'entity':
|
||||||
case 'htmlall':
|
case 'htmlall':
|
||||||
if (Smarty::$_MBSTRING) {
|
if (Smarty::$_MBSTRING) {
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
function smarty_modifiercompiler_upper($params)
|
function smarty_modifiercompiler_upper($params)
|
||||||
{
|
{
|
||||||
if (Smarty::$_MBSTRING) {
|
if (Smarty::$_MBSTRING) {
|
||||||
return 'mb_strtoupper(' . $params[ 0 ] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')';
|
return 'mb_strtoupper(' . $params[ 0 ] . ' ?? \'\', \'' . addslashes(Smarty::$_CHARSET) . '\')';
|
||||||
}
|
}
|
||||||
// no MBString fallback
|
// no MBString fallback
|
||||||
return 'strtoupper(' . $params[ 0 ] . ')';
|
return 'strtoupper(' . $params[ 0 ] . ' ?? \'\')';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,9 +44,43 @@ if (!function_exists('smarty_mb_str_replace')) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$parts = mb_split(preg_quote($search), $subject) ?: array();
|
$mb_reg_charset = mb_regex_encoding();
|
||||||
|
// Check if mbstring regex is using UTF-8
|
||||||
|
$reg_is_unicode = !strcasecmp($mb_reg_charset, "UTF-8");
|
||||||
|
if(!$reg_is_unicode) {
|
||||||
|
// ...and set to UTF-8 if not
|
||||||
|
mb_regex_encoding("UTF-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if charset used by Smarty is matching one used by regex...
|
||||||
|
$current_charset = mb_regex_encoding();
|
||||||
|
$convert_result = (bool)strcasecmp(Smarty::$_CHARSET, $current_charset);
|
||||||
|
if($convert_result) {
|
||||||
|
// ...convert to it if not.
|
||||||
|
$subject = mb_convert_encoding($subject, $current_charset, Smarty::$_CHARSET);
|
||||||
|
$search = mb_convert_encoding($search, $current_charset, Smarty::$_CHARSET);
|
||||||
|
$replace = mb_convert_encoding($replace, $current_charset, Smarty::$_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = mb_split(preg_quote($search), $subject ?? "") ?: array();
|
||||||
|
// If original regex encoding was not unicode...
|
||||||
|
if(!$reg_is_unicode) {
|
||||||
|
// ...restore original regex encoding to avoid breaking the system.
|
||||||
|
mb_regex_encoding($mb_reg_charset);
|
||||||
|
}
|
||||||
|
if($parts === false) {
|
||||||
|
// This exception is thrown if call to mb_split failed.
|
||||||
|
// Usually it happens, when $search or $replace are not valid for given mb_regex_encoding().
|
||||||
|
// There may be other cases for it to fail, please file an issue if you find a reproducible one.
|
||||||
|
throw new SmartyException("Source string is not a valid $current_charset sequence (probably)");
|
||||||
|
}
|
||||||
|
|
||||||
$count = count($parts) - 1;
|
$count = count($parts) - 1;
|
||||||
$subject = implode($replace, $parts);
|
$subject = implode($replace, $parts);
|
||||||
|
// Convert results back to charset used by Smarty, if needed.
|
||||||
|
if($convert_result) {
|
||||||
|
$subject = mb_convert_encoding($subject, Smarty::$_CHARSET, $current_charset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $subject;
|
return $subject;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class Smarty_Internal_Compile_Private_Print_Expression extends Smarty_Internal_C
|
|||||||
}
|
}
|
||||||
// autoescape html
|
// autoescape html
|
||||||
if ($compiler->template->smarty->escape_html) {
|
if ($compiler->template->smarty->escape_html) {
|
||||||
$output = "htmlspecialchars({$output}, ENT_QUOTES, '" . addslashes(Smarty::$_CHARSET) . "')";
|
$output = "htmlspecialchars((string) {$output}, ENT_QUOTES, '" . addslashes(Smarty::$_CHARSET) . "')";
|
||||||
}
|
}
|
||||||
// loop over registered filters
|
// loop over registered filters
|
||||||
if (!empty($compiler->template->smarty->registered_filters[ Smarty::FILTER_VARIABLE ])) {
|
if (!empty($compiler->template->smarty->registered_filters[ Smarty::FILTER_VARIABLE ])) {
|
||||||
|
|||||||
@@ -29,12 +29,7 @@ class Smarty_Internal_Runtime_WriteFile
|
|||||||
{
|
{
|
||||||
$_error_reporting = error_reporting();
|
$_error_reporting = error_reporting();
|
||||||
error_reporting($_error_reporting & ~E_NOTICE & ~E_WARNING);
|
error_reporting($_error_reporting & ~E_NOTICE & ~E_WARNING);
|
||||||
$_file_perms = property_exists($smarty, '_file_perms') ? $smarty->_file_perms : 0644;
|
$old_umask = umask(0);
|
||||||
$_dir_perms =
|
|
||||||
property_exists($smarty, '_dir_perms') ? (isset($smarty->_dir_perms) ? $smarty->_dir_perms : 0777) : 0771;
|
|
||||||
if ($_file_perms !== null) {
|
|
||||||
$old_umask = umask(0);
|
|
||||||
}
|
|
||||||
$_dirpath = dirname($_filepath);
|
$_dirpath = dirname($_filepath);
|
||||||
// if subdirs, create dir structure
|
// if subdirs, create dir structure
|
||||||
if ($_dirpath !== '.') {
|
if ($_dirpath !== '.') {
|
||||||
@@ -42,7 +37,7 @@ class Smarty_Internal_Runtime_WriteFile
|
|||||||
// loop if concurrency problem occurs
|
// loop if concurrency problem occurs
|
||||||
// see https://bugs.php.net/bug.php?id=35326
|
// see https://bugs.php.net/bug.php?id=35326
|
||||||
while (!is_dir($_dirpath)) {
|
while (!is_dir($_dirpath)) {
|
||||||
if (@mkdir($_dirpath, $_dir_perms, true)) {
|
if (@mkdir($_dirpath, 0771, true)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
clearstatcache();
|
clearstatcache();
|
||||||
@@ -89,11 +84,9 @@ class Smarty_Internal_Runtime_WriteFile
|
|||||||
error_reporting($_error_reporting);
|
error_reporting($_error_reporting);
|
||||||
throw new SmartyException("unable to write file {$_filepath}");
|
throw new SmartyException("unable to write file {$_filepath}");
|
||||||
}
|
}
|
||||||
if ($_file_perms !== null) {
|
// set file permissions
|
||||||
// set file permissions
|
chmod($_filepath, 0644);
|
||||||
chmod($_filepath, $_file_perms);
|
umask($old_umask);
|
||||||
umask($old_umask);
|
|
||||||
}
|
|
||||||
error_reporting($_error_reporting);
|
error_reporting($_error_reporting);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -422,9 +422,6 @@ abstract class Smarty_Internal_TemplateCompilerBase
|
|||||||
try {
|
try {
|
||||||
// save template object in compiler class
|
// save template object in compiler class
|
||||||
$this->template = $template;
|
$this->template = $template;
|
||||||
if (property_exists($this->template->smarty, 'plugin_search_order')) {
|
|
||||||
$this->plugin_search_order = $this->template->smarty->plugin_search_order;
|
|
||||||
}
|
|
||||||
if ($this->smarty->debugging) {
|
if ($this->smarty->debugging) {
|
||||||
if (!isset($this->smarty->_debug)) {
|
if (!isset($this->smarty->_debug)) {
|
||||||
$this->smarty->_debug = new Smarty_Internal_Debug();
|
$this->smarty->_debug = new Smarty_Internal_Debug();
|
||||||
|
|||||||
+1
@@ -210,6 +210,7 @@ class PluginFunctionHtmlSelectDateTest extends PHPUnit_Smarty
|
|||||||
public function setUp(): void
|
public function setUp(): void
|
||||||
{
|
{
|
||||||
$this->setUpSmarty(dirname(__FILE__));
|
$this->setUpSmarty(dirname(__FILE__));
|
||||||
|
$this->smarty->setErrorReporting(E_ALL & ~E_DEPRECATED);
|
||||||
|
|
||||||
$year = date('Y');
|
$year = date('Y');
|
||||||
$this->now = mktime(15, 0, 0, 2, 20, $year);
|
$this->now = mktime(15, 0, 0, 2, 20, $year);
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace UnitTests\TemplateSource\TagTests\PluginModifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class for modifier tests
|
||||||
|
*
|
||||||
|
* @runTestsInSeparateProcess
|
||||||
|
* @preserveGlobalState disabled
|
||||||
|
* @backupStaticAttributes enabled
|
||||||
|
*/
|
||||||
|
class PluginModifierExplodeTest extends \PHPUnit_Smarty
|
||||||
|
{
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
$this->setUpSmarty(__DIR__);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
* @throws \SmartyException
|
||||||
|
*
|
||||||
|
* @dataProvider explodeDataProvider
|
||||||
|
*/
|
||||||
|
public function testExplode($template, $subject, $expectedString)
|
||||||
|
{
|
||||||
|
$this->smarty->assign('subject', $subject);
|
||||||
|
|
||||||
|
$tpl = $this->smarty->createTemplate($template);
|
||||||
|
$res = $this->smarty->fetch($tpl);
|
||||||
|
|
||||||
|
$this->assertEquals($expectedString, $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function explodeDataProvider()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'default' => [
|
||||||
|
'template' => 'string:{","|explode:$subject|json_encode}',
|
||||||
|
'subject' => 'a,b,c,d',
|
||||||
|
'expectedString' => '["a","b","c","d"]',
|
||||||
|
],
|
||||||
|
'withNoDelimiterFound' => [
|
||||||
|
'template' => 'string:{","|explode:$subject|json_encode}',
|
||||||
|
'subject' => 'abcd',
|
||||||
|
'expectedString' => '["abcd"]',
|
||||||
|
],
|
||||||
|
'withNull' => [
|
||||||
|
'template' => 'string:{","|explode:$subject|json_encode}',
|
||||||
|
'subject' => null,
|
||||||
|
'expectedString' => '[""]',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace UnitTests\TemplateSource\TagTests\PluginModifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class for modifier tests
|
||||||
|
*
|
||||||
|
* @runTestsInSeparateProcess
|
||||||
|
* @preserveGlobalState disabled
|
||||||
|
* @backupStaticAttributes enabled
|
||||||
|
*/
|
||||||
|
class PluginModifierNumberFormatTest extends \PHPUnit_Smarty
|
||||||
|
{
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
$this->setUpSmarty(__DIR__);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
* @throws \SmartyException
|
||||||
|
*
|
||||||
|
* @dataProvider numberFormatDataProvider
|
||||||
|
*/
|
||||||
|
public function testNumberFormat($template, $subject, $expectedString)
|
||||||
|
{
|
||||||
|
$this->smarty->assign('subject', $subject);
|
||||||
|
|
||||||
|
$tpl = $this->smarty->createTemplate($template);
|
||||||
|
|
||||||
|
$this->assertEquals($expectedString, $this->smarty->fetch($tpl));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function numberFormatDataProvider()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'default' => [
|
||||||
|
'template' => 'string:{$subject|number_format}',
|
||||||
|
'subject' => 12345,
|
||||||
|
'expectedString' => "12,345",
|
||||||
|
],
|
||||||
|
'withDecimalDefault' => [
|
||||||
|
'template' => 'string:{$subject|number_format}',
|
||||||
|
'subject' => 12345.6789,
|
||||||
|
'expectedString' => "12,346",
|
||||||
|
],
|
||||||
|
'withDecimalAndExtras' => [
|
||||||
|
'template' => 'string:{$subject|number_format:2:"-":"~"}',
|
||||||
|
'subject' => 12345.6789,
|
||||||
|
'expectedString' => "12~345-68",
|
||||||
|
],
|
||||||
|
'withNull' => [
|
||||||
|
'template' => 'string:{$subject|number_format}',
|
||||||
|
'subject' => null,
|
||||||
|
'expectedString' => 0,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace UnitTests\TemplateSource\TagTests\PluginModifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class for modifier tests
|
||||||
|
*
|
||||||
|
* @runTestsInSeparateProcess
|
||||||
|
* @preserveGlobalState disabled
|
||||||
|
* @backupStaticAttributes enabled
|
||||||
|
*/
|
||||||
|
class PluginModifierReplaceTest extends \PHPUnit_Smarty
|
||||||
|
{
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
$this->setUpSmarty(__DIR__);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
* @throws \SmartyException
|
||||||
|
*
|
||||||
|
* @dataProvider replaceDataProvider
|
||||||
|
*/
|
||||||
|
public function testReplace($template, $subject, $expectedString)
|
||||||
|
{
|
||||||
|
$this->smarty->assign('subject', $subject);
|
||||||
|
|
||||||
|
$tpl = $this->smarty->createTemplate($template);
|
||||||
|
|
||||||
|
$this->assertEquals($expectedString, $this->smarty->fetch($tpl));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function replaceDataProvider()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'default' => [
|
||||||
|
'template' => 'string:{$subject|replace:",":"-"}',
|
||||||
|
'subject' => "a,b,c,d",
|
||||||
|
'expectedString' => "a-b-c-d",
|
||||||
|
],
|
||||||
|
'doNothing' => [
|
||||||
|
'template' => 'string:{$subject|replace:"":""}',
|
||||||
|
'subject' => "a,b,c,d",
|
||||||
|
'expectedString' => "a,b,c,d",
|
||||||
|
],
|
||||||
|
'withNull' => [
|
||||||
|
'template' => 'string:{$subject|replace:"":""}',
|
||||||
|
'subject' => null,
|
||||||
|
'expectedString' => "",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-2
@@ -63,6 +63,11 @@ class PluginModifierUnescapeTest extends PHPUnit_Smarty
|
|||||||
$tpl = $this->smarty->createTemplate('string:{"' . $encoded . '"|unescape:"url"}');
|
$tpl = $this->smarty->createTemplate('string:{"' . $encoded . '"|unescape:"url"}');
|
||||||
$this->assertEquals($result, $this->smarty->fetch($tpl));
|
$this->assertEquals($result, $this->smarty->fetch($tpl));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
public function testCharset()
|
||||||
|
{
|
||||||
|
$tpl = $this->smarty->createTemplate("string:{''Stiff Opposition Expected to Casketless Funeral Plan''|unescape:'htmlall':'utf-8'}");
|
||||||
|
$this->assertEquals("'Stiff Opposition Expected to Casketless Funeral Plan'", $this->smarty->fetch($tpl));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -156,4 +156,12 @@ class MathTest extends PHPUnit_Smarty
|
|||||||
$this->assertEquals($expected, $this->smarty->fetch($tpl));
|
$this->assertEquals($expected, $this->smarty->fetch($tpl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRand()
|
||||||
|
{
|
||||||
|
$tpl = $this->smarty->createTemplate('eval:{$x = "0"}{math equation="x * rand()" x=$x}');
|
||||||
|
// this assertion may seem silly, but it serves to prove that using rand() without a parameter
|
||||||
|
// will not trigger a security error (see https://github.com/smarty-php/smarty/issues/794)
|
||||||
|
$this->assertEquals("0", $this->smarty->fetch($tpl));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Smarty PHPunit tests - issue #549 regression tests
|
||||||
|
*
|
||||||
|
* @package PHPunit
|
||||||
|
* @author Andrey Repin <anrdaemon@yandex.ru>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class for compiler tests
|
||||||
|
*
|
||||||
|
* @runTestsInSeparateProcess
|
||||||
|
* @preserveGlobalState disabled
|
||||||
|
* @backupStaticAttributes enabled
|
||||||
|
*
|
||||||
|
* mb_split breaks if Smarty encoding is not the same as mbstring regex encoding.
|
||||||
|
*/
|
||||||
|
class MbSplitEncodingIssue549Test extends PHPUnit_Smarty
|
||||||
|
{
|
||||||
|
/** @var string Saved Smarty charset */
|
||||||
|
private $charset;
|
||||||
|
|
||||||
|
/** @var array Source data for tests, hexed to protect from accidental reencoding */
|
||||||
|
private $data = array(
|
||||||
|
"subject" => '4772c3bc6e6577616c64', // "Grünewald"
|
||||||
|
"pattern" => '77616c64', // "wald"
|
||||||
|
"replacement" => '7374c3bc726d', // "stürm"
|
||||||
|
"result" => '4772c3bc6e657374c3bc726d', // "Grünestürm"
|
||||||
|
);
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
if(!\Smarty::$_MBSTRING)
|
||||||
|
{
|
||||||
|
$this->markTestSkipped("mbstring extension is not in use by Smarty");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->charset = \Smarty::$_CHARSET;
|
||||||
|
$this->setUpSmarty(dirname(__FILE__));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
\Smarty::$_CHARSET = $this->charset ?: \Smarty::$_CHARSET;
|
||||||
|
$this->cleanDirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Provider for testReplaceModifier
|
||||||
|
*/
|
||||||
|
public function encodingPairsProvider()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
"with non-UNICODE src/non-UNICODE regex (PHP < 5.6 default)" => array("Windows-1252", "EUC-JP"),
|
||||||
|
"with UTF-8 src/non-UNICODE regex (PHP < 5.6 default)" => array("UTF-8", "EUC-JP"),
|
||||||
|
"with UTF-8 src/UTF-8 regex (PHP >= 5.6)" => array("UTF-8", "UTF-8"),
|
||||||
|
"with non-UNICODE src/UTF-8 regex" => array("Windows-1252", "UTF-8"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test behavior of `replace` modifier with different source and regex encodings
|
||||||
|
*
|
||||||
|
* @dataProvider encodingPairsProvider
|
||||||
|
*/
|
||||||
|
public function testReplaceModifier($mb_int_encoding, $mb_regex_encoding)
|
||||||
|
{
|
||||||
|
$data = $this->data;
|
||||||
|
\array_walk($data, function(&$value, $key) use($mb_int_encoding) {
|
||||||
|
$value = \mb_convert_encoding(pack("H*", $value), $mb_int_encoding, "UTF-8");
|
||||||
|
});
|
||||||
|
\extract($data, \EXTR_SKIP);
|
||||||
|
|
||||||
|
\mb_regex_encoding($mb_regex_encoding);
|
||||||
|
\Smarty::$_CHARSET = $mb_int_encoding;
|
||||||
|
$this->assertEquals($result, $this->smarty->fetch("string:{\"$subject\"|replace:\"$pattern\":\"$replacement\"}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Ignore anything in here, but keep this directory
|
||||||
|
*
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Ignore anything in here, but keep this directory
|
||||||
|
*
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
FROM php:7.1-cli
|
||||||
|
|
||||||
|
## 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
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
FROM php:7.2-cli
|
||||||
|
|
||||||
|
## 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
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
FROM php:7.3-cli
|
||||||
|
|
||||||
|
## 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
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
FROM php:7.4-cli
|
||||||
|
|
||||||
|
## 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
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
FROM php:8.0-cli
|
||||||
|
|
||||||
|
## 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
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
FROM php:8.1-cli
|
||||||
|
|
||||||
|
## 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
|
||||||
Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
composer update && php ./vendor/phpunit/phpunit/phpunit
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
|
||||||
|
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||||
|
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
|
||||||
|
|
||||||
|
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
|
||||||
|
then
|
||||||
|
>&2 echo 'ERROR: Invalid installer checksum'
|
||||||
|
rm composer-setup.php
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
php composer-setup.php --quiet
|
||||||
|
RESULT=$?
|
||||||
|
rm composer-setup.php
|
||||||
|
exit $RESULT
|
||||||
Reference in New Issue
Block a user