Compare commits

...

37 Commits

Author SHA1 Message Date
Simon Wisselink c2b31f7a90 mental notes 2022-09-22 23:32:10 +02:00
Simon Wisselink 489d647841 whitespace 2022-09-22 23:26:46 +02:00
Simon Wisselink cc113d4eb7 Use smarty_strtolower_ascii in autoloader to. 2022-09-22 23:24:32 +02:00
Simon Wisselink 0a44dca645 Merge branch 'master' into i155-fix 2022-09-22 23:22:41 +02:00
Simon Wisselink 3ce328b6d0 Implemented locale safe strotoupper, strolower and ucfirst functions for translating user string to filenames etc.
Fixes #155
2022-09-22 23:19:04 +02:00
Simon Wisselink 612bd3f657 Fixed PHP8.1 deprecation errors in strip_tags (#803) 2022-09-22 14:55:20 +02:00
Simon Wisselink 9eea30ec1e Removed now superfluous phpunit.sh 2022-09-22 14:44:45 +02:00
Simon Wisselink ea95e8b047 Re-organize all testrunners to use the same script(s). (#812) 2022-09-22 14:31:49 +02:00
Simon Wisselink 474138fd7e Updated changelog 2022-09-22 14:31:01 +02:00
Mathias b91c04bfcf Fixed PHP8.1 deprecation errors passing null to parameter in trim (#807)
Fixed a PHP 8.1 deprecation error:  trim(): Passing null to parameter #1 ($string) of type string is deprecated in cacheresource_keyvaluestore.php on line 247 and in cacheresource_keyvaluestore.php on line 431
2022-09-22 14:29:51 +02:00
Simon Wisselink c53342c9fc Silence deprecation errors for strtime in PHP8.1 or higher
Fixes #672 (#811)
2022-09-22 14:11:36 +02:00
Simon Wisselink f8a958cd53 Update changelog 2022-09-21 21:56:39 +02:00
Jonathan Stoll 45345e75ec Fix Variable Usage (#808)
Fix Variable Usage in Exception message when unable to load subtemplate
2022-09-21 21:54:41 +02:00
Simon Wisselink bf7d6b8bd8 Include docs en demo in the releases.
Fixes #799
2022-09-20 22:45:16 +02:00
Simon Wisselink 32a11b34ea Added changelog 2022-09-18 17:18:32 +02:00
Storyxx db80246b58 fix compilation for caching templates (#801) 2022-09-18 17:15:56 +02:00
Hypolite Petovan d683641f90 Fix wrong indentation in libs/plugins/modifier.capitalize.php (#802) 2022-09-18 11:14:59 +02:00
Simon Wisselink e2e68b3622 clean output buffer for Throwable instead of just Exception (#797)
Fixes #514
2022-09-14 13:47:36 +02:00
Simon Wisselink ffa2b81a8e Merge branch 'release/4.2.1' 2022-09-14 12:59:01 +02:00
Simon Wisselink c693d81370 version bump 2022-09-14 12:58:59 +02:00
Simon Wisselink 813c83f7a3 Fixed unselected year/month/day not working in html_select_date
Fixes #395
2022-09-14 12:44:37 +02:00
Simon Wisselink 55ea25d1f5 Applied appropriate javascript and html escaping in mailto plugin to counter injection attacks
Fixes #454
2022-09-14 11:38:18 +02:00
Simon Wisselink d304d349b4 Fixed PHP8.1 deprecation errors in capitalize modifier
Fixes #789
2022-09-13 12:19:44 +02:00
Simon Wisselink 7494818434 prevent double CI workflows in PRs 2022-09-12 16:02:42 +02:00
Simon Wisselink 50d5890eac Exclude unit test files from git export 2022-09-12 15:52:32 +02:00
Simon Wisselink 6872e78238 Utility script for running unit tests on all PHP versions locally 2022-09-12 15:50:09 +02:00
Simon Wisselink 5479e3362c Fixed use of rand() without a parameter in math function (#795)
* Fixed use of `rand()` without a parameter in math function
Fixes #794
2022-09-12 12:13:42 +02:00
Simon Wisselink f8f97b4e2d Fixed PHP8.1 deprecation errors in upper modifier #788 2022-09-10 12:34:20 +02:00
Mark Fettig 1bc7c722a3 address PHP 8.1 'explode', 'number_format', and 'replace' deprecations (#755) 2022-09-09 22:39:24 +02:00
Simon Wisselink 02968a82b5 Update SECURITY.md
Removed comment that still indicated v4 wasn’t released yet.
2022-08-16 22:43:47 +02:00
Simon Wisselink 97aeb14c6f Merge branch 'release/4.2.0' 2022-08-01 23:57:38 +02:00
Simon Wisselink ed454551a3 version bump 2022-08-01 23:57:36 +02:00
Simon Wisselink f4b26a3cbf Fixed second param of unescape modifier (#778)
Fixes #777
2022-08-01 23:49:19 +02:00
Simon Wisselink 20a8026ccd Merge branch 'fix-issue-549-v3' of github.com:AnrDaemon/smarty into AnrDaemon-fix-issue-549-v3 (#771) 2022-07-19 22:55:07 +02:00
Simon Wisselink 27910bf2c1 git push origin masterMerge branch 'JonisoftGermany-master' 2022-07-17 00:54:29 +02:00
Alec Smecher a3621b375e Update libs/sysplugins/smarty_internal_compile_private_special_variable.php
Fixed variable naming typo (thanks!)

Co-Authored-By: Alexkurd <7689609+Alexkurd@users.noreply.github.com>
2020-04-15 08:30:35 -07:00
Alec Smecher 0124bc3aa0 #155 Adapt Smarty upper/lower functions to be codesafe (e.g. for Turkish locale) 2020-04-14 15:03:31 -07:00
44 changed files with 675 additions and 112 deletions
+1 -2
View File
@@ -7,11 +7,10 @@
# exclude from git export
/tests export-ignore
/demo export-ignore
/docs export-ignore
/utilities export-ignore
/docker-compose.yml export-ignore
/.github export-ignore
/run_tests_for_all_php_versions.sh export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/make-release.sh export-ignore
+5 -7
View File
@@ -1,8 +1,10 @@
# https://help.github.com/en/categories/automating-your-workflow-with-github-actions
on:
- pull_request
- push
pull_request:
push:
branches:
- 'master'
name: CI
@@ -69,9 +71,5 @@ jobs:
restore-keys: |
${{ runner.os }}-php-${{ matrix.php-version }}-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress --no-suggest
- name: Run tests with phpunit
run: ./phpunit.sh
run: ./run-tests.sh
+29
View File
@@ -6,6 +6,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Changed
- Include docs and demo in the releases [#799](https://github.com/smarty-php/smarty/issues/799)
### Fixed
- Output buffer is now cleaned for internal PHP errors as well, not just for Exceptions [#514](https://github.com/smarty-php/smarty/issues/514)
- Fixed recursion and out of memory errors when caching in complicated template set-ups using inheritance and includes [#801](https://github.com/smarty-php/smarty/pull/801)
- Fixed PHP8.1 deprecation errors in strip_tags
- Fix Variable Usage in Exception message when unable to load subtemplate [#808](https://github.com/smarty-php/smarty/pull/808)
- Fixed PHP8.1 deprecation notices for strftime [#672](https://github.com/smarty-php/smarty/issues/672)
- Fixed PHP8.1 deprecation errors passing null to parameter in trim [#807](https://github.com/smarty-php/smarty/pull/807)
- Adapt Smarty upper/lower functions to be codesafe (e.g. for Turkish locale) [#586](https://github.com/smarty-php/smarty/pull/586)
## [4.2.1] - 2022-09-14
### Security
- Applied appropriate javascript and html escaping in mailto plugin to counter injection attacks [#454](https://github.com/smarty-php/smarty/issues/454)
### Fixed
- Fixed PHP8.1 deprecation notices 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 PHP8.1 deprecation notices in capitalize modifier [#789](https://github.com/smarty-php/smarty/issues/789)
- Fixed use of `rand()` without a parameter in math function [#794](https://github.com/smarty-php/smarty/issues/794)
- Fixed unselected year/month/day not working in html_select_date [#395](https://github.com/smarty-php/smarty/issues/395)
## [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)
+1 -1
View File
@@ -2,7 +2,7 @@
## 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 |
| ------- | ------------------ |
+2 -1
View File
@@ -3,10 +3,11 @@ services:
base:
build:
context: .
dockerfile: ./utilities/testrunners/php71/Dockerfile
volumes:
- .:/app
working_dir: /app
entrypoint: sh ./utilities/testrunners/run-test.sh
entrypoint: sh ./run-tests.sh
php71:
extends:
service: base
+6 -1
View File
@@ -5,6 +5,11 @@
* @package Smarty
*/
if (!defined('SMARTY_HELPER_FUNCTIONS_LOADED')) {
include dirname(__FILE__) . '/functions.php';
}
/**
* Smarty Autoloader
*
@@ -89,7 +94,7 @@ class Smarty_Autoloader
if ($class[ 0 ] !== 'S' || strpos($class, 'Smarty') !== 0) {
return;
}
$_class = strtolower($class);
$_class = smarty_strtolower_ascii($class);
if (isset(self::$rootClasses[ $_class ])) {
$file = self::$SMARTY_DIR . self::$rootClasses[ $_class ];
if (is_file($file)) {
+10 -1
View File
@@ -60,12 +60,21 @@ if (!defined('SMARTY_MBSTRING')) {
*/
define('SMARTY_MBSTRING', function_exists('mb_get_info'));
}
/**
* Load helper functions
*/
if (!defined('SMARTY_HELPER_FUNCTIONS_LOADED')) {
include dirname(__FILE__) . '/functions.php';
}
/**
* Load Smarty_Autoloader
*/
if (!class_exists('Smarty_Autoloader')) {
include dirname(__FILE__) . '/bootstrap.php';
}
/**
* Load always needed external class files
*/
@@ -98,7 +107,7 @@ class Smarty extends Smarty_Internal_TemplateBase
/**
* smarty version
*/
const SMARTY_VERSION = '4.1.1';
const SMARTY_VERSION = '4.2.1';
/**
* define variable scopes
*/
+51
View File
@@ -0,0 +1,51 @@
<?php
/**
* This file is part of the Smarty package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Registers some helper/polyfill functions.
*/
const SMARTY_HELPER_FUNCTIONS_LOADED = true;
/**
* Converts the first characters in $string to uppercase (A-Z) if it is an ASCII lowercase character (a-z).
*
* May not be required when running PHP8.2+: https://wiki.php.net/rfc/strtolower-ascii
*
* @param $string
*
* @return string
*/
function smarty_ucfirst_ascii($string): string {
return smarty_strtoupper_ascii(substr($string, 0, 1)) . substr($string, 1);
}
/**
* Converts all uppercase ASCII characters (A-Z) in $string to lowercase (a-z).
*
* May not be required when running PHP8.2+: https://wiki.php.net/rfc/strtolower-ascii
*
* @param $string
*
* @return string
*/
function smarty_strtolower_ascii($string): string {
return strtr($string, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
}
/**
* Converts all lowercase ASCII characters (a-z) in $string to uppercase (A-Z).
*
* May not be required when running PHP8.2+: https://wiki.php.net/rfc/strtolower-ascii
*
* @param $string
*
* @return string
*/
function smarty_strtoupper_ascii($string): string {
return strtr($string, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
}
+40 -33
View File
@@ -101,6 +101,7 @@ function smarty_function_html_select_date($params, Smarty_Internal_Template $tem
$field_separator = "\n";
$option_separator = "\n";
$time = null;
// $all_empty = null;
// $day_empty = null;
// $month_empty = null;
@@ -113,17 +114,7 @@ function smarty_function_html_select_date($params, Smarty_Internal_Template $tem
foreach ($params as $_key => $_value) {
switch ($_key) {
case 'time':
if (!is_array($_value) && $_value !== null) {
$template->_checkPlugins(
array(
array(
'function' => 'smarty_make_timestamp',
'file' => SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php'
)
)
);
$time = smarty_make_timestamp($_value);
}
$$_key = $_value; // we'll handle conversion below
break;
case 'month_names':
if (is_array($_value) && count($_value) === 12) {
@@ -178,43 +169,59 @@ function smarty_function_html_select_date($params, Smarty_Internal_Template $tem
}
// Note: date() is faster than strftime()
// Note: explode(date()) is faster than date() date() date()
if (isset($params[ 'time' ]) && is_array($params[ 'time' ])) {
if (isset($params[ 'time' ][ $prefix . 'Year' ])) {
if (isset($time) && is_array($time)) {
if (isset($time[$prefix . 'Year'])) {
// $_REQUEST[$field_array] given
foreach (array(
'Y' => 'Year',
'm' => 'Month',
'd' => 'Day'
) as $_elementKey => $_elementName) {
foreach ([
'Y' => 'Year',
'm' => 'Month',
'd' => 'Day'
] as $_elementKey => $_elementName) {
$_variableName = '_' . strtolower($_elementName);
$$_variableName =
isset($params[ 'time' ][ $prefix . $_elementName ]) ? $params[ 'time' ][ $prefix . $_elementName ] :
isset($time[$prefix . $_elementName]) ? $time[$prefix . $_elementName] :
date($_elementKey);
}
} elseif (isset($params[ 'time' ][ $field_array ][ $prefix . 'Year' ])) {
} elseif (isset($time[$field_array][$prefix . 'Year'])) {
// $_REQUEST given
foreach (array(
'Y' => 'Year',
'm' => 'Month',
'd' => 'Day'
) as $_elementKey => $_elementName) {
foreach ([
'Y' => 'Year',
'm' => 'Month',
'd' => 'Day'
] as $_elementKey => $_elementName) {
$_variableName = '_' . strtolower($_elementName);
$$_variableName = isset($params[ 'time' ][ $field_array ][ $prefix . $_elementName ]) ?
$params[ 'time' ][ $field_array ][ $prefix . $_elementName ] : date($_elementKey);
$$_variableName = isset($time[$field_array][$prefix . $_elementName]) ?
$time[$field_array][$prefix . $_elementName] : date($_elementKey);
}
} else {
// no date found, use NOW
list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d'));
[$_year, $_month, $_day] = explode('-', date('Y-m-d'));
}
} elseif (isset($time) && preg_match("/(\d*)-(\d*)-(\d*)/", $time, $matches)) {
$_year = $_month = $_day = null;
if ($matches[1] > '') $_year = (int) $matches[1];
if ($matches[2] > '') $_month = (int) $matches[2];
if ($matches[3] > '') $_day = (int) $matches[3];
} elseif ($time === null) {
if (array_key_exists('time', $params)) {
$_year = $_month = $_day = $time = null;
$_year = $_month = $_day = null;
} else {
list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d'));
[$_year, $_month, $_day] = explode('-', date('Y-m-d'));
}
} else {
list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d', $time));
$template->_checkPlugins(
array(
array(
'function' => 'smarty_make_timestamp',
'file' => SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php'
)
)
);
$time = smarty_make_timestamp($time);
[$_year, $_month, $_day] = explode('-', date('Y-m-d', $time));
}
// make syntax "+N" or "-N" work with $start_year and $end_year
// Note preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match) is slower than trim+substr
foreach (array(
@@ -309,8 +316,8 @@ function smarty_function_html_select_date($params, Smarty_Internal_Template $tem
for ($i = 1; $i <= 12; $i++) {
$_val = sprintf('%02d', $i);
$_text = isset($month_names) ? smarty_function_escape_special_chars($month_names[ $i ]) :
($month_format === '%m' ? $_val : strftime($month_format, $_month_timestamps[ $i ]));
$_value = $month_value_format === '%m' ? $_val : strftime($month_value_format, $_month_timestamps[ $i ]);
($month_format === '%m' ? $_val : @strftime($month_format, $_month_timestamps[ $i ]));
$_value = $month_value_format === '%m' ? $_val : @strftime($month_value_format, $_month_timestamps[ $i ]);
$_html_months .= '<option value="' . $_value . '"' . ($_val == $_month ? ' selected="selected"' : '') .
'>' . $_text . '</option>' . $option_separator;
}
+18 -10
View File
@@ -48,8 +48,13 @@
*/
function smarty_function_mailto($params)
{
static $_allowed_encoding =
array('javascript' => true, 'javascript_charcode' => true, 'hex' => true, 'none' => true);
static $_allowed_encoding = [
'javascript' => true,
'javascript_charcode' => true,
'hex' => true,
'none' => true
];
$extra = '';
if (empty($params[ 'address' ])) {
trigger_error("mailto: missing 'address' parameter", E_USER_WARNING);
@@ -57,19 +62,19 @@ function smarty_function_mailto($params)
} else {
$address = $params[ 'address' ];
}
$text = $address;
// netscape and mozilla do not decode %40 (@) in BCC field (bug?)
// so, don't encode it.
$search = array('%40', '%2C');
$replace = array('@', ',');
$mail_parms = array();
$mail_parms = [];
foreach ($params as $var => $value) {
switch ($var) {
case 'cc':
case 'bcc':
case 'followupto':
if (!empty($value)) {
$mail_parms[] = $var . '=' . str_replace($search, $replace, rawurlencode($value));
$mail_parms[] = $var . '=' . str_replace(['%40', '%2C'], ['@', ','], rawurlencode($value));
}
break;
case 'subject':
@@ -83,6 +88,7 @@ function smarty_function_mailto($params)
default:
}
}
if ($mail_parms) {
$address .= '?' . join('&', $mail_parms);
}
@@ -94,19 +100,21 @@ function smarty_function_mailto($params)
);
return;
}
$string = '<a href="mailto:' . htmlspecialchars($address, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, Smarty::$_CHARSET) .
'" ' . $extra . '>' . htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, Smarty::$_CHARSET) . '</a>';
if ($encode === 'javascript') {
$string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
$js_encode = '';
for ($x = 0, $_length = strlen($string); $x < $_length; $x++) {
$js_encode .= '%' . bin2hex($string[ $x ]);
}
return '<script type="text/javascript">document.write(unescape(\'' . $js_encode . '\'))</script>';
} elseif ($encode === 'javascript_charcode') {
$string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
for ($x = 0, $_length = strlen($string); $x < $_length; $x++) {
$ord[] = ord($string[ $x ]);
}
return '<script type="text/javascript">document.write(String.fromCharCode(' . implode(',', $ord) . '))</script>';
return '<script type="text/javascript">document.write(String.fromCharCode(' . implode(',', $ord) . '))</script>';
} elseif ($encode === 'hex') {
preg_match('!^(.*)(\?.*)$!', $address, $match);
if (!empty($match[ 2 ])) {
@@ -129,6 +137,6 @@ function smarty_function_mailto($params)
return '<a href="' . $mailto . $address_encode . '" ' . $extra . '>' . $text_encode . '</a>';
} else {
// no encoding
return '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
return $string;
}
}
+1 -1
View File
@@ -70,7 +70,7 @@ function smarty_function_math($params, $template)
$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]*))';
$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)) {
trigger_error("math: illegal characters", E_USER_WARNING);
+2
View File
@@ -22,6 +22,8 @@
*/
function smarty_modifier_capitalize($string, $uc_digits = false, $lc_rest = false)
{
$string = (string) $string;
if (Smarty::$_MBSTRING) {
if ($lc_rest) {
// uppercase (including hyphenated words)
+2 -1
View File
@@ -78,7 +78,8 @@ function smarty_modifier_date_format($string, $format = null, $default_date = ''
}
$format = str_replace($_win_from, $_win_to, $format);
}
return strftime($format, $timestamp);
// @ to suppress deprecation errors when running in PHP8.1 or higher.
return @strftime($format, $timestamp);
} else {
return date($format, $timestamp);
}
+25
View File
@@ -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);
}
+26
View File
@@ -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);
}
+2 -2
View File
@@ -21,8 +21,8 @@
function smarty_modifiercompiler_strip_tags($params)
{
if (!isset($params[ 1 ]) || $params[ 1 ] === true || trim($params[ 1 ], '"') === 'true') {
return "preg_replace('!<[^>]*?>!', ' ', {$params[0]})";
return "preg_replace('!<[^>]*?>!', ' ', {$params[0]} ?: '')";
} else {
return 'strip_tags(' . $params[ 0 ] . ')';
return 'strip_tags((string) ' . $params[ 0 ] . ')';
}
}
+15 -7
View File
@@ -14,20 +14,28 @@
* @author Rodney Rehm
*
* @param array $params parameters
* @param Smarty_Internal_TemplateCompilerBase $compiler
*
* @return string with compiled code
*/
function smarty_modifiercompiler_unescape($params)
function smarty_modifiercompiler_unescape($params, Smarty_Internal_TemplateCompilerBase $compiler)
{
if (!isset($params[ 1 ])) {
$params[ 1 ] = 'html';
}
$compiler->template->_checkPlugins(
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 ])) {
$params[ 2 ] = '\'' . addslashes(Smarty::$_CHARSET) . '\'';
} else {
$params[ 2 ] = "'{$params[ 2 ]}'";
}
switch (trim($params[ 1 ], '"\'')) {
switch ($esc_type) {
case 'entity':
case 'htmlall':
if (Smarty::$_MBSTRING) {
+2 -2
View File
@@ -21,8 +21,8 @@
function smarty_modifiercompiler_upper($params)
{
if (Smarty::$_MBSTRING) {
return 'mb_strtoupper(' . $params[ 0 ] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')';
return 'mb_strtoupper(' . $params[ 0 ] . ' ?? \'\', \'' . addslashes(Smarty::$_CHARSET) . '\')';
}
// no MBString fallback
return 'strtoupper(' . $params[ 0 ] . ')';
return 'strtoupper(' . $params[ 0 ] . ' ?? \'\')';
}
+35 -1
View File
@@ -44,9 +44,43 @@ if (!function_exists('smarty_mb_str_replace')) {
}
}
} 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;
$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;
}
+2 -2
View File
@@ -205,11 +205,11 @@ abstract class Smarty_CacheResource
}
// try sysplugins dir
if (isset(self::$sysplugins[ $type ])) {
$cache_resource_class = 'Smarty_Internal_CacheResource_' . ucfirst($type);
$cache_resource_class = 'Smarty_Internal_CacheResource_' . smarty_ucfirst_ascii($type);
return $smarty->_cache[ 'cacheresource_handlers' ][ $type ] = new $cache_resource_class();
}
// try plugins dir
$cache_resource_class = 'Smarty_CacheResource_' . ucfirst($type);
$cache_resource_class = 'Smarty_CacheResource_' . smarty_ucfirst_ascii($type);
if ($smarty->loadPlugin($cache_resource_class)) {
return $smarty->_cache[ 'cacheresource_handlers' ][ $type ] = new $cache_resource_class();
}
@@ -244,7 +244,7 @@ abstract class Smarty_CacheResource_KeyValueStore extends Smarty_CacheResource
*/
protected function sanitize($string)
{
$string = trim($string, '|');
$string = trim((string)$string, '|');
if (!$string) {
return '';
}
@@ -428,7 +428,7 @@ abstract class Smarty_CacheResource_KeyValueStore extends Smarty_CacheResource
$t[] = 'IVK#COMPILE' . $_compile;
}
$_name .= '#';
$cid = trim($cache_id, '|');
$cid = trim((string)$cache_id, '|');
if (!$cid) {
return $t;
}
@@ -143,7 +143,7 @@ class Smarty_Internal_Compile_Private_ForeachSection extends Smarty_Internal_Com
foreach ($this->resultOffsets as $key => $offset) {
foreach ($match[ $offset ] as $m) {
if (!empty($m)) {
$this->matchResults[ $key ][ strtolower($m) ] = true;
$this->matchResults[ $key ][ smarty_strtolower_ascii($m) ] = true;
}
}
}
@@ -213,12 +213,12 @@ class Smarty_Internal_Compile_Private_ForeachSection extends Smarty_Internal_Com
*/
public function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
$tag = strtolower(trim($parameter[ 0 ], '"\''));
$tag = smarty_strtolower_ascii(trim($parameter[ 0 ], '"\''));
$name = isset($parameter[ 1 ]) ? $compiler->getId($parameter[ 1 ]) : false;
if (!$name) {
$compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", null, true);
}
$property = isset($parameter[ 2 ]) ? strtolower($compiler->getId($parameter[ 2 ])) : false;
$property = isset($parameter[ 2 ]) ? smarty_strtolower_ascii($compiler->getId($parameter[ 2 ])) : false;
if (!$property || !in_array($property, $this->nameProperties)) {
$compiler->trigger_template_error("missing or illegal \$smarty.{$tag} property attribute", null, true);
}
@@ -29,7 +29,7 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
$_index = preg_split("/\]\[/", substr($parameter, 1, strlen($parameter) - 2));
$variable = strtolower($compiler->getId($_index[ 0 ]));
$variable = smarty_strtolower_ascii($compiler->getId($_index[ 0 ]));
if ($variable === false) {
$compiler->trigger_template_error("special \$Smarty variable name index can not be variable", null, true);
}
@@ -40,7 +40,7 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C
case 'foreach':
case 'section':
if (!isset(Smarty_Internal_TemplateCompilerBase::$_tag_objects[ $variable ])) {
$class = 'Smarty_Internal_Compile_' . ucfirst($variable);
$class = 'Smarty_Internal_Compile_' . smarty_ucfirst_ascii($variable);
Smarty_Internal_TemplateCompilerBase::$_tag_objects[ $variable ] = new $class;
}
return Smarty_Internal_TemplateCompilerBase::$_tag_objects[ $variable ]->compileSpecialVariable(
@@ -76,7 +76,7 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C
$compiler->trigger_template_error("(secure mode) super globals not permitted");
break;
}
$compiled_ref = '$_' . strtoupper($variable);
$compiled_ref = '$_' . smarty_strtoupper_ascii($variable);
break;
case 'template':
return 'basename($_smarty_tpl->source->filepath)';
@@ -88,20 +88,19 @@ class Smarty_Internal_Extension_Handler
$objType = $data->_objType;
$propertyType = false;
if (!isset($this->resolvedProperties[ $match[ 0 ] ][ $objType ])) {
$property = isset($this->resolvedProperties[ 'property' ][ $basename ]) ?
$this->resolvedProperties[ 'property' ][ $basename ] :
$property = $this->resolvedProperties[ 'property' ][ $basename ] = strtolower(
join(
'_',
preg_split(
'/([A-Z][^A-Z]*)/',
$basename,
-1,
PREG_SPLIT_NO_EMPTY |
PREG_SPLIT_DELIM_CAPTURE
)
$property = $this->resolvedProperties['property'][$basename] ??
$this->resolvedProperties['property'][$basename] = smarty_strtolower_ascii(
join(
'_',
preg_split(
'/([A-Z][^A-Z]*)/',
$basename,
-1,
PREG_SPLIT_NO_EMPTY |
PREG_SPLIT_DELIM_CAPTURE
)
);
)
);
if ($property !== false) {
if (property_exists($data, $property)) {
$propertyType = $this->resolvedProperties[ $match[ 0 ] ][ $objType ] = 1;
@@ -145,7 +144,7 @@ class Smarty_Internal_Extension_Handler
public function upperCase($name)
{
$_name = explode('_', $name);
$_name = array_map('ucfirst', $_name);
$_name = array_map('smarty_ucfirst_ascii', $_name);
return implode('_', $_name);
}
@@ -40,7 +40,7 @@ class Smarty_Internal_Method_LoadPlugin
throw new SmartyException("plugin {$plugin_name} is not a valid name format");
}
if (!empty($match[ 2 ])) {
$file = SMARTY_SYSPLUGINS_DIR . strtolower($plugin_name) . '.php';
$file = SMARTY_SYSPLUGINS_DIR . smarty_strtolower_ascii($plugin_name) . '.php';
if (isset($this->plugin_files[ $file ])) {
if ($this->plugin_files[ $file ] !== false) {
return $this->plugin_files[ $file ];
@@ -60,7 +60,7 @@ class Smarty_Internal_Method_LoadPlugin
}
// plugin filename is expected to be: [type].[name].php
$_plugin_filename = "{$match[1]}.{$match[4]}.php";
$_lower_filename = strtolower($_plugin_filename);
$_lower_filename = smarty_strtolower_ascii($_plugin_filename);
if (isset($this->plugin_files)) {
if (isset($this->plugin_files[ 'plugins_dir' ][ $_lower_filename ])) {
if (!$smarty->use_include_path || $this->plugin_files[ 'plugins_dir' ][ $_lower_filename ] !== false) {
@@ -32,7 +32,7 @@ class Smarty_Internal_Method_MustCompile
{
if (!$_template->source->exists) {
if ($_template->_isSubTpl()) {
$parent_resource = " in '$_template->parent->template_resource}'";
$parent_resource = " in '{$_template->parent->template_resource}'";
} else {
$parent_resource = '';
}
+2 -2
View File
@@ -292,7 +292,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
$smarty = &$this->smarty;
$_templateId = $smarty->_getTemplateId($template, $cache_id, $compile_id, $caching, $tpl);
// recursive call ?
if (isset($tpl->templateId) ? $tpl->templateId : $tpl->_getTemplateId() !== $_templateId) {
if ((isset($tpl->templateId) ? $tpl->templateId : $tpl->_getTemplateId()) !== $_templateId) {
// already in template cache?
if (isset(self::$tplObjCache[ $_templateId ])) {
// copy data from cached object
@@ -358,7 +358,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
}
if ($tpl->caching === 9999) {
if (!isset($tpl->compiled)) {
$this->loadCompiled(true);
$tpl->loadCompiled(true);
}
if ($tpl->compiled->has_nocache_code) {
$this->cached->hashes[ $tpl->compiled->nocache_hash ] = true;
@@ -257,7 +257,7 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data
error_reporting($_smarty_old_error_level);
}
return $result;
} catch (Exception $e) {
} catch (Throwable $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
@@ -605,7 +605,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
if (strcasecmp($name, 'isset') === 0 || strcasecmp($name, 'empty') === 0
|| strcasecmp($name, 'array') === 0 || is_callable($name)
) {
$func_name = strtolower($name);
$func_name = smarty_strtolower_ascii($name);
if ($func_name === 'isset') {
if (count($parameter) === 0) {
@@ -765,7 +765,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
if (!isset(self::$_tag_objects[ $tag ])) {
// lazy load internal compiler plugin
$_tag = explode('_', $tag);
$_tag = array_map('ucfirst', $_tag);
$_tag = array_map('smarty_ucfirst_ascii', $_tag);
$class_name = 'Smarty_Internal_Compile_' . implode('_', $_tag);
if (class_exists($class_name)
&& (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this))
+2 -2
View File
@@ -76,11 +76,11 @@ abstract class Smarty_Resource
}
// try sysplugins dir
if (isset(self::$sysplugins[ $type ])) {
$_resource_class = 'Smarty_Internal_Resource_' . ucfirst($type);
$_resource_class = 'Smarty_Internal_Resource_' . smarty_ucfirst_ascii($type);
return $smarty->_cache[ 'resource_handlers' ][ $type ] = new $_resource_class();
}
// try plugins dir
$_resource_class = 'Smarty_Resource_' . ucfirst($type);
$_resource_class = 'Smarty_Resource_' . smarty_ucfirst_ascii($type);
if ($smarty->loadPlugin($_resource_class)) {
if (class_exists($_resource_class, false)) {
return $smarty->_cache[ 'resource_handlers' ][ $type ] = new $_resource_class();
-2
View File
@@ -1,2 +0,0 @@
#! /bin/bash
vendor/phpunit/phpunit/phpunit
+44
View File
@@ -0,0 +1,44 @@
#!/bin/bash
Help()
{
# Display Help
echo "Runs PHPUnit tests for all PHP versions supported by this version of Smarty."
echo
echo "Syntax: $0 [-e|h]"
echo "options:"
echo "e Exclude a group of unit tests, e.g. -e 'slow'"
echo "h Print this Help."
echo
}
Exclude=""
# Get the options
while getopts ":he:" option; do
case $option in
e) # Exclude
echo $OPTARG
Exclude=$OPTARG;;
h) # display Help
Help
exit;;
\?) # Invalid option
echo "Error: Invalid option"
exit;;
esac
done
if [ -z $Exclude ];
then
Entrypoint="./run-tests.sh"
else
Entrypoint="./run-tests.sh $Exclude"
fi
# Runs tests for all supported PHP versions
docker-compose run --entrypoint "$Entrypoint" php71 && \
docker-compose run --entrypoint "$Entrypoint" php72 && \
docker-compose run --entrypoint "$Entrypoint" php73 && \
docker-compose run --entrypoint "$Entrypoint" php74 && \
docker-compose run --entrypoint "$Entrypoint" php80 && \
docker-compose run --entrypoint "$Entrypoint" php81
Executable
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
composer update
php -r 'echo "\nPHP version " . phpversion() . ". ";';
if [ -z $1 ];
then
echo "Running all unit tests.\n"
php ./vendor/phpunit/phpunit/phpunit
else
echo "Running all unit tests, except tests marked with @group $1.\n"
php ./vendor/phpunit/phpunit/phpunit --exclude-group $1
fi
@@ -210,6 +210,7 @@ class PluginFunctionHtmlSelectDateTest extends PHPUnit_Smarty
public function setUp(): void
{
$this->setUpSmarty(dirname(__FILE__));
$this->smarty->setErrorReporting(E_ALL & ~E_DEPRECATED);
$year = date('Y');
$this->now = mktime(15, 0, 0, 2, 20, $year);
@@ -238,6 +239,7 @@ class PluginFunctionHtmlSelectDateTest extends PHPUnit_Smarty
$this->years['default'] = "<option value=\"{$year}\" selected=\"selected\">{$year}</option>";
$this->years['none'] = "<option value=\"{$year}\">{$year}</option>";
}
protected function reverse($string)
@@ -394,6 +396,33 @@ class PluginFunctionHtmlSelectDateTest extends PHPUnit_Smarty
$this->assertEquals($result, $tpl->fetch());
}
public function testEmptyDayWithDateString() {
$n = "\n";
$result = '<select name="Date_Month">' . $n . $this->months['default'] . $n . '</select>'
. $n . '<select name="Date_Day">' . $n . '<option value="">day</option>' . $n . $this->days['none'] . $n . '</select>'
. $n . '<select name="Date_Year">' . $n . $this->years['start_2005'] . $n . '</select>';
$tpl = $this->smarty->createTemplate('eval:{html_select_date time="2022-02-" day_empty="day" start_year=2005}');
$this->assertEquals($result, $tpl->fetch());
}
public function testEmptyMonthWithDateStrings() {
$n = "\n";
$result = '<select name="Date_Month">' . $n . '<option value="">month</option>' . $n . $this->months['none'] . $n . '</select>'
. $n . '<select name="Date_Day">' . $n . $this->days['default'] . $n . '</select>'
. $n . '<select name="Date_Year">' . $n . $this->years['start_2005'] . $n . '</select>';
$tpl = $this->smarty->createTemplate('eval:{html_select_date time="2022--20" month_empty="month" start_year=2005}');
$this->assertEquals($result, $tpl->fetch());
}
public function testEmptyYearWithDateStrings() {
$n = "\n";
$result = '<select name="Date_Month">' . $n . $this->months['default'] . $n . '</select>'
. $n . '<select name="Date_Day">' . $n . $this->days['default'] . $n . '</select>'
. $n . '<select name="Date_Year">' . $n . '<option value="">year</option>' . $n . $this->years['none'] . $n . '</select>';
$tpl = $this->smarty->createTemplate('eval:{html_select_date time="-02-20" year_empty="year"}');
$this->assertEquals($result, $tpl->fetch());
}
public function testId()
{
$n = "\n";
@@ -150,7 +150,7 @@ class PluginFunctionMailtoTest extends PHPUnit_Smarty
public function testUmlauts()
{
$result = '<a href="mailto:me+smtpext@example.com?cc=you@example.com,they@example.com&subject=h%C3%A4llo%20w%C3%B6rld" >me+smtpext@example.com</a>';
$result = '<a href="mailto:me+smtpext@example.com?cc=you@example.com,they@example.com&amp;subject=h%C3%A4llo%20w%C3%B6rld" >me+smtpext@example.com</a>';
$tpl = $this->smarty->createTemplate('eval:{mailto address="me+smtpext@example.com" cc="you@example.com,they@example.com" subject="hällo wörld"}');
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
}
@@ -158,9 +158,26 @@ class PluginFunctionMailtoTest extends PHPUnit_Smarty
public function testUmlautsWithoutMbstring()
{
Smarty::$_MBSTRING = false;
$result = '<a href="mailto:me+smtpext@example.com?cc=you@example.com,they@example.com&subject=h%C3%A4llo%20w%C3%B6rld" >me+smtpext@example.com</a>';
$result = '<a href="mailto:me+smtpext@example.com?cc=you@example.com,they@example.com&amp;subject=h%C3%A4llo%20w%C3%B6rld" >me+smtpext@example.com</a>';
$tpl = $this->smarty->createTemplate('eval:{mailto address="me+smtpext@example.com" cc="you@example.com,they@example.com" subject="hällo wörld"}');
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
Smarty::$_MBSTRING = true;
}
public function testJavascriptChars()
{
$result = '<script type="text/javascript">document.write(unescape(\'%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%26%71%75%6f%74%3b%26%67%74%3b%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%26%23%30%33%39%3b%29%3b%20%61%6c%65%72%74%28%26%71%75%6f%74%3b%69%6e%6a%65%63%74%69%6f%6e%26%71%75%6f%74%3b%29%3b%20%2f%2f%22%20%3e%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%26%71%75%6f%74%3b%26%67%74%3b%6d%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%26%23%30%33%39%3b%29%3b%20%61%6c%65%72%74%28%26%71%75%6f%74%3b%69%6e%6a%65%63%74%69%6f%6e%26%71%75%6f%74%3b%29%3b%20%2f%2f%3c%2f%61%3e\'))</script>';
$this->smarty->assign('address', 'me@example.com">me@example.com\'); alert("injection"); //');
$tpl = $this->smarty->createTemplate('eval:{mailto address=$address encode=javascript}');
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
}
public function testHtmlChars()
{
$result = '<a href="mailto:me@example.com&quot;&gt;&lt;h1&gt;" class="email">me@example.com&quot;&gt;&lt;h1&gt;</a>';
$this->smarty->assign('address', 'me@example.com"><h1>');
$tpl = $this->smarty->createTemplate('eval:{mailto address=$address extra=\'class="email"\'}');
$this->assertEquals(str_replace("\r", '', $result), $this->smarty->fetch($tpl));
}
}
@@ -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' => '[""]',
],
];
}
}
@@ -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' => "",
],
];
}
}
@@ -63,6 +63,11 @@ class PluginModifierUnescapeTest extends PHPUnit_Smarty
$tpl = $this->smarty->createTemplate('string:{"' . $encoded . '"|unescape:"url"}');
$this->assertEquals($result, $this->smarty->fetch($tpl));
}
}
?>
public function testCharset()
{
$tpl = $this->smarty->createTemplate("string:{'&#039;Stiff Opposition Expected to Casketless Funeral Plan&#039;'|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));
}
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
*
-2
View File
@@ -1,2 +0,0 @@
#!/bin/sh
composer update && php ./vendor/phpunit/phpunit/phpunit