diff --git a/.gitattributes b/.gitattributes index bbf8135e..c6644c99 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,8 +8,9 @@ # exclude from git export /tests 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 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e27b60bf..33224fcb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 @@ -29,6 +31,7 @@ jobs: - "7.4" - "8.0" - "8.1" + - "8.2" compiler: - default @@ -40,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 @@ -69,9 +75,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 diff --git a/.gitignore b/.gitignore index 5bd891e4..67f0dc51 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ lexer/*.php lexer/*.php.bak lexer/*.out -utilies/*.php # Dev phpunit* diff --git a/CHANGELOG.md b/CHANGELOG.md index 93c5cbb7..5b5b0179 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,64 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed +- `$smarty->muteUndefinedOrNullWarnings()` now also mutes PHP7 notices for undefined array indexes [#736](https://github.com/smarty-php/smarty/issues/736) +- `$smarty->muteUndefinedOrNullWarnings()` now treats undefined vars and array access of a null or false variables + equivalent across all supported PHP versions + +## [4.3.0] - 2022-11-22 + +### 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) +- Dropped remaining references to removed PHP-support in Smarty 4 from docs, lexer and security class. [#816](https://github.com/smarty-php/smarty/issues/816) +- Support umask when writing (template) files and set dir permissions to 777 [#548](https://github.com/smarty-php/smarty/issues/548) [#819](https://github.com/smarty-php/smarty/issues/819) + +### 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) +- Bug fix for underscore and limited length in template name in custom resources [#581](https://github.com/smarty-php/smarty/pull/581) + + +## [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) + +## [4.1.1] - 2022-05-17 + +### Security +- Prevent PHP injection through malicious block name or include file name. This addresses CVE-2022-29221 + +### Fixed +- Exclude docs and demo from export and composer [#751](https://github.com/smarty-php/smarty/pull/751) - PHP 8.1 deprecation notices in demo/plugins/cacheresource.pdo.php [#706](https://github.com/smarty-php/smarty/issues/706) - PHP 8.1 deprecation notices in truncate modifier [#699](https://github.com/smarty-php/smarty/issues/699) - Math equation `max(x, y)` didn't work anymore [#721](https://github.com/smarty-php/smarty/issues/721) +- Fix PHP 8.1 deprecated warning when calling rtrim [#743](https://github.com/smarty-php/smarty/pull/743) +- PHP 8.1: fix deprecation in escape modifier [#727](https://github.com/smarty-php/smarty/pull/727) ## [4.1.0] - 2022-02-06 diff --git a/README.md b/README.md index 782f0b2c..0ef3cfab 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.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/). diff --git a/SECURITY.md b/SECURITY.md index d98ea018..ae9d5dc8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -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 | | ------- | ------------------ | diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..cc90fb8b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,45 @@ +version: "2" +services: + base: + build: + context: . + dockerfile: ./utilities/testrunners/php71/Dockerfile + volumes: + - .:/app + working_dir: /app + entrypoint: sh ./run-tests.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 + php82: + extends: + service: base + build: + dockerfile: ./utilities/testrunners/php82/Dockerfile diff --git a/docs/appendixes/tips.md b/docs/appendixes/tips.md index b0ea40cc..cdcc56b1 100644 --- a/docs/appendixes/tips.md +++ b/docs/appendixes/tips.md @@ -188,67 +188,6 @@ See also [`{html_select_date}`](#language.function.html.select.date), [`date_format`](#language.modifier.date.format) and [`$smarty.now`](#language.variables.smarty.now), -WAP/WML {#tips.wap} -======= - -WAP/WML templates require a php [Content-Type -header](&url.php-manual;header) to be passed along with the template. -The easist way to do this would be to write a custom function that -prints the header. If you are using [caching](#caching), that won\'t -work so we\'ll do it using the [`{insert}`](#language.function.insert) -tag; remember `{insert}` tags are not cached! Be sure that there is -nothing output to the browser before the template, or else the header -may fail. - - - - - - -your Smarty template *must* begin with the insert tag : - - - {insert name=header content="Content-Type: text/vnd.wap.wml"} - - - - - - - - - - - -

- Welcome to WAP with Smarty! - Press OK to continue... -

-
- - -

- Pretty easy isn't it? -

