diff --git a/.gitignore b/.gitignore index d255d19..366b364 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ error_log* smarty_compile # Backups / Altlasten +/libs/smarty.4.1.1.bak/ *.bak *.bak2 *.bak3 diff --git a/core/admin_role.class.php b/core/admin_role.class.php index 777fbc1..0d0ac45 100644 --- a/core/admin_role.class.php +++ b/core/admin_role.class.php @@ -10,6 +10,7 @@ include_once './core/main.class.php'; +#[\AllowDynamicProperties] class Admin_role extends Main { public $list_table_config = array ( diff --git a/core/base.class.php b/core/base.class.php index 544c075..133448a 100644 --- a/core/base.class.php +++ b/core/base.class.php @@ -16,6 +16,7 @@ include_once './core/customer.class.php'; include_once './core/customer_group.class.php'; include_once './core/admin_role.class.php'; +#[\AllowDynamicProperties] class base { public $logger; diff --git a/core/config.class.php b/core/config.class.php index cb92a87..764e73b 100644 --- a/core/config.class.php +++ b/core/config.class.php @@ -11,6 +11,7 @@ include_once './core/logger.class.php'; include_once './core/main.class.php'; +#[\AllowDynamicProperties] class Config extends Main { protected $base_object; diff --git a/core/customer.class.php b/core/customer.class.php index 74f83a5..b09ac5c 100644 --- a/core/customer.class.php +++ b/core/customer.class.php @@ -16,6 +16,7 @@ include_once './core/cs_ticket.class.php'; include_once './core/customergroups.class.php'; include_once './core/main.class.php'; +#[\AllowDynamicProperties] class Customer extends Main { protected $base_object; diff --git a/core/customer_group.class.php b/core/customer_group.class.php index ccfd68f..a49ec5b 100644 --- a/core/customer_group.class.php +++ b/core/customer_group.class.php @@ -10,6 +10,7 @@ include_once './core/main.class.php'; +#[\AllowDynamicProperties] class Customer_group extends Main { protected $base_object; diff --git a/core/customergroups.class.php b/core/customergroups.class.php index 9be1c21..b057b49 100644 --- a/core/customergroups.class.php +++ b/core/customergroups.class.php @@ -8,6 +8,7 @@ * Carteasy is a web shop system */ +#[\AllowDynamicProperties] class CustomerGroups { private $table_fields = array( diff --git a/core/item.class.php b/core/item.class.php index afc0c23..f4531fc 100644 --- a/core/item.class.php +++ b/core/item.class.php @@ -19,6 +19,7 @@ include_once './core/customer_group.class.php'; include_once './core/itemschema.class.php'; include_once './core/structure.class.php'; +#[\AllowDynamicProperties] class Item extends Main { public $list_table_config = array( diff --git a/core/structure.class.php b/core/structure.class.php index cd7ae39..0eb18a5 100644 --- a/core/structure.class.php +++ b/core/structure.class.php @@ -8,6 +8,7 @@ * Carteasy is a web shop system */ +#[\AllowDynamicProperties] class Structure extends Main { protected $base_object; diff --git a/core/website.class.php b/core/website.class.php index 71f1cf5..a98a29e 100644 --- a/core/website.class.php +++ b/core/website.class.php @@ -13,6 +13,7 @@ include_once './core/manufacturer.class.php'; include_once './core/shoppingcart.class.php'; include_once './core/memory.class.php'; +#[\AllowDynamicProperties] class website { private $db; diff --git a/libs/smarty/CHANGELOG.md b/libs/smarty/CHANGELOG.md index 784cc09..3af862d 100644 --- a/libs/smarty/CHANGELOG.md +++ b/libs/smarty/CHANGELOG.md @@ -6,10 +6,116 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [4.5.6] - 2025-08-26 +- Fixed that modifiers called like function would be compiled to modifier name instead of calling the registered callback [#1100](https://github.com/smarty-php/smarty/issues/1100) +- Replace SMARTY_VERSION constant with $smarty.version in debug.tpl [#1073](https://github.com/smarty-php/smarty/issues/1073) + + +- Fixed escaping of array/object keys in debug_print_var + +## [4.5.5] - 2024-11-21 + +- Support the deprecations introduced in PHP 8.4 and added tests for PHP 8.4 [#1084](https://github.com/smarty-php/smarty/pull/1084) + +## [4.5.4] - 2024-08-14 +- Fixed that using `count()` would trigger a deprecation notice. [#813](https://github.com/smarty-php/smarty/issues/813) + + +## [4.5.3] - 2024-05-28 +- Fixed a code injection vulnerability in extends-tag. This addresses CVE-2024-35226. + + +## [4.5.2] - 2024-04-06 +- Fixed argument must be passed by reference error introduced in v4.5.1 [#964](https://github.com/smarty-php/smarty/issues/964) + +## [4.5.1] - 2024-03-18 +- 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.5.0] - 2024-03-18 +- (this release accidentally didn't contain any changes, fixed in 4.5.1) + +## [4.4.1] - 2024-02-26 +- Fixed internal release-tooling + +## [4.4.0] - 2024-02-26 +- 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 + +### Fixed +- `|strip_tags` does not work if the input is 0 [#890](https://github.com/smarty-php/smarty/issues/890) +- Use of negative numbers in {math} equations [#895](https://github.com/smarty-php/smarty/issues/895) + +## [4.3.2] - 2023-07-19 + +### Fixed +- `$smarty->muteUndefinedOrNullWarnings()` now also mutes PHP8 warnings for undefined properties + +## [4.3.1] - 2023-03-28 + +### Security +- Fixed Cross site scripting vulnerability in Javascript escaping. This addresses CVE-2023-28447. + +### 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 +- `$smarty->muteUndefinedOrNullWarnings()` now allows dereferencing of non-objects across all supported PHP versions [#831](https://github.com/smarty-php/smarty/issues/831) +- PHP 8.1 deprecation warnings on null strings in modifiers [#834](https://github.com/smarty-php/smarty/pull/834) + +## [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- +- 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) diff --git a/libs/smarty/README.md b/libs/smarty/README.md index 782f0b2..b6271e6 100644 --- a/libs/smarty/README.md +++ b/libs/smarty/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.4. ## Installation Smarty versions 3.1.11 or later can be installed with [Composer](https://getcomposer.org/). diff --git a/libs/smarty/SECURITY.md b/libs/smarty/SECURITY.md index d98ea01..80b5ef5 100644 --- a/libs/smarty/SECURITY.md +++ b/libs/smarty/SECURITY.md @@ -2,18 +2,19 @@ ## 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 | -| ------- | ------------------ | -| 4.0.x | :white_check_mark: | +|---------|--------------------| +| 4.3.x | :white_check_mark: | | 3.1.x | :white_check_mark: | | < 3.1 | :x: | ## Reporting a Vulnerability - If you have discovered a security issue with Smarty, please contact us at mail [at] simonwisselink.nl. Do not - disclose your findings publicly and PLEASE PLEASE do not file an Issue. +If you have discovered a security issue with Smarty, please contact us at mail [at] simonwisselink.nl. Do not +disclose your findings publicly and **PLEASE** do not file an Issue (because that would disclose your findings +publicly.) We will try to confirm the vulnerability and develop a fix if appropriate. When we release the fix, we will publish a security release. Please let us know if you want to be credited. diff --git a/libs/smarty/changelog/.gitkeep b/libs/smarty/changelog/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/libs/smarty/demo/configs/test.conf b/libs/smarty/demo/configs/test.conf new file mode 100644 index 0000000..5eac748 --- /dev/null +++ b/libs/smarty/demo/configs/test.conf @@ -0,0 +1,5 @@ +title = Welcome to Smarty! +cutoff_size = 40 + +[setup] +bold = true diff --git a/libs/smarty/demo/index.php b/libs/smarty/demo/index.php new file mode 100644 index 0000000..3aed371 --- /dev/null +++ b/libs/smarty/demo/index.php @@ -0,0 +1,35 @@ +force_compile = true; +$smarty->debugging = true; +$smarty->caching = true; +$smarty->cache_lifetime = 120; +$smarty->assign("Name", "Fred Irving Johnathan Bradley Peppergill", true); +$smarty->assign("FirstName", array("John", "Mary", "James", "Henry")); +$smarty->assign("LastName", array("Doe", "Smith", "Johnson", "Case")); +$smarty->assign( + "Class", + array( + array("A", "B", "C", "D"), + array("E", "F", "G", "H"), + array("I", "J", "K", "L"), + array("M", "N", "O", "P") + ) +); +$smarty->assign( + "contacts", + array( + array("phone" => "1", "fax" => "2", "cell" => "3"), + array("phone" => "555-4444", "fax" => "555-3333", "cell" => "760-1234") + ) +); +$smarty->assign("option_values", array("NY", "NE", "KS", "IA", "OK", "TX")); +$smarty->assign("option_output", array("New York", "Nebraska", "Kansas", "Iowa", "Oklahoma", "Texas")); +$smarty->assign("option_selected", "NE"); +$smarty->display('index.tpl'); diff --git a/libs/smarty/demo/plugins/cacheresource.apc.php b/libs/smarty/demo/plugins/cacheresource.apc.php new file mode 100644 index 0000000..7867cc5 --- /dev/null +++ b/libs/smarty/demo/plugins/cacheresource.apc.php @@ -0,0 +1,85 @@ + $v) { + $_res[ $k ] = $v; + } + return $_res; + } + + /** + * Save values for a set of keys to cache + * + * @param array $keys list of values to save + * @param int $expire expiration time + * + * @return boolean true on success, false on failure + */ + protected function write(array $keys, $expire = null) + { + foreach ($keys as $k => $v) { + apc_store($k, $v, $expire); + } + return true; + } + + /** + * Remove values from cache + * + * @param array $keys list of keys to delete + * + * @return boolean true on success, false on failure + */ + protected function delete(array $keys) + { + foreach ($keys as $k) { + apc_delete($k); + } + return true; + } + + /** + * Remove *all* values from cache + * + * @return boolean true on success, false on failure + */ + protected function purge() + { + return apc_clear_cache('user'); + } +} diff --git a/libs/smarty/demo/plugins/cacheresource.memcache.php b/libs/smarty/demo/plugins/cacheresource.memcache.php new file mode 100644 index 0000000..71fe9d3 --- /dev/null +++ b/libs/smarty/demo/plugins/cacheresource.memcache.php @@ -0,0 +1,99 @@ +memcache = new Memcached(); + } else { + $this->memcache = new Memcache(); + } + $this->memcache->addServer('127.0.0.1', 11211); + } + + /** + * Read values for a set of keys from cache + * + * @param array $keys list of keys to fetch + * + * @return array list of values with the given keys used as indexes + * @return boolean true on success, false on failure + */ + protected function read(array $keys) + { + $res = array(); + foreach ($keys as $key) { + $k = sha1($key); + $res[$key] = $this->memcache->get($k); + } + return $res; + } + + /** + * Save values for a set of keys to cache + * + * @param array $keys list of values to save + * @param int $expire expiration time + * + * @return boolean true on success, false on failure + */ + protected function write(array $keys, $expire = null) + { + foreach ($keys as $k => $v) { + $k = sha1($k); + if (class_exists('Memcached')) { + $this->memcache->set($k, $v, $expire); + } else { + $this->memcache->set($k, $v, 0, $expire); + } + } + return true; + } + + /** + * Remove values from cache + * + * @param array $keys list of keys to delete + * + * @return boolean true on success, false on failure + */ + protected function delete(array $keys) + { + foreach ($keys as $k) { + $k = sha1($k); + $this->memcache->delete($k); + } + return true; + } + + /** + * Remove *all* values from cache + * + * @return boolean true on success, false on failure + */ + protected function purge() + { + return $this->memcache->flush(); + } +} diff --git a/libs/smarty/demo/plugins/cacheresource.mysql.php b/libs/smarty/demo/plugins/cacheresource.mysql.php new file mode 100644 index 0000000..c5037eb --- /dev/null +++ b/libs/smarty/demo/plugins/cacheresource.mysql.php @@ -0,0 +1,183 @@ +CREATE TABLE IF NOT EXISTS `output_cache` ( + * `id` CHAR(40) NOT NULL COMMENT 'sha1 hash', + * `name` VARCHAR(250) NOT NULL, + * `cache_id` VARCHAR(250) NULL DEFAULT NULL, + * `compile_id` VARCHAR(250) NULL DEFAULT NULL, + * `modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + * `content` LONGTEXT NOT NULL, + * PRIMARY KEY (`id`), + * INDEX(`name`), + * INDEX(`cache_id`), + * INDEX(`compile_id`), + * INDEX(`modified`) + * ) ENGINE = InnoDB; + * + * @package CacheResource-examples + * @author Rodney Rehm + */ +class Smarty_CacheResource_Mysql extends Smarty_CacheResource_Custom +{ + /** + * @var \PDO + */ + protected $db; + + /** + * @var \PDOStatement + */ + protected $fetch; + + /** + * @var \PDOStatement + */ + protected $fetchTimestamp; + + /** + * @var \PDOStatement + */ + protected $save; + + /** + * Smarty_CacheResource_Mysql constructor. + * + * @throws \SmartyException + */ + public function __construct() + { + try { + $this->db = new PDO("mysql:dbname=test;host=127.0.0.1", "smarty"); + } catch (PDOException $e) { + throw new SmartyException('Mysql Resource failed: ' . $e->getMessage()); + } + $this->fetch = $this->db->prepare('SELECT modified, content FROM output_cache WHERE id = :id'); + $this->fetchTimestamp = $this->db->prepare('SELECT modified FROM output_cache WHERE id = :id'); + $this->save = $this->db->prepare( + 'REPLACE INTO output_cache (id, name, cache_id, compile_id, content) + VALUES (:id, :name, :cache_id, :compile_id, :content)' + ); + } + + /** + * fetch cached content and its modification time from data source + * + * @param string $id unique cache content identifier + * @param string $name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param string $content cached content + * @param integer $mtime cache modification timestamp (epoch) + * + * @return void + */ + protected function fetch($id, $name, $cache_id, $compile_id, &$content, &$mtime) + { + $this->fetch->execute(array('id' => $id)); + $row = $this->fetch->fetch(); + $this->fetch->closeCursor(); + if ($row) { + $content = $row[ 'content' ]; + $mtime = strtotime($row[ 'modified' ]); + } else { + $content = null; + $mtime = null; + } + } + + /** + * Fetch cached content's modification timestamp from data source + * + * @note implementing this method is optional. Only implement it if modification times can be accessed faster than + * loading the complete cached content. + * + * @param string $id unique cache content identifier + * @param string $name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * + * @return integer|boolean timestamp (epoch) the template was modified, or false if not found + */ + protected function fetchTimestamp($id, $name, $cache_id, $compile_id) + { + $this->fetchTimestamp->execute(array('id' => $id)); + $mtime = strtotime($this->fetchTimestamp->fetchColumn()); + $this->fetchTimestamp->closeCursor(); + return $mtime; + } + + /** + * Save content to cache + * + * @param string $id unique cache content identifier + * @param string $name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer|null $exp_time seconds till expiration time in seconds or null + * @param string $content content to cache + * + * @return boolean success + */ + protected function save($id, $name, $cache_id, $compile_id, $exp_time, $content) + { + $this->save->execute( + array('id' => $id, + 'name' => $name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'content' => $content,) + ); + return !!$this->save->rowCount(); + } + + /** + * Delete content from cache + * + * @param string $name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer|null $exp_time seconds till expiration or null + * + * @return integer number of deleted caches + */ + protected function delete($name, $cache_id, $compile_id, $exp_time) + { + // delete the whole cache + if ($name === null && $cache_id === null && $compile_id === null && $exp_time === null) { + // returning the number of deleted caches would require a second query to count them + $query = $this->db->query('TRUNCATE TABLE output_cache'); + return -1; + } + // build the filter + $where = array(); + // equal test name + if ($name !== null) { + $where[] = 'name = ' . $this->db->quote($name); + } + // equal test compile_id + if ($compile_id !== null) { + $where[] = 'compile_id = ' . $this->db->quote($compile_id); + } + // range test expiration time + if ($exp_time !== null) { + $where[] = 'modified < DATE_SUB(NOW(), INTERVAL ' . intval($exp_time) . ' SECOND)'; + } + // equal test cache_id and match sub-groups + if ($cache_id !== null) { + $where[] = + '(cache_id = ' . + $this->db->quote($cache_id) . + ' OR cache_id LIKE ' . + $this->db->quote($cache_id . '|%') . + ')'; + } + // run delete query + $query = $this->db->query('DELETE FROM output_cache WHERE ' . join(' AND ', $where)); + return $query->rowCount(); + } +} diff --git a/libs/smarty/demo/plugins/cacheresource.pdo.php b/libs/smarty/demo/plugins/cacheresource.pdo.php new file mode 100644 index 0000000..ae3ebbf --- /dev/null +++ b/libs/smarty/demo/plugins/cacheresource.pdo.php @@ -0,0 +1,346 @@ +setCachingType('pdo'); + * $smarty->loadPlugin('Smarty_CacheResource_Pdo'); + * $smarty->registerCacheResource('pdo', new Smarty_CacheResource_Pdo($cnx, 'smarty_cache')); + * + * @author Beno!t POLASZEK - 2014 + */ +class Smarty_CacheResource_Pdo extends Smarty_CacheResource_Custom +{ + /** + * @var string[] + */ + protected $fetchStatements = array('default' => 'SELECT %2$s + FROM %1$s + WHERE 1 + AND id = :id + AND cache_id IS NULL + AND compile_id IS NULL', + 'withCacheId' => 'SELECT %2$s + FROM %1$s + WHERE 1 + AND id = :id + AND cache_id = :cache_id + AND compile_id IS NULL', + 'withCompileId' => 'SELECT %2$s + FROM %1$s + WHERE 1 + AND id = :id + AND compile_id = :compile_id + AND cache_id IS NULL', + 'withCacheIdAndCompileId' => 'SELECT %2$s + FROM %1$s + WHERE 1 + AND id = :id + AND cache_id = :cache_id + AND compile_id = :compile_id'); + + /** + * @var string + */ + protected $insertStatement = 'INSERT INTO %s + + SET id = :id, + name = :name, + cache_id = :cache_id, + compile_id = :compile_id, + modified = CURRENT_TIMESTAMP, + expire = DATE_ADD(CURRENT_TIMESTAMP, INTERVAL :expire SECOND), + content = :content + + ON DUPLICATE KEY UPDATE + name = :name, + cache_id = :cache_id, + compile_id = :compile_id, + modified = CURRENT_TIMESTAMP, + expire = DATE_ADD(CURRENT_TIMESTAMP, INTERVAL :expire SECOND), + content = :content'; + + /** + * @var string + */ + protected $deleteStatement = 'DELETE FROM %1$s WHERE %2$s'; + + /** + * @var string + */ + protected $truncateStatement = 'TRUNCATE TABLE %s'; + + /** + * @var string + */ + protected $fetchColumns = 'modified, content'; + + /** + * @var string + */ + protected $fetchTimestampColumns = 'modified'; + + /** + * @var \PDO + */ + protected $pdo; + + /** + * @var + */ + protected $table; + + /** + * @var null + */ + protected $database; + + /** + * Constructor + * + * @param PDO $pdo PDO : active connection + * @param string $table : table (or view) name + * @param string $database : optional - if table is located in another db + * + * @throws \SmartyException + */ + public function __construct(PDO $pdo, $table, $database = null) + { + if (is_null($table)) { + throw new SmartyException("Table name for caching can't be null"); + } + $this->pdo = $pdo; + $this->table = $table; + $this->database = $database; + $this->fillStatementsWithTableName(); + } + + /** + * Fills the table name into the statements. + * + * @return $this Current Instance + * @access protected + */ + protected function fillStatementsWithTableName() + { + foreach ($this->fetchStatements as &$statement) { + $statement = sprintf($statement, $this->getTableName(), '%s'); + } + $this->insertStatement = sprintf($this->insertStatement, $this->getTableName()); + $this->deleteStatement = sprintf($this->deleteStatement, $this->getTableName(), '%s'); + $this->truncateStatement = sprintf($this->truncateStatement, $this->getTableName()); + return $this; + } + + /** + * Gets the fetch statement, depending on what you specify + * + * @param string $columns : the column(s) name(s) you want to retrieve from the database + * @param string $id unique cache content identifier + * @param string|null $cache_id cache id + * @param string|null $compile_id compile id + * + * @access protected + * @return \PDOStatement + */ + protected function getFetchStatement($columns, $id, $cache_id = null, $compile_id = null) + { + $args = array(); + if (!is_null($cache_id) && !is_null($compile_id)) { + $query = $this->fetchStatements[ 'withCacheIdAndCompileId' ] and + $args = array('id' => $id, 'cache_id' => $cache_id, 'compile_id' => $compile_id); + } elseif (is_null($cache_id) && !is_null($compile_id)) { + $query = $this->fetchStatements[ 'withCompileId' ] and + $args = array('id' => $id, 'compile_id' => $compile_id); + } elseif (!is_null($cache_id) && is_null($compile_id)) { + $query = $this->fetchStatements[ 'withCacheId' ] and $args = array('id' => $id, 'cache_id' => $cache_id); + } else { + $query = $this->fetchStatements[ 'default' ] and $args = array('id' => $id); + } + $query = sprintf($query, $columns); + $stmt = $this->pdo->prepare($query); + foreach ($args as $key => $value) { + $stmt->bindValue($key, $value); + } + return $stmt; + } + + /** + * fetch cached content and its modification time from data source + * + * @param string $id unique cache content identifier + * @param string $name template name + * @param string|null $cache_id cache id + * @param string|null $compile_id compile id + * @param string $content cached content + * @param integer $mtime cache modification timestamp (epoch) + * + * @return void + * @access protected + */ + protected function fetch($id, $name, $cache_id, $compile_id, &$content, &$mtime) + { + $stmt = $this->getFetchStatement($this->fetchColumns, $id, $cache_id, $compile_id); + $stmt->execute(); + $row = $stmt->fetch(); + $stmt->closeCursor(); + if ($row) { + $content = $this->outputContent($row[ 'content' ]); + $mtime = strtotime($row[ 'modified' ]); + } else { + $content = null; + $mtime = null; + } + } + + /** + * Fetch cached content's modification timestamp from data source + * {@internal implementing this method is optional. + * Only implement it if modification times can be accessed faster than loading the complete cached content.}} + * + * @param string $id unique cache content identifier + * @param string $name template name + * @param string|null $cache_id cache id + * @param string|null $compile_id compile id + * + * @return integer|boolean timestamp (epoch) the template was modified, or false if not found + * @access protected + */ + // protected function fetchTimestamp($id, $name, $cache_id = null, $compile_id = null) { + // $stmt = $this->getFetchStatement($this->fetchTimestampColumns, $id, $cache_id, $compile_id); + // $stmt -> execute(); + // $mtime = strtotime($stmt->fetchColumn()); + // $stmt -> closeCursor(); + // return $mtime; + // } + /** + * Save content to cache + * + * @param string $id unique cache content identifier + * @param string $name template name + * @param string|null $cache_id cache id + * @param string|null $compile_id compile id + * @param integer|null $exp_time seconds till expiration time in seconds or null + * @param string $content content to cache + * + * @return boolean success + * @access protected + */ + protected function save($id, $name, $cache_id, $compile_id, $exp_time, $content) + { + $stmt = $this->pdo->prepare($this->insertStatement); + $stmt->bindValue('id', $id); + $stmt->bindValue('name', $name); + $stmt->bindValue('cache_id', $cache_id, (is_null($cache_id)) ? PDO::PARAM_NULL : PDO::PARAM_STR); + $stmt->bindValue('compile_id', $compile_id, (is_null($compile_id)) ? PDO::PARAM_NULL : PDO::PARAM_STR); + $stmt->bindValue('expire', (int)$exp_time, PDO::PARAM_INT); + $stmt->bindValue('content', $this->inputContent($content)); + $stmt->execute(); + return !!$stmt->rowCount(); + } + + /** + * Encodes the content before saving to database + * + * @param string $content + * + * @return string $content + * @access protected + */ + protected function inputContent($content) + { + return $content; + } + + /** + * Decodes the content before saving to database + * + * @param string $content + * + * @return string $content + * @access protected + */ + protected function outputContent($content) + { + return $content; + } + + /** + * Delete content from cache + * + * @param string|null $name template name + * @param string|null $cache_id cache id + * @param string|null $compile_id compile id + * @param integer|null|-1 $exp_time seconds till expiration or null + * + * @return integer number of deleted caches + * @access protected + */ + protected function delete($name = null, $cache_id = null, $compile_id = null, $exp_time = null) + { + // delete the whole cache + if ($name === null && $cache_id === null && $compile_id === null && $exp_time === null) { + // returning the number of deleted caches would require a second query to count them + $this->pdo->query($this->truncateStatement); + return -1; + } + // build the filter + $where = array(); + // equal test name + if ($name !== null) { + $where[] = 'name = ' . $this->pdo->quote($name); + } + // equal test cache_id and match sub-groups + if ($cache_id !== null) { + $where[] = + '(cache_id = ' . + $this->pdo->quote($cache_id) . + ' OR cache_id LIKE ' . + $this->pdo->quote($cache_id . '|%') . + ')'; + } + // equal test compile_id + if ($compile_id !== null) { + $where[] = 'compile_id = ' . $this->pdo->quote($compile_id); + } + // for clearing expired caches + if ($exp_time === Smarty::CLEAR_EXPIRED) { + $where[] = 'expire < CURRENT_TIMESTAMP'; + } // range test expiration time + elseif ($exp_time !== null) { + $where[] = 'modified < DATE_SUB(NOW(), INTERVAL ' . intval($exp_time) . ' SECOND)'; + } + // run delete query + $query = $this->pdo->query(sprintf($this->deleteStatement, join(' AND ', $where))); + return $query->rowCount(); + } + + /** + * Gets the formatted table name + * + * @return string + * @access protected + */ + protected function getTableName() + { + return (is_null($this->database)) ? "`{$this->table}`" : "`{$this->database}`.`{$this->table}`"; + } +} diff --git a/libs/smarty/demo/plugins/cacheresource.pdo_gzip.php b/libs/smarty/demo/plugins/cacheresource.pdo_gzip.php new file mode 100644 index 0000000..5560b9e --- /dev/null +++ b/libs/smarty/demo/plugins/cacheresource.pdo_gzip.php @@ -0,0 +1,42 @@ +setCachingType('pdo_gzip'); + * $smarty->loadPlugin('Smarty_CacheResource_Pdo_Gzip'); + * $smarty->registerCacheResource('pdo_gzip', new Smarty_CacheResource_Pdo_Gzip($cnx, 'smarty_cache')); + * + * @require Smarty_CacheResource_Pdo class + * @author Beno!t POLASZEK - 2014 + */ +class Smarty_CacheResource_Pdo_Gzip extends Smarty_CacheResource_Pdo +{ + /** + * Encodes the content before saving to database + * + * @param string $content + * + * @return string $content + * @access protected + */ + protected function inputContent($content) + { + return gzdeflate($content); + } + + /** + * Decodes the content before saving to database + * + * @param string $content + * + * @return string $content + * @access protected + */ + protected function outputContent($content) + { + return gzinflate($content); + } +} diff --git a/libs/smarty/demo/plugins/resource.extendsall.php b/libs/smarty/demo/plugins/resource.extendsall.php new file mode 100644 index 0000000..fba9b4f --- /dev/null +++ b/libs/smarty/demo/plugins/resource.extendsall.php @@ -0,0 +1,62 @@ +smarty->getTemplateDir() as $key => $directory) { + try { + $s = Smarty_Resource::source(null, $source->smarty, 'file:' . '[' . $key . ']' . $source->name); + if (!$s->exists) { + continue; + } + $sources[ $s->uid ] = $s; + $uid .= $s->filepath; + $timestamp = $s->timestamp > $timestamp ? $s->timestamp : $timestamp; + } catch (SmartyException $e) { + } + } + if (!$sources) { + $source->exists = false; + return; + } + $sources = array_reverse($sources, true); + reset($sources); + $s = current($sources); + $source->components = $sources; + $source->filepath = $s->filepath; + $source->uid = sha1($uid . $source->smarty->_joined_template_dir); + $source->exists = true; + $source->timestamp = $timestamp; + } + + /** + * Disable timestamp checks for extendsall resource. + * The individual source components will be checked. + * + * @return bool false + */ + public function checkTimestamps() + { + return false; + } +} diff --git a/libs/smarty/demo/plugins/resource.mysql.php b/libs/smarty/demo/plugins/resource.mysql.php new file mode 100644 index 0000000..95a3c2b --- /dev/null +++ b/libs/smarty/demo/plugins/resource.mysql.php @@ -0,0 +1,101 @@ +CREATE TABLE IF NOT EXISTS `templates` ( + * `name` varchar(100) NOT NULL, + * `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + * `source` text, + * PRIMARY KEY (`name`) + * ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + * Demo data: + *
INSERT INTO `templates` (`name`, `modified`, `source`) VALUES ('test.tpl', "2010-12-25 22:00:00", '{$x="hello
+ * world"}{$x}');
+ *
+ *
+ * @package Resource-examples
+ * @author Rodney Rehm
+ */
+class Smarty_Resource_Mysql extends Smarty_Resource_Custom
+{
+ /**
+ * PDO instance
+ *
+ * @var \PDO
+ */
+ protected $db;
+
+ /**
+ * prepared fetch() statement
+ *
+ * @var \PDOStatement
+ */
+ protected $fetch;
+
+ /**
+ * prepared fetchTimestamp() statement
+ *
+ * @var \PDOStatement
+ */
+ protected $mtime;
+
+ /**
+ * Smarty_Resource_Mysql constructor.
+ *
+ * @throws \SmartyException
+ */
+ public function __construct()
+ {
+ try {
+ $this->db = new PDO("mysql:dbname=test;host=127.0.0.1", "smarty");
+ } catch (PDOException $e) {
+ throw new SmartyException('Mysql Resource failed: ' . $e->getMessage());
+ }
+ $this->fetch = $this->db->prepare('SELECT modified, source FROM templates WHERE name = :name');
+ $this->mtime = $this->db->prepare('SELECT modified FROM templates WHERE name = :name');
+ }
+
+ /**
+ * Fetch a template and its modification time from database
+ *
+ * @param string $name template name
+ * @param string $source template source
+ * @param integer $mtime template modification timestamp (epoch)
+ *
+ * @return void
+ */
+ protected function fetch($name, &$source, &$mtime)
+ {
+ $this->fetch->execute(array('name' => $name));
+ $row = $this->fetch->fetch();
+ $this->fetch->closeCursor();
+ if ($row) {
+ $source = $row[ 'source' ];
+ $mtime = strtotime($row[ 'modified' ]);
+ } else {
+ $source = null;
+ $mtime = null;
+ }
+ }
+
+ /**
+ * Fetch a template's modification time from database
+ *
+ * @note implementing this method is optional. Only implement it if modification times can be accessed faster than
+ * loading the comple template source.
+ *
+ * @param string $name template name
+ *
+ * @return integer timestamp (epoch) the template was modified
+ */
+ protected function fetchTimestamp($name)
+ {
+ $this->mtime->execute(array('name' => $name));
+ $mtime = $this->mtime->fetchColumn();
+ $this->mtime->closeCursor();
+ return strtotime($mtime);
+ }
+}
diff --git a/libs/smarty/demo/plugins/resource.mysqls.php b/libs/smarty/demo/plugins/resource.mysqls.php
new file mode 100644
index 0000000..148a8dd
--- /dev/null
+++ b/libs/smarty/demo/plugins/resource.mysqls.php
@@ -0,0 +1,77 @@
+CREATE TABLE IF NOT EXISTS `templates` (
+ * `name` varchar(100) NOT NULL,
+ * `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ * `source` text,
+ * PRIMARY KEY (`name`)
+ * ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+ * Demo data:
+ * INSERT INTO `templates` (`name`, `modified`, `source`) VALUES ('test.tpl', "2010-12-25 22:00:00", '{$x="hello
+ * world"}{$x}');
+ *
+ *
+ * @package Resource-examples
+ * @author Rodney Rehm
+ */
+class Smarty_Resource_Mysqls extends Smarty_Resource_Custom
+{
+ /**
+ * PDO instance
+ *
+ * @var \PDO
+ */
+ protected $db;
+
+ /**
+ * prepared fetch() statement
+ *
+ * @var \PDOStatement
+ */
+ protected $fetch;
+
+ /**
+ * Smarty_Resource_Mysqls constructor.
+ *
+ * @throws \SmartyException
+ */
+ public function __construct()
+ {
+ try {
+ $this->db = new PDO("mysql:dbname=test;host=127.0.0.1", "smarty");
+ } catch (PDOException $e) {
+ throw new SmartyException('Mysql Resource failed: ' . $e->getMessage());
+ }
+ $this->fetch = $this->db->prepare('SELECT modified, source FROM templates WHERE name = :name');
+ }
+
+ /**
+ * Fetch a template and its modification time from database
+ *
+ * @param string $name template name
+ * @param string $source template source
+ * @param integer $mtime template modification timestamp (epoch)
+ *
+ * @return void
+ */
+ protected function fetch($name, &$source, &$mtime)
+ {
+ $this->fetch->execute(array('name' => $name));
+ $row = $this->fetch->fetch();
+ $this->fetch->closeCursor();
+ if ($row) {
+ $source = $row[ 'source' ];
+ $mtime = strtotime($row[ 'modified' ]);
+ } else {
+ $source = null;
+ $mtime = null;
+ }
+ }
+}
diff --git a/libs/smarty/demo/templates/footer.tpl b/libs/smarty/demo/templates/footer.tpl
new file mode 100644
index 0000000..e04310f
--- /dev/null
+++ b/libs/smarty/demo/templates/footer.tpl
@@ -0,0 +1,2 @@
+