diff --git a/libs/sysplugins/smarty_cacheresource.php b/libs/sysplugins/smarty_cacheresource.php new file mode 100644 index 0000000..2a4552c --- /dev/null +++ b/libs/sysplugins/smarty_cacheresource.php @@ -0,0 +1,220 @@ + 'smarty_internal_cacheresource_file.php',); + + /** + * populate Cached Object with meta data from Resource + * + * @param Smarty_Template_Cached $cached cached object + * @param Smarty_Internal_Template $_template template object + * + * @return void + */ + abstract public function populate(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template); + + /** + * populate Cached Object with timestamp and exists from Resource + * + * @param Smarty_Template_Cached $cached + * + * @return void + */ + abstract public function populateTimestamp(Smarty_Template_Cached $cached); + + /** + * Read the cached template and process header + * + * @param Smarty_Internal_Template $_template template object + * @param Smarty_Template_Cached $cached cached object + * @param boolean $update flag if called because cache update + * + * @return boolean true or false if the cached content does not exist + */ + abstract public function process(Smarty_Internal_Template $_template, Smarty_Template_Cached $cached = null, + $update = false); + + /** + * Write the rendered template output to cache + * + * @param Smarty_Internal_Template $_template template object + * @param string $content content to cache + * + * @return boolean success + */ + abstract public function writeCachedContent(Smarty_Internal_Template $_template, $content); + + /** + * Read cached template from cache + * + * @param Smarty_Internal_Template $_template template object + * + * @return string content + */ + abstract function readCachedContent(Smarty_Internal_Template $_template); + + /** + * Return cached content + * + * @param Smarty_Internal_Template $_template template object + * + * @return null|string + */ + public function getCachedContent(Smarty_Internal_Template $_template) + { + if ($_template->cached->handler->process($_template)) { + ob_start(); + $unifunc = $_template->cached->unifunc; + $unifunc($_template); + return ob_get_clean(); + } + + return null; + } + + /** + * Empty cache + * + * @param Smarty $smarty Smarty object + * @param integer $exp_time expiration time (number of seconds, not timestamp) + * + * @return integer number of cache files deleted + */ + abstract public function clearAll(Smarty $smarty, $exp_time = null); + + /** + * Empty cache for a specific template + * + * @param Smarty $smarty Smarty object + * @param string $resource_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer $exp_time expiration time (number of seconds, not timestamp) + * + * @return integer number of cache files deleted + */ + abstract public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time); + + /** + * @param Smarty $smarty + * @param Smarty_Template_Cached $cached + * + * @return bool|null + */ + public function locked(Smarty $smarty, Smarty_Template_Cached $cached) + { + // theoretically locking_timeout should be checked against time_limit (max_execution_time) + $start = microtime(true); + $hadLock = null; + while ($this->hasLock($smarty, $cached)) { + $hadLock = true; + if (microtime(true) - $start > $smarty->locking_timeout) { + // abort waiting for lock release + return false; + } + sleep(1); + } + + return $hadLock; + } + + /** + * Check is cache is locked for this template + * + * @param Smarty $smarty + * @param Smarty_Template_Cached $cached + * + * @return bool + */ + public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + // check if lock exists + return false; + } + + /** + * Lock cache for this template + * + * @param Smarty $smarty + * @param Smarty_Template_Cached $cached + * + * @return bool + */ + public function acquireLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + // create lock + return true; + } + + /** + * Unlock cache for this template + * + * @param Smarty $smarty + * @param Smarty_Template_Cached $cached + * + * @return bool + */ + public function releaseLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + // release lock + return true; + } + + /** + * Load Cache Resource Handler + * + * @param Smarty $smarty Smarty object + * @param string $type name of the cache resource + * + * @throws SmartyException + * @return Smarty_CacheResource Cache Resource Handler + */ + public static function load(Smarty $smarty, $type = null) + { + if (!isset($type)) { + $type = $smarty->caching_type; + } + + // try smarty's cache + if (isset($smarty->_cache[ 'cacheresource_handlers' ][ $type ])) { + return $smarty->_cache[ 'cacheresource_handlers' ][ $type ]; + } + + // try registered resource + if (isset($smarty->registered_cache_resources[ $type ])) { + // do not cache these instances as they may vary from instance to instance + return $smarty->_cache[ 'cacheresource_handlers' ][ $type ] = $smarty->registered_cache_resources[ $type ]; + } + // try sysplugins dir + if (isset(self::$sysplugins[ $type ])) { + $cache_resource_class = 'Smarty_Internal_CacheResource_' . ucfirst($type); + return $smarty->_cache[ 'cacheresource_handlers' ][ $type ] = new $cache_resource_class(); + } + // try plugins dir + $cache_resource_class = 'Smarty_CacheResource_' . ucfirst($type); + if ($smarty->loadPlugin($cache_resource_class)) { + return $smarty->_cache[ 'cacheresource_handlers' ][ $type ] = new $cache_resource_class(); + } + // give up + throw new SmartyException("Unable to load cache resource '{$type}'"); + } +} diff --git a/libs/sysplugins/smarty_cacheresource_custom.php b/libs/sysplugins/smarty_cacheresource_custom.php new file mode 100644 index 0000000..8f1290e --- /dev/null +++ b/libs/sysplugins/smarty_cacheresource_custom.php @@ -0,0 +1,275 @@ +cache_id) ? preg_replace('![^\w\|]+!', '_', $cached->cache_id) : null; + $_compile_id = isset($cached->compile_id) ? preg_replace('![^\w]+!', '_', $cached->compile_id) : null; + $path = $cached->source->uid . $_cache_id . $_compile_id; + $cached->filepath = sha1($path); + if ($_template->smarty->cache_locking) { + $cached->lock_id = sha1('lock.' . $path); + } + $this->populateTimestamp($cached); + } + + /** + * populate Cached Object with timestamp and exists from Resource + * + * @param Smarty_Template_Cached $cached + * + * @return void + */ + public function populateTimestamp(Smarty_Template_Cached $cached) + { + $mtime = + $this->fetchTimestamp($cached->filepath, $cached->source->name, $cached->cache_id, $cached->compile_id); + if ($mtime !== null) { + $cached->timestamp = $mtime; + $cached->exists = !!$cached->timestamp; + + return; + } + $timestamp = null; + $this->fetch($cached->filepath, $cached->source->name, $cached->cache_id, $cached->compile_id, $cached->content, + $timestamp); + $cached->timestamp = isset($timestamp) ? $timestamp : false; + $cached->exists = !!$cached->timestamp; + } + + /** + * Read the cached template and process the header + * + * @param \Smarty_Internal_Template $_smarty_tpl do not change variable name, is used by compiled template + * @param Smarty_Template_Cached $cached cached object + * @param boolean $update flag if called because cache update + * + * @return boolean true or false if the cached content does not exist + */ + public function process(Smarty_Internal_Template $_smarty_tpl, Smarty_Template_Cached $cached = null, + $update = false) + { + if (!$cached) { + $cached = $_smarty_tpl->cached; + } + $content = $cached->content ? $cached->content : null; + $timestamp = $cached->timestamp ? $cached->timestamp : null; + if ($content === null || !$timestamp) { + $this->fetch($_smarty_tpl->cached->filepath, $_smarty_tpl->source->name, $_smarty_tpl->cache_id, + $_smarty_tpl->compile_id, $content, $timestamp); + } + if (isset($content)) { + eval("?>" . $content); + $cached->content = null; + return true; + } + + return false; + } + + /** + * Write the rendered template output to cache + * + * @param Smarty_Internal_Template $_template template object + * @param string $content content to cache + * + * @return boolean success + */ + public function writeCachedContent(Smarty_Internal_Template $_template, $content) + { + return $this->save($_template->cached->filepath, $_template->source->name, $_template->cache_id, + $_template->compile_id, $_template->cache_lifetime, $content); + } + + /** + * Read cached template from cache + * + * @param Smarty_Internal_Template $_template template object + * + * @return string|boolean content + */ + public function readCachedContent(Smarty_Internal_Template $_template) + { + $content = $_template->cached->content ? $_template->cached->content : null; + $timestamp = null; + if ($content === null) { + $timestamp = null; + $this->fetch($_template->cached->filepath, $_template->source->name, $_template->cache_id, + $_template->compile_id, $content, $timestamp); + } + if (isset($content)) { + return $content; + } + return false; + } + + /** + * Empty cache + * + * @param Smarty $smarty Smarty object + * @param integer $exp_time expiration time (number of seconds, not timestamp) + * + * @return integer number of cache files deleted + */ + public function clearAll(Smarty $smarty, $exp_time = null) + { + return $this->delete(null, null, null, $exp_time); + } + + /** + * Empty cache for a specific template + * + * @param Smarty $smarty Smarty object + * @param string $resource_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer $exp_time expiration time (number of seconds, not timestamp) + * + * @return integer number of cache files deleted + */ + public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time) + { + $cache_name = null; + + if (isset($resource_name)) { + $source = Smarty_Template_Source::load(null, $smarty, $resource_name); + if ($source->exists) { + $cache_name = $source->name; + } else { + return 0; + } + } + + return $this->delete($cache_name, $cache_id, $compile_id, $exp_time); + } + + /** + * Check is cache is locked for this template + * + * @param Smarty $smarty Smarty object + * @param Smarty_Template_Cached $cached cached object + * + * @return boolean true or false if cache is locked + */ + public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + $id = $cached->lock_id; + $name = $cached->source->name . '.lock'; + + $mtime = $this->fetchTimestamp($id, $name, $cached->cache_id, $cached->compile_id); + if ($mtime === null) { + $this->fetch($id, $name, $cached->cache_id, $cached->compile_id, $content, $mtime); + } + return $mtime && ($t = time()) - $mtime < $smarty->locking_timeout; + } + + /** + * Lock cache for this template + * + * @param Smarty $smarty Smarty object + * @param Smarty_Template_Cached $cached cached object + * + * @return bool|void + */ + public function acquireLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + $cached->is_locked = true; + $id = $cached->lock_id; + $name = $cached->source->name . '.lock'; + $this->save($id, $name, $cached->cache_id, $cached->compile_id, $smarty->locking_timeout, ''); + } + + /** + * Unlock cache for this template + * + * @param Smarty $smarty Smarty object + * @param Smarty_Template_Cached $cached cached object + * + * @return bool|void + */ + public function releaseLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + $cached->is_locked = false; + $name = $cached->source->name . '.lock'; + $this->delete($name, $cached->cache_id, $cached->compile_id, null); + } +} diff --git a/libs/sysplugins/smarty_cacheresource_keyvaluestore.php b/libs/sysplugins/smarty_cacheresource_keyvaluestore.php new file mode 100644 index 0000000..bab1b5c --- /dev/null +++ b/libs/sysplugins/smarty_cacheresource_keyvaluestore.php @@ -0,0 +1,507 @@ +filepath = $_template->source->uid . '#' . $this->sanitize($cached->source->resource) . '#' . + $this->sanitize($cached->cache_id) . '#' . $this->sanitize($cached->compile_id); + + $this->populateTimestamp($cached); + } + + /** + * populate Cached Object with timestamp and exists from Resource + * + * @param Smarty_Template_Cached $cached cached object + * + * @return void + */ + public function populateTimestamp(Smarty_Template_Cached $cached) + { + if (!$this->fetch($cached->filepath, $cached->source->name, $cached->cache_id, $cached->compile_id, $content, + $timestamp, $cached->source->uid) + ) { + return; + } + $cached->content = $content; + $cached->timestamp = (int) $timestamp; + $cached->exists = !!$cached->timestamp; + } + + /** + * Read the cached template and process the header + * + * @param \Smarty_Internal_Template $_smarty_tpl do not change variable name, is used by compiled template + * @param Smarty_Template_Cached $cached cached object + * @param boolean $update flag if called because cache update + * + * @return boolean true or false if the cached content does not exist + */ + public function process(Smarty_Internal_Template $_smarty_tpl, Smarty_Template_Cached $cached = null, + $update = false) + { + if (!$cached) { + $cached = $_smarty_tpl->cached; + } + $content = $cached->content ? $cached->content : null; + $timestamp = $cached->timestamp ? $cached->timestamp : null; + if ($content === null || !$timestamp) { + if (!$this->fetch($_smarty_tpl->cached->filepath, $_smarty_tpl->source->name, $_smarty_tpl->cache_id, + $_smarty_tpl->compile_id, $content, $timestamp, $_smarty_tpl->source->uid) + ) { + return false; + } + } + if (isset($content)) { + eval("?>" . $content); + + return true; + } + + return false; + } + + /** + * Write the rendered template output to cache + * + * @param Smarty_Internal_Template $_template template object + * @param string $content content to cache + * + * @return boolean success + */ + public function writeCachedContent(Smarty_Internal_Template $_template, $content) + { + $this->addMetaTimestamp($content); + + return $this->write(array($_template->cached->filepath => $content), $_template->cache_lifetime); + } + + /** + * Read cached template from cache + * + * @param Smarty_Internal_Template $_template template object + * + * @return string|false content + */ + public function readCachedContent(Smarty_Internal_Template $_template) + { + $content = $_template->cached->content ? $_template->cached->content : null; + $timestamp = null; + if ($content === null) { + if (!$this->fetch($_template->cached->filepath, $_template->source->name, $_template->cache_id, + $_template->compile_id, $content, $timestamp, $_template->source->uid) + ) { + return false; + } + } + if (isset($content)) { + return $content; + } + return false; + } + + /** + * Empty cache + * {@internal the $exp_time argument is ignored altogether }} + * + * @param Smarty $smarty Smarty object + * @param integer $exp_time expiration time [being ignored] + * + * @return integer number of cache files deleted [always -1] + * @uses purge() to clear the whole store + * @uses invalidate() to mark everything outdated if purge() is inapplicable + */ + public function clearAll(Smarty $smarty, $exp_time = null) + { + if (!$this->purge()) { + $this->invalidate(null); + } + return - 1; + } + + /** + * Empty cache for a specific template + * {@internal the $exp_time argument is ignored altogether}} + * + * @param Smarty $smarty Smarty object + * @param string $resource_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer $exp_time expiration time [being ignored] + * + * @return integer number of cache files deleted [always -1] + * @uses buildCachedFilepath() to generate the CacheID + * @uses invalidate() to mark CacheIDs parent chain as outdated + * @uses delete() to remove CacheID from cache + */ + public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time) + { + $uid = $this->getTemplateUid($smarty, $resource_name); + $cid = $uid . '#' . $this->sanitize($resource_name) . '#' . $this->sanitize($cache_id) . '#' . + $this->sanitize($compile_id); + $this->delete(array($cid)); + $this->invalidate($cid, $resource_name, $cache_id, $compile_id, $uid); + return - 1; + } + + /** + * Get template's unique ID + * + * @param Smarty $smarty Smarty object + * @param string $resource_name template name + * + * @return string filepath of cache file + * @throws \SmartyException + * + */ + protected function getTemplateUid(Smarty $smarty, $resource_name) + { + if (isset($resource_name)) { + $source = Smarty_Template_Source::load(null, $smarty, $resource_name); + if ($source->exists) { + return $source->uid; + } + } + return ''; + } + + /** + * Sanitize CacheID components + * + * @param string $string CacheID component to sanitize + * + * @return string sanitized CacheID component + */ + protected function sanitize($string) + { + $string = trim($string, '|'); + if (!$string) { + return ''; + } + return preg_replace('#[^\w\|]+#S', '_', $string); + } + + /** + * Fetch and prepare a cache object. + * + * @param string $cid CacheID to fetch + * @param string $resource_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param string $content cached content + * @param integer &$timestamp cached timestamp (epoch) + * @param string $resource_uid resource's uid + * + * @return boolean success + */ + protected function fetch($cid, $resource_name = null, $cache_id = null, $compile_id = null, &$content = null, + &$timestamp = null, $resource_uid = null) + { + $t = $this->read(array($cid)); + $content = !empty($t[ $cid ]) ? $t[ $cid ] : null; + $timestamp = null; + + if ($content && ($timestamp = $this->getMetaTimestamp($content))) { + $invalidated = + $this->getLatestInvalidationTimestamp($cid, $resource_name, $cache_id, $compile_id, $resource_uid); + if ($invalidated > $timestamp) { + $timestamp = null; + $content = null; + } + } + + return !!$content; + } + + /** + * Add current microtime to the beginning of $cache_content + * {@internal the header uses 8 Bytes, the first 4 Bytes are the seconds, the second 4 Bytes are the microseconds}} + * + * @param string &$content the content to be cached + */ + protected function addMetaTimestamp(&$content) + { + $mt = explode(" ", microtime()); + $ts = pack("NN", $mt[ 1 ], (int) ($mt[ 0 ] * 100000000)); + $content = $ts . $content; + } + + /** + * Extract the timestamp the $content was cached + * + * @param string &$content the cached content + * + * @return float the microtime the content was cached + */ + protected function getMetaTimestamp(&$content) + { + extract(unpack('N1s/N1m/a*content', $content)); + /** + * @var int $s + * @var int $m + */ + return $s + ($m / 100000000); + } + + /** + * Invalidate CacheID + * + * @param string $cid CacheID + * @param string $resource_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param string $resource_uid source's uid + * + * @return void + */ + protected function invalidate($cid = null, $resource_name = null, $cache_id = null, $compile_id = null, + $resource_uid = null) + { + $now = microtime(true); + $key = null; + // invalidate everything + if (!$resource_name && !$cache_id && !$compile_id) { + $key = 'IVK#ALL'; + } // invalidate all caches by template + else { + if ($resource_name && !$cache_id && !$compile_id) { + $key = 'IVK#TEMPLATE#' . $resource_uid . '#' . $this->sanitize($resource_name); + } // invalidate all caches by cache group + else { + if (!$resource_name && $cache_id && !$compile_id) { + $key = 'IVK#CACHE#' . $this->sanitize($cache_id); + } // invalidate all caches by compile id + else { + if (!$resource_name && !$cache_id && $compile_id) { + $key = 'IVK#COMPILE#' . $this->sanitize($compile_id); + } // invalidate by combination + else { + $key = 'IVK#CID#' . $cid; + } + } + } + } + $this->write(array($key => $now)); + } + + /** + * Determine the latest timestamp known to the invalidation chain + * + * @param string $cid CacheID to determine latest invalidation timestamp of + * @param string $resource_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param string $resource_uid source's filepath + * + * @return float the microtime the CacheID was invalidated + */ + protected function getLatestInvalidationTimestamp($cid, $resource_name = null, $cache_id = null, $compile_id = null, + $resource_uid = null) + { + // abort if there is no CacheID + if (false && !$cid) { + return 0; + } + // abort if there are no InvalidationKeys to check + if (!($_cid = $this->listInvalidationKeys($cid, $resource_name, $cache_id, $compile_id, $resource_uid))) { + return 0; + } + + // there are no InValidationKeys + if (!($values = $this->read($_cid))) { + return 0; + } + // make sure we're dealing with floats + $values = array_map('floatval', $values); + + return max($values); + } + + /** + * Translate a CacheID into the list of applicable InvalidationKeys. + * Splits "some|chain|into|an|array" into array( '#clearAll#', 'some', 'some|chain', 'some|chain|into', ... ) + * + * @param string $cid CacheID to translate + * @param string $resource_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param string $resource_uid source's filepath + * + * @return array list of InvalidationKeys + * @uses $invalidationKeyPrefix to prepend to each InvalidationKey + */ + protected function listInvalidationKeys($cid, $resource_name = null, $cache_id = null, $compile_id = null, + $resource_uid = null) + { + $t = array('IVK#ALL'); + $_name = $_compile = '#'; + if ($resource_name) { + $_name .= $resource_uid . '#' . $this->sanitize($resource_name); + $t[] = 'IVK#TEMPLATE' . $_name; + } + if ($compile_id) { + $_compile .= $this->sanitize($compile_id); + $t[] = 'IVK#COMPILE' . $_compile; + } + $_name .= '#'; + $cid = trim($cache_id, '|'); + if (!$cid) { + return $t; + } + $i = 0; + while (true) { + // determine next delimiter position + $i = strpos($cid, '|', $i); + // add complete CacheID if there are no more delimiters + if ($i === false) { + $t[] = 'IVK#CACHE#' . $cid; + $t[] = 'IVK#CID' . $_name . $cid . $_compile; + $t[] = 'IVK#CID' . $_name . $_compile; + break; + } + $part = substr($cid, 0, $i); + // add slice to list + $t[] = 'IVK#CACHE#' . $part; + $t[] = 'IVK#CID' . $_name . $part . $_compile; + // skip past delimiter position + $i ++; + } + + return $t; + } + + /** + * Check is cache is locked for this template + * + * @param Smarty $smarty Smarty object + * @param Smarty_Template_Cached $cached cached object + * + * @return boolean true or false if cache is locked + */ + public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + $key = 'LOCK#' . $cached->filepath; + $data = $this->read(array($key)); + + return $data && time() - $data[ $key ] < $smarty->locking_timeout; + } + + /** + * Lock cache for this template + * + * @param Smarty $smarty Smarty object + * @param Smarty_Template_Cached $cached cached object + * + * @return bool|void + */ + public function acquireLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + $cached->is_locked = true; + $key = 'LOCK#' . $cached->filepath; + $this->write(array($key => time()), $smarty->locking_timeout); + } + + /** + * Unlock cache for this template + * + * @param Smarty $smarty Smarty object + * @param Smarty_Template_Cached $cached cached object + * + * @return bool|void + */ + public function releaseLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + $cached->is_locked = false; + $key = 'LOCK#' . $cached->filepath; + $this->delete(array($key)); + } + + /** + * 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 + */ + abstract protected function read(array $keys); + + /** + * 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 + */ + abstract protected function write(array $keys, $expire = null); + + /** + * Remove values from cache + * + * @param array $keys list of keys to delete + * + * @return boolean true on success, false on failure + */ + abstract protected function delete(array $keys); + + /** + * Remove *all* values from cache + * + * @return boolean true on success, false on failure + */ + protected function purge() + { + return false; + } +} diff --git a/libs/sysplugins/smarty_data.php b/libs/sysplugins/smarty_data.php new file mode 100644 index 0000000..b9f5de9 --- /dev/null +++ b/libs/sysplugins/smarty_data.php @@ -0,0 +1,68 @@ +dataObjectName = 'Data_object ' . (isset($name) ? "'{$name}'" : self::$count); + $this->smarty = $smarty; + if (is_object($_parent)) { + // when object set up back pointer + $this->parent = $_parent; + } elseif (is_array($_parent)) { + // set up variable values + foreach ($_parent as $_key => $_val) { + $this->tpl_vars[ $_key ] = new Smarty_Variable($_val); + } + } elseif ($_parent != null) { + throw new SmartyException("Wrong type for template variables"); + } + } +} diff --git a/libs/sysplugins/smarty_internal_block.php b/libs/sysplugins/smarty_internal_block.php new file mode 100644 index 0000000..a33ad1b --- /dev/null +++ b/libs/sysplugins/smarty_internal_block.php @@ -0,0 +1,90 @@ +name = $name; + $this->tplIndex = $tplIndex; + } + + /** + * Compiled block code overloaded by {block} class + * + * @param \Smarty_Internal_Template $tpl + */ + public function callBlock(Smarty_Internal_Template $tpl) + { + } +} \ No newline at end of file diff --git a/libs/sysplugins/smarty_internal_cacheresource_file.php b/libs/sysplugins/smarty_internal_cacheresource_file.php new file mode 100644 index 0000000..5eb99fb --- /dev/null +++ b/libs/sysplugins/smarty_internal_cacheresource_file.php @@ -0,0 +1,225 @@ +source; + $smarty = &$_template->smarty; + $_compile_dir_sep = $smarty->use_sub_dirs ? $smarty->ds : '^'; + $_filepath = sha1($source->uid . $smarty->_joined_template_dir); + $cached->filepath = $smarty->getCacheDir(); + if (isset($_template->cache_id)) { + $cached->filepath .= preg_replace(array('![^\w|]+!', + '![|]+!'), array('_', + $_compile_dir_sep), + $_template->cache_id) . $_compile_dir_sep; + } + if (isset($_template->compile_id)) { + $cached->filepath .= preg_replace('![^\w]+!', '_', $_template->compile_id) . $_compile_dir_sep; + } + // if use_sub_dirs, break file into directories + if ($smarty->use_sub_dirs) { + $cached->filepath .= $_filepath[ 0 ] . $_filepath[ 1 ] . $smarty->ds . $_filepath[ 2 ] . $_filepath[ 3 ] . + $smarty->ds . + $_filepath[ 4 ] . $_filepath[ 5 ] . $smarty->ds; + } + $cached->filepath .= $_filepath; + $basename = $source->handler->getBasename($source); + if (!empty($basename)) { + $cached->filepath .= '.' . $basename; + } + if ($smarty->cache_locking) { + $cached->lock_id = $cached->filepath . '.lock'; + } + $cached->filepath .= '.php'; + $cached->timestamp = $cached->exists = is_file($cached->filepath); + if ($cached->exists) { + $cached->timestamp = filemtime($cached->filepath); + } + } + + /** + * populate Cached Object with timestamp and exists from Resource + * + * @param Smarty_Template_Cached $cached cached object + * + * @return void + */ + public function populateTimestamp(Smarty_Template_Cached $cached) + { + $cached->timestamp = $cached->exists = is_file($cached->filepath); + if ($cached->exists) { + $cached->timestamp = filemtime($cached->filepath); + } + } + + /** + * Read the cached template and process its header + * + * @param \Smarty_Internal_Template $_smarty_tpl do not change variable name, is used by compiled template + * @param Smarty_Template_Cached $cached cached object + * @param bool $update flag if called because cache update + * + * @return boolean true or false if the cached content does not exist + */ + public function process(Smarty_Internal_Template $_smarty_tpl, Smarty_Template_Cached $cached = null, + $update = false) + { + $_smarty_tpl->cached->valid = false; + if ($update && defined('HHVM_VERSION')) { + eval("?>" . file_get_contents($_smarty_tpl->cached->filepath)); + return true; + } else { + return @include $_smarty_tpl->cached->filepath; + } + } + + /** + * Write the rendered template output to cache + * + * @param Smarty_Internal_Template $_template template object + * @param string $content content to cache + * + * @return boolean success + */ + public function writeCachedContent(Smarty_Internal_Template $_template, $content) + { + if ($_template->smarty->ext->_writeFile->writeFile($_template->cached->filepath, $content, + $_template->smarty) === true + ) { + if (function_exists('opcache_invalidate') && + (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api"))) < 1 + ) { + opcache_invalidate($_template->cached->filepath, true); + } elseif (function_exists('apc_compile_file')) { + apc_compile_file($_template->cached->filepath); + } + $cached = $_template->cached; + $cached->timestamp = $cached->exists = is_file($cached->filepath); + if ($cached->exists) { + $cached->timestamp = filemtime($cached->filepath); + return true; + } + } + return false; + } + + /** + * Read cached template from cache + * + * @param Smarty_Internal_Template $_template template object + * + * @return string content + */ + public function readCachedContent(Smarty_Internal_Template $_template) + { + if (is_file($_template->cached->filepath)) { + return file_get_contents($_template->cached->filepath); + } + return false; + } + + /** + * Empty cache + * + * @param Smarty $smarty + * @param integer $exp_time expiration time (number of seconds, not timestamp) + * + * @return integer number of cache files deleted + */ + public function clearAll(Smarty $smarty, $exp_time = null) + { + return $smarty->ext->_cacheResourceFile->clear($smarty, null, null, null, $exp_time); + } + + /** + * Empty cache for a specific template + * + * @param Smarty $smarty + * @param string $resource_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer $exp_time expiration time (number of seconds, not timestamp) + * + * @return integer number of cache files deleted + */ + public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time) + { + return $smarty->ext->_cacheResourceFile->clear($smarty, $resource_name, $cache_id, $compile_id, $exp_time); + } + + /** + * Check is cache is locked for this template + * + * @param Smarty $smarty Smarty object + * @param Smarty_Template_Cached $cached cached object + * + * @return boolean true or false if cache is locked + */ + public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + if (version_compare(PHP_VERSION, '5.3.0', '>=')) { + clearstatcache(true, $cached->lock_id); + } else { + clearstatcache(); + } + if (is_file($cached->lock_id)) { + $t = filemtime($cached->lock_id); + return $t && (time() - $t < $smarty->locking_timeout); + } else { + return false; + } + } + + /** + * Lock cache for this template + * + * @param Smarty $smarty Smarty object + * @param Smarty_Template_Cached $cached cached object + * + * @return bool|void + */ + public function acquireLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + $cached->is_locked = true; + touch($cached->lock_id); + } + + /** + * Unlock cache for this template + * + * @param Smarty $smarty Smarty object + * @param Smarty_Template_Cached $cached cached object + * + * @return bool|void + */ + public function releaseLock(Smarty $smarty, Smarty_Template_Cached $cached) + { + $cached->is_locked = false; + @unlink($cached->lock_id); + } +} diff --git a/libs/sysplugins/smarty_internal_compile_append.php b/libs/sysplugins/smarty_internal_compile_append.php new file mode 100644 index 0000000..8539d6b --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_append.php @@ -0,0 +1,51 @@ +required_attributes = array('var', 'value'); + $this->shorttag_order = array('var', 'value'); + $this->optional_attributes = array('scope', 'index'); + $this->mapCache = array(); + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + // map to compile assign attributes + if (isset($_attr[ 'index' ])) { + $_params[ 'smarty_internal_index' ] = '[' . $_attr[ 'index' ] . ']'; + unset($_attr[ 'index' ]); + } else { + $_params[ 'smarty_internal_index' ] = '[]'; + } + $_new_attr = array(); + foreach ($_attr as $key => $value) { + $_new_attr[] = array($key => $value); + } + // call compile assign + return parent::compile($_new_attr, $compiler, $_params); + } +} diff --git a/libs/sysplugins/smarty_internal_compile_assign.php b/libs/sysplugins/smarty_internal_compile_assign.php new file mode 100644 index 0000000..3bd3384 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_assign.php @@ -0,0 +1,94 @@ + Smarty::SCOPE_LOCAL, 'parent' => Smarty::SCOPE_PARENT, + 'root' => Smarty::SCOPE_ROOT, 'global' => Smarty::SCOPE_GLOBAL, + 'tpl_root' => Smarty::SCOPE_TPL_ROOT, 'smarty' => Smarty::SCOPE_SMARTY); + + /** + * Compiles code for the {assign} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return string compiled code + * @throws \SmartyCompilerException + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + // the following must be assigned at runtime because it will be overwritten in Smarty_Internal_Compile_Append + $this->required_attributes = array('var', 'value'); + $this->shorttag_order = array('var', 'value'); + $this->optional_attributes = array('scope'); + $this->mapCache = array(); + $_nocache = false; + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + // nocache ? + if ($_var = $compiler->getId($_attr[ 'var' ])) { + $_var = "'{$_var}'"; + } else { + $_var = $_attr[ 'var' ]; + } + if ($compiler->tag_nocache || $compiler->nocache) { + $_nocache = true; + // create nocache var to make it know for further compiling + $compiler->setNocacheInVariable($_attr[ 'var' ]); + } + // scope setup + if ($_attr[ 'noscope' ]) { + $_scope = - 1; + } else { + $_scope = $compiler->convertScope($_attr, $this->valid_scopes); + } + // optional parameter + $_params = ""; + if ($_nocache || $_scope) { + $_params .= ' ,' . var_export($_nocache, true); + } + if ($_scope) { + $_params .= ' ,' . $_scope; + } + if (isset($parameter[ 'smarty_internal_index' ])) { + $output = + "tpl_vars[{$_var}]) ? \$_smarty_tpl->tpl_vars[{$_var}]->value : array();\n"; + $output .= "if (!is_array(\$_tmp_array) || \$_tmp_array instanceof ArrayAccess) {\n"; + $output .= "settype(\$_tmp_array, 'array');\n"; + $output .= "}\n"; + $output .= "\$_tmp_array{$parameter['smarty_internal_index']} = {$_attr['value']};\n"; + $output .= "\$_smarty_tpl->_assignInScope({$_var}, \$_tmp_array{$_params});\n?>"; + } else { + $output = "_assignInScope({$_var}, {$_attr['value']}{$_params});\n?>"; + } + return $output; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_block.php b/libs/sysplugins/smarty_internal_compile_block.php new file mode 100644 index 0000000..5098d62 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_block.php @@ -0,0 +1,202 @@ + + */ +class Smarty_Internal_Compile_Block extends Smarty_Internal_Compile_Shared_Inheritance +{ + /** + * Attribute definition: Overwrites base class. + * + * @var array + * @see Smarty_Internal_CompileBase + */ + public $required_attributes = array('name'); + + /** + * Attribute definition: Overwrites base class. + * + * @var array + * @see Smarty_Internal_CompileBase + */ + public $shorttag_order = array('name'); + + /** + * Attribute definition: Overwrites base class. + * + * @var array + * @see Smarty_Internal_CompileBase + */ + public $option_flags = array('hide', 'nocache'); + + /** + * Attribute definition: Overwrites base class. + * + * @var array + * @see Smarty_Internal_CompileBase + */ + public $optional_attributes = array('assign'); + + /** + * Saved compiler object + * + * @var Smarty_Internal_TemplateCompilerBase + */ + public $compiler = null; + + /** + * Compiles code for the {block} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return bool true + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + if (!isset($compiler->_cache[ 'blockNesting' ])) { + $compiler->_cache[ 'blockNesting' ] = 0; + } + if ($compiler->_cache[ 'blockNesting' ] == 0) { + // make sure that inheritance gets initialized in template code + $this->registerInit($compiler); + $this->option_flags = array('hide', 'nocache', 'append', 'prepend'); + } else { + $this->option_flags = array('hide', 'nocache'); + } + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + $compiler->_cache[ 'blockNesting' ] ++; + $_className = 'Block_' . preg_replace('![^\w]+!', '_', uniqid(rand(), true)); + $compiler->_cache[ 'blockName' ][ $compiler->_cache[ 'blockNesting' ] ] = $_attr[ 'name' ]; + $compiler->_cache[ 'blockClass' ][ $compiler->_cache[ 'blockNesting' ] ] = $_className; + $compiler->_cache[ 'blockParams' ][ $compiler->_cache[ 'blockNesting' ] ] = array(); + $compiler->_cache[ 'blockParams' ][ 1 ][ 'subBlocks' ][ trim($_attr[ 'name' ], '"\'') ][] = $_className; + $this->openTag($compiler, 'block', array($_attr, $compiler->nocache, $compiler->parser->current_buffer, + $compiler->template->compiled->has_nocache_code, + $compiler->template->caching)); + // must whole block be nocache ? + if ($compiler->tag_nocache) { + $i = 0; + } + $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; + // $compiler->suppressNocacheProcessing = true; + if ($_attr[ 'nocache' ] === true) { + //$compiler->trigger_template_error('nocache option not allowed', $compiler->parser->lex->taglineno); + } + $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); + $compiler->template->compiled->has_nocache_code = false; + $compiler->suppressNocacheProcessing = true; + } +} + +/** + * Smarty Internal Plugin Compile BlockClose Class + * + */ +class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_Inheritance +{ + /** + * Compiles code for the {/block} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return bool true + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + list($_attr, $_nocache, $_buffer, $_has_nocache_code, $_caching) = $this->closeTag($compiler, array('block')); + // init block parameter + $_block = $compiler->_cache[ 'blockParams' ][ $compiler->_cache[ 'blockNesting' ] ]; + unset($compiler->_cache[ 'blockParams' ][ $compiler->_cache[ 'blockNesting' ] ]); + $_name = $_attr[ 'name' ]; + $_assign = isset($_attr[ 'assign' ]) ? $_attr[ 'assign' ] : null; + unset($_attr[ 'assign' ], $_attr[ 'name' ]); + foreach ($_attr as $name => $stat) { + if ((is_bool($stat) && $stat !== false) || (!is_bool($stat) && $stat != 'false')) { + $_block[ $name ] = 'true'; + } + } + $_className = $compiler->_cache[ 'blockClass' ][ $compiler->_cache[ 'blockNesting' ] ]; + // get compiled block code + $_functionCode = $compiler->parser->current_buffer; + // setup buffer for template function code + $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); + + $output = " $value) { + $output .= "public \${$property} = " . var_export($value,true) .";\n"; + } + $output .= "public function callBlock(Smarty_Internal_Template \$_smarty_tpl) {\n"; + //$output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n"; + if ($compiler->template->compiled->has_nocache_code) { + $output .= "\$_smarty_tpl->cached->hashes['{$compiler->template->compiled->nocache_hash}'] = true;\n"; + } + if (isset($_assign)) { + $output .= "ob_start();\n"; + } + $output .= "?>\n"; + $compiler->parser->current_buffer->append_subtree($compiler->parser, + new Smarty_Internal_ParseTree_Tag($compiler->parser, + $output)); + $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); + $output = "assign({$_assign}, ob_get_clean());\n"; + } + $output .= "}\n"; + $output .= "}\n"; + $output .= "/* {/block {$_name}} */\n\n"; + $output .= "?>\n"; + $compiler->parser->current_buffer->append_subtree($compiler->parser, + new Smarty_Internal_ParseTree_Tag($compiler->parser, + $output)); + $compiler->blockOrFunctionCode .= $f = $compiler->parser->current_buffer->to_smarty_php($compiler->parser); + $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); + // nocache plugins must be copied + if (!empty($compiler->template->compiled->required_plugins[ 'nocache' ])) { + foreach ($compiler->template->compiled->required_plugins[ 'nocache' ] as $plugin => $tmp) { + foreach ($tmp as $type => $data) { + $compiler->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin ][ $type ] = + $data; + } + } + } + + // restore old status + $compiler->template->compiled->has_nocache_code = $_has_nocache_code; + $compiler->tag_nocache = $compiler->nocache; + $compiler->nocache = $_nocache; + $compiler->parser->current_buffer = $_buffer; + $output = "_cache[ 'blockNesting' ] == 1) { + $output .= "\$_smarty_tpl->inheritance->instanceBlock(\$_smarty_tpl, '$_className', $_name);\n"; + } else { + $output .= "\$_smarty_tpl->inheritance->instanceBlock(\$_smarty_tpl, '$_className', $_name, \$this->tplIndex);\n"; + } + $output .= "?>\n"; + $compiler->_cache[ 'blockNesting' ] --; + if ($compiler->_cache[ 'blockNesting' ] == 0) { + unset($compiler->_cache[ 'blockNesting' ]); + } + $compiler->has_code = true; + $compiler->suppressNocacheProcessing = true; + return $output; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_block_child.php b/libs/sysplugins/smarty_internal_compile_block_child.php new file mode 100644 index 0000000..bb070eb --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_block_child.php @@ -0,0 +1,54 @@ + + */ +class Smarty_Internal_Compile_Block_Child extends Smarty_Internal_CompileBase +{ + /** + * Attribute definition: Overwrites base class. + * + * @var array + * @see Smarty_Internal_CompileBase + */ + public $option_flags = array(); + + /** + * Saved compiler object + * + * @var Smarty_Internal_TemplateCompilerBase + */ + public $compiler = null; + + /** + * Compiles code for the {block_parent} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return bool true + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + if (!isset($compiler->_cache[ 'blockNesting' ])) { + $compiler->trigger_template_error(' tag {$smarty.block.child} used outside {block} tags ', + $compiler->parser->lex->taglineno); + } + $compiler->has_code = true; + $compiler->suppressNocacheProcessing = true; + $compiler->_cache[ 'blockParams' ][ $compiler->_cache[ 'blockNesting' ] ][ 'callsChild' ] = 'true'; + $output = "inheritance->callChild(\$_smarty_tpl, \$this);\n?>\n"; + return $output; + } +} \ No newline at end of file diff --git a/libs/sysplugins/smarty_internal_compile_block_parent.php b/libs/sysplugins/smarty_internal_compile_block_parent.php new file mode 100644 index 0000000..0ec1e84 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_block_parent.php @@ -0,0 +1,73 @@ + + */ +class Smarty_Internal_Compile_Block_Parent extends Smarty_Internal_Compile_Shared_Inheritance +{ + + /** + * Attribute definition: Overwrites base class. + * + * @var array + * @see Smarty_Internal_CompileBase + */ + public $optional_attributes = array('name'); + + /** + * Attribute definition: Overwrites base class. + * + * @var array + * @see Smarty_Internal_CompileBase + */ + public $shorttag_order = array('name'); + + /** + * Attribute definition: Overwrites base class. + * + * @var array + * @see Smarty_Internal_CompileBase + */ + public $option_flags = array(); + + /** + * Saved compiler object + * + * @var Smarty_Internal_TemplateCompilerBase + */ + public $compiler = null; + + /** + * Compiles code for the {block_parent} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return bool true + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + if (!isset($compiler->_cache[ 'blockNesting' ])) { + $compiler->trigger_template_error(' tag {$smarty.block.parent} used outside {block} tags ', + $compiler->parser->lex->taglineno); + } + $compiler->suppressNocacheProcessing = true; + $compiler->has_code = true; + $output = "inheritance->callParent(\$_smarty_tpl, \$this" . + (isset($_attr[ 'name' ]) ? ", {$_attr[ 'name' ]}" : '') . ");\n?>\n"; + return $output; + } +} \ No newline at end of file diff --git a/libs/sysplugins/smarty_internal_compile_break.php b/libs/sysplugins/smarty_internal_compile_break.php new file mode 100644 index 0000000..5015738 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_break.php @@ -0,0 +1,110 @@ +checkLevels($args, $compiler); + $output = "getTagCompiler('foreach'); + $output .= $foreachCompiler->compileRestore($foreachLevels); + } + $output .= "break {$levels};?>"; + return $output; + } + + /** + * check attributes and return array of break and foreach levels + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param string $tag tag name + * + * @return array + * @throws \SmartyCompilerException + */ + public function checkLevels($args, Smarty_Internal_TemplateCompilerBase $compiler, $tag = 'break') + { + static $_is_loopy = array('for' => true, 'foreach' => true, 'while' => true, 'section' => true); + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + + if ($_attr[ 'nocache' ] === true) { + $compiler->trigger_template_error('nocache option not allowed', null, true); + } + + if (isset($_attr[ 'levels' ])) { + if (!is_numeric($_attr[ 'levels' ])) { + $compiler->trigger_template_error('level attribute must be a numeric constant', null, true); + } + $levels = $_attr[ 'levels' ]; + } else { + $levels = 1; + } + $level_count = $levels; + $stack_count = count($compiler->_tag_stack) - 1; + $foreachLevels = 0; + $lastTag = ''; + while ($level_count >= 0 && $stack_count >= 0) { + if (isset($_is_loopy[ $compiler->_tag_stack[ $stack_count ][ 0 ] ])) { + $lastTag = $compiler->_tag_stack[ $stack_count ][ 0 ]; + if ($level_count === 0) { + break; + } + $level_count --; + if ($compiler->_tag_stack[ $stack_count ][ 0 ] === 'foreach') { + $foreachLevels ++; + } + } + $stack_count --; + } + if ($level_count != 0) { + $compiler->trigger_template_error("cannot {$tag} {$levels} level(s)", null, true); + } + if ($lastTag === 'foreach' && $tag === 'break') { + $foreachLevels --; + } + return array($levels, $foreachLevels); + } +} diff --git a/libs/sysplugins/smarty_internal_compile_call.php b/libs/sysplugins/smarty_internal_compile_call.php new file mode 100644 index 0000000..739df5e --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_call.php @@ -0,0 +1,89 @@ +getAttributes($compiler, $args); + // save possible attributes + if (isset($_attr[ 'assign' ])) { + // output will be stored in a smarty variable instead of being displayed + $_assign = $_attr[ 'assign' ]; + } + //$_name = trim($_attr['name'], "'\""); + $_name = $_attr[ 'name' ]; + unset($_attr[ 'name' ], $_attr[ 'assign' ], $_attr[ 'nocache' ]); + // set flag (compiled code of {function} must be included in cache file + if (!$compiler->template->caching || $compiler->nocache || $compiler->tag_nocache) { + $_nocache = 'true'; + } else { + $_nocache = 'false'; + } + $_paramsArray = array(); + foreach ($_attr as $_key => $_value) { + if (is_int($_key)) { + $_paramsArray[] = "$_key=>$_value"; + } else { + $_paramsArray[] = "'$_key'=>$_value"; + } + } + $_params = 'array(' . implode(",", $_paramsArray) . ')'; + //$compiler->suppressNocacheProcessing = true; + // was there an assign attribute + if (isset($_assign)) { + $_output = + "smarty->ext->_tplFunction->callTemplateFunction(\$_smarty_tpl, {$_name}, {$_params}, {$_nocache});\n\$_smarty_tpl->assign({$_assign}, ob_get_clean());?>\n"; + } else { + $_output = + "smarty->ext->_tplFunction->callTemplateFunction(\$_smarty_tpl, {$_name}, {$_params}, {$_nocache});?>\n"; + } + return $_output; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_capture.php b/libs/sysplugins/smarty_internal_compile_capture.php new file mode 100644 index 0000000..564b1f6 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_capture.php @@ -0,0 +1,112 @@ +getId($parameter[ 1 ]) : null; + if (!$name) { + //$compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", null, true); + } + return '$_smarty_tpl->smarty->ext->_capture->getBuffer($_smarty_tpl'.(isset($name)?", '{$name}')":')'); + } + + /** + * Compiles code for the {capture} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param null $parameter + * + * @return string compiled code + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter = null) + { + // check and get attributes + $_attr = $this->getAttributes($compiler, $args, $parameter, 'capture'); + + $buffer = isset($_attr[ 'name' ]) ? $_attr[ 'name' ] : "'default'"; + $assign = isset($_attr[ 'assign' ]) ? $_attr[ 'assign' ] : 'null'; + $append = isset($_attr[ 'append' ]) ? $_attr[ 'append' ] : 'null'; + + $compiler->_cache[ 'capture_stack' ][] = array($compiler->nocache); + // maybe nocache because of nocache variables + $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; + $_output = "smarty->ext->_capture->open(\$_smarty_tpl, $buffer, $assign, $append);?>"; + + return $_output; + } +} + +/** + * Smarty Internal Plugin Compile Captureclose Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_CaptureClose extends Smarty_Internal_CompileBase +{ + /** + * Compiles code for the {/capture} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param null $parameter + * + * @return string compiled code + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + // check and get attributes + $_attr = $this->getAttributes($compiler, $args, $parameter, '/capture'); + // must endblock be nocache? + if ($compiler->nocache) { + $compiler->tag_nocache = true; + } + + list($compiler->nocache) = array_pop($compiler->_cache[ 'capture_stack' ]); + + return "smarty->ext->_capture->close(\$_smarty_tpl);?>"; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_config_load.php b/libs/sysplugins/smarty_internal_compile_config_load.php new file mode 100644 index 0000000..7c6e9b5 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_config_load.php @@ -0,0 +1,98 @@ + Smarty::SCOPE_LOCAL, 'parent' => Smarty::SCOPE_PARENT, + 'root' => Smarty::SCOPE_ROOT, 'tpl_root' => Smarty::SCOPE_TPL_ROOT, + 'smarty' => Smarty::SCOPE_SMARTY, 'global' => Smarty::SCOPE_SMARTY); + + /** + * Compiles code for the {config_load} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * + * @return string compiled code + * @throws \SmartyCompilerException + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler) + { + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + + if ($_attr[ 'nocache' ] === true) { + $compiler->trigger_template_error('nocache option not allowed', null, true); + } + + // save possible attributes + $conf_file = $_attr[ 'file' ]; + if (isset($_attr[ 'section' ])) { + $section = $_attr[ 'section' ]; + } else { + $section = 'null'; + } + // scope setup + if ($_attr[ 'noscope' ]) { + $_scope = - 1; + } else { + $_scope = $compiler->convertScope($_attr, $this->valid_scopes); + } + + // create config object + $_output = + "smarty->ext->configLoad->_loadConfigFile(\$_smarty_tpl, {$conf_file}, {$section}, {$_scope});\n?>\n"; + + return $_output; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_continue.php b/libs/sysplugins/smarty_internal_compile_continue.php new file mode 100644 index 0000000..7492c7d --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_continue.php @@ -0,0 +1,42 @@ +checkLevels($args, $compiler, 'continue'); + $output = " 1) { + /* @var Smarty_Internal_Compile_Foreach $foreachCompiler */ + $foreachCompiler = $compiler->getTagCompiler('foreach'); + $output .= $foreachCompiler->compileRestore($foreachLevels - 1); + } + $output .= "continue {$levels};?>"; + return $output; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_debug.php b/libs/sysplugins/smarty_internal_compile_debug.php new file mode 100644 index 0000000..1668e72 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_debug.php @@ -0,0 +1,42 @@ +getAttributes($compiler, $args); + + // compile always as nocache + $compiler->tag_nocache = true; + + // display debug template + $_output = + "display_debug(\$_smarty_tpl);\n"; + $_output .= "unset(\$_smarty_debug);\n?>"; + return $_output; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_eval.php b/libs/sysplugins/smarty_internal_compile_eval.php new file mode 100644 index 0000000..97a3c29 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_eval.php @@ -0,0 +1,72 @@ +getAttributes($compiler, $args); + if (isset($_attr[ 'assign' ])) { + // output will be stored in a smarty variable instead of being displayed + $_assign = $_attr[ 'assign' ]; + } + + // create template object + $_output = "\$_template = new {$compiler->smarty->template_class}('eval:'." . $_attr[ 'var' ] . + ", \$_smarty_tpl->smarty, \$_smarty_tpl);"; + //was there an assign attribute? + if (isset($_assign)) { + $_output .= "\$_smarty_tpl->assign($_assign,\$_template->fetch());"; + } else { + $_output .= "echo \$_template->fetch();"; + } + + return ""; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_extends.php b/libs/sysplugins/smarty_internal_compile_extends.php new file mode 100644 index 0000000..83cb805 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_extends.php @@ -0,0 +1,144 @@ +getAttributes($compiler, $args); + if ($_attr[ 'nocache' ] === true) { + $compiler->trigger_template_error('nocache option not allowed', $compiler->parser->lex->line - 1); + } + if (strpos($_attr[ 'file' ], '$_tmp') !== false) { + $compiler->trigger_template_error('illegal value for file attribute', $compiler->parser->lex->line - 1); + } + // add code to initialize inheritance + $this->registerInit($compiler, true); + $file = trim($_attr[ 'file' ], '\'"'); + if (strlen($file) > 8 && substr($file, 0, 8) == 'extends:') { + // generate code for each template + $files = array_reverse(explode('|', substr($file, 8))); + $i = 0; + foreach ($files as $file) { + if ($file[ 0 ] == '"') { + $file = trim($file, '".'); + } else { + $file = "'{$file}'"; + } + $i ++; + if ($i == count($files) && isset($_attr[ 'extends_resource' ])) { + $this->compileEndChild($compiler); + } + $this->compileInclude($compiler, $file); + } + if (!isset($_attr[ 'extends_resource' ])) { + $this->compileEndChild($compiler); + } + } else { + $this->compileEndChild($compiler, $_attr[ 'file' ]); + } + $compiler->has_code = false; + return ''; + } + + /** + * Add code for inheritance endChild() method to end of template + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler + * @param null|string $template optional inheritance parent template + */ + private function compileEndChild(Smarty_Internal_TemplateCompilerBase $compiler, $template = null) + { + $inlineUids = ''; + if (isset($template) && $compiler->smarty->merge_compiled_includes) { + $code = $compiler->compileTag('include', array($template, array('scope' => 'parent'))); + if (preg_match("/([,][\s]*['][a-z0-9]+['][,][\s]*[']content.*['])[)]/", $code, $match)) { + $inlineUids = $match[ 1 ]; + } + } + $compiler->parser->template_postfix[] = new Smarty_Internal_ParseTree_Tag($compiler->parser, + "inheritance->endChild(\$_smarty_tpl" . + (isset($template) ? + ', ' . $template . $inlineUids : + '') . ");\n?>\n"); + } + + /** + * Add code for including subtemplate to end of template + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler + * @param string $template subtemplate name + */ + private function compileInclude(Smarty_Internal_TemplateCompilerBase $compiler, $template) + { + $compiler->parser->template_postfix[] = new Smarty_Internal_ParseTree_Tag($compiler->parser, + $compiler->compileTag('include', + array($template, + array('scope' => 'parent')))); + } + + /** + * Create source code for {extends} from source components array + * + * @param []\Smarty_Internal_Template_Source $components + * + * @return string + */ + public static function extendsSourceArrayCode($components) + { + $resources = array(); + foreach ($components as $source) { + $resources[] = $source->resource; + } + return '{extends file=\'extends:' . join('|', $resources) . '\' extends_resource=true}'; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_for.php b/libs/sysplugins/smarty_internal_compile_for.php new file mode 100644 index 0000000..e5e7c61 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_for.php @@ -0,0 +1,170 @@ +loopNesting ++; + if ($parameter == 0) { + $this->required_attributes = array('start', 'to'); + $this->optional_attributes = array('max', 'step'); + } else { + $this->required_attributes = array('start', 'ifexp', 'var', 'step'); + $this->optional_attributes = array(); + } + $this->mapCache = array(); + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + + $output = "tpl_vars[$var] = new Smarty_Variable(null, \$_smarty_tpl->isRenderingCache);\n"; + $output .= "\$_smarty_tpl->tpl_vars[$var]->value{$index} = {$_statement['value']};\n"; + } + if (is_array($_attr[ 'var' ])) { + $var = $_attr[ 'var' ][ 'var' ]; + $index = $_attr[ 'var' ][ 'smarty_internal_index' ]; + } else { + $var = $_attr[ 'var' ]; + $index = ''; + } + $output .= "if ($_attr[ifexp]) {\nfor (\$_foo=true;$_attr[ifexp]; \$_smarty_tpl->tpl_vars[$var]->value{$index}$_attr[step]) {\n"; + } else { + $_statement = $_attr[ 'start' ]; + if (is_array($_statement[ 'var' ])) { + $var = $_statement[ 'var' ][ 'var' ]; + $index = $_statement[ 'var' ][ 'smarty_internal_index' ]; + } else { + $var = $_statement[ 'var' ]; + $index = ''; + } + $output .= "\$_smarty_tpl->tpl_vars[$var] = new Smarty_Variable(null, \$_smarty_tpl->isRenderingCache);"; + if (isset($_attr[ 'step' ])) { + $output .= "\$_smarty_tpl->tpl_vars[$var]->step = $_attr[step];"; + } else { + $output .= "\$_smarty_tpl->tpl_vars[$var]->step = 1;"; + } + if (isset($_attr[ 'max' ])) { + $output .= "\$_smarty_tpl->tpl_vars[$var]->total = (int) min(ceil((\$_smarty_tpl->tpl_vars[$var]->step > 0 ? $_attr[to]+1 - ($_statement[value]) : $_statement[value]-($_attr[to])+1)/abs(\$_smarty_tpl->tpl_vars[$var]->step)),$_attr[max]);\n"; + } else { + $output .= "\$_smarty_tpl->tpl_vars[$var]->total = (int) ceil((\$_smarty_tpl->tpl_vars[$var]->step > 0 ? $_attr[to]+1 - ($_statement[value]) : $_statement[value]-($_attr[to])+1)/abs(\$_smarty_tpl->tpl_vars[$var]->step));\n"; + } + $output .= "if (\$_smarty_tpl->tpl_vars[$var]->total > 0) {\n"; + $output .= "for (\$_smarty_tpl->tpl_vars[$var]->value{$index} = $_statement[value], \$_smarty_tpl->tpl_vars[$var]->iteration = 1;\$_smarty_tpl->tpl_vars[$var]->iteration <= \$_smarty_tpl->tpl_vars[$var]->total;\$_smarty_tpl->tpl_vars[$var]->value{$index} += \$_smarty_tpl->tpl_vars[$var]->step, \$_smarty_tpl->tpl_vars[$var]->iteration++) {\n"; + $output .= "\$_smarty_tpl->tpl_vars[$var]->first = \$_smarty_tpl->tpl_vars[$var]->iteration == 1;"; + $output .= "\$_smarty_tpl->tpl_vars[$var]->last = \$_smarty_tpl->tpl_vars[$var]->iteration == \$_smarty_tpl->tpl_vars[$var]->total;"; + } + $output .= "?>"; + + $this->openTag($compiler, 'for', array('for', $compiler->nocache)); + // maybe nocache because of nocache variables + $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; + // return compiled code + return $output; + } +} + +/** + * Smarty Internal Plugin Compile Forelse Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_Forelse extends Smarty_Internal_CompileBase +{ + /** + * Compiles code for the {forelse} tag + * + * @param array $args array with attributes from parser + * @param object $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return string compiled code + */ + public function compile($args, $compiler, $parameter) + { + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + + list($openTag, $nocache) = $this->closeTag($compiler, array('for')); + $this->openTag($compiler, 'forelse', array('forelse', $nocache)); + + return ""; + } +} + +/** + * Smarty Internal Plugin Compile Forclose Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_Forclose extends Smarty_Internal_CompileBase +{ + /** + * Compiles code for the {/for} tag + * + * @param array $args array with attributes from parser + * @param object $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return string compiled code + */ + public function compile($args, $compiler, $parameter) + { + $compiler->loopNesting --; + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + // must endblock be nocache? + if ($compiler->nocache) { + $compiler->tag_nocache = true; + } + + list($openTag, $compiler->nocache) = $this->closeTag($compiler, array('for', 'forelse')); + + $output = "\n"; + return $output; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_foreach.php b/libs/sysplugins/smarty_internal_compile_foreach.php new file mode 100644 index 0000000..5ddd42d --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_foreach.php @@ -0,0 +1,344 @@ +loopNesting ++; + // init + $this->isNamed = false; + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + $from = $_attr[ 'from' ]; + $item = $compiler->getId($_attr[ 'item' ]); + if ($item === false) { + $item = $compiler->getVariableName($_attr[ 'item' ]); + } + $key = $name = null; + $attributes = array('item' => $item); + if (isset($_attr[ 'key' ])) { + $key = $compiler->getId($_attr[ 'key' ]); + if ($key === false) { + $key = $compiler->getVariableName($_attr[ 'key' ]); + } + $attributes[ 'key' ] = $key; + } + if (isset($_attr[ 'name' ])) { + $this->isNamed = true; + $name = $attributes[ 'name' ] = $compiler->getId($_attr[ 'name' ]); + } + foreach ($attributes as $a => $v) { + if ($v === false) { + $compiler->trigger_template_error("'{$a}' attribute/variable has illegal value", null, true); + } + } + $fromName = $compiler->getVariableName($_attr[ 'from' ]); + if ($fromName) { + foreach (array('item', 'key') as $a) { + if (isset($attributes[ $a ]) && $attributes[ $a ] == $fromName) { + $compiler->trigger_template_error("'{$a}' and 'from' may not have same variable name '{$fromName}'", + null, true); + } + } + } + + $itemVar = "\$_smarty_tpl->tpl_vars['{$item}']"; + $local = '$__foreach_' . $attributes[ 'item' ] . '_' . $this->counter ++ . '_'; + // search for used tag attributes + $itemAttr = array(); + $namedAttr = array(); + $this->scanForProperties($attributes, $compiler); + if (!empty($this->matchResults[ 'item' ])) { + $itemAttr = $this->matchResults[ 'item' ]; + } + if (!empty($this->matchResults[ 'named' ])) { + $namedAttr = $this->matchResults[ 'named' ]; + } + if (isset($_attr[ 'properties' ]) && preg_match_all("/['](.*?)[']/", $_attr[ 'properties' ], $match)) { + foreach ($match[ 1 ] as $prop) { + if (in_array($prop, $this->itemProperties)) { + $itemAttr[ $prop ] = true; + } else { + $compiler->trigger_template_error("Invalid property '{$prop}'", null, true); + } + } + if ($this->isNamed) { + foreach ($match[ 1 ] as $prop) { + if (in_array($prop, $this->nameProperties)) { + $nameAttr[ $prop ] = true; + } else { + $compiler->trigger_template_error("Invalid property '{$prop}'", null, true); + } + } + } + } + if (isset($itemAttr[ 'first' ])) { + $itemAttr[ 'index' ] = true; + } + if (isset($namedAttr[ 'first' ])) { + $namedAttr[ 'index' ] = true; + } + if (isset($namedAttr[ 'last' ])) { + $namedAttr[ 'iteration' ] = true; + $namedAttr[ 'total' ] = true; + } + if (isset($itemAttr[ 'last' ])) { + $itemAttr[ 'iteration' ] = true; + $itemAttr[ 'total' ] = true; + } + if (isset($namedAttr[ 'show' ])) { + $namedAttr[ 'total' ] = true; + } + if (isset($itemAttr[ 'show' ])) { + $itemAttr[ 'total' ] = true; + } + $keyTerm = ''; + if (isset($attributes[ 'key' ])) { + $keyTerm = "\$_smarty_tpl->tpl_vars['{$key}']->value => "; + } + if (isset($itemAttr[ 'key' ])) { + $keyTerm = "{$itemVar}->key => "; + } + if ($this->isNamed) { + $foreachVar = "\$_smarty_tpl->tpl_vars['__smarty_foreach_{$attributes['name']}']"; + } + $needTotal = isset($itemAttr[ 'total' ]); + // Register tag + $this->openTag($compiler, 'foreach', + array('foreach', $compiler->nocache, $local, $itemVar, empty($itemAttr) ? 1 : 2)); + // maybe nocache because of nocache variables + $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; + // generate output code + $output = "smarty->ext->_foreach->init(\$_smarty_tpl, $from, " . + var_export($item, true); + if ($name || $needTotal || $key) { + $output .= ', ' . var_export($needTotal, true); + } + if ($name || $key) { + $output .= ', ' . var_export($key, true); + } + if ($name) { + $output .= ', ' . var_export($name, true) . ', ' . var_export($namedAttr, true); + } + $output .= ");\n"; + if (isset($itemAttr[ 'show' ])) { + $output .= "{$itemVar}->show = ({$itemVar}->total > 0);\n"; + } + if (isset($itemAttr[ 'iteration' ])) { + $output .= "{$itemVar}->iteration = 0;\n"; + } + if (isset($itemAttr[ 'index' ])) { + $output .= "{$itemVar}->index = -1;\n"; + } + $output .= "if (\$_from !== null) {\n"; + $output .= "foreach (\$_from as {$keyTerm}{$itemVar}->value) {\n"; + if (isset($attributes[ 'key' ]) && isset($itemAttr[ 'key' ])) { + $output .= "\$_smarty_tpl->tpl_vars['{$key}']->value = {$itemVar}->key;\n"; + } + if (isset($itemAttr[ 'iteration' ])) { + $output .= "{$itemVar}->iteration++;\n"; + } + if (isset($itemAttr[ 'index' ])) { + $output .= "{$itemVar}->index++;\n"; + } + if (isset($itemAttr[ 'first' ])) { + $output .= "{$itemVar}->first = !{$itemVar}->index;\n"; + } + if (isset($itemAttr[ 'last' ])) { + $output .= "{$itemVar}->last = {$itemVar}->iteration == {$itemVar}->total;\n"; + } + if (isset($foreachVar)) { + if (isset($namedAttr[ 'iteration' ])) { + $output .= "{$foreachVar}->value['iteration']++;\n"; + } + if (isset($namedAttr[ 'index' ])) { + $output .= "{$foreachVar}->value['index']++;\n"; + } + if (isset($namedAttr[ 'first' ])) { + $output .= "{$foreachVar}->value['first'] = !{$foreachVar}->value['index'];\n"; + } + if (isset($namedAttr[ 'last' ])) { + $output .= "{$foreachVar}->value['last'] = {$foreachVar}->value['iteration'] == {$foreachVar}->value['total'];\n"; + } + } + if (!empty($itemAttr)) { + $output .= "{$local}saved = {$itemVar};\n"; + } + $output .= "?>"; + + return $output; + } + + /** + * Compiles code for to restore saved template variables + * + * @param int $levels number of levels to restore + * + * @return string compiled code + */ + public function compileRestore($levels) + { + return "\$_smarty_tpl->smarty->ext->_foreach->restore(\$_smarty_tpl, {$levels});\n"; + } +} + +/** + * Smarty Internal Plugin Compile Foreachelse Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_Foreachelse extends Smarty_Internal_CompileBase +{ + /** + * Compiles code for the {foreachelse} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return string compiled code + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + + list($openTag, $nocache, $local, $itemVar, $restore) = $this->closeTag($compiler, array('foreach')); + $this->openTag($compiler, 'foreachelse', array('foreachelse', $nocache, $local, $itemVar, 0)); + $output = "\n"; + return $output; + } +} + +/** + * Smarty Internal Plugin Compile Foreachclose Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_Foreachclose extends Smarty_Internal_CompileBase +{ + /** + * Compiles code for the {/foreach} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return string compiled code + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + $compiler->loopNesting --; + // must endblock be nocache? + if ($compiler->nocache) { + $compiler->tag_nocache = true; + } + + list($openTag, $compiler->nocache, $local, $itemVar, $restore) = + $this->closeTag($compiler, array('foreach', 'foreachelse')); + $output = " 0) { + $output .= "}\n"; + } + $output .= "}\n"; + /* @var Smarty_Internal_Compile_Foreach $foreachCompiler */ + $foreachCompiler = $compiler->getTagCompiler('foreach'); + $output .= $foreachCompiler->compileRestore(1); + $output .= "?>\n"; + return $output; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_function.php b/libs/sysplugins/smarty_internal_compile_function.php new file mode 100644 index 0000000..b7cd9e1 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_function.php @@ -0,0 +1,216 @@ +getAttributes($compiler, $args); + + if ($_attr[ 'nocache' ] === true) { + $compiler->trigger_template_error('nocache option not allowed', null, true); + } + unset($_attr[ 'nocache' ]); + $_name = trim($_attr[ 'name' ], "'\""); + $compiler->parent_compiler->tpl_function[ $_name ] = array(); + $save = array($_attr, $compiler->parser->current_buffer, $compiler->template->compiled->has_nocache_code, + $compiler->template->caching); + $this->openTag($compiler, 'function', $save); + // Init temporary context + $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); + $compiler->template->compiled->has_nocache_code = false; + return true; + } +} + +/** + * Smarty Internal Plugin Compile Functionclose Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase +{ + + /** + * Compiler object + * + * @var object + */ + private $compiler = null; + + /** + * Compiles code for the {/function} tag + * + * @param array $args array with attributes from parser + * @param object|\Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return bool true + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + $this->compiler = $compiler; + $saved_data = $this->closeTag($compiler, array('function')); + $_attr = $saved_data[ 0 ]; + $_name = trim($_attr[ 'name' ], "'\""); + $compiler->parent_compiler->tpl_function[ $_name ][ 'compiled_filepath' ] = + $compiler->parent_compiler->template->compiled->filepath; + $compiler->parent_compiler->tpl_function[ $_name ][ 'uid' ] = $compiler->template->source->uid; + $_parameter = $_attr; + unset($_parameter[ 'name' ]); + // default parameter + $_paramsArray = array(); + foreach ($_parameter as $_key => $_value) { + if (is_int($_key)) { + $_paramsArray[] = "$_key=>$_value"; + } else { + $_paramsArray[] = "'$_key'=>$_value"; + } + } + if (!empty($_paramsArray)) { + $_params = 'array(' . implode(",", $_paramsArray) . ')'; + $_paramsCode = "\$params = array_merge($_params, \$params);\n"; + } else { + $_paramsCode = ''; + } + $_functionCode = $compiler->parser->current_buffer; + // setup buffer for template function code + $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); + + $_funcName = "smarty_template_function_{$_name}_{$compiler->template->compiled->nocache_hash}"; + $_funcNameCaching = $_funcName . '_nocache'; + if ($compiler->template->compiled->has_nocache_code) { + $compiler->parent_compiler->tpl_function[ $_name ][ 'call_name_caching' ] = $_funcNameCaching; + $output = "compiled->has_nocache_code = true;\n"; + $output .= $_paramsCode; + $output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_Variable(\$value, \$_smarty_tpl->isRenderingCache);\n}"; + $output .= "\$params = var_export(\$params, true);\n"; + $output .= "echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/smarty->ext->_tplFunction->saveTemplateVariables(\\\$_smarty_tpl, '{$_name}');\nforeach (\$params as \\\$key => \\\$value) {\n\\\$_smarty_tpl->tpl_vars[\\\$key] = new Smarty_Variable(\\\$value, \\\$_smarty_tpl->isRenderingCache);\n}\n?>"; + $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n\";?>"; + $compiler->parser->current_buffer->append_subtree($compiler->parser, + new Smarty_Internal_ParseTree_Tag($compiler->parser, + $output)); + $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); + $output = "template->compiled->nocache_hash}%%*/smarty->ext->_tplFunction->restoreTemplateVariables(\\\$_smarty_tpl, '{$_name}');?>\n"; + $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";\n?>"; + $output .= "template->compiled->nocache_hash}', \$_smarty_tpl->compiled->nocache_hash, ob_get_clean());\n"; + $output .= "}\n}\n"; + $output .= "/*/ {$_funcName}_nocache */\n\n"; + $output .= "?>\n"; + $compiler->parser->current_buffer->append_subtree($compiler->parser, + new Smarty_Internal_ParseTree_Tag($compiler->parser, + $output)); + $_functionCode = new Smarty_Internal_ParseTree_Tag($compiler->parser, + preg_replace_callback("/((<\?php )?echo '\/\*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/([\S\s]*?)\/\*\/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/", + array($this, 'removeNocache'), + $_functionCode->to_smarty_php($compiler->parser))); + } + $compiler->parent_compiler->tpl_function[ $_name ][ 'call_name' ] = $_funcName; + $output = " \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_Variable(\$value, \$_smarty_tpl->isRenderingCache);\n}?>"; + $compiler->parser->current_buffer->append_subtree($compiler->parser, + new Smarty_Internal_ParseTree_Tag($compiler->parser, + $output)); + $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); + $output = "\n"; + $compiler->parser->current_buffer->append_subtree($compiler->parser, + new Smarty_Internal_ParseTree_Tag($compiler->parser, + $output)); + $compiler->parent_compiler->blockOrFunctionCode .= $compiler->parser->current_buffer->to_smarty_php($compiler->parser); + // nocache plugins must be copied + if (!empty($compiler->template->compiled->required_plugins[ 'nocache' ])) { + foreach ($compiler->template->compiled->required_plugins[ 'nocache' ] as $plugin => $tmp) { + foreach ($tmp as $type => $data) { + $compiler->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin ][ $type ] = + $data; + } + } + } + // restore old buffer + + $compiler->parser->current_buffer = $saved_data[ 1 ]; + // restore old status + $compiler->template->compiled->has_nocache_code = $saved_data[ 2 ]; + $compiler->template->caching = $saved_data[ 3 ]; + return true; + } + + /** + * Remove nocache code + * + * @param $match + * + * @return string + */ + function removeNocache($match) + { + $code = + preg_replace("/((<\?php )?echo '\/\*%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/)|(\/\*\/%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/", + '', $match[ 0 ]); + $code = str_replace(array('\\\'', '\\\\\''), array('\'', '\\\''), $code); + return $code; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_if.php b/libs/sysplugins/smarty_internal_compile_if.php new file mode 100644 index 0000000..14db55d --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_if.php @@ -0,0 +1,211 @@ +getAttributes($compiler, $args); + $this->openTag($compiler, 'if', array(1, $compiler->nocache)); + // must whole block be nocache ? + $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; + + if (!array_key_exists("if condition", $parameter)) { + $compiler->trigger_template_error("missing if condition", null, true); + } + + if (is_array($parameter[ 'if condition' ])) { + if (is_array($parameter[ 'if condition' ][ 'var' ])) { + $var = $parameter[ 'if condition' ][ 'var' ][ 'var' ]; + } else { + $var = $parameter[ 'if condition' ][ 'var' ]; + } + if ($compiler->nocache) { + // create nocache var to make it know for further compiling + $compiler->setNocacheInVariable($var); + } + $prefixVar = $compiler->getNewPrefixVariable(); + $_output = "\n"; + $assignAttr = array(); + $assignAttr[][ 'value' ] = "{$prefixVar}"; + $assignCompiler = new Smarty_Internal_Compile_Assign(); + if (is_array($parameter[ 'if condition' ][ 'var' ])) { + $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ][ 'var' ]; + $_output .= $assignCompiler->compile($assignAttr, $compiler, + array('smarty_internal_index' => $parameter[ 'if condition' ][ 'var' ][ 'smarty_internal_index' ])); + } else { + $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ]; + $_output .= $assignCompiler->compile($assignAttr, $compiler, array()); + } + $_output .= ""; + return $_output; + } else { + return ""; + } + } +} + +/** + * Smarty Internal Plugin Compile Else Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_Else extends Smarty_Internal_CompileBase +{ + /** + * Compiles code for the {else} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return string compiled code + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + list($nesting, $compiler->tag_nocache) = $this->closeTag($compiler, array('if', 'elseif')); + $this->openTag($compiler, 'else', array($nesting, $compiler->tag_nocache)); + + return ""; + } +} + +/** + * Smarty Internal Plugin Compile ElseIf Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_Elseif extends Smarty_Internal_CompileBase +{ + /** + * Compiles code for the {elseif} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return string compiled code + * @throws \SmartyCompilerException + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + + list($nesting, $compiler->tag_nocache) = $this->closeTag($compiler, array('if', 'elseif')); + + if (!array_key_exists("if condition", $parameter)) { + $compiler->trigger_template_error("missing elseif condition", null, true); + } + + $assignCode = ''; + $var = ''; + if (is_array($parameter[ 'if condition' ])) { + $condition_by_assign = true; + if (is_array($parameter[ 'if condition' ][ 'var' ])) { + $var = $parameter[ 'if condition' ][ 'var' ][ 'var' ]; + } else { + $var = $parameter[ 'if condition' ][ 'var' ]; + } + if ($compiler->nocache) { + // create nocache var to make it know for further compiling + $compiler->setNocacheInVariable($var); + } + $prefixVar = $compiler->getNewPrefixVariable(); + $assignCode = "\n"; + $assignCompiler = new Smarty_Internal_Compile_Assign(); + $assignAttr = array(); + $assignAttr[][ 'value' ] = "{$prefixVar}"; + if (is_array($parameter[ 'if condition' ][ 'var' ])) { + $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ][ 'var' ]; + $assignCode .= $assignCompiler->compile($assignAttr, $compiler, + array('smarty_internal_index' => $parameter[ 'if condition' ][ 'var' ][ 'smarty_internal_index' ])); + } else { + $assignAttr[][ 'var' ] = $parameter[ 'if condition' ][ 'var' ]; + $assignCode .= $assignCompiler->compile($assignAttr, $compiler, array()); + } + } else { + $condition_by_assign = false; + } + + $prefixCode = $compiler->getPrefixCode(); + if (empty($prefixCode)) { + if ($condition_by_assign) { + $this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache)); + $_output = $compiler->appendCode("", $assignCode); + return $compiler->appendCode($_output, ""); + } else { + $this->openTag($compiler, 'elseif', array($nesting, $compiler->tag_nocache)); + return ""; + } + } else { + $_output = $compiler->appendCode("", $prefixCode); + $this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache)); + if ($condition_by_assign) { + $_output = $compiler->appendCode($_output, $assignCode); + return $compiler->appendCode($_output, ""); + } else { + return $compiler->appendCode($_output, ""); + } + } + } +} + +/** + * Smarty Internal Plugin Compile Ifclose Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_Ifclose extends Smarty_Internal_CompileBase +{ + /** + * Compiles code for the {/if} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return string compiled code + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + // must endblock be nocache? + if ($compiler->nocache) { + $compiler->tag_nocache = true; + } + list($nesting, $compiler->nocache) = $this->closeTag($compiler, array('if', 'else', 'elseif')); + $tmp = ''; + for ($i = 0; $i < $nesting; $i ++) { + $tmp .= '}'; + } + + return ""; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_include.php b/libs/sysplugins/smarty_internal_compile_include.php new file mode 100644 index 0000000..a81b0c7 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_include.php @@ -0,0 +1,344 @@ + Smarty::SCOPE_PARENT, 'root' => Smarty::SCOPE_ROOT, + 'global' => Smarty::SCOPE_GLOBAL, 'tpl_root' => Smarty::SCOPE_TPL_ROOT, + 'smarty' => Smarty::SCOPE_SMARTY); + + /** + * Compiles code for the {include} tag + * + * @param array $args array with attributes from parser + * @param Smarty_Internal_SmartyTemplateCompiler $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @throws SmartyCompilerException + * @return string compiled code + */ + public function compile($args, Smarty_Internal_SmartyTemplateCompiler $compiler, $parameter) + { + $uid = $t_hash = null; + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + + $fullResourceName = $source_resource = $_attr[ 'file' ]; + $variable_template = false; + $cache_tpl = false; + // parse resource_name + if (preg_match('/^([\'"])(([A-Za-z0-9_\-]{2,})[:])?(([^$()]+)|(.+))\1$/', $source_resource, $match)) { + $type = !empty($match[ 3 ]) ? $match[ 3 ] : $compiler->template->smarty->default_resource_type; + $name = !empty($match[ 5 ]) ? $match[ 5 ] : $match[ 6 ]; + $handler = Smarty_Resource::load($compiler->smarty, $type); + if ($handler->recompiled || $handler->uncompiled) { + $variable_template = true; + } + if (!$variable_template) { + if ($type != 'string') { + $fullResourceName = "{$type}:{$name}"; + $compiled = $compiler->parent_compiler->template->compiled; + if (isset($compiled->includes[ $fullResourceName ])) { + $compiled->includes[ $fullResourceName ] ++; + $cache_tpl = true; + } else { + if ("{$compiler->template->source->type}:{$compiler->template->source->name}" == + $fullResourceName + ) { + // recursive call of current template + $compiled->includes[ $fullResourceName ] = 2; + $cache_tpl = true; + } else { + $compiled->includes[ $fullResourceName ] = 1; + } + } + $fullResourceName = $match[ 1 ] . $fullResourceName . $match[ 1 ]; + } + } + if (empty($match[ 5 ])) { + $variable_template = true; + } + } else { + $variable_template = true; + } + + // scope setup + $_scope = $compiler->convertScope($_attr, $this->valid_scopes); + + // set flag to cache subtemplate object when called within loop or template name is variable. + if ($cache_tpl || $variable_template || $compiler->loopNesting > 0) { + $_cache_tpl = 'true'; + } else { + $_cache_tpl = 'false'; + } + // assume caching is off + $_caching = Smarty::CACHING_OFF; + + $call_nocache = $compiler->tag_nocache || $compiler->nocache; + + // caching was on and {include} is not in nocache mode + if ($compiler->template->caching && !$compiler->nocache && !$compiler->tag_nocache) { + $_caching = self::CACHING_NOCACHE_CODE; + } + + // flag if included template code should be merged into caller + $merge_compiled_includes = ($compiler->smarty->merge_compiled_includes || $_attr[ 'inline' ] === true) && + !$compiler->template->source->handler->recompiled; + + if ($merge_compiled_includes) { + // variable template name ? + if ($variable_template) { + $merge_compiled_includes = false; + } + // variable compile_id? + if (isset($_attr[ 'compile_id' ]) && $compiler->isVariable($_attr[ 'compile_id' ])) { + $merge_compiled_includes = false; + } + } + + /* + * if the {include} tag provides individual parameter for caching or compile_id + * the subtemplate must not be included into the common cache file and is treated like + * a call in nocache mode. + * + */ + if ($_attr[ 'nocache' ] !== true && $_attr[ 'caching' ]) { + $_caching = $_new_caching = (int) $_attr[ 'caching' ]; + $call_nocache = true; + } else { + $_new_caching = Smarty::CACHING_LIFETIME_CURRENT; + } + if (isset($_attr[ 'cache_lifetime' ])) { + $_cache_lifetime = $_attr[ 'cache_lifetime' ]; + $call_nocache = true; + $_caching = $_new_caching; + } else { + $_cache_lifetime = '$_smarty_tpl->cache_lifetime'; + } + if (isset($_attr[ 'cache_id' ])) { + $_cache_id = $_attr[ 'cache_id' ]; + $call_nocache = true; + $_caching = $_new_caching; + } else { + $_cache_id = '$_smarty_tpl->cache_id'; + } + if (isset($_attr[ 'compile_id' ])) { + $_compile_id = $_attr[ 'compile_id' ]; + } else { + $_compile_id = '$_smarty_tpl->compile_id'; + } + + // if subtemplate will be called in nocache mode do not merge + if ($compiler->template->caching && $call_nocache) { + $merge_compiled_includes = false; + } + // assign attribute + if (isset($_attr[ 'assign' ])) { + // output will be stored in a smarty variable instead of being displayed + if ($_assign = $compiler->getId($_attr[ 'assign' ])) { + $_assign = "'{$_assign}'"; + if ($compiler->tag_nocache || $compiler->nocache || $call_nocache) { + // create nocache var to make it know for further compiling + $compiler->setNocacheInVariable($_attr[ 'assign' ]); + } + } else { + $_assign = $_attr[ 'assign' ]; + } + } + + $has_compiled_template = false; + if ($merge_compiled_includes) { + $c_id = isset($_attr[ 'compile_id' ]) ? $_attr[ 'compile_id' ] : $compiler->template->compile_id; + // we must observe different compile_id and caching + $t_hash = sha1($c_id . ($_caching ? '--caching' : '--nocaching')); + $compiler->smarty->allow_ambiguous_resources = true; + /* @var Smarty_Internal_Template $tpl */ + $tpl = new $compiler->smarty->template_class (trim($fullResourceName, '"\''), $compiler->smarty, + $compiler->template, $compiler->template->cache_id, $c_id, + $_caching); + $uid = $tpl->source->type . $tpl->source->uid; + if (!isset($compiler->parent_compiler->mergedSubTemplatesData[ $uid ][ $t_hash ])) { + $has_compiled_template = $this->compileInlineTemplate($compiler, $tpl, $t_hash); + } else { + $has_compiled_template = true; + } + unset($tpl); + } + // delete {include} standard attributes + unset($_attr[ 'file' ], $_attr[ 'assign' ], $_attr[ 'cache_id' ], $_attr[ 'compile_id' ], $_attr[ 'cache_lifetime' ], $_attr[ 'nocache' ], $_attr[ 'caching' ], $_attr[ 'scope' ], $_attr[ 'inline' ]); + // remaining attributes must be assigned as smarty variable + $_vars = 'array()'; + if (!empty($_attr)) { + $_pairs = array(); + // create variables + foreach ($_attr as $key => $value) { + $_pairs[] = "'$key'=>$value"; + } + $_vars = 'array(' . join(',', $_pairs) . ')'; + } + $update_compile_id = $compiler->template->caching && !$compiler->tag_nocache && !$compiler->nocache && + $_compile_id != '$_smarty_tpl->compile_id'; + if ($has_compiled_template && !$call_nocache) { + $_output = "makeNocacheCode("\$_compile_id_save[] = \$_smarty_tpl->compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n"); + } + if (!empty($_attr) && $_caching == 9999 && $compiler->template->caching) { + $_vars_nc = "foreach ($_vars as \$ik => \$iv) {\n"; + $_vars_nc .= "\$_smarty_tpl->tpl_vars[\$ik] = new Smarty_Variable(\$iv);\n"; + $_vars_nc .= "}\n"; + $_output .= substr($compiler->processNocacheCode('\n", true), 6, - 3); + } + if (isset($_assign)) { + $_output .= "ob_start();\n"; + } + $_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, {$_scope}, {$_cache_tpl}, '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['uid']}', '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['func']}');\n"; + if (isset($_assign)) { + $_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n"; + } + if ($update_compile_id) { + $_output .= $compiler->makeNocacheCode("\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n"); + } + $_output .= "?>\n"; + + return $_output; + } + + if ($call_nocache) { + $compiler->tag_nocache = true; + } + $_output = "compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n"; + } + // was there an assign attribute + if (isset($_assign)) { + $_output .= "ob_start();\n"; + } + $_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_scope, {$_cache_tpl});\n"; + if (isset($_assign)) { + $_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n"; + } + if ($update_compile_id) { + $_output .= "\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n"; + } + $_output .= "?>\n"; + return $_output; + } + + /** + * Compile inline sub template + * + * @param \Smarty_Internal_SmartyTemplateCompiler $compiler + * @param \Smarty_Internal_Template $tpl + * @param string $t_hash + * + * @return bool + */ + public function compileInlineTemplate(Smarty_Internal_SmartyTemplateCompiler $compiler, + Smarty_Internal_Template $tpl, $t_hash) + { + $uid = $tpl->source->type . $tpl->source->uid; + if (!($tpl->source->handler->uncompiled) && $tpl->source->exists) { + $compiler->parent_compiler->mergedSubTemplatesData[ $uid ][ $t_hash ][ 'uid' ] = $tpl->source->uid; + if (isset($compiler->template->inheritance)) { + $tpl->inheritance = clone $compiler->template->inheritance; + } + $tpl->compiled = new Smarty_Template_Compiled(); + $tpl->compiled->nocache_hash = $compiler->parent_compiler->template->compiled->nocache_hash; + $tpl->loadCompiler(); + // save unique function name + $compiler->parent_compiler->mergedSubTemplatesData[ $uid ][ $t_hash ][ 'func' ] = + $tpl->compiled->unifunc = 'content_' . str_replace(array('.', ','), '_', uniqid('', true)); + // make sure whole chain gets compiled + $tpl->mustCompile = true; + $compiler->parent_compiler->mergedSubTemplatesData[ $uid ][ $t_hash ][ 'nocache_hash' ] = + $tpl->compiled->nocache_hash; + if ($compiler->template->source->type == 'file') { + $sourceInfo = $compiler->template->source->filepath; + } else { + $basename = $compiler->template->source->handler->getBasename($compiler->template->source); + $sourceInfo = $compiler->template->source->type . ':' . + ($basename ? $basename : $compiler->template->source->name); + } + // get compiled code + $compiled_code = "compiled->unifunc} (\$_smarty_tpl) {\n"; + $compiled_code .= "?>\n" . $tpl->compiler->compileTemplateSource($tpl, null, $compiler->parent_compiler); + $compiled_code .= "\n"; + $compiled_code .= $tpl->compiler->postFilter($tpl->compiler->blockOrFunctionCode); + $compiled_code .= ""; + unset($tpl->compiler); + if ($tpl->compiled->has_nocache_code) { + // replace nocache_hash + $compiled_code = + str_replace("{$tpl->compiled->nocache_hash}", $compiler->template->compiled->nocache_hash, + $compiled_code); + $compiler->template->compiled->has_nocache_code = true; + } + $compiler->parent_compiler->mergedSubTemplatesCode[ $tpl->compiled->unifunc ] = $compiled_code; + return true; + } else { + return false; + } + } +} diff --git a/libs/sysplugins/smarty_internal_compile_include_php.php b/libs/sysplugins/smarty_internal_compile_include_php.php new file mode 100644 index 0000000..77586da --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_include_php.php @@ -0,0 +1,111 @@ +smarty instanceof SmartyBC)) { + throw new SmartyException("{include_php} is deprecated, use SmartyBC class to enable"); + } + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + + /** @var Smarty_Internal_Template $_smarty_tpl + * used in evaluated code + */ + $_smarty_tpl = $compiler->template; + $_filepath = false; + $_file = null; + eval('$_file = @' . $_attr[ 'file' ] . ';'); + if (!isset($compiler->smarty->security_policy) && file_exists($_file)) { + $_filepath = $compiler->smarty->_realpath($_file, true); + } else { + if (isset($compiler->smarty->security_policy)) { + $_dir = $compiler->smarty->security_policy->trusted_dir; + } else { + $_dir = $compiler->smarty->trusted_dir; + } + if (!empty($_dir)) { + foreach ((array) $_dir as $_script_dir) { + $_path = $compiler->smarty->_realpath($_script_dir . $compiler->smarty->ds . $_file, true); + if (file_exists($_path)) { + $_filepath = $_path; + break; + } + } + } + } + if ($_filepath == false) { + $compiler->trigger_template_error("{include_php} file '{$_file}' is not readable", null, true); + } + + if (isset($compiler->smarty->security_policy)) { + $compiler->smarty->security_policy->isTrustedPHPDir($_filepath); + } + + if (isset($_attr[ 'assign' ])) { + // output will be stored in a smarty variable instead of being displayed + $_assign = $_attr[ 'assign' ]; + } + $_once = '_once'; + if (isset($_attr[ 'once' ])) { + if ($_attr[ 'once' ] == 'false') { + $_once = ''; + } + } + + if (isset($_assign)) { + return "assign({$_assign},ob_get_clean());\n?>"; + } else { + return "\n"; + } + } +} diff --git a/libs/sysplugins/smarty_internal_compile_insert.php b/libs/sysplugins/smarty_internal_compile_insert.php new file mode 100644 index 0000000..02ef67c --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_insert.php @@ -0,0 +1,155 @@ +getAttributes($compiler, $args); + //Does tag create output + $compiler->has_output = isset($_attr[ 'assign' ]) ? false : true; + + $nocacheParam = $compiler->template->caching && ($compiler->tag_nocache || $compiler->nocache); + if (!$nocacheParam) { + // do not compile as nocache code + $compiler->suppressNocacheProcessing = true; + } + $compiler->tag_nocache = true; + $_smarty_tpl = $compiler->template; + $_name = null; + $_script = null; + + $_output = 'template->tpl_vars[ $var ])) { + $compiler->template->tpl_vars[ $var ]->nocache = true; + } else { + $compiler->template->tpl_vars[ $var ] = new Smarty_Variable(null, true); + } + } + if (isset($_attr[ 'script' ])) { + // script which must be included + $_function = "smarty_insert_{$_name}"; + $_smarty_tpl = $compiler->template; + $_filepath = false; + eval('$_script = @' . $_attr[ 'script' ] . ';'); + if (!isset($compiler->smarty->security_policy) && file_exists($_script)) { + $_filepath = $_script; + } else { + if (isset($compiler->smarty->security_policy)) { + $_dir = $compiler->smarty->security_policy->trusted_dir; + } else { + $_dir = $compiler->smarty instanceof SmartyBC ? $compiler->smarty->trusted_dir : null; + } + if (!empty($_dir)) { + foreach ((array) $_dir as $_script_dir) { + $_script_dir = rtrim($_script_dir, '/\\') . $compiler->smarty->ds; + if (file_exists($_script_dir . $_script)) { + $_filepath = $_script_dir . $_script; + break; + } + } + } + } + if ($_filepath == false) { + $compiler->trigger_template_error("{insert} missing script file '{$_script}'", null, true); + } + // code for script file loading + $_output .= "require_once '{$_filepath}' ;"; + require_once $_filepath; + if (!is_callable($_function)) { + $compiler->trigger_template_error(" {insert} function '{$_function}' is not callable in script file '{$_script}'", + null, true); + } + } else { + $_filepath = 'null'; + $_function = "insert_{$_name}"; + // function in PHP script ? + if (!is_callable($_function)) { + // try plugin + if (!$_function = $compiler->getPlugin($_name, 'insert')) { + $compiler->trigger_template_error("{insert} no function or plugin found for '{$_name}'", null, + true); + } + } + } + // delete {insert} standard attributes + unset($_attr[ 'name' ], $_attr[ 'assign' ], $_attr[ 'script' ], $_attr[ 'nocache' ]); + // convert attributes into parameter array string + $_paramsArray = array(); + foreach ($_attr as $_key => $_value) { + $_paramsArray[] = "'$_key' => $_value"; + } + $_params = 'array(' . implode(", ", $_paramsArray) . ')'; + // call insert + if (isset($_assign)) { + if ($_smarty_tpl->caching && !$nocacheParam) { + $_output .= "echo Smarty_Internal_Nocache_Insert::compile ('{$_function}',{$_params}, \$_smarty_tpl, '{$_filepath}',{$_assign});?>"; + } else { + $_output .= "\$_smarty_tpl->assign({$_assign} , {$_function} ({$_params},\$_smarty_tpl), true);?>"; + } + } else { + if ($_smarty_tpl->caching && !$nocacheParam) { + $_output .= "echo Smarty_Internal_Nocache_Insert::compile ('{$_function}',{$_params}, \$_smarty_tpl, '{$_filepath}');?>"; + } else { + $_output .= "echo {$_function}({$_params},\$_smarty_tpl);?>"; + } + } + + return $_output; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_ldelim.php b/libs/sysplugins/smarty_internal_compile_ldelim.php new file mode 100644 index 0000000..7251dcd --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_ldelim.php @@ -0,0 +1,40 @@ +getAttributes($compiler, $args); + if ($_attr[ 'nocache' ] === true) { + $compiler->trigger_template_error('nocache option not allowed', null, true); + } + // this tag does not return compiled code + $compiler->has_code = true; + + return $compiler->smarty->left_delimiter; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_make_nocache.php b/libs/sysplugins/smarty_internal_compile_make_nocache.php new file mode 100644 index 0000000..720dd68 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_make_nocache.php @@ -0,0 +1,64 @@ +getAttributes($compiler, $args); + if ($compiler->template->caching) { + $output = "smarty->ext->_make_nocache->save(\$_smarty_tpl, {$_attr[ 'var' ]});\n?>\n"; + $compiler->has_code = true; + $compiler->suppressNocacheProcessing = true; + return $output; + } else { + return true; + } + } +} diff --git a/libs/sysplugins/smarty_internal_compile_nocache.php b/libs/sysplugins/smarty_internal_compile_nocache.php new file mode 100644 index 0000000..b29a993 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_nocache.php @@ -0,0 +1,75 @@ +getAttributes($compiler, $args); + $this->openTag($compiler, 'nocache', array($compiler->nocache)); + // enter nocache mode + $compiler->nocache = true; + // this tag does not return compiled code + $compiler->has_code = false; + + return true; + } +} + +/** + * Smarty Internal Plugin Compile Nocacheclose Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_Nocacheclose extends Smarty_Internal_CompileBase +{ + /** + * Compiles code for the {/nocache} tag + * This tag does not generate compiled output. It only sets a compiler flag. + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * + * @return bool + */ + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler) + { + $_attr = $this->getAttributes($compiler, $args); + // leave nocache mode + list($compiler->nocache) = $this->closeTag($compiler, array('nocache')); + // this tag does not return compiled code + $compiler->has_code = false; + + return true; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_private_block_plugin.php b/libs/sysplugins/smarty_internal_compile_private_block_plugin.php new file mode 100644 index 0000000..6175642 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_private_block_plugin.php @@ -0,0 +1,122 @@ +getAttributes($compiler, $args); + $this->nesting ++; + unset($_attr[ 'nocache' ]); + list($callback, $_paramsArray, $callable) = $this->setup($compiler, $_attr, $tag, $function); + $_params = 'array(' . implode(",", $_paramsArray) . ')'; + + // compile code + $output = "nesting} = isset({$callback[0]}) ? {$callback[0]} : null;\n"; + $callback = "\$_block_plugin{$this->nesting}{$callback[1]}"; + } + if (isset($callable)) { + $output .= "if (!is_callable({$callable})) {\nthrow new SmartyException('block tag \'{$tag}\' not callable or registered');\n}\n"; + } + $output .= "\$_smarty_tpl->smarty->_cache['_tag_stack'][] = array('{$tag}', {$_params});\n"; + $output .= "\$_block_repeat=true;\necho {$callback}({$_params}, null, \$_smarty_tpl, \$_block_repeat);\nwhile (\$_block_repeat) {\nob_start();\n?>"; + $this->openTag($compiler, $tag, array($_params, $compiler->nocache, $callback)); + // maybe nocache because of nocache variables or nocache plugin + $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; + } else { + // must endblock be nocache? + if ($compiler->nocache) { + $compiler->tag_nocache = true; + } + // closing tag of block plugin, restore nocache + list($_params, $compiler->nocache, $callback) = $this->closeTag($compiler, substr($tag, 0, - 5)); + //Does tag create output + $compiler->has_output = isset($_params[ 'assign' ]) ? false : true; + // compile code + if (!isset($parameter[ 'modifier_list' ])) { + $mod_pre = $mod_post = $mod_content = ''; + $mod_content2 = 'ob_get_clean()'; + } else { + $mod_content2 = "\$_block_content{$this->nesting}"; + $mod_content = "\$_block_content{$this->nesting} = ob_get_clean();\n"; + $mod_pre = "ob_start();\n"; + $mod_post = 'echo ' . $compiler->compileTag('private_modifier', array(), + array('modifierlist' => $parameter[ 'modifier_list' ], + 'value' => 'ob_get_clean()')) . ";\n"; + } + $output = "smarty->_cache['_tag_stack']);"; + $output .= "?>"; + } + return $output . "\n"; + } + + /** + * Setup callback and parameter array + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler + * @param array $_attr attributes + * @param string $tag + * @param string $function + * + * @return array + */ + public function setup(Smarty_Internal_TemplateCompilerBase $compiler, $_attr, $tag, $function) + { + $_paramsArray = array(); + foreach ($_attr as $_key => $_value) { + if (is_int($_key)) { + $_paramsArray[] = "$_key=>$_value"; + } else { + $_paramsArray[] = "'$_key'=>$_value"; + } + } + return array($function, $_paramsArray, null); + } +} diff --git a/libs/sysplugins/smarty_internal_compile_private_foreachsection.php b/libs/sysplugins/smarty_internal_compile_private_foreachsection.php new file mode 100644 index 0000000..bf569be --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_private_foreachsection.php @@ -0,0 +1,221 @@ +propertyPreg = '~('; + $this->startOffset = 0; + $this->resultOffsets = array(); + $this->matchResults = array('named' => array(), 'item' => array()); + if ($this->isNamed) { + $this->buildPropertyPreg(true, $attributes); + } + if (isset($this->itemProperties)) { + if ($this->isNamed) { + $this->propertyPreg .= '|'; + } + $this->buildPropertyPreg(false, $attributes); + } + $this->propertyPreg .= ')\W~i'; + // Template source + $this->matchTemplateSource($compiler); + // Parent template source + $this->matchParentTemplateSource($compiler); + // {block} source + $this->matchBlockSource($compiler); + } + + /** + * Build property preg string + * + * @param bool $named + * @param array $attributes + */ + public function buildPropertyPreg($named, $attributes) + { + if ($named) { + $this->resultOffsets[ 'named' ] = $this->startOffset + 3; + $this->propertyPreg .= "([\$]smarty[.]{$this->tagName}[.]{$attributes['name']}[.]("; + $properties = $this->nameProperties; + } else { + $this->resultOffsets[ 'item' ] = $this->startOffset + 3; + $this->propertyPreg .= "([\$]{$attributes['item']}[@]("; + $properties = $this->itemProperties; + } + $this->startOffset += count($properties) + 2; + $propName = reset($properties); + while ($propName) { + $this->propertyPreg .= "({$propName})"; + $propName = next($properties); + if ($propName) { + $this->propertyPreg .= '|'; + } + } + $this->propertyPreg .= '))'; + } + + /** + * Find matches in source string + * + * @param string $source + */ + public function matchProperty($source) + { + preg_match_all($this->propertyPreg, $source, $match, PREG_SET_ORDER); + foreach ($this->resultOffsets as $key => $offset) { + foreach ($match as $m) { + if (isset($m[ $offset ]) && !empty($m[ $offset ])) { + $this->matchResults[ $key ][ strtolower($m[ $offset ]) ] = true; + } + } + } + } + + /** + * Find matches in template source + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler + */ + public function matchTemplateSource(Smarty_Internal_TemplateCompilerBase $compiler) + { + $this->matchProperty($compiler->parser->lex->data); + } + + /** + * Find matches in all parent template source + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler + */ + public function matchParentTemplateSource(Smarty_Internal_TemplateCompilerBase $compiler) + { + // search parent compiler template source + $nextCompiler = $compiler; + while ($nextCompiler !== $nextCompiler->parent_compiler) { + $nextCompiler = $nextCompiler->parent_compiler; + if ($compiler !== $nextCompiler) { + // get template source + $_content = $nextCompiler->template->source->getContent(); + if ($_content != '') { + // run pre filter if required + if ((isset($nextCompiler->smarty->autoload_filters[ 'pre' ]) || + isset($nextCompiler->smarty->registered_filters[ 'pre' ])) + ) { + $_content = $nextCompiler->smarty->ext->_filterHandler->runFilter('pre', $_content, + $nextCompiler->template); + } + $this->matchProperty($_content); + } + } + } + } + + /** + * Find matches in {block} tag source + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler + */ + public function matchBlockSource(Smarty_Internal_TemplateCompilerBase $compiler) + { + } + + /** + * Compiles code for the {$smarty.foreach.xxx} or {$smarty.section.xxx}tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return string compiled code + * @throws \SmartyCompilerException + */ + public function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + $tag = strtolower(trim($parameter[ 0 ], '"\'')); + $name = isset($parameter[ 1 ]) ? $compiler->getId($parameter[ 1 ]) : false; + if (!$name) { + $compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", null, true); + } + $property = isset($parameter[ 2 ]) ? strtolower($compiler->getId($parameter[ 2 ])) : false; + if (!$property || !in_array($property, $this->nameProperties)) { + $compiler->trigger_template_error("missing or illegal \$smarty.{$tag} property attribute", null, true); + } + $tagVar = "'__smarty_{$tag}_{$name}'"; + return "(isset(\$_smarty_tpl->tpl_vars[{$tagVar}]->value['{$property}']) ? \$_smarty_tpl->tpl_vars[{$tagVar}]->value['{$property}'] : null)"; + } +} \ No newline at end of file diff --git a/libs/sysplugins/smarty_internal_compile_private_function_plugin.php b/libs/sysplugins/smarty_internal_compile_private_function_plugin.php new file mode 100644 index 0000000..26529bb --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_private_function_plugin.php @@ -0,0 +1,74 @@ +getAttributes($compiler, $args); + + unset($_attr[ 'nocache' ]); + // convert attributes into parameter array string + $_paramsArray = array(); + foreach ($_attr as $_key => $_value) { + if (is_int($_key)) { + $_paramsArray[] = "$_key=>$_value"; + } else { + $_paramsArray[] = "'$_key'=>$_value"; + } + } + $_params = 'array(' . implode(",", $_paramsArray) . ')'; + // compile code + $output = "{$function}({$_params},\$_smarty_tpl)"; + if (!empty($parameter[ 'modifierlist' ])) { + $output = $compiler->compileTag('private_modifier', array(), + array('modifierlist' => $parameter[ 'modifierlist' ], + 'value' => $output)); + } + //Does tag create output + $compiler->has_output = true; + $output = "\n"; + return $output; + } +} diff --git a/libs/sysplugins/smarty_internal_compile_private_modifier.php b/libs/sysplugins/smarty_internal_compile_private_modifier.php new file mode 100644 index 0000000..5f8130b --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_private_modifier.php @@ -0,0 +1,150 @@ +getAttributes($compiler, $args); + $output = $parameter[ 'value' ]; + // loop over list of modifiers + foreach ($parameter[ 'modifierlist' ] as $single_modifier) { + $modifier = $single_modifier[ 0 ]; + $single_modifier[ 0 ] = $output; + $params = implode(',', $single_modifier); + // check if we know already the type of modifier + if (isset($compiler->known_modifier_type[ $modifier ])) { + $modifier_types = array($compiler->known_modifier_type[ $modifier ]); + } else { + $modifier_types = array(1, 2, 3, 4, 5, 6); + } + foreach ($modifier_types as $type) { + switch ($type) { + case 1: + // registered modifier + if (isset($compiler->smarty->registered_plugins[ Smarty::PLUGIN_MODIFIER ][ $modifier ])) { + if (is_callable($compiler->smarty->registered_plugins[ Smarty::PLUGIN_MODIFIER ][ $modifier ][ 0 ])) { + $output = + sprintf('call_user_func_array($_smarty_tpl->registered_plugins[ \'%s\' ][ %s ][ 0 ], array( %s ))', + Smarty::PLUGIN_MODIFIER, var_export($modifier, true), $params); + $compiler->known_modifier_type[ $modifier ] = $type; + break 2; + } + } + break; + case 2: + // registered modifier compiler + if (isset($compiler->smarty->registered_plugins[ Smarty::PLUGIN_MODIFIERCOMPILER ][ $modifier ][ 0 ])) { + $output = + call_user_func($compiler->smarty->registered_plugins[ Smarty::PLUGIN_MODIFIERCOMPILER ][ $modifier ][ 0 ], + $single_modifier, $compiler->smarty); + $compiler->known_modifier_type[ $modifier ] = $type; + break 2; + } + break; + case 3: + // modifiercompiler plugin + if ($compiler->smarty->loadPlugin('smarty_modifiercompiler_' . $modifier)) { + // check if modifier allowed + if (!is_object($compiler->smarty->security_policy) || + $compiler->smarty->security_policy->isTrustedModifier($modifier, $compiler) + ) { + $plugin = 'smarty_modifiercompiler_' . $modifier; + $output = $plugin($single_modifier, $compiler); + } + $compiler->known_modifier_type[ $modifier ] = $type; + break 2; + } + break; + case 4: + // modifier plugin + if ($function = $compiler->getPlugin($modifier, Smarty::PLUGIN_MODIFIER)) { + // check if modifier allowed + if (!is_object($compiler->smarty->security_policy) || + $compiler->smarty->security_policy->isTrustedModifier($modifier, $compiler) + ) { + $output = "{$function}({$params})"; + } + $compiler->known_modifier_type[ $modifier ] = $type; + break 2; + } + break; + case 5: + // PHP function + if (is_callable($modifier)) { + // check if modifier allowed + if (!is_object($compiler->smarty->security_policy) || + $compiler->smarty->security_policy->isTrustedPhpModifier($modifier, $compiler) + ) { + $output = "{$modifier}({$params})"; + } + $compiler->known_modifier_type[ $modifier ] = $type; + break 2; + } + break; + case 6: + // default plugin handler + if (isset($compiler->default_handler_plugins[ Smarty::PLUGIN_MODIFIER ][ $modifier ]) || + (is_callable($compiler->smarty->default_plugin_handler_func) && + $compiler->getPluginFromDefaultHandler($modifier, Smarty::PLUGIN_MODIFIER)) + ) { + $function = $compiler->default_handler_plugins[ Smarty::PLUGIN_MODIFIER ][ $modifier ][ 0 ]; + // check if modifier allowed + if (!is_object($compiler->smarty->security_policy) || + $compiler->smarty->security_policy->isTrustedModifier($modifier, $compiler) + ) { + if (!is_array($function)) { + $output = "{$function}({$params})"; + } else { + if (is_object($function[ 0 ])) { + $output = $function[ 0 ] . '->'. $function[ 1 ] . '(' . $params . ')'; + } else { + $output = $function[ 0 ] . '::' . $function[ 1 ] . '(' . $params . ')'; + } + } + } + if (isset($compiler->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $modifier ][ Smarty::PLUGIN_MODIFIER ][ 'file' ]) || + isset($compiler->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $modifier ][ Smarty::PLUGIN_MODIFIER ][ 'file' ]) + ) { + // was a plugin + $compiler->known_modifier_type[ $modifier ] = 4; + } else { + $compiler->known_modifier_type[ $modifier ] = $type; + } + break 2; + } + } + } + if (!isset($compiler->known_modifier_type[ $modifier ])) { + $compiler->trigger_template_error("unknown modifier \"" . $modifier . "\"", null, true); + } + } + + return $output; + } +} \ No newline at end of file