Skip to content

Commit

Permalink
PHP8.2 compatibility (#775)
Browse files Browse the repository at this point in the history
* PHP8.2 compatibility

* PHP8.2 compatibility : Fixed unit tests

* PHP8.2 compatibility : Replace ENT_COMPAT by ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401

* PHP8.2 compatibility : Remove deprecated utf8_decode

* PHP8.2 compatibility : Remove HTML-ENTITIES parameter

* Removed some unused code for clarity, updated the changelog.

* More concise escape implementation and unit test to cover both modifierplugin and modifiercompiler.

* Fix htmlall unescape of quotes without mbstring too

Co-authored-by: Simon Wisselink <s.wisselink@iwink.nl>
  • Loading branch information
Progi1984 and wisskid authored Nov 22, 2022
1 parent f817209 commit c016895
Show file tree
Hide file tree
Showing 22 changed files with 95 additions and 129 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
- "7.4"
- "8.0"
- "8.1"
- "8.2"

compiler:
- default
Expand All @@ -42,6 +43,9 @@ jobs:
- os: ubuntu-latest
php-version: "8.1"
compiler: jit
- os: ubuntu-latest
php-version: "8.2"
compiler: jit

steps:
- name: Checkout
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- PHP8.2 compatibility [#775](https://github.com/smarty-php/smarty/pull/775)

### Changed
- Include docs and demo in the releases [#799](https://github.com/smarty-php/smarty/issues/799)
- Using PHP functions as modifiers now triggers a deprecation notice because we will drop support for this in the next major release [#813](https://github.com/smarty-php/smarty/issues/813)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 can be run with PHP 7.1 to PHP 8.1.
Smarty can be run with PHP 7.1 to PHP 8.2.

## Installation
Smarty versions 3.1.11 or later can be installed with [Composer](https://getcomposer.org/).
Expand Down
5 changes: 5 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,8 @@ services:
service: base
build:
dockerfile: ./utilities/testrunners/php81/Dockerfile
php82:
extends:
service: base
build:
dockerfile: ./utilities/testrunners/php82/Dockerfile
2 changes: 1 addition & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ What is Smarty?
==============

## Requirements
Smarty can be run with PHP 7.1 to PHP 8.1.
Smarty can be run with PHP 7.1 to PHP 8.2.

## Installation
Smarty versions 3.1.11 or later can be installed with [Composer](https://getcomposer.org/).
Expand Down
81 changes: 4 additions & 77 deletions libs/plugins/modifier.escape.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
*/
function smarty_modifier_escape($string, $esc_type = 'html', $char_set = null, $double_encode = true)
{
static $_double_encode = true;
static $is_loaded_1 = false;
static $is_loaded_2 = false;
if (!$char_set) {
Expand All @@ -34,87 +33,15 @@ function smarty_modifier_escape($string, $esc_type = 'html', $char_set = null, $

switch ($esc_type) {
case 'html':
if ($_double_encode) {
// php >=5.3.2 - go native
return htmlspecialchars($string, ENT_QUOTES, $char_set, $double_encode);
} else {
if ($double_encode) {
// php <5.2.3 - only handle double encoding
return htmlspecialchars($string, ENT_QUOTES, $char_set);
} else {
// php <5.2.3 - prevent double encoding
$string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
$string = htmlspecialchars($string, ENT_QUOTES, $char_set);
$string = str_replace(
array(
'%%%SMARTY_START%%%',
'%%%SMARTY_END%%%'
),
array(
'&',
';'
),
$string
);
return $string;
}
}
return htmlspecialchars($string, ENT_QUOTES, $char_set, $double_encode);
// no break
case 'htmlall':
if (Smarty::$_MBSTRING) {
// mb_convert_encoding ignores htmlspecialchars()
if ($_double_encode) {
// php >=5.3.2 - go native
$string = htmlspecialchars($string, ENT_QUOTES, $char_set, $double_encode);
} else {
if ($double_encode) {
// php <5.2.3 - only handle double encoding
$string = htmlspecialchars($string, ENT_QUOTES, $char_set);
} else {
// php <5.2.3 - prevent double encoding
$string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
$string = htmlspecialchars($string, ENT_QUOTES, $char_set);
$string =
str_replace(
array(
'%%%SMARTY_START%%%',
'%%%SMARTY_END%%%'
),
array(
'&',
';'
),
$string
);
return $string;
}
}
// htmlentities() won't convert everything, so use mb_convert_encoding
return mb_convert_encoding($string, 'HTML-ENTITIES', $char_set);
$string = mb_convert_encoding($string, 'UTF-8', $char_set);
return htmlentities($string, ENT_QUOTES, 'UTF-8', $double_encode);
}
// no MBString fallback
if ($_double_encode) {
return htmlentities($string, ENT_QUOTES, $char_set, $double_encode);
} else {
if ($double_encode) {
return htmlentities($string, ENT_QUOTES, $char_set);
} else {
$string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
$string = htmlentities($string, ENT_QUOTES, $char_set);
$string = str_replace(
array(
'%%%SMARTY_START%%%',
'%%%SMARTY_END%%%'
),
array(
'&',
';'
),
$string
);
return $string;
}
}
return htmlentities($string, ENT_QUOTES, $char_set, $double_encode);
// no break
case 'url':
return rawurlencode($string);
Expand Down
41 changes: 8 additions & 33 deletions libs/plugins/modifiercompiler.escape.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@
* @param Smarty_Internal_TemplateCompilerBase $compiler
*
* @return string with compiled code
* @throws \SmartyException
* @throws SmartyException
*/
function smarty_modifiercompiler_escape($params, Smarty_Internal_TemplateCompilerBase $compiler)
{
static $_double_encode = true;
static $is_loaded = false;
$compiler->template->_checkPlugins(
array(
array(
Expand All @@ -41,41 +39,18 @@ function smarty_modifiercompiler_escape($params, Smarty_Internal_TemplateCompile
}
switch ($esc_type) {
case 'html':
if ($_double_encode) {
return 'htmlspecialchars((string)' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ', ' .
var_export($double_encode, true) . ')';
} elseif ($double_encode) {
return 'htmlspecialchars((string)' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ')';
} else {
// fall back to modifier.escape.php
}
return 'htmlspecialchars((string)' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ', ' .
var_export($double_encode, true) . ')';
// no break
case 'htmlall':
if (Smarty::$_MBSTRING) {
if ($_double_encode) {
// php >=5.2.3 - go native
return 'mb_convert_encoding(htmlspecialchars((string)' . $params[ 0 ] . ', ENT_QUOTES, ' .
var_export($char_set, true) . ', ' . var_export($double_encode, true) .
'), "HTML-ENTITIES", ' . var_export($char_set, true) . ')';
} elseif ($double_encode) {
// php <5.2.3 - only handle double encoding
return 'mb_convert_encoding(htmlspecialchars((string)' . $params[ 0 ] . ', ENT_QUOTES, ' .
var_export($char_set, true) . '), "HTML-ENTITIES", ' . var_export($char_set, true) . ')';
} else {
// fall back to modifier.escape.php
}
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 MBString fallback
if ($_double_encode) {
// php >=5.2.3 - go native
return 'htmlentities((string)' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ', ' .
var_export($double_encode, true) . ')';
} elseif ($double_encode) {
// php <5.2.3 - only handle double encoding
return 'htmlentities((string)' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ')';
} else {
// fall back to modifier.escape.php
}
return 'htmlentities((string)' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ', ' .
var_export($double_encode, true) . ')';
// no break
case 'url':
return 'rawurlencode((string)' . $params[ 0 ] . ')';
Expand Down
4 changes: 2 additions & 2 deletions libs/plugins/modifiercompiler.unescape.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ function smarty_modifiercompiler_unescape($params, Smarty_Internal_TemplateCompi
case 'entity':
case 'htmlall':
if (Smarty::$_MBSTRING) {
return 'mb_convert_encoding(' . $params[ 0 ] . ', ' . $params[ 2 ] . ', \'HTML-ENTITIES\')';
return 'html_entity_decode(mb_convert_encoding(' . $params[ 0 ] . ', ' . $params[ 2 ] . ', \'UTF-8\'), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, ' . $params[ 2 ] . ')';
}
return 'html_entity_decode(' . $params[ 0 ] . ', ENT_NOQUOTES, ' . $params[ 2 ] . ')';
return 'html_entity_decode(' . $params[ 0 ] . ', ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, ' . $params[ 2 ] . ')';
case 'html':
return 'htmlspecialchars_decode(' . $params[ 0 ] . ', ENT_QUOTES)';
case 'url':
Expand Down
1 change: 1 addition & 0 deletions libs/sysplugins/smarty_internal_extension_handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
* @property Smarty_Internal_Method_RegisterPlugin $registerPlugin
* @property mixed|\Smarty_Template_Cached configLoad
*/
#[\AllowDynamicProperties]
class Smarty_Internal_Extension_Handler
{
public $objType = null;
Expand Down
2 changes: 1 addition & 1 deletion libs/sysplugins/smarty_internal_runtime_make_nocache.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function save(Smarty_Internal_Template $tpl, $var)
{
if (isset($tpl->tpl_vars[ $var ])) {
$export =
preg_replace('/^Smarty_Variable::__set_state[(]|[)]$/', '', var_export($tpl->tpl_vars[ $var ], true));
preg_replace('/^\\\\?Smarty_Variable::__set_state[(]|[)]$/', '', var_export($tpl->tpl_vars[ $var ], true));
if (preg_match('/(\w+)::__set_state/', $export, $match)) {
throw new SmartyException("{make_nocache \${$var}} in template '{$tpl->source->name}': variable does contain object '{$match[1]}' not implementing method '__set_state'");
}
Expand Down
1 change: 1 addition & 0 deletions libs/sysplugins/smarty_internal_template.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*
* @method bool mustCompile()
*/
#[\AllowDynamicProperties]
class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
{
/**
Expand Down
1 change: 1 addition & 0 deletions libs/sysplugins/smarty_security.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
/**
* This class does contain the security settings
*/
#[\AllowDynamicProperties]
class Smarty_Security
{

Expand Down
1 change: 1 addition & 0 deletions libs/sysplugins/smarty_variable.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* @package Smarty
* @subpackage Template
*/
#[\AllowDynamicProperties]
class Smarty_Variable
{
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ public function testSmartyIsCached()
}
}

#[AllowDynamicProperties]
class ResourceStream
{
private $position;
Expand Down
1 change: 1 addition & 0 deletions tests/UnitTests/SecurityTests/SecurityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ class Security extends Smarty_Security
{

}
#[AllowDynamicProperties]
class ResourceStreamSecurity
{
private $position;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
*/
class CompileRegisteredObjectFunctionTest extends PHPUnit_Smarty
{
/**
* @var RegObject
*/
private $object;

public function setUp(): void
{
$this->setUpSmarty(__DIR__);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function setUp(): void
public function testToLatin1()
{
$encoded = "hällö wörld 1";
$result = utf8_decode($encoded);
$result = mb_convert_encoding($encoded, 'ISO-8859-1', 'UTF-8');
$tpl = $this->smarty->createTemplate('string:{"' . $encoded . '"|to_charset}');
$this->assertEquals(str_replace("\r", '', $result), $tpl->fetch());
}
Expand All @@ -33,7 +33,7 @@ public function testToLatin1WithoutMbstring()
Smarty::$_MBSTRING = false;
$this->smarty->setCompileId('mb');
$encoded = "hällö wörld 2";
$result = utf8_decode($encoded);
$result = mb_convert_encoding($encoded, 'ISO-8859-1', 'UTF-8');
$tpl = $this->smarty->createTemplate('string:{"' . $encoded . '"|to_charset}');
$this->assertEquals($encoded, $tpl->fetch());
Smarty::$_MBSTRING = true;
Expand All @@ -42,7 +42,7 @@ public function testToLatin1WithoutMbstring()
public function testFromLatin1()
{
$result = "hällö wörld 3";
$encoded = utf8_decode($result);
$encoded = mb_convert_encoding($result, 'ISO-8859-1', 'UTF-8');
$tpl = $this->smarty->createTemplate('string:{"' . $encoded . '"|from_charset}');
$this->assertEquals(str_replace("\r", '', $result), $tpl->fetch());
}
Expand All @@ -52,7 +52,7 @@ public function testFromLatin1WithoutMbstring()
Smarty::$_MBSTRING = false;
$this->smarty->setCompileId('mb');
$result = "hällö wörld 4";
$encoded = utf8_decode($result);
$encoded = mb_convert_encoding($result, 'ISO-8859-1', 'UTF-8');
$tpl = $this->smarty->createTemplate('string:{"' . $encoded . '"|from_charset}');
$this->assertEquals($encoded, $tpl->fetch());
Smarty::$_MBSTRING = true;
Expand Down
Loading

0 comments on commit c016895

Please sign in to comment.