-
-
- - - Componentized Templates {#tips.componentized.templates} ======================= @@ -259,7 +198,7 @@ Smarty object, [`assign()`](#api.assign) the variables and [`display()`](#api.display) the template. So lets say for example we have a stock ticker on our template. We would collect the stock data in our application, then assign these variables in the template and display -it. Now wouldn\'t it be nice if you could add this stock ticker to any +it. Now wouldn't it be nice if you could add this stock ticker to any application by merely including the template, and not worry about fetching the data up front? @@ -301,9 +240,7 @@ assigning it to a template variable. -See also [`{include_php}`](#language.function.include.php), -[`{include}`](#language.function.include) and -[`{php}`](#language.function.php). +See also: [`{include}`](#language.function.include). Obfuscating E-mail Addresses {#tips.obfuscating.email} ============================ diff --git a/docs/appendixes/troubleshooting.md b/docs/appendixes/troubleshooting.md index fe012c12..d605dd2b 100644 --- a/docs/appendixes/troubleshooting.md +++ b/docs/appendixes/troubleshooting.md @@ -109,7 +109,7 @@ the corresponding error is in the template. -- This means that your application registered a custom error hander +- This means that your application registered a custom error handler (using [set\_error\_handler()](&url.php-manual;set_error_handler)) which is not respecting the given `$errno` as it should. If, for whatever reason, this is the desired behaviour of your custom error diff --git a/docs/designers/language-basic-syntax/language-syntax-attributes.md b/docs/designers/language-basic-syntax/language-syntax-attributes.md index 0fa7c773..417ac972 100644 --- a/docs/designers/language-basic-syntax/language-syntax-attributes.md +++ b/docs/designers/language-basic-syntax/language-syntax-attributes.md @@ -3,7 +3,7 @@ Attributes {#language.syntax.attributes} Most of the [functions](#language.syntax.functions) take attributes that specify or modify their behavior. Attributes to Smarty functions are -much like HTML attributes. Static values don\'t have to be enclosed in +much like HTML attributes. Static values don't have to be enclosed in quotes, but it is required for literal strings. Variables with or without modifiers may also be used, and should not be in quotes. You can even use PHP function results, plugin results and complex expressions. diff --git a/docs/designers/language-builtin-functions.md b/docs/designers/language-builtin-functions.md index 6c0879d6..fa615555 100644 --- a/docs/designers/language-builtin-functions.md +++ b/docs/designers/language-builtin-functions.md @@ -16,7 +16,6 @@ Built-in Functions {#language.builtin.functions} - [{function}](./language-builtin-functions/language-function-function.md) - [{if},{elseif},{else}](./language-builtin-functions/language-function-if.md) - [{include}](./language-builtin-functions/language-function-include.md) -- [{include_php}](./language-builtin-functions/language-function-include.php) - [{insert}](./language-builtin-functions/language-function-insert.md) - [{ldelim},{rdelim}](./language-builtin-functions/language-function-ldelim.md) - [{literal}](./language-builtin-functions/language-function-literal.md) diff --git a/docs/designers/language-builtin-functions/language-function-assign.md b/docs/designers/language-builtin-functions/language-function-assign.md index 3d3615bf..e4d50d30 100644 --- a/docs/designers/language-builtin-functions/language-function-assign.md +++ b/docs/designers/language-builtin-functions/language-function-assign.md @@ -135,7 +135,6 @@ The following functions can also *optionally* assign template variables. [`{capture}`](#language.function.capture), [`{include}`](#language.function.include), -[`{include_php}`](#language.function.include.php), [`{insert}`](#language.function.insert), [`{counter}`](#language.function.counter), [`{cycle}`](#language.function.cycle), diff --git a/docs/designers/language-builtin-functions/language-function-block.md b/docs/designers/language-builtin-functions/language-function-block.md index 941997a5..82659852 100644 --- a/docs/designers/language-builtin-functions/language-function-block.md +++ b/docs/designers/language-builtin-functions/language-function-block.md @@ -3,14 +3,14 @@ `{block}` is used to define a named area of template source for template inheritance. For details see section of [Template -Interitance](#advanced.features.template.inheritance). +Inheritance](#advanced.features.template.inheritance). The `{block}` template source area of a child template will replace the -correponding areas in the parent template(s). +corresponding areas in the parent template(s). Optionally `{block}` areas of child and parent templates can be merged into each other. You can append or prepend the parent `{block}` content -by using the `append` or `prepend` option flag with the childs `{block}` +by using the `append` or `prepend` option flag with the child's `{block}` definition. With the {\$smarty.block.parent} the `{block}` content of the parent template can be inserted at any location of the child `{block}` content. {\$smarty.block.child} inserts the `{block}` content diff --git a/docs/designers/language-builtin-functions/language-function-extends.md b/docs/designers/language-builtin-functions/language-function-extends.md index 9559e7c5..59f24645 100644 --- a/docs/designers/language-builtin-functions/language-function-extends.md +++ b/docs/designers/language-builtin-functions/language-function-extends.md @@ -3,7 +3,7 @@ `{extends}` tags are used in child templates in template inheritance for extending parent templates. For details see section of [Template -Interitance](#advanced.features.template.inheritance). +Inheritance](#advanced.features.template.inheritance). - The `{extends}` tag must be on the first line of the template. @@ -33,5 +33,5 @@ Interitance](#advanced.features.template.inheritance). -See also [Template Interitance](#advanced.features.template.inheritance) +See also [Template Inheritance](#advanced.features.template.inheritance) and [`{block}`](#language.function.block). diff --git a/docs/designers/language-builtin-functions/language-function-for.md b/docs/designers/language-builtin-functions/language-function-for.md index 0545c172..5445f6f3 100644 --- a/docs/designers/language-builtin-functions/language-function-for.md +++ b/docs/designers/language-builtin-functions/language-function-for.md @@ -2,7 +2,7 @@ ===== The `{for}{forelse}` tag is used to create simple loops. The following -different formarts are supported: +different formats are supported: - `{for $var=$start to $end}` simple loop with step size of 1. diff --git a/docs/designers/language-builtin-functions/language-function-include-php.md b/docs/designers/language-builtin-functions/language-function-include-php.md deleted file mode 100644 index 8fc074a2..00000000 --- a/docs/designers/language-builtin-functions/language-function-include-php.md +++ /dev/null @@ -1,74 +0,0 @@ -{include\_php} {#language.function.include.php} -============== - -> **Note** -> -> `{include_php}` is deprecated from Smarty, use registered plugins to -> properly insulate presentation from the application code. As of Smarty -> 3.1 the `{include_php}` tags are only available from [SmartyBC](#bc). - - Attribute Name Type Required Default Description - ---------------- --------- ---------- --------- ---------------------------------------------------------------------------------- - file string Yes *n/a* The name of the php file to include as absolute path - once boolean No *TRUE* whether or not to include the php file more than once if included multiple times - assign string No *n/a* The name of the variable that the output of include\_php will be assigned to - -**Option Flags:** - - Name Description - --------- ---------------------------------------- - nocache Disables caching of inluded PHP script - -`{include_php}` tags are used to include a php script in your template. -The path of the attribute `file` can be either absolute, or relative to -[`$trusted_dir`](#variable.trusted.dir). If security is enabled, then -the script must be located in the `$trusted_dir` path of the securty -policy. See the [Security](#advanced.features.security) section for -details. - -By default, php files are only included once even if called multiple -times in the template. You can specify that it should be included every -time with the `once` attribute. Setting once to FALSE will include the -php script each time it is included in the template. - -You can optionally pass the `assign` attribute, which will specify a -template variable name that the output of `{include_php}` will be -assigned to instead of displayed. - -The smarty object is available as `$_smarty_tpl->smarty` within the PHP -script that you include. - -The `load_nav.php` file: - - - query('select url, name from navigation order by name'); - $this->assign('navigation', $db->getRows()); - - ?> - - - -where the template is: - - - {* absolute path, or relative to $trusted_dir *} - {include_php file='/path/to/load_nav.php'} - {include_php '/path/to/load_nav.php'} {* short-hand *} - - {foreach item='nav' from=$navigation} - {$nav.name}
- {/foreach} - - - -See also [`{include}`](#language.function.include), -[`$trusted_dir`](#variable.trusted.dir), -[`{php}`](#language.function.php), -[`{capture}`](#language.function.capture), [template -resources](#resources) and [componentized -templates](#tips.componentized.templates) diff --git a/docs/designers/language-builtin-functions/language-function-include.md b/docs/designers/language-builtin-functions/language-function-include.md index 956d893e..bda2d802 100644 --- a/docs/designers/language-builtin-functions/language-function-include.md +++ b/docs/designers/language-builtin-functions/language-function-include.md @@ -131,7 +131,7 @@ cache lifetime of 500 seconds. In this example included template will be cached independent of the -global cahing setting. +global caching setting. {include 'sub_template.tpl' caching} @@ -188,7 +188,5 @@ current template. -See also [`{include_php}`](#language.function.include.php), -[`{insert}`](#language.function.insert), -[`{php}`](#language.function.php), [template resources](#resources) and +See also [`{insert}`](#language.function.insert), [template resources](#resources) and [componentized templates](#tips.componentized.templates). diff --git a/docs/designers/language-builtin-functions/language-function-insert.md b/docs/designers/language-builtin-functions/language-function-insert.md index e37c7389..e5bc7dcb 100644 --- a/docs/designers/language-builtin-functions/language-function-insert.md +++ b/docs/designers/language-builtin-functions/language-function-insert.md @@ -65,7 +65,7 @@ and display the returned results in place of the {insert} tag. The path can be either absolute, or relative to [`$trusted_dir`](#variable.trusted.dir). If security is enabled, then the script must be located in the `$trusted_dir` path of the - securty policy. See the [Security](#advanced.features.security) + security policy. See the [Security](#advanced.features.security) section for details. The Smarty object is passed as the second argument. This way you can diff --git a/docs/designers/language-builtin-functions/language-function-section.md b/docs/designers/language-builtin-functions/language-function-section.md index 0bab5c71..b28bb924 100644 --- a/docs/designers/language-builtin-functions/language-function-section.md +++ b/docs/designers/language-builtin-functions/language-function-section.md @@ -251,8 +251,8 @@ The above example will output: {section}\'s can be nested as deep as you like. With nested {section}\'s, you can access complex data structures, such as -multi-dimensional arrays. This is an example `.php` script thats -assign\'s the arrays. +multi-dimensional arrays. This is an example `.php` script that +assigns the arrays. > If security is enabled and you are fetching a file from the local > file system, `{fetch}` will only allow files from within the - > `$secure_dir` path of the securty policy. See the + > `$secure_dir` path of the security policy. See the > [Security](#advanced.features.security) section for details. - If the `assign` attribute is set, the output of the `{fetch}` diff --git a/docs/designers/language-custom-functions/language-function-html-image.md b/docs/designers/language-custom-functions/language-function-html-image.md index 76740a1f..e21f2a12 100644 --- a/docs/designers/language-custom-functions/language-function-html-image.md +++ b/docs/designers/language-custom-functions/language-function-html-image.md @@ -19,7 +19,7 @@ automatically calculated from the image file if they are not supplied. from. If not given, the web server\'s document root `$_ENV['DOCUMENT_ROOT']` is used as the base. If security is enabled, then the image must be located in the `$secure_dir` path of - the securty policy. See the [Security](#advanced.features.security) + the security policy. See the [Security](#advanced.features.security) section for details. - `href` is the href value to link the image to. If link is supplied, diff --git a/docs/designers/language-modifiers.md b/docs/designers/language-modifiers.md index 4cb69cd1..4626dbe5 100644 --- a/docs/designers/language-modifiers.md +++ b/docs/designers/language-modifiers.md @@ -115,7 +115,7 @@ These parameters follow the modifier name and are separated by a `:` - Secondly - if security is enabled, all php-functions that are to be used as modifiers have to be declared trusted in the - `$modifiers` property of the securty policy. See the + `$modifiers` property of the security policy. See the [Security](../programmers/advanced-features/advanced-features-security.md) section for details. See also [`registerPlugin()`](../programmers/api-functions/api-register-plugin.md), [combining diff --git a/docs/designers/language-modifiers/language-modifier-from-charset.md b/docs/designers/language-modifiers/language-modifier-from-charset.md index 8b7fdd50..1c301c3b 100644 --- a/docs/designers/language-modifiers/language-modifier-from-charset.md +++ b/docs/designers/language-modifiers/language-modifier-from-charset.md @@ -15,5 +15,5 @@ modifier](#language.modifier.to_charset). > modifier should only be used in cases where the application cannot > anticipate that a certain string is required in another encoding. -See also [Charset Enconding](#charset), [from\_charset +See also [Charset Encoding](#charset), [from\_charset modifier](#language.modifier.from_charset). diff --git a/docs/designers/language-modifiers/language-modifier-to-charset.md b/docs/designers/language-modifiers/language-modifier-to-charset.md index 6c53232c..a0d95f53 100644 --- a/docs/designers/language-modifiers/language-modifier-to-charset.md +++ b/docs/designers/language-modifiers/language-modifier-to-charset.md @@ -15,5 +15,5 @@ modifier](#language.modifier.from_charset). > modifier should only be used in cases where the application cannot > anticipate that a certain string is required in another encoding. -See also [Charset Enconding](#charset), [from\_charset +See also [Charset Encoding](#charset), [from\_charset modifier](#language.modifier.from_charset). diff --git a/docs/designers/language-variables/language-variables-smarty.md b/docs/designers/language-variables/language-variables-smarty.md index f9aa2330..e2949e0e 100644 --- a/docs/designers/language-variables/language-variables-smarty.md +++ b/docs/designers/language-variables/language-variables-smarty.md @@ -157,13 +157,13 @@ Returns the version of Smarty the template was compiled with. ---------------------- Returns block text from child template. See [Template -interitance](#advanced.features.template.inheritance). +inheritance](#advanced.features.template.inheritance). {\$smarty.block.parent} {#language.variables.smarty.block.parent} ----------------------- Returns block text from parent template. See [Template -interitance](#advanced.features.template.inheritance) +inheritance](#advanced.features.template.inheritance) {\$smarty.ldelim}, {\$smarty.rdelim} {#language.variables.smarty.ldelim} ------------------------------------ diff --git a/docs/getting-started.md b/docs/getting-started.md index de55ffe8..2a1391f4 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -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/). diff --git a/docs/programmers/advanced-features/advanced-features-objects.md b/docs/programmers/advanced-features/advanced-features-objects.md index 6b4870b5..88bd647a 100644 --- a/docs/programmers/advanced-features/advanced-features-objects.md +++ b/docs/programmers/advanced-features/advanced-features-objects.md @@ -29,7 +29,7 @@ determined by your needs, but use the first method whenever possible to keep template syntax to a minimum. If security is enabled, no private methods or functions can be accessed -(beginningwith \'\_\'). If a method and property of the same name exist, +(beginning with \'\_\'). If a method and property of the same name exist, the method will be used. You can restrict the methods and properties that can be accessed by diff --git a/docs/programmers/advanced-features/advanced-features-security.md b/docs/programmers/advanced-features/advanced-features-security.md index 98817a43..730915f1 100644 --- a/docs/programmers/advanced-features/advanced-features-security.md +++ b/docs/programmers/advanced-features/advanced-features-security.md @@ -2,36 +2,20 @@ Security {#advanced.features.security} ======== Security is good for situations when you have untrusted parties editing -the templates eg via ftp, and you want to reduce the risk of system +the templates e.g. via ftp, and you want to reduce the risk of system security compromises through the template language. The settings of the security policy are defined by properties of an instance of the Smarty\_Security class. These are the possible settings: -- `$php_handling` determines how Smarty to handle PHP code embedded in - templates. Possible values are: - - - Smarty::PHP\_PASSTHRU -\> echo PHP tags as they are - - - Smarty::PHP\_QUOTE -\> escape tags as entities - - - Smarty::PHP\_REMOVE -\> remove php tags - - - Smarty::PHP\_ALLOW -\> execute php tags - - The default value is Smarty::PHP\_PASSTHRU. - - If security is enabled the [`$php_handling`](#variable.php.handling) - setting of the Smarty object is not checked for security. - - `$secure_dir` is an array of template directories that are considered secure. [`$template_dir`](#variable.template.dir) - concidered secure implicitly. The default is an empty array. + considered secure implicitly. The default is an empty array. - `$trusted_dir` is an array of all directories that are considered trusted. Trusted directories are where you keep php scripts that are executed directly from the templates with - [`{include_php}`](#language.function.include.php). The default is an + [`{insert}`](#language.function.insert.php). The default is an empty array. - `$trusted_uri` is an array of regular expressions matching URIs that @@ -43,7 +27,7 @@ instance of the Smarty\_Security class. These are the possible settings: like authentication-tokens). The expression `'#https?://.*smarty.net$#i'` would allow accessing - the follwing URIs: + the following URIs: - `http://smarty.net/foo` @@ -110,12 +94,8 @@ instance of the Smarty\_Security class. These are the possible settings: super globals can be accessed by the template. The default is \"true\". -- `$allow_php_tag` is a boolean flag which controls if {php} and - {include\_php} tags can be used by the template. The default is - \"false\". - If security is enabled, no private methods, functions or properties of -static classes or assigned objects can be accessed (beginningwith +static classes or assigned objects can be accessed (beginning with \'\_\') by the template. To customize the security policy settings you can extend the @@ -128,8 +108,6 @@ Smarty\_Security class or create an instance of it. class My_Security_Policy extends Smarty_Security { // disable all PHP functions public $php_functions = null; - // remove PHP tags - public $php_handling = Smarty::PHP_REMOVE; // allow everthing as modifier public $php_modifiers = array(); } @@ -145,8 +123,6 @@ Smarty\_Security class or create an instance of it. $my_security_policy = new Smarty_Security($smarty); // disable all PHP functions $my_security_policy->php_functions = null; - // remove PHP tags - $my_security_policy->php_handling = Smarty::PHP_REMOVE; // allow everthing as modifier $my_security_policy->php_modifiers = array(); // enable security @@ -164,5 +140,5 @@ Smarty\_Security class or create an instance of it. > **Note** > > Most security policy settings are only checked when the template gets -> compiled. For that reasion you should delete all cached and compiled +> compiled. For that reason you should delete all cached and compiled > template files when you change your security settings. diff --git a/docs/programmers/advanced-features/advanced-features-template-inheritance.md b/docs/programmers/advanced-features/advanced-features-template-inheritance.md index 25295c38..ce47310c 100644 --- a/docs/programmers/advanced-features/advanced-features-template-inheritance.md +++ b/docs/programmers/advanced-features/advanced-features-template-inheritance.md @@ -33,7 +33,7 @@ can override all or some of the parent named block areas. you can define the whole template inheritance tree in the PHP script when you are calling [`fetch()`](#api.fetch) or [`display()`](#api.display) with the `extends:` template resource - type. The later provides even more flexibillity. + type. The later provides even more flexibility. > **Note** > diff --git a/docs/programmers/advanced-features/advanced-features-template-settings.md b/docs/programmers/advanced-features/advanced-features-template-settings.md index df1f86a8..b06430ff 100644 --- a/docs/programmers/advanced-features/advanced-features-template-settings.md +++ b/docs/programmers/advanced-features/advanced-features-template-settings.md @@ -8,7 +8,7 @@ Modifications done to the Smarty object will be global for all templates. However the Smarty class variables and functions can be accessed or -called by induvidual template objects. Modification done to a template +called by individual template objects. Modification done to a template object will apply only for that template and its included subtemplates. diff --git a/docs/programmers/api-functions/api-create-data.md b/docs/programmers/api-functions/api-create-data.md index 2d9f281b..7e083776 100644 --- a/docs/programmers/api-functions/api-create-data.md +++ b/docs/programmers/api-functions/api-create-data.md @@ -26,7 +26,7 @@ the following parameters: variables assigned to any of the objects in it\'s parent chain. Data objects are used to create scopes for assigned variables. They can -be used to have controll which variables are seen by which templates. +be used to control which variables are seen by which templates. **Note** -> -> Embedding PHP code into templates is highly discouraged. Use [custom -> functions](#plugins.functions) or [modifiers](#plugins.modifiers) -> instead. diff --git a/docs/programmers/api-variables/variable-trusted-dir.md b/docs/programmers/api-variables/variable-trusted-dir.md index 3d1a308f..9720ae8a 100644 --- a/docs/programmers/api-variables/variable-trusted-dir.md +++ b/docs/programmers/api-variables/variable-trusted-dir.md @@ -5,4 +5,4 @@ array of all directories that are considered trusted. Trusted directories are where you keep php scripts that are executed directly from the templates with -[`{include_php}`](#language.function.include.php). +[`{insert}`](#language.function.insert.php). diff --git a/docs/programmers/api-variables/variable-use-sub-dirs.md b/docs/programmers/api-variables/variable-use-sub-dirs.md index a95ac415..d973c240 100644 --- a/docs/programmers/api-variables/variable-use-sub-dirs.md +++ b/docs/programmers/api-variables/variable-use-sub-dirs.md @@ -10,7 +10,7 @@ environments do not allow PHP processes to create directories, so this must be disabled which is the default. Sub directories are more efficient, so use them if you can. -Theoretically you get much better perfomance on a filesystem with 10 +Theoretically you get much better performance on a filesystem with 10 directories each having 100 files, than with 1 directory having 1000 files. This was certainly the case with Solaris 7 (UFS)\... with newer filesystems such as ext3 and especially reiserfs, the difference is diff --git a/docs/programmers/caching/caching-groups.md b/docs/programmers/caching/caching-groups.md index 98e5d45c..7e248b2f 100644 --- a/docs/programmers/caching/caching-groups.md +++ b/docs/programmers/caching/caching-groups.md @@ -25,10 +25,10 @@ like. - You CANNOT remove a specified template name under multiple cache groups such as `'/a/b/*/foo.tpl'`, the cache grouping works left-to-right ONLY. You will need to group your templates under a - single cache group heirarchy to be able to clear them as a group. + single cache group hierarchy to be able to clear them as a group. Cache grouping should not be confused with your template directory -heirarchy, the cache grouping has no knowledge of how your templates are +hierarchy, the cache grouping has no knowledge of how your templates are structured. So for example, if you have a template structure like `themes/blue/index.tpl` and you want to be able to clear all the cache files for the "blue" theme, you will need to create a cache group diff --git a/docs/programmers/charset.md b/docs/programmers/charset.md index 72842b3f..9dedf4dc 100644 --- a/docs/programmers/charset.md +++ b/docs/programmers/charset.md @@ -5,17 +5,17 @@ Charset Encoding {#charset.encoding} ================ 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 -`SMARTY_RESOURCE_CHAR_SET` constant, Smarty recognizes `UTF-8` as the -internal charset if [Multibyte String](https://www.php.net/mbstring) is -available, `ISO-8859-1` if not. +and UTF-8 being the most popular. Unless you change `Smarty::$_CHARSET`, +Smarty recognizes `UTF-8` as the internal charset if +[Multibyte String](https://www.php.net/mbstring) is available, +`ISO-8859-1` if not. > **Note** > > `ISO-8859-1` has been PHP\'s default internal charset since the > beginning. Unicode has been evolving since 1991. Since then it has > become the one charset to conquer them all, as it is capable of -> encoding most of the known characters even accross different character +> encoding most of the known characters even across different character > systems (latin, cyrillic, japanese, ...). `UTF-8` is unicode\'s most > used encoding, as it allows referencing the thousands of character > with the smallest size overhead possible. @@ -36,8 +36,9 @@ available, `ISO-8859-1` if not. if (function_exists('mb_internal_charset')) { mb_internal_charset('EUC-JP'); } - define('SMARTY_RESOURCE_CHAR_SET', 'EUC-JP'); + require_once 'libs/Smarty.class.php'; + Smarty::$_CHARSET = 'EUC-JP'; $smarty = new Smarty(); diff --git a/docs/programmers/resources/resources-extends.md b/docs/programmers/resources/resources-extends.md index ad2e8f5d..d7213d89 100644 --- a/docs/programmers/resources/resources-extends.md +++ b/docs/programmers/resources/resources-extends.md @@ -3,20 +3,20 @@ Extends Template Resources {#resources.extends} The `extends:` resource is used to define child/parent relationships for template inheritance from the PHP script. For details see section of -[Template Interitance](#advanced.features.template.inheritance). +[Template Inheritance](#advanced.features.template.inheritance). As of Smarty 3.1 the `extends:` resource may use any available [template resource](#resources), including `string:` and `eval:`. When [templates from strings](#resources.string) are used, make sure they are properly (url or base64) encoded. Is an `eval:` resource found within an inheritance chain, its \"don\'t save a compile file\" property is -superseeded by the `extends:` resource. The templates within an +superseded by the `extends:` resource. The templates within an inheritance chain are not compiled separately, though. Only a single compiled template will be generated. > **Note** > -> Use this when inheritance is required programatically. When inheriting +> Use this when inheritance is required programmatically. When inheriting > within PHP, it is not obvious from the child template what inheritance > took place. If you have a choice, it is normally more flexible and > intuitive to handle inheritance chains from within the templates. diff --git a/docs/programmers/resources/resources-file.md b/docs/programmers/resources/resources-file.md index 986cfffc..e49f4737 100644 --- a/docs/programmers/resources/resources-file.md +++ b/docs/programmers/resources/resources-file.md @@ -47,7 +47,7 @@ Templates from a specific \$template\_dir {#templates.from.specified.template.di Smarty 3.1 introduced the bracket-syntax for specifying an element from [`$template_dir`](#variable.template.dir). This allows websites employing multiple sets of templates better control over which template -to acces. +to access. The bracket-syntax can be used from anywhere you can specify the `file:` resource type. diff --git a/docs/programmers/smarty-constants.md b/docs/programmers/smarty-constants.md index 042ea5e3..de04e1b5 100644 --- a/docs/programmers/smarty-constants.md +++ b/docs/programmers/smarty-constants.md @@ -23,5 +23,4 @@ to determine the appropriate value automatically. If defined, the path -See also [`$smarty.const`](../designers/language-variables/language-variables-smarty.md) and -[`$php_handling constants`](./api-variables/variable-php-handling.md) +See also [`$smarty.const`](../designers/language-variables/language-variables-smarty.md). diff --git a/lexer/smarty_internal_templatelexer.plex b/lexer/smarty_internal_templatelexer.plex index 67c840d7..2cd46df9 100644 --- a/lexer/smarty_internal_templatelexer.plex +++ b/lexer/smarty_internal_templatelexer.plex @@ -161,7 +161,6 @@ class Smarty_Internal_Templatelexer 'COMMENT' => 'comment', 'AS' => 'as', 'TO' => 'to', - 'PHP' => '" '"<", "==" ... logical operator', 'TLOGOP' => '"lt", "eq" ... logical operator; "is div by" ... if condition', 'SCOND' => '"is even" ... if condition', diff --git a/libs/Autoloader.php b/libs/Autoloader.php index 1673ce2f..da7e32ab 100644 --- a/libs/Autoloader.php +++ b/libs/Autoloader.php @@ -5,6 +5,11 @@ * @package Smarty */ + +if (!defined('SMARTY_HELPER_FUNCTIONS_LOADED')) { + include __DIR__ . '/functions.php'; +} + /** * Smarty Autoloader * @@ -73,7 +78,7 @@ class Smarty_Autoloader */ public static function register($prepend = false) { - self::$SMARTY_DIR = defined('SMARTY_DIR') ? SMARTY_DIR : dirname(__FILE__) . DIRECTORY_SEPARATOR; + self::$SMARTY_DIR = defined('SMARTY_DIR') ? SMARTY_DIR : __DIR__ . DIRECTORY_SEPARATOR; self::$SMARTY_SYSPLUGINS_DIR = defined('SMARTY_SYSPLUGINS_DIR') ? SMARTY_SYSPLUGINS_DIR : self::$SMARTY_DIR . 'sysplugins' . DIRECTORY_SEPARATOR; spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend); @@ -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)) { diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php index 0abbe6a7..5351b579 100644 --- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -36,7 +36,7 @@ if (!defined('SMARTY_DIR')) { /** * */ - define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); + define('SMARTY_DIR', __DIR__ . DIRECTORY_SEPARATOR); } /** * set SMARTY_SYSPLUGINS_DIR to absolute path to Smarty internal plugins. @@ -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 __DIR__ . '/functions.php'; +} + /** * Load Smarty_Autoloader */ if (!class_exists('Smarty_Autoloader')) { - include dirname(__FILE__) . '/bootstrap.php'; + include __DIR__ . '/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.0'; + const SMARTY_VERSION = '4.3.0'; /** * define variable scopes */ @@ -867,7 +876,7 @@ class Smarty extends Smarty_Internal_TemplateBase $this->plugins_dir = (array)$this->plugins_dir; } foreach ($this->plugins_dir as $k => $v) { - $this->plugins_dir[ $k ] = $this->_realpath(rtrim($v, '/\\') . DIRECTORY_SEPARATOR, true); + $this->plugins_dir[ $k ] = $this->_realpath(rtrim($v ?? '', '/\\') . DIRECTORY_SEPARATOR, true); } $this->_cache[ 'plugin_files' ] = array(); $this->_pluginsDirNormalized = true; @@ -1345,7 +1354,7 @@ class Smarty extends Smarty_Internal_TemplateBase */ private function _normalizeDir($dirName, $dir) { - $this->{$dirName} = $this->_realpath(rtrim($dir, "/\\") . DIRECTORY_SEPARATOR, true); + $this->{$dirName} = $this->_realpath(rtrim($dir ?? '', "/\\") . DIRECTORY_SEPARATOR, true); } /** @@ -1367,7 +1376,7 @@ class Smarty extends Smarty_Internal_TemplateBase } foreach ($dir as $k => $v) { if (!isset($processed[ $k ])) { - $dir[ $k ] = $v = $this->_realpath(rtrim($v, "/\\") . DIRECTORY_SEPARATOR, true); + $dir[ $k ] = $v = $this->_realpath(rtrim($v ?? '', "/\\") . DIRECTORY_SEPARATOR, true); $processed[ $k ] = true; } } @@ -1377,8 +1386,7 @@ class Smarty extends Smarty_Internal_TemplateBase } /** - * Activates PHP7 compatibility mode: - * - converts E_WARNINGS for "undefined array key" and "trying to read property of null" errors to E_NOTICE + * Mutes errors for "undefined index", "undefined array key" and "trying to read property of null". * * @void */ @@ -1387,7 +1395,7 @@ class Smarty extends Smarty_Internal_TemplateBase } /** - * Indicates if PHP7 compatibility mode is set. + * Indicates if Smarty will mute errors for "undefined index", "undefined array key" and "trying to read property of null". * @bool */ public function isMutingUndefinedOrNullWarnings(): bool { diff --git a/libs/bootstrap.php b/libs/bootstrap.php index 2c830468..a226ac04 100644 --- a/libs/bootstrap.php +++ b/libs/bootstrap.php @@ -11,6 +11,6 @@ * Load and register Smarty Autoloader */ if (!class_exists('Smarty_Autoloader')) { - include dirname(__FILE__) . '/Autoloader.php'; + include __DIR__ . '/Autoloader.php'; } Smarty_Autoloader::register(true); diff --git a/libs/debug.tpl b/libs/debug.tpl index edc7bef9..4f82a582 100644 --- a/libs/debug.tpl +++ b/libs/debug.tpl @@ -1,9 +1,9 @@ {capture name='_smarty_debug' assign=debug_output} - - + + Smarty Debug Console - @@ -112,11 +115,11 @@

included templates & config files (load time in seconds)

{foreach $template_data as $template} - {$template.name} -
   + {$template.name} +
   (compile {$template['compile_time']|string_format:"%.5f"}) (render {$template['render_time']|string_format:"%.5f"}) (cache {$template['cache_time']|string_format:"%.5f"}) -
+
{/foreach}
{/if} @@ -125,13 +128,22 @@ {foreach $assigned_vars as $vars} - - + + + - - {/foreach}

${$vars@key}

- {if isset($vars['nocache'])}Nocache
{/if} - {if isset($vars['scope'])}Origin: {$vars['scope']|debug_print_var nofilter}{/if} +
+

${$vars@key}

+ {if isset($vars['nocache'])}Nocache
{/if} + {if isset($vars['scope'])}Origin: {$vars['scope']|debug_print_var nofilter}{/if} +
+

Value

+ {$vars['value']|debug_print_var:10:80 nofilter} +
+ {if isset($vars['attributes'])} +

Attributes

+ {$vars['attributes']|debug_print_var nofilter} + {/if}

Value

{$vars['value']|debug_print_var:10:80 nofilter}
{if isset($vars['attributes'])}

Attributes

{$vars['attributes']|debug_print_var nofilter} {/if}
@@ -139,11 +151,14 @@ {foreach $config_vars as $vars} - - + + - {/foreach} diff --git a/libs/functions.php b/libs/functions.php new file mode 100644 index 00000000..bac00e52 --- /dev/null +++ b/libs/functions.php @@ -0,0 +1,51 @@ + $_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_separator; } diff --git a/libs/plugins/function.mailto.php b/libs/plugins/function.mailto.php index 834d0535..671ac069 100644 --- a/libs/plugins/function.mailto.php +++ b/libs/plugins/function.mailto.php @@ -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 = '' . htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, Smarty::$_CHARSET) . ''; + if ($encode === 'javascript') { - $string = '' . $text . ''; $js_encode = ''; for ($x = 0, $_length = strlen($string); $x < $_length; $x++) { $js_encode .= '%' . bin2hex($string[ $x ]); } return ''; } elseif ($encode === 'javascript_charcode') { - $string = '' . $text . ''; for ($x = 0, $_length = strlen($string); $x < $_length; $x++) { $ord[] = ord($string[ $x ]); } - return ''; + return ''; } elseif ($encode === 'hex') { preg_match('!^(.*)(\?.*)$!', $address, $match); if (!empty($match[ 2 ])) { @@ -129,6 +137,6 @@ function smarty_function_mailto($params) return '' . $text_encode . ''; } else { // no encoding - return '' . $text . ''; + return $string; } } diff --git a/libs/plugins/function.math.php b/libs/plugins/function.math.php index 8560e944..f9cf67fe 100644 --- a/libs/plugins/function.math.php +++ b/libs/plugins/function.math.php @@ -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); diff --git a/libs/plugins/modifier.capitalize.php b/libs/plugins/modifier.capitalize.php index c5fc400a..2903d61d 100644 --- a/libs/plugins/modifier.capitalize.php +++ b/libs/plugins/modifier.capitalize.php @@ -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) diff --git a/libs/plugins/modifier.count.php b/libs/plugins/modifier.count.php new file mode 100644 index 00000000..ca35fc11 --- /dev/null +++ b/libs/plugins/modifier.count.php @@ -0,0 +1,36 @@ + Prior to PHP 8.0.0, if the parameter was neither an array nor an object that implements the Countable interface, + * > 1 would be returned, unless value was null, in which case 0 would be returned. + */ + + if ($arrayOrObject instanceof Countable || is_array($arrayOrObject)) { + return count($arrayOrObject, (int) $mode); + } elseif ($arrayOrObject === null) { + return 0; + } + return 1; +} diff --git a/libs/plugins/modifier.date_format.php b/libs/plugins/modifier.date_format.php index 8e7e0b6e..e3589fd0 100644 --- a/libs/plugins/modifier.date_format.php +++ b/libs/plugins/modifier.date_format.php @@ -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); } diff --git a/libs/plugins/modifier.escape.php b/libs/plugins/modifier.escape.php index 47489aa9..11e44682 100644 --- a/libs/plugins/modifier.escape.php +++ b/libs/plugins/modifier.escape.php @@ -23,95 +23,25 @@ */ 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) { $char_set = Smarty::$_CHARSET; } + + $string = (string)$string; + 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); diff --git a/libs/plugins/modifier.explode.php b/libs/plugins/modifier.explode.php new file mode 100644 index 00000000..5186fde3 --- /dev/null +++ b/libs/plugins/modifier.explode.php @@ -0,0 +1,25 @@ +=8.1 + return explode($separator, $string ?? '', $limit ?? PHP_INT_MAX); +} diff --git a/libs/plugins/modifier.number_format.php b/libs/plugins/modifier.number_format.php new file mode 100644 index 00000000..8c612601 --- /dev/null +++ b/libs/plugins/modifier.number_format.php @@ -0,0 +1,26 @@ +=8.1 + return number_format($num ?? 0.0, $decimals, $decimal_separator, $thousands_separator); +} diff --git a/libs/plugins/modifiercompiler.escape.php b/libs/plugins/modifiercompiler.escape.php index 70b95cc9..602c3dbf 100644 --- a/libs/plugins/modifiercompiler.escape.php +++ b/libs/plugins/modifiercompiler.escape.php @@ -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( @@ -41,53 +39,30 @@ function smarty_modifiercompiler_escape($params, Smarty_Internal_TemplateCompile } switch ($esc_type) { case 'html': - if ($_double_encode) { - return 'htmlspecialchars(' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ', ' . - var_export($double_encode, true) . ')'; - } elseif ($double_encode) { - return 'htmlspecialchars(' . $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(' . $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(' . $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(' . $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(' . $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(' . $params[ 0 ] . ')'; + return 'rawurlencode((string)' . $params[ 0 ] . ')'; case 'urlpathinfo': - return 'str_replace("%2F", "/", rawurlencode(' . $params[ 0 ] . '))'; + return 'str_replace("%2F", "/", rawurlencode((string)' . $params[ 0 ] . '))'; case 'quotes': // escape unescaped single quotes - return 'preg_replace("%(? "\\\\\\\\", "\'" => "\\\\\'", "\"" => "\\\\\"", "\\r" => "\\\\r", "\\n" => "\\\n", " "<\/", "

#{$vars@key}#

- {if isset($vars['scope'])}Origin: {$vars['scope']|debug_print_var nofilter}{/if} +
+

#{$vars@key}#

+ {if isset($vars['scope'])}Origin: {$vars['scope']|debug_print_var nofilter}{/if} +
+ {$vars['value']|debug_print_var:10:80 nofilter} {$vars['value']|debug_print_var:10:80 nofilter}