diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00072c8c..04624c0f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,7 @@ jobs: - "8.0" - "8.1" - "8.2" + - "8.3" compiler: - default @@ -46,7 +47,9 @@ jobs: - os: ubuntu-latest php-version: "8.2" compiler: jit - + - os: ubuntu-latest + php-version: "8.3" + compiler: jit steps: - name: Checkout uses: actions/checkout@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index c0d59260..6fd2a6c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Using unregistered static class methods in expressions now also 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) +## [4.4.1] - 2024-02-26 +- Fixed internal release-tooling + +## [4.4.0] - 2024-02-26 +### Changed +- Using the `|implode`, `|json_encode` and `|substr` modifiers does not generate a deprecation warning anymore as they will continue to be supported in v5 [#939](https://github.com/smarty-php/smarty/issues/939) + +### Added +- PHP8.3 support [#925](https://github.com/smarty-php/smarty/issues/925) + +### Fixed +- Incorrect compilation of expressions when escape_html=true [#930](https://github.com/smarty-php/smarty/pull/930) + ## [4.3.4] - 2023-09-14 ## [4.3.3] - 2023-09-14 diff --git a/README.md b/README.md index 0ef3cfab..9b8706d4 100644 --- a/README.md +++ b/README.md @@ -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.2. +Smarty can be run with PHP 7.1 to PHP 8.3. ## Installation Smarty versions 3.1.11 or later can be installed with [Composer](https://getcomposer.org/). diff --git a/changelog/.gitkeep b/changelog/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docker-compose.yml b/docker-compose.yml index 4f940b2c..ff759f5f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,3 +42,8 @@ services: service: base build: dockerfile: ./utilities/testrunners/php82/Dockerfile + php83: + extends: + service: base + build: + dockerfile: ./utilities/testrunners/php83/Dockerfile \ No newline at end of file diff --git a/docs/getting-started.md b/docs/getting-started.md index 2ffbbd11..f549e50e 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,7 +1,7 @@ # Getting started ## Requirements -Smarty can be run with PHP 7.1 to PHP 8.2. +Smarty can be run with PHP 7.1 to PHP 8.3. ## Installation Smarty can be installed with [Composer](https://getcomposer.org/). diff --git a/docs/upgrading.md b/docs/upgrading.md new file mode 100644 index 00000000..667a1422 --- /dev/null +++ b/docs/upgrading.md @@ -0,0 +1,38 @@ +# Upgrading from an older version + +## Upgrading from v3 to v4 + +Smarty 4 is mostly identical to Smarty 3. Most notably, it adds support for PHP8 and drops support for PHP7.0 and below. +Additionally, some deprecated features that have long been discouraged have been dropped from the language. + +### Muting PHP8 warnings +If you simultaneously upgrade Smarty to v4 van PHP to v8, you may notice your error logs filling up with warnings about undefined or null template vars +due to a change in how PHP handles these. This may be helpful to spot errors, but if you find this annoying, you can use +`$smarty->muteUndefinedOrNullWarnings()` to make Smarty convert these warnings into notices. + +### ASP tags +You can no longer user ASP-style tags like `<% %>` and `<%= %>` in your templates. +Replace them with `{...}` tags. + +### SmartyBC +Check your codebase for `SmartyBC`. +We have dropped deprecated API calls that where only accessible through the SmartyBC class. + +### No more embedded PHP +We have completely dropped support for `{php}` and `{include_php}` tags and embedded PHP in templates. +Check your templates for this, and rewrite any embedded PHP blocks, by moving logic to your PHP files or by +creating a [plugin function](./programmers/plugins/plugins-functions.md). + +### Other changes + +Search your code for the following changes: + +- `SMARTY_RESOURCE_CHAR_SET` and `SMARTY_RESOURCE_DATE_FORMAT` constants have been removed +- `Smarty::muteExpectedErrors` and `Smarty::unmuteExpectedErrors` API methods have been removed +- `Smarty::getVariable` method has been removed. Use [Smarty::getTemplateVars](programmers/api-functions/api-get-template-vars.md) instead. +- [Smarty::registerResource](programmers/api-functions/api-register-resource.md) no longer accepts an array of callback functions + + + + + diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php index f102d889..0a47c835 100644 --- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -107,7 +107,7 @@ class Smarty extends Smarty_Internal_TemplateBase /** * smarty version */ - const SMARTY_VERSION = '4.3.4'; + const SMARTY_VERSION = '4.4.1'; /** * define variable scopes */ diff --git a/libs/plugins/modifier.implode.php b/libs/plugins/modifier.implode.php new file mode 100644 index 00000000..679d71d7 --- /dev/null +++ b/libs/plugins/modifier.implode.php @@ -0,0 +1,15 @@ +template->smarty->escape_html) { - $output = "htmlspecialchars((string) {$output}, ENT_QUOTES, '" . addslashes(Smarty::$_CHARSET) . "')"; + $output = "htmlspecialchars((string) ({$output}), ENT_QUOTES, '" . addslashes(Smarty::$_CHARSET) . "')"; } // loop over registered filters if (!empty($compiler->template->smarty->registered_filters[ Smarty::FILTER_VARIABLE ])) { diff --git a/libs/sysplugins/smarty_internal_errorhandler.php b/libs/sysplugins/smarty_internal_errorhandler.php index 6f526c38..4ddcfcd1 100644 --- a/libs/sysplugins/smarty_internal_errorhandler.php +++ b/libs/sysplugins/smarty_internal_errorhandler.php @@ -94,7 +94,7 @@ class Smarty_Internal_ErrorHandler } if ($this->allowUndefinedArrayKeys && preg_match( - '/^(Undefined index|Undefined array key|Trying to access array offset on value of type)/', + '/^(Undefined index|Undefined array key|Trying to access array offset on)/', $errstr )) { return; // suppresses this error diff --git a/make-release.sh b/make-release.sh index e893deb3..64268e83 100755 --- a/make-release.sh +++ b/make-release.sh @@ -8,10 +8,11 @@ else fi git checkout -b "release/$1" -sed -i "s/## \\[Unreleased\\]/## \\[Unreleased\\]\\n\\n## \\[$1\\] - $(date +%Y-%m-%d)/" CHANGELOG.md -sed -i "s/const SMARTY_VERSION = '[^']\+';/const SMARTY_VERSION = '$1';/" libs/Smarty.class.php -git add CHANGELOG.md libs/Smarty.class.php +php utilities/update-changelog.php $1 +php utilities/update-smarty-version-number.php $1 + +git add changelog CHANGELOG.md libs/Smarty.class.php git commit -m "version bump" git checkout support/4.3 diff --git a/mkdocs.yml b/mkdocs.yml index 7762cd75..66949b80 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -26,7 +26,9 @@ markdown_extensions: nav: - Home: 'index.md' - - 'Getting started': 'getting-started.md' + - 'Getting started': + - Introduction: 'getting-started.md' + - 'Upgrading from an older version': 'upgrading.md' - 'Designers': - 'Basic Syntax': - Introduction: 'designers/language-basic-syntax/index.md' diff --git a/run-tests-for-all-php-versions.sh b/run-tests-for-all-php-versions.sh index b64f01e4..79bebb8a 100755 --- a/run-tests-for-all-php-versions.sh +++ b/run-tests-for-all-php-versions.sh @@ -10,4 +10,6 @@ docker-compose run php72 ./run-tests.sh $@ && \ docker-compose run php73 ./run-tests.sh $@ && \ docker-compose run php74 ./run-tests.sh $@ && \ docker-compose run php80 ./run-tests.sh $@ && \ -docker-compose run php81 ./run-tests.sh $@ +docker-compose run php81 ./run-tests.sh $@ && \ +docker-compose run php82 ./run-tests.sh $@ && \ +docker-compose run php83 ./run-tests.sh $@ diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierImplodeTest.php b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierImplodeTest.php new file mode 100644 index 00000000..5b816aaf --- /dev/null +++ b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierImplodeTest.php @@ -0,0 +1,44 @@ +setUpSmarty(__DIR__); + } + + public function testDefault() + { + $tpl = $this->smarty->createTemplate('string:{""|implode:$v}'); + $tpl->assign("v", ["1", "2"]); + $this->assertEquals("12", $this->smarty->fetch($tpl)); + } + public function testWithSeparator() + { + $tpl = $this->smarty->createTemplate('string:{","|implode:$v}'); + $tpl->assign("v", ["a", "b"]); + $this->assertEquals("a,b", $this->smarty->fetch($tpl)); + } + public function testInConditional() + { + $tpl = $this->smarty->createTemplate('string:{if implode("", $v) == "abc"}good{else}bad{/if}'); + $tpl->assign("v", ['a','b','c']); + $this->assertEquals("good", $this->smarty->fetch($tpl)); + } + public function testInConditionalWithSeparator() + { + $tpl = $this->smarty->createTemplate('string:{if implode("-", $v) == "a-b-c"}good{else}bad{/if}'); + $tpl->assign("v", ['a','b','c']); + $this->assertEquals("good", $this->smarty->fetch($tpl)); + } +} diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierJsonEncodeTest.php b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierJsonEncodeTest.php new file mode 100644 index 00000000..965c8a6d --- /dev/null +++ b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierJsonEncodeTest.php @@ -0,0 +1,76 @@ +setUpSmarty(__DIR__); + } + + /** + * @dataProvider dataForDefault + */ + public function testDefault($value, $expected) + { + $tpl = $this->smarty->createTemplate('string:{$v|json_encode}'); + $tpl->assign("v", $value); + $this->assertEquals($expected, $this->smarty->fetch($tpl)); + } + + /** + * @dataProvider dataForDefault + */ + public function testDefaultAsFunction($value, $expected) + { + $tpl = $this->smarty->createTemplate('string:{json_encode($v)}'); + $tpl->assign("v", $value); + $this->assertEquals($expected, $this->smarty->fetch($tpl)); + } + + public function dataForDefault() { + return [ + ["abc", '"abc"'], + [["abc"], '["abc"]'], + [["abc",["a"=>2]], '["abc",{"a":2}]'], + ]; + } + + /** + * @dataProvider dataForForceObject + */ + public function testForceObject($value, $expected) + { + $tpl = $this->smarty->createTemplate('string:{$v|json_encode:16}'); + $tpl->assign("v", $value); + $this->assertEquals($expected, $this->smarty->fetch($tpl)); + } + + /** + * @dataProvider dataForForceObject + */ + public function testForceObjectAsFunction($value, $expected) + { + $tpl = $this->smarty->createTemplate('string:{json_encode($v,16)}'); + $tpl->assign("v", $value); + $this->assertEquals($expected, $this->smarty->fetch($tpl)); + } + + public function dataForForceObject() { + return [ + ["abc", '"abc"'], + [["abc"], '{"0":"abc"}'], + [["abc",["a"=>2]], '{"0":"abc","1":{"a":2}}'], + ]; + } + +} diff --git a/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierSubstrTest.php b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierSubstrTest.php new file mode 100644 index 00000000..42abf869 --- /dev/null +++ b/tests/UnitTests/TemplateSource/TagTests/PluginModifier/PluginModifierSubstrTest.php @@ -0,0 +1,48 @@ +setUpSmarty(__DIR__); + } + + public function testDefault() + { + $tpl = $this->smarty->createTemplate('string:{$v|substr:1}'); + $tpl->assign("v", "abc"); + $this->assertEquals("bc", $this->smarty->fetch($tpl)); + } + + public function testTwoArguments() + { + $tpl = $this->smarty->createTemplate('string:{$v|substr:1:1}'); + $tpl->assign("v", "abc"); + $this->assertEquals("b", $this->smarty->fetch($tpl)); + } + + public function testNegativeOffset() + { + $tpl = $this->smarty->createTemplate('string:{$v|substr:-1}'); + $tpl->assign("v", "abc"); + $this->assertEquals("c", $this->smarty->fetch($tpl)); + } + + public function testInConditional() + { + $tpl = $this->smarty->createTemplate('string:{if substr($v, -1) == "c"}good{else}bad{/if}'); + $tpl->assign("v", "abc"); + $this->assertEquals("good", $this->smarty->fetch($tpl)); + } + +} diff --git a/utilities/testrunners/php83/Dockerfile b/utilities/testrunners/php83/Dockerfile new file mode 100644 index 00000000..83cd8255 --- /dev/null +++ b/utilities/testrunners/php83/Dockerfile @@ -0,0 +1,10 @@ +FROM php:8.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 diff --git a/utilities/update-changelog.php b/utilities/update-changelog.php new file mode 100644 index 00000000..f5b9534f --- /dev/null +++ b/utilities/update-changelog.php @@ -0,0 +1,42 @@ +