Kaynağa Gözat

Add view class

Zhu Jinhui 7 yıl önce
ebeveyn
işleme
38dfc693a3
100 değiştirilmiş dosya ile 13399 ekleme ve 10 silme
  1. 126 0
      Qii/View/Dependence.php
  2. 90 0
      Qii/View/Includes.php
  3. 14 0
      Qii/View/Intf.php
  4. 28 0
      Qii/View/Loader.php
  5. 170 0
      Qii/View/Render.php
  6. 90 0
      Qii/View/Requires.php
  7. 151 0
      Qii/View/Resource.php
  8. 131 0
      Qii/View/Smarty.php
  9. 0 10
      Qii/View/Vendor.php
  10. 107 0
      Qii/View/smarty/Autoloader.php
  11. 1529 0
      Qii/View/smarty/Smarty.class.php
  12. 455 0
      Qii/View/smarty/SmartyBC.class.php
  13. 160 0
      Qii/View/smarty/debug.tpl
  14. 112 0
      Qii/View/smarty/plugins/block.textformat.php
  15. 73 0
      Qii/View/smarty/plugins/function.counter.php
  16. 105 0
      Qii/View/smarty/plugins/function.cycle.php
  17. 221 0
      Qii/View/smarty/plugins/function.fetch.php
  18. 249 0
      Qii/View/smarty/plugins/function.html_checkboxes.php
  19. 164 0
      Qii/View/smarty/plugins/function.html_image.php
  20. 204 0
      Qii/View/smarty/plugins/function.html_options.php
  21. 232 0
      Qii/View/smarty/plugins/function.html_radios.php
  22. 391 0
      Qii/View/smarty/plugins/function.html_select_date.php
  23. 366 0
      Qii/View/smarty/plugins/function.html_select_time.php
  24. 176 0
      Qii/View/smarty/plugins/function.html_table.php
  25. 153 0
      Qii/View/smarty/plugins/function.mailto.php
  26. 104 0
      Qii/View/smarty/plugins/function.math.php
  27. 101 0
      Qii/View/smarty/plugins/modifier.capitalize.php
  28. 65 0
      Qii/View/smarty/plugins/modifier.date_format.php
  29. 112 0
      Qii/View/smarty/plugins/modifier.debug_print_var.php
  30. 200 0
      Qii/View/smarty/plugins/modifier.escape.php
  31. 58 0
      Qii/View/smarty/plugins/modifier.regex_replace.php
  32. 34 0
      Qii/View/smarty/plugins/modifier.replace.php
  33. 27 0
      Qii/View/smarty/plugins/modifier.spacify.php
  34. 66 0
      Qii/View/smarty/plugins/modifier.truncate.php
  35. 29 0
      Qii/View/smarty/plugins/modifiercompiler.cat.php
  36. 32 0
      Qii/View/smarty/plugins/modifiercompiler.count_characters.php
  37. 27 0
      Qii/View/smarty/plugins/modifiercompiler.count_paragraphs.php
  38. 27 0
      Qii/View/smarty/plugins/modifiercompiler.count_sentences.php
  39. 32 0
      Qii/View/smarty/plugins/modifiercompiler.count_words.php
  40. 35 0
      Qii/View/smarty/plugins/modifiercompiler.default.php
  41. 117 0
      Qii/View/smarty/plugins/modifiercompiler.escape.php
  42. 33 0
      Qii/View/smarty/plugins/modifiercompiler.from_charset.php
  43. 33 0
      Qii/View/smarty/plugins/modifiercompiler.indent.php
  44. 31 0
      Qii/View/smarty/plugins/modifiercompiler.lower.php
  45. 21 0
      Qii/View/smarty/plugins/modifiercompiler.noprint.php
  46. 25 0
      Qii/View/smarty/plugins/modifiercompiler.string_format.php
  47. 33 0
      Qii/View/smarty/plugins/modifiercompiler.strip.php
  48. 29 0
      Qii/View/smarty/plugins/modifiercompiler.strip_tags.php
  49. 33 0
      Qii/View/smarty/plugins/modifiercompiler.to_charset.php
  50. 50 0
      Qii/View/smarty/plugins/modifiercompiler.unescape.php
  51. 29 0
      Qii/View/smarty/plugins/modifiercompiler.upper.php
  52. 51 0
      Qii/View/smarty/plugins/modifiercompiler.wordwrap.php
  53. 89 0
      Qii/View/smarty/plugins/outputfilter.trimwhitespace.php
  54. 34 0
      Qii/View/smarty/plugins/shared.escape_special_chars.php
  55. 36 0
      Qii/View/smarty/plugins/shared.literal_compiler_param.php
  56. 45 0
      Qii/View/smarty/plugins/shared.make_timestamp.php
  57. 55 0
      Qii/View/smarty/plugins/shared.mb_str_replace.php
  58. 54 0
      Qii/View/smarty/plugins/shared.mb_unicode.php
  59. 75 0
      Qii/View/smarty/plugins/shared.mb_wordwrap.php
  60. 19 0
      Qii/View/smarty/plugins/variablefilter.htmlspecialchars.php
  61. 220 0
      Qii/View/smarty/sysplugins/smarty_cacheresource.php
  62. 275 0
      Qii/View/smarty/sysplugins/smarty_cacheresource_custom.php
  63. 507 0
      Qii/View/smarty/sysplugins/smarty_cacheresource_keyvaluestore.php
  64. 68 0
      Qii/View/smarty/sysplugins/smarty_data.php
  65. 90 0
      Qii/View/smarty/sysplugins/smarty_internal_block.php
  66. 220 0
      Qii/View/smarty/sysplugins/smarty_internal_cacheresource_file.php
  67. 51 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_append.php
  68. 94 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_assign.php
  69. 247 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_block.php
  70. 77 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_break.php
  71. 89 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_call.php
  72. 112 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_capture.php
  73. 98 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_config_load.php
  74. 77 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_continue.php
  75. 42 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_debug.php
  76. 72 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_eval.php
  77. 134 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_extends.php
  78. 170 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_for.php
  79. 330 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_foreach.php
  80. 216 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_function.php
  81. 208 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_if.php
  82. 345 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_include.php
  83. 111 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_include_php.php
  84. 155 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_insert.php
  85. 40 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_ldelim.php
  86. 64 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_make_nocache.php
  87. 75 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_nocache.php
  88. 123 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_private_block_plugin.php
  89. 221 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_private_foreachsection.php
  90. 74 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_private_function_plugin.php
  91. 157 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_private_modifier.php
  92. 42 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_private_object_block_function.php
  93. 86 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_private_object_function.php
  94. 220 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_private_php.php
  95. 162 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_private_print_expression.php
  96. 72 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_private_registered_block.php
  97. 82 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_private_registered_function.php
  98. 126 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_private_special_variable.php
  99. 40 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_rdelim.php
  100. 469 0
      Qii/View/smarty/sysplugins/smarty_internal_compile_section.php

+ 126 - 0
Qii/View/Dependence.php

@@ -0,0 +1,126 @@
+<?php
+/**
+ * 模板里边添加依赖文件
+ * 
+ */
+namespace Qii\View;
+
+class Dependence
+{
+	public static $dependence = array();
+	public static $blockCss = array();
+	public static $blockHTML = array();
+	public static $blockJS = array();
+
+	public static $assignBlocks = array();
+
+	public function __construct(){
+	}
+	public static function getAssignBlock($blockName)
+	{
+		if (isset(self::$assignBlocks[$blockName])) {
+			return self::$assignBlocks[$blockName];
+		}
+		return;
+	}
+
+	public static function addCssBlock()
+	{
+		ob_start();
+	}
+
+	public static function addCssBlockEnd()
+	{
+		$block = ob_get_contents();
+		ob_end_clean();
+		self::$blockCss[] = $block;
+	}
+
+	public static function addHtmlBlock()
+	{
+		ob_start();
+	}
+
+	public static function addHtmlBlockEnd($assignBlock = null)
+	{
+		$block = ob_get_contents();
+		ob_end_clean();
+		if ($assignBlock) {
+			self::$assignBlocks[$assignBlock] = $block;
+			return;
+		}
+		self::$blockHTML[] = $block;
+	}
+
+	public static function addJsBlock()
+	{
+		ob_start();
+	}
+
+	public static function addJsBlockEnd()
+	{
+		$block = ob_get_contents();
+		ob_end_clean();
+		self::$blockJS[] = $block;
+	}
+
+	/**
+	 * 设置js文件依赖
+	 * @param string $file js文件路径
+	 */
+	public static function setDependenceJS($file)
+	{
+		if (is_array($file)) {
+			foreach ($file AS $f) {
+				self::setDependenceJS($f);
+			}
+		} else {
+			self::$dependence['blockLinkJs'][] = $file;
+		}
+	}
+
+	/**
+	 * 设置js方法块依赖
+	 * @param string $file js文件路径
+	 */
+	public static function setDependenceBlockJS($file)
+	{
+		if (is_array($file)) {
+			foreach ($file AS $f) {
+				self::setDependenceBlockJS($f);
+			}
+		} else {
+			self::$dependence['blockJs'][] = $file;
+		}
+	}
+
+	/**
+	 * 设置css文件依赖
+	 * @param string $file css文件路径
+	 */
+	public static function setDependenceCss($file)
+	{
+		if (is_array($file)) {
+			foreach ($file AS $f) {
+				self::setDependenceCss($f);
+			}
+		} else {
+			self::$dependence['blockLinkCss'][] = $file;
+		}
+	}
+
+	/**
+	 * 设置css方法块依赖
+	 * @param string $file css文件路径
+	 */
+	public static function setDependenceBlockCss($file)
+	{
+		if (is_array($file)) {
+			foreach ($file AS $f) {
+				self::setDependenceBlockCss($f);
+			}
+		} else {
+			self::$dependence['blockCss'][] = $file;
+		}
+	}
+}

+ 90 - 0
Qii/View/Includes.php

@@ -0,0 +1,90 @@
+<?php
+/**
+ * @author Jinhui.zhu    <jinhui.zhu@live.cn>
+ * @version  $Id: include.php 2 2012-07-06 08:50:19Z jinhui.zhu $
+ *
+ * 视图部分,提供供显示的方法,支持include
+ *
+ */
+namespace Qii\View;
+
+class Includes
+{
+	const VERSION = '1.2';
+	public $data;
+	private $viewPath;
+	private $_blocks = array();
+
+	public function __construct()
+	{
+		$appConfigure = \Qii\Config\Register::getAppConfigure(\Qii\Config\Register::get(\Qii\Consts::APP_INI_FILE));
+		$this->viewPath = $appConfigure['view']['path'];
+	}
+
+	/**
+	 * Assign
+	 *
+	 * @param Mix $name
+	 * @param Mix $val
+	 */
+	public function assign($name, $val = null)
+	{
+		if (isset($val)) {
+			$this->data[$name] = $val;
+		} else if (is_array($name)) {
+			foreach ($name AS $k => $v) {
+				$this->data[$k] = $v;
+			}
+		}
+	}
+
+	/**
+	 * 设置块,可以将块放在页面上任意位置,块的开始,setEndBlock为结束,内容将会缓存到$this->_blocks中
+	 *
+	 * @param String $block
+	 */
+	public function setStartBlock($block)
+	{
+		$this->_blocks[$block] = '';
+		ob_start();
+	}
+
+	/**
+	 * 设置块,此处是结束
+	 *
+	 * @param String $block
+	 */
+	public function setEndBlock($block)
+	{
+		$content = ob_get_contents();
+		ob_end_clean();
+		$this->_blocks[$block] = $content;
+	}
+
+	/**
+	 * 返回块里边的内容
+	 *
+	 * @param String $block
+	 * @return String
+	 */
+	public function displayBlock($block)
+	{
+		return isset($this->_blocks[$block]) ? $this->_blocks[$block] : '';
+	}
+
+	/**
+	 * 载入数据和模板
+	 *
+	 * @param String $tpl
+	 */
+	public function display($tpl)
+	{
+		$tpl = $this->viewPath . DS . $tpl;
+		extract((array)$this->data);
+		if (!\Qii::setError(is_file($tpl), 1405, $tpl . ' does not exist')) {
+			include($tpl);
+		}
+	}
+}
+
+?>

+ 14 - 0
Qii/View/Intf.php

@@ -0,0 +1,14 @@
+<?php
+/**
+ * View Intferface
+ */
+namespace Qii\View;
+
+interface Intf
+{
+	public function assign($spec, $value = null);
+
+	public function fetch($tpl);
+
+	public function display($tpl);
+}

+ 28 - 0
Qii/View/Loader.php

@@ -0,0 +1,28 @@
+<?php
+namespace Qii\View;
+
+class Loader
+{
+	protected $view;
+	protected $allow = array('smarty', 'require', 'include');
+	
+	public function __construct()
+	{
+
+	}
+	
+	public function setView($engine, $policy = array())
+	{
+		if(!in_array($engine, $this->allow))
+		{
+			throw new \Qii\Exceptions\Unsupport(\Qii::i('Unsupport method', $engine));
+		}
+		$class = '\Qii\View\\'. ucwords($engine);
+		return $this->view = new $class();
+	}
+
+	public function getView()
+	{
+		return $this->view;
+	}
+}

+ 170 - 0
Qii/View/Render.php

@@ -0,0 +1,170 @@
+<?php
+namespace Qii\View;
+
+class Render
+{
+	protected $_view;
+	public function __construct(&$view, \Qii\View\Resource $resource)
+	{
+		$this->_view = $view;
+	}
+
+	/**
+	 * renderJS
+	 * @param \widget\resource $resource 资源
+	 */
+	public function renderLinkJs(\Qii\View\Resource $resource)
+	{
+		$blockJs = array();
+		if (isset(\Qii\View\Dependence::$dependence['blockLinkJs'])) {
+			$resource->addBlockLinkJs(\Qii\View\Dependence::$dependence['blockLinkJs']);
+		}
+		if ($resource->blockLinkJs) {
+			if (is_array($resource->blockLinkJs)) {
+				foreach ($resource->blockLinkJs AS $js) {
+					if ($js == '') continue;
+					$blockJs[] = '<script src="' . \Qii\Request\Url::getSourceFullUrl($js) . '"></script>';
+				}
+			} else {
+				$blockJs[] = '<script src="' . \Qii\Request\Url::getSourceFullUrl($resource->blockLinkJs) . '"></script>';
+			}
+		}
+		$this->_view->assign('blockLinkJs', "\n" . join("\n", $blockJs) . "\n");
+	}
+
+	/**
+	 * renderCss
+	 * @param \widget\resource $resource 资源
+	 */
+	public function renderLinkCss(\Qii\View\Resource $resource)
+	{
+		$blockCss = array();
+		if (isset(\Qii\View\Dependence::$dependence['blockLinkCss'])) {
+			$resource->addBlockLinkCss(\Qii\View\Dependence::$dependence['blockLinkCss']);
+		}
+		if ($resource->blockLinkCss) {
+			if (is_array($resource->blockLinkCss)) {
+				foreach ($resource->blockLinkCss AS $css) {
+					if ($css == '') continue;
+					$blockCss[] = '<link href="' . \Qii\Request\Url::getSourceFullUrl($css) . '" rel="stylesheet">';
+				}
+			} else {
+				$blockCss[] = '<link href="' . \Qii\Request\Url::getSourceFullUrl($resource->blockLinkCss) . '" rel="stylesheet">';
+			}
+		}
+		$this->_view->assign('blockLinkCss', "\n" . join("\n", $blockCss) . "\n");
+	}
+
+	/**
+	 * renderJS
+	 * @param \widget\resource $resource 资源
+	 */
+	public function renderJs(\Qii\View\Resource $resource)
+	{
+		$blockJs = '';
+		if (isset(\Qii\View\Dependence::$dependence['blockJs'])) {
+			$resource->addBlockJs(\Qii\View\Dependence::$dependence['blockJs']);
+		}
+		if ($resource->blockJs) {
+			if (is_array($resource->blockJs)) {
+				foreach ($resource->blockJs AS $js) {
+					if ($js == '') continue;
+					$blockJs .= $this->_view->fetch($js);
+				}
+			} else {
+				$blockJs .= $this->_view->fetch($resource->blockJs);
+			}
+		}
+		$blockJs .= join('\n', \Qii\View\Dependence::$blockJS);
+		$this->_view->assign('blockJs', "\n" . $blockJs . "\n");
+	}
+
+	/**
+	 * renderCss
+	 * @param \widget\resource $resource 资源
+	 */
+	public function renderCss(\Qii\View\Resource $resource)
+	{
+		$blockCss = '';
+		if (isset(\Qii\View\Dependence::$dependence['blockCss'])) {
+			$resource->addBlockCss(\Qii\View\Dependence::$dependence['blockCss']);
+		}
+		if ($resource->blockCss) {
+			if (is_array($resource->blockCss)) {
+				foreach ($resource->blockCss AS $css) {
+					if ($css == '') continue;
+					$blockCss .= $this->_view->fetch($css);
+				}
+			} else {
+				$blockCss .= $this->_view->fetch($resource->blockCss);
+			}
+		}
+		$blockCss .= join('\n', \Qii\View\Dependence::$blockCss);
+		$this->_view->assign('blockCss', "\n" . $blockCss . "\n");
+	}
+
+	/**
+	 * 通过页面定义的资源去显示内容
+	 *
+	 * @param string $tpl 模板名
+	 */
+	public function render(\Qii\View\Resource $resource)
+	{
+		$this->_view->assign('pageTitle', $resource->title);
+		$this->_view->assign('bodyClass', $resource->bodyClass);
+		$html = array();
+		$html[] = '<div class="' . $resource->wrapperClass . '">';
+		$dependence = array();
+		//todo 针对dependence当方法在后边的情况还没处理完
+		$executed = array();
+		foreach ($resource->resource AS $index => $res) {
+			$callFunction = $res;
+			$className = array_shift($res);
+			$method = array_shift($res);
+
+			//如果是存在依赖,先跳过,等依赖的执行了再执行
+			if (isset($resource->dependence[$className . ':' . $method]) && !isset($executed[$resource->dependence[$className . ':' . $method]])) {
+				$dependence[$resource->dependence[$className . ':' . $method]][] = array($index, $callFunction);
+				$html[$index] = '';
+				continue;
+			}
+			$executed[$className . ':' . $method] = true;
+			$class = \Qii\Autoloader\Psr4::loadClass($className);
+			$class->controller = $this;
+			$class->actionId = $this->_action;
+			$class->input = $resource->input;
+			//如果是返回了false,就直接退出
+			$result = call_user_func_array(array($class, $method), $res);
+			if ($result === false) {
+				return false;
+			}
+			$html[$index] = $result;
+			//如果是依赖的方法已经执行,此处再执行原有的方法
+			if (isset($dependence[$className . ':' . $method])) {
+				foreach ($dependence[$className . ':' . $method] AS $key => $val) {
+					$i = $val[0];
+					$subRes = $val[1];
+					$className = array_shift($subRes);
+					$method = array_shift($subRes);
+
+					$class = \Qii\Autoloader\Psr4::loadClass($className);
+					$class->controller = $this;
+					$class->actionId = $this->_action;
+					$class->input = $resource->input;
+					$executed[$className . ':' . $method] = true;
+					$result = call_user_func_array(array($class, $method), $subRes);
+					//如果是返回了false,就直接退出
+					if ($result === false) {
+						return false;
+					}
+					$html[$i] = $result;
+					unset($dependence[$key]);
+				}
+			}
+		}
+		$html[] = '</div>';
+		$html[] = join('\n', \Qii\View\Dependence::$blockHTML);;
+
+		$this->_view->assign('bodyBlock', join("\n", $html));
+	}
+}

+ 90 - 0
Qii/View/Requires.php

@@ -0,0 +1,90 @@
+<?php
+/**
+ * @author Jinhui.zhu    <jinhui.zhu@live.cn>
+ * @version  $Id: require.php 2 2012-07-06 08:50:19Z jinhui.zhu $
+ *
+ * 视图部分,提供供显示的方法,支持require
+ *
+ */
+namespace Qii\View;
+
+class Requires
+{
+	const VERSION = '1.2';
+	public $data;
+	private $viewPath;
+	private $_blocks = array();
+
+	public function __construct()
+	{
+		$appConfigure = \Qii\Config\Register::getAppConfigure(\Qii\Config\Register::get(\Qii\Consts::APP_INI_FILE));
+		$this->viewPath = $appConfigure['view']['path'];
+	}
+
+	/**
+	 * 设置块,可以将块放在页面上任意位置,块的开始,setEndBlock为结束,内容将会缓存到$this->_blocks中
+	 *
+	 * @param String $block
+	 */
+	public function setStartBlock($block)
+	{
+		$this->_blocks[$block] = '';
+		ob_start();
+	}
+
+	/**
+	 * 设置块,此处是结束
+	 *
+	 * @param String $block
+	 */
+	public function setEndBlock($block)
+	{
+		$content = ob_get_contents();
+		ob_end_clean();
+		$this->_blocks[$block] = $content;
+	}
+
+	/**
+	 * 返回块里边的内容
+	 *
+	 * @param String $block
+	 * @return String
+	 */
+	public function displayBlock($block)
+	{
+		return isset($this->_blocks[$block]) ? $this->_blocks[$block] : '';
+	}
+
+	/**
+	 * Assign
+	 *
+	 * @param Mix $name
+	 * @param Mix $val
+	 */
+	public function assign($name, $val)
+	{
+		if (isset($val)) {
+			$this->data[$name] = $val;
+		} else if (is_array($name)) {
+			foreach ($name AS $k => $v) {
+				$this->data[$k] = $v;
+			}
+		}
+	}
+
+	/**
+	 * 载入数据和模板
+	 *
+	 * @param String $tpl
+	 */
+	public function display($tpl)
+	{
+		$tpl = $this->viewPath . DS . $tpl;
+		extract((array)$this->data);
+		if (!\Qii::setError(is_file($tpl), __LINE__, 1405, $tpl)) {
+			require($tpl);
+		}
+	}
+}
+
+?>

+ 151 - 0
Qii/View/Resource.php

@@ -0,0 +1,151 @@
+<?php
+/**
+ * 资源
+ * 
+ */
+namespace Qii\View;
+
+class Resource
+{
+	//页面标题
+	public $title = '';
+	//meta 标签
+	public $meta = array();
+	public $htmlBlock = array();
+	public $htmlBlockJS = array();
+	public $htmlBlockCss = array();
+
+	//块js,里边可能包含js代码及js链接,是完整的文件
+	public $blockJs = '';
+	//js路径,渲染的时候加上标签
+	public $blockLinkJs = '';
+	//css块,css代码及css文件路径,是完整的css文件
+	public $blockCss = '';
+	//css路径,渲染的时候加上标签
+	public $blockLinkCss = '';
+	//资源处理队列依赖的模块,如果有依赖就等依赖执行完以后再执行
+	public $dependence = array();
+	//资源处理队列
+	public $resource = array();
+	public function __construct(array $resource)
+	{
+		if(empty($resource)) _e(100003, __LINE__);
+		$this->resource($resource);
+		return $this;
+	}
+
+	/**
+	 * 添加blocks
+	 */
+	public function addBlocks($blocks)
+	{
+		if (!$blocks) return;
+		if (is_array($blocks)) {
+			$this->addBlocks($blocks);
+		}
+		$this->blocks .= $blocks;
+	}
+
+	/**
+	 * 添加JS
+	 */
+	public function addblockLinkJs($js)
+	{
+		if (!$js) return;
+		if (empty($this->blockLinkJs)) $this->blockLinkJs = array();
+		if ($this->blockLinkJs && !is_array($this->blockLinkJs)) {
+			$this->blockLinkJs = array($this->blockLinkJs);
+		}
+		if (is_array($js)) {
+			$this->blockLinkJs = array_merge($this->blockLinkJs, $js);
+		} else {
+			$this->blockLinkJs[] = $js;
+		}
+		$this->blockLinkJs = $this->array_unique($this->blockLinkJs);
+		return $this->blockLinkJs;
+	}
+
+	/**
+	 * 添加js block
+	 */
+	public function addBlockJs($js)
+	{
+		if (!$js) return;
+		if (empty($this->blockJs)) $this->blockJs = array();
+		if ($this->blockJs && !is_array($this->blockJs)) {
+			$this->blockJs = array($this->blockJs);
+		}
+		if (is_array($js)) {
+			$this->blockJs = array_merge($this->blockJs, $js);
+		} else {
+			$this->blockJs[] = $js;
+		}
+		$this->blockJs = $this->array_unique($this->blockJs);
+		return $this->blockJs;
+	}
+
+	/**
+	 * 添加css
+	 */
+	public function addBlockLinkCss($css)
+	{
+		if (!$css) return;
+		if (empty($this->blockLinkCss)) $this->blockLinkCss = array();
+		if ($this->blockLinkCss && !is_array($this->blockLinkCss)) {
+			$this->blockLinkCss = array($this->blockLinkCss);
+		}
+		if (is_array($css)) {
+			$this->blockLinkCss = array_merge($this->blockLinkCss, $css);
+		} else {
+			$this->blockLinkCss[] = $css;
+		}
+		$this->blockLinkCss = $this->array_unique($this->blockLinkCss);
+		return $this->blockLinkCss;
+	}
+
+	/**
+	 * 添加css block
+	 */
+	public function addBlockCss($css)
+	{
+		if (!$css) return;
+		if (empty($this->blockCss)) $this->blockCss = array();
+		if ($this->blockCss && !is_array($this->blockCss)) {
+			$this->blockCss = array($this->blockCss);
+		}
+		if (is_array($css)) {
+			$this->blockCss = array_merge($this->blockCss, $css);
+		} else {
+			$this->blockCss[] = $css;
+		}
+		$this->blockCss = array_unique($this->blockCss);
+		return $this->blockCss;
+	}
+	/**
+	 * 避免重复
+	 * @array array $array
+	 */
+	public function array_unique($array)
+	{
+		if (is_array($array)) return array_unique($array);
+		return $array;
+	}
+
+	/**
+	 * 格式化资源数据
+	 * @return stdClass
+	 */
+	public function resource(array $resource)
+	{
+		if (!isset($resource['title'])) _e(100001);
+		if (!isset($resource['resource']) || !is_array($resource['resource'])) _e(100002);
+		$this->title = $resource['title'];
+		$this->blockJs = isset($resource['blockJs']) ? $this->array_unique($resource['blockJs']) : '';
+		$this->blockCss = isset($resource['blockCss']) ? $this->array_unique($resource['blockCss']) : '';
+		$this->blockLinkJs = isset($resource['blockLinkJs']) ? $this->array_unique($resource['blockLinkJs']) : '';
+		$this->blockLinkCss = isset($resource['blockLinkCss']) ? $this->array_unique($resource['blockLinkCss']) : '';
+		$this->dependence = isset($resource['dependence']) ? $resource['dependence'] : array();
+		$this->resource = isset($resource['resource']) ? $resource['resource'] : array();
+		return $this;
+	}
+}

+ 131 - 0
Qii/View/Smarty.php

@@ -0,0 +1,131 @@
+<?php
+/**
+ * @author Jinhui.zhu    <jinhui.zhu@live.cn>
+ * @version  $Id: smarty.php 2 2012-07-06 08:50:19Z jinhui.zhu $
+ *
+ * 视图部分,提供供显示的方法,支持smarty
+ *
+ */
+namespace Qii\View;
+
+\Qii\Autoloader\Import::requires(Qii_DIR . DS . 'View' . DS . 'smarty' . DS . 'Autoloader.php');
+\Smarty_Autoloader::register(true);
+\Qii\Autoloader\Import::requires(Qii_DIR . DS . DS . 'View' . DS . 'smarty' . DS . 'SmartyBC.class.php');
+\Qii\Autoloader\Import::requires(Qii_DIR . DS . DS . 'View' . DS . 'smarty' . DS . 'sysplugins' .DS. 'smartyexception.php');
+\Qii\Autoloader\Import::requires(Qii_DIR . DS . DS . 'View' . DS . 'smarty' . DS . 'sysplugins' .DS. 'smartycompilerexception.php');
+
+class Smarty extends \SmartyBC
+{
+	const VERSION = '1.2';
+	public $caching = false;//是否缓存
+	public $left_delimiter = '{#';//变量左边界
+	public $right_delimiter = '#}';//变量右边界
+	public $compile_check = true;//是否检查模板有变动
+	public $debugging = false;//是否调试
+	public $compile_dir = 'tmp/compile';//编译目录
+	public $template_dir = 'view';//模板目录
+	public $config_dir = 'configure';//配置文件目录
+	public $plugins_dir = 'smarty/plugins/';//插件目录
+	public $cache_dir = 'tmp/cache/';//缓存目录
+	public $cache_id = '';//缓存文件ID
+	public $cache_lifetime = 3600;//缓存时间
+
+	/**
+	 * 用户直接输出这个实例化的类后会输出当前类的名称
+	 *
+	 * @return String
+	 */
+	public function __toString()
+	{
+		return get_class($this);
+	}
+
+	/**
+	 * 设置块,可以将块放在页面上任意位置,块的开始,setEndBlock为结束,内容将会缓存到$this->_blocks中
+	 *
+	 * @param String $block
+	 */
+	public function setStartBlock($block)
+	{
+		$this->_blocks[$block] = '';
+		ob_clean();
+		ob_start();
+	}
+
+	/**
+	 * 设置块,此处是结束
+	 *
+	 * @param String $block
+	 */
+	public function setEndBlock($block)
+	{
+		$content = ob_get_contents();
+		ob_end_clean();
+		$this->_blocks[$block] = $content;
+	}
+
+	/**
+	 * 返回块里边的内容
+	 *
+	 * @param String $block
+	 * @return String
+	 */
+	public function getBlock($block)
+	{
+		return isset($this->_blocks[$block]) ? $this->_blocks[$block] : '';
+	}
+
+	/**
+	 * 显示块里边的内容
+	 *
+	 * @param String $block
+	 * @return null
+	 */
+	public function displayBlock($block)
+	{
+		echo $this->getBlock($block);
+	}
+
+	/**
+	 * View构造函数
+	 *
+	 */
+	public function __construct()
+	{
+		parent::__construct();
+		$appConfigure = \Qii\Config\Register::getAppConfigure(\Qii\Config\Register::get(\Qii\Config\Consts::APP_INI_FILE));
+		$viewInfo = $appConfigure['view']['smarty'];
+		if (isset($viewInfo['ldelimiter']) && !empty($viewInfo['ldelimiter'])) $this->left_delimiter = $viewInfo['ldelimiter'];//变量左边界
+		if (isset($viewInfo['rdelimiter']) && !empty($viewInfo['rdelimiter'])) $this->right_delimiter = $viewInfo['rdelimiter'];//变量右边界
+		if (isset($viewInfo['path']) && !empty($viewInfo['path'])) $this->template_dir = \Qii\Autoloader\Psr4::realpath(\Qii\Autoloader\Psr4::getInstance()->getFolderByPrefix($viewInfo['path']));
+		if (isset($viewInfo['compile']) && !empty($viewInfo['compile'])) $this->compile_dir = \Qii\Autoloader\Psr4::realpath(\Qii\Autoloader\Psr4::getInstance()->getFolderByPrefix($viewInfo['compile']));
+		if (isset($viewInfo['cache']) && !empty($viewInfo['cache'])) $this->cache_dir = \Qii\Autoloader\Psr4::realpath(\Qii\Autoloader\Psr4::getInstance()->getFolderByPrefix($viewInfo['cache']));
+		if (isset($viewInfo['lifetime']) && !empty($viewInfo['lifetime'])) $this->cache_lifetime = $viewInfo['lifetime'];
+		//将老版本过度到新版本
+		$this->setTemplateDir($this->template_dir)
+			->setCompileDir($this->compile_dir)
+			->setPluginsDir(SMARTY_PLUGINS_DIR)
+			->setCacheDir($this->cache_dir)
+			->setConfigDir($this->config_dir);
+		$this->disableSecurity();
+		$this->allow_php_templates = true;
+	}
+
+	/**
+	 * displays a Smarty template
+	 *
+	 * @param string $template the resource handle of the template file or template object
+	 * @param mixed $cache_id cache id to be used with this template
+	 * @param mixed $compile_id compile id to be used with this template
+	 * @param object $parent next higher level of Smarty variables
+	 */
+	public function display($template = null, $cache_id = null, $compile_id = null, $parent = null)
+	{
+		if (!empty($this->_blocks)) {
+			$this->assign($this->_blocks);
+		}
+		parent::display($template, $cache_id, $compile_id, $parent);
+	}
+}
+
+?>

+ 0 - 10
Qii/View/Vendor.php

@@ -1,10 +0,0 @@
-<?php
-namespace Qii\View;
-
-class Vendor
-{
-    public function __construct($config = [])
-    {
-        
-    }
-}

+ 107 - 0
Qii/View/smarty/Autoloader.php

@@ -0,0 +1,107 @@
+<?php
+/**
+ * Smarty Autoloader
+ *
+ * @package    Smarty
+ */
+
+/**
+ * Smarty Autoloader
+ *
+ * @package    Smarty
+ * @author     Uwe Tews
+ *             Usage:
+ *             require_once '...path/Autoloader.php';
+ *             Smarty_Autoloader::register();
+ *             $smarty = new Smarty();
+ *             Note:       This autoloader is not needed if you use Composer.
+ *             Composer will automatically add the classes of the Smarty package to it common autoloader.
+ */
+class Smarty_Autoloader
+{
+    /**
+     * Filepath to Smarty root
+     *
+     * @var string
+     */
+    public static $SMARTY_DIR = '';
+
+    /**
+     * Filepath to Smarty internal plugins
+     *
+     * @var string
+     */
+    public static $SMARTY_SYSPLUGINS_DIR = '';
+
+    /**
+     * Array with Smarty core classes and their filename
+     *
+     * @var array
+     */
+    public static $rootClasses = array('smarty' => 'Smarty.class.php', 'smartybc' => 'SmartyBC.class.php',);
+
+    /**
+     * Registers Smarty_Autoloader backward compatible to older installations.
+     *
+     * @param bool $prepend Whether to prepend the autoloader or not.
+     */
+    public static function registerBC($prepend = false)
+    {
+        /**
+         * register the class autoloader
+         */
+        if (!defined('SMARTY_SPL_AUTOLOAD')) {
+            define('SMARTY_SPL_AUTOLOAD', 0);
+        }
+        if (SMARTY_SPL_AUTOLOAD &&
+            set_include_path(get_include_path() . PATH_SEPARATOR . SMARTY_SYSPLUGINS_DIR) !== false
+        ) {
+            $registeredAutoLoadFunctions = spl_autoload_functions();
+            if (!isset($registeredAutoLoadFunctions[ 'spl_autoload' ])) {
+                spl_autoload_register();
+            }
+        } else {
+            self::register($prepend);
+        }
+    }
+
+    /**
+     * Registers Smarty_Autoloader as an SPL autoloader.
+     *
+     * @param bool $prepend Whether to prepend the autoloader or not.
+     */
+    public static function register($prepend = false)
+    {
+        self::$SMARTY_DIR = defined('SMARTY_DIR') ? SMARTY_DIR : dirname(__FILE__) . DIRECTORY_SEPARATOR;
+        self::$SMARTY_SYSPLUGINS_DIR = defined('SMARTY_SYSPLUGINS_DIR') ? SMARTY_SYSPLUGINS_DIR :
+            self::$SMARTY_DIR . 'sysplugins' . DIRECTORY_SEPARATOR;
+        if (version_compare(phpversion(), '5.3.0', '>=')) {
+            spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
+        } else {
+            spl_autoload_register(array(__CLASS__, 'autoload'));
+        }
+    }
+
+    /**
+     * Handles auto loading of classes.
+     *
+     * @param string $class A class name.
+     */
+    public static function autoload($class)
+    {
+        $_class = strtolower($class);
+        if (strpos($_class, 'smarty') !== 0) {
+            return;
+        }
+        $file = self::$SMARTY_SYSPLUGINS_DIR . $_class . '.php';
+        if (is_file($file)) {
+            include $file;
+        } else if (isset(self::$rootClasses[ $_class ])) {
+            $file = self::$SMARTY_DIR . self::$rootClasses[ $_class ];
+            if (is_file($file)) {
+                include $file;
+            }
+        }
+        return;
+    }
+}

+ 1529 - 0
Qii/View/smarty/Smarty.class.php

@@ -0,0 +1,1529 @@
+<?php
+/**
+ * Project:     Smarty: the PHP compiling template engine
+ * File:        Smarty.class.php
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * For questions, help, comments, discussion, etc., please join the
+ * Smarty mailing list. Send a blank e-mail to
+ * smarty-discussion-subscribe@googlegroups.com
+ *
+ * @link      http://www.smarty.net/
+ * @copyright 2016 New Digital Group, Inc.
+ * @copyright 2016 Uwe Tews
+ * @author    Monte Ohrt <monte at ohrt dot com>
+ * @author    Uwe Tews
+ * @author    Rodney Rehm
+ * @package   Smarty
+ * @version   3.1.30
+ */
+
+/**
+ * define shorthand directory separator constant
+ */
+if (!defined('DS')) {
+    define('DS', DIRECTORY_SEPARATOR);
+}
+
+/**
+ * set SMARTY_DIR to absolute path to Smarty library files.
+ * Sets SMARTY_DIR only if user application has not already defined it.
+ */
+if (!defined('SMARTY_DIR')) {
+    define('SMARTY_DIR', dirname(__FILE__) . DS);
+}
+
+/**
+ * set SMARTY_SYSPLUGINS_DIR to absolute path to Smarty internal plugins.
+ * Sets SMARTY_SYSPLUGINS_DIR only if user application has not already defined it.
+ */
+if (!defined('SMARTY_SYSPLUGINS_DIR')) {
+    define('SMARTY_SYSPLUGINS_DIR', SMARTY_DIR . 'sysplugins' . DS);
+}
+if (!defined('SMARTY_PLUGINS_DIR')) {
+    define('SMARTY_PLUGINS_DIR', SMARTY_DIR . 'plugins' . DS);
+}
+if (!defined('SMARTY_MBSTRING')) {
+    define('SMARTY_MBSTRING', function_exists('mb_get_info'));
+}
+if (!defined('SMARTY_RESOURCE_CHAR_SET')) {
+    // UTF-8 can only be done properly when mbstring is available!
+    /**
+     * @deprecated in favor of Smarty::$_CHARSET
+     */
+    define('SMARTY_RESOURCE_CHAR_SET', SMARTY_MBSTRING ? 'UTF-8' : 'ISO-8859-1');
+}
+if (!defined('SMARTY_RESOURCE_DATE_FORMAT')) {
+    /**
+     * @deprecated in favor of Smarty::$_DATE_FORMAT
+     */
+    define('SMARTY_RESOURCE_DATE_FORMAT', '%b %e, %Y');
+}
+
+/**
+ * Try loading the Smarty_Internal_Data class
+ * If we fail we must load Smarty's autoloader.
+ * Otherwise we may have a global autoloader like Composer
+ */
+if (!class_exists('Smarty_Autoloader', false)) {
+    if (!class_exists('Smarty_Internal_Data', true)) {
+        require_once dirname(__FILE__) . '/Autoloader.php';
+        Smarty_Autoloader::registerBC();
+    }
+}
+
+/**
+ * Load always needed external class files
+ */
+if (!class_exists('Smarty_Internal_Data', false)) {
+    require_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_data.php';
+}
+require_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_extension_handler.php';
+require_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_templatebase.php';
+require_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_template.php';
+require_once SMARTY_SYSPLUGINS_DIR . 'smarty_resource.php';
+require_once SMARTY_SYSPLUGINS_DIR . 'smarty_variable.php';
+require_once SMARTY_SYSPLUGINS_DIR . 'smarty_template_source.php';
+require_once SMARTY_SYSPLUGINS_DIR . 'smarty_template_resource_base.php';
+
+/**
+ * This is the main Smarty class
+ *
+ * @package Smarty
+ *
+ * The following methods will be dynamically loaded by the extension handler when they are called.
+ * They are located in a corresponding Smarty_Internal_Method_xxxx class
+ *
+ * @method int clearAllCache(int $exp_time = null, string $type = null)
+ * @method int clearCache(string $template_name, string $cache_id = null, string $compile_id = null, int $exp_time = null, string $type = null)
+ * @method int compileAllTemplates(string $extension = '.tpl', bool $force_compile = false, int $time_limit = 0, int $max_errors = null)
+ * @method int compileAllConfig(string $extension = '.conf', bool $force_compile = false, int $time_limit = 0, int $max_errors = null)
+ * @method int clearCompiledTemplate($resource_name = null, $compile_id = null, $exp_time = null)
+ */
+class Smarty extends Smarty_Internal_TemplateBase
+{
+    /**#@+
+     * constant definitions
+     */
+
+    /**
+     * smarty version
+     */
+    const SMARTY_VERSION = '3.1.30';
+
+    /**
+     * define variable scopes
+     */
+    const SCOPE_LOCAL = 1;
+
+    const SCOPE_PARENT = 2;
+
+    const SCOPE_TPL_ROOT = 4;
+
+    const SCOPE_ROOT = 8;
+
+    const SCOPE_SMARTY = 16;
+
+    const SCOPE_GLOBAL = 32;
+
+    /**
+     * define caching modes
+     */
+    const CACHING_OFF = 0;
+
+    const CACHING_LIFETIME_CURRENT = 1;
+
+    const CACHING_LIFETIME_SAVED = 2;
+
+    /**
+     * define constant for clearing cache files be saved expiration dates
+     */
+    const CLEAR_EXPIRED = - 1;
+
+    /**
+     * define compile check modes
+     */
+    const COMPILECHECK_OFF = 0;
+
+    const COMPILECHECK_ON = 1;
+
+    const COMPILECHECK_CACHEMISS = 2;
+
+    /**
+     * define debug modes
+     */
+    const DEBUG_OFF = 0;
+
+    const DEBUG_ON = 1;
+
+    const DEBUG_INDIVIDUAL = 2;
+
+    /**
+     * modes for handling of "<?php ... ?>" tags in templates.
+     */
+    const PHP_PASSTHRU = 0; //-> print tags as plain text
+
+    const PHP_QUOTE = 1; //-> escape tags as entities
+
+    const PHP_REMOVE = 2; //-> escape tags as entities
+
+    const PHP_ALLOW = 3; //-> escape tags as entities
+
+    /**
+     * filter types
+     */
+    const FILTER_POST = 'post';
+
+    const FILTER_PRE = 'pre';
+
+    const FILTER_OUTPUT = 'output';
+
+    const FILTER_VARIABLE = 'variable';
+
+    /**
+     * plugin types
+     */
+    const PLUGIN_FUNCTION = 'function';
+
+    const PLUGIN_BLOCK = 'block';
+
+    const PLUGIN_COMPILER = 'compiler';
+
+    const PLUGIN_MODIFIER = 'modifier';
+
+    const PLUGIN_MODIFIERCOMPILER = 'modifiercompiler';
+
+    /**
+     * Resource caching modes
+     * (not used since 3.1.30)
+     */
+    const RESOURCE_CACHE_OFF = 0;
+
+    const RESOURCE_CACHE_AUTOMATIC = 1; // cache template objects by rules
+
+    const RESOURCE_CACHE_TEMPLATE = 2; // cache all template objects
+
+    const RESOURCE_CACHE_ON = 4;    // cache source and compiled resources
+
+    /**#@-*/
+
+    /**
+     * assigned global tpl vars
+     */
+    public static $global_tpl_vars = array();
+
+    /**
+     * error handler returned by set_error_handler() in Smarty::muteExpectedErrors()
+     */
+    public static $_previous_error_handler = null;
+
+    /**
+     * contains directories outside of SMARTY_DIR that are to be muted by muteExpectedErrors()
+     */
+    public static $_muted_directories = array();
+
+    /**
+     * Flag denoting if Multibyte String functions are available
+     */
+    public static $_MBSTRING = SMARTY_MBSTRING;
+
+    /**
+     * The character set to adhere to (e.g. "UTF-8")
+     */
+    public static $_CHARSET = SMARTY_RESOURCE_CHAR_SET;
+
+    /**
+     * The date format to be used internally
+     * (accepts date() and strftime())
+     */
+    public static $_DATE_FORMAT = SMARTY_RESOURCE_DATE_FORMAT;
+
+    /**
+     * Flag denoting if PCRE should run in UTF-8 mode
+     */
+    public static $_UTF8_MODIFIER = 'u';
+
+    /**
+     * Flag denoting if operating system is windows
+     */
+    public static $_IS_WINDOWS = false;
+
+    /**#@+
+     * variables
+     */
+
+    /**
+     * auto literal on delimiters with whitespace
+     *
+     * @var boolean
+     */
+    public $auto_literal = true;
+
+    /**
+     * display error on not assigned variables
+     *
+     * @var boolean
+     */
+    public $error_unassigned = false;
+
+    /**
+     * look up relative file path in include_path
+     *
+     * @var boolean
+     */
+    public $use_include_path = false;
+
+    /**
+     * template directory
+     *
+     * @var array
+     */
+    protected $template_dir = array('./templates/');
+
+    /**
+     * flags for normalized template directory entries
+     *
+     * @var array
+     */
+    protected $_processedTemplateDir = array();
+
+    /**
+     * flag if template_dir is normalized
+     *
+     * @var bool
+     */
+    public $_templateDirNormalized = false;
+
+    /**
+     * joined template directory string used in cache keys
+     *
+     * @var string
+     */
+    public $_joined_template_dir = null;
+
+    /**
+     * config directory
+     *
+     * @var array
+     */
+    protected $config_dir = array('./configs/');
+
+    /**
+     * flags for normalized template directory entries
+     *
+     * @var array
+     */
+    protected $_processedConfigDir = array();
+
+    /**
+     * flag if config_dir is normalized
+     *
+     * @var bool
+     */
+    public $_configDirNormalized = false;
+
+    /**
+     * joined config directory string used in cache keys
+     *
+     * @var string
+     */
+    public $_joined_config_dir = null;
+
+    /**
+     * default template handler
+     *
+     * @var callable
+     */
+    public $default_template_handler_func = null;
+
+    /**
+     * default config handler
+     *
+     * @var callable
+     */
+    public $default_config_handler_func = null;
+
+    /**
+     * default plugin handler
+     *
+     * @var callable
+     */
+    public $default_plugin_handler_func = null;
+
+    /**
+     * compile directory
+     *
+     * @var string
+     */
+    protected $compile_dir = './templates_c/';
+
+    /**
+     * flag if template_dir is normalized
+     *
+     * @var bool
+     */
+    public $_compileDirNormalized = false;
+
+    /**
+     * plugins directory
+     *
+     * @var array
+     */
+    protected $plugins_dir = array();
+
+    /**
+     * flag if plugins_dir is normalized
+     *
+     * @var bool
+     */
+    public $_pluginsDirNormalized = false;
+
+    /**
+     * cache directory
+     *
+     * @var string
+     */
+    protected $cache_dir = './cache/';
+
+    /**
+     * flag if template_dir is normalized
+     *
+     * @var bool
+     */
+    public $_cacheDirNormalized = false;
+
+    /**
+     * force template compiling?
+     *
+     * @var boolean
+     */
+    public $force_compile = false;
+
+    /**
+     * check template for modifications?
+     *
+     * @var boolean
+     */
+    public $compile_check = true;
+
+    /**
+     * use sub dirs for compiled/cached files?
+     *
+     * @var boolean
+     */
+    public $use_sub_dirs = false;
+
+    /**
+     * allow ambiguous resources (that are made unique by the resource handler)
+     *
+     * @var boolean
+     */
+    public $allow_ambiguous_resources = false;
+
+    /**
+     * merge compiled includes
+     *
+     * @var boolean
+     */
+    public $merge_compiled_includes = false;
+
+    /**
+     * force cache file creation
+     *
+     * @var boolean
+     */
+    public $force_cache = false;
+
+    /**
+     * template left-delimiter
+     *
+     * @var string
+     */
+    public $left_delimiter = "{";
+
+    /**
+     * template right-delimiter
+     *
+     * @var string
+     */
+    public $right_delimiter = "}";
+
+    /**#@+
+     * security
+     */
+    /**
+     * class name
+     * This should be instance of Smarty_Security.
+     *
+     * @var string
+     * @see Smarty_Security
+     */
+    public $security_class = 'Smarty_Security';
+
+    /**
+     * implementation of security class
+     *
+     * @var Smarty_Security
+     */
+    public $security_policy = null;
+
+    /**
+     * controls handling of PHP-blocks
+     *
+     * @var integer
+     */
+    public $php_handling = self::PHP_PASSTHRU;
+
+    /**
+     * controls if the php template file resource is allowed
+     *
+     * @var bool
+     */
+    public $allow_php_templates = false;
+
+    /**#@-*/
+    /**
+     * debug mode
+     * Setting this to true enables the debug-console.
+     *
+     * @var boolean
+     */
+    public $debugging = false;
+
+    /**
+     * This determines if debugging is enable-able from the browser.
+     * <ul>
+     *  <li>NONE => no debugging control allowed</li>
+     *  <li>URL => enable debugging when SMARTY_DEBUG is found in the URL.</li>
+     * </ul>
+     *
+     * @var string
+     */
+    public $debugging_ctrl = 'NONE';
+
+    /**
+     * Name of debugging URL-param.
+     * Only used when $debugging_ctrl is set to 'URL'.
+     * The name of the URL-parameter that activates debugging.
+     *
+     * @var string
+     */
+    public $smarty_debug_id = 'SMARTY_DEBUG';
+
+    /**
+     * Path of debug template.
+     *
+     * @var string
+     */
+    public $debug_tpl = null;
+
+    /**
+     * When set, smarty uses this value as error_reporting-level.
+     *
+     * @var int
+     */
+    public $error_reporting = null;
+
+    /**#@+
+     * config var settings
+     */
+
+    /**
+     * Controls whether variables with the same name overwrite each other.
+     *
+     * @var boolean
+     */
+    public $config_overwrite = true;
+
+    /**
+     * Controls whether config values of on/true/yes and off/false/no get converted to boolean.
+     *
+     * @var boolean
+     */
+    public $config_booleanize = true;
+
+    /**
+     * Controls whether hidden config sections/vars are read from the file.
+     *
+     * @var boolean
+     */
+    public $config_read_hidden = false;
+
+    /**#@-*/
+
+    /**#@+
+     * resource locking
+     */
+
+    /**
+     * locking concurrent compiles
+     *
+     * @var boolean
+     */
+    public $compile_locking = true;
+
+    /**
+     * Controls whether cache resources should use locking mechanism
+     *
+     * @var boolean
+     */
+    public $cache_locking = false;
+
+    /**
+     * seconds to wait for acquiring a lock before ignoring the write lock
+     *
+     * @var float
+     */
+    public $locking_timeout = 10;
+
+    /**#@-*/
+
+    /**
+     * resource type used if none given
+     * Must be an valid key of $registered_resources.
+     *
+     * @var string
+     */
+    public $default_resource_type = 'file';
+
+    /**
+     * caching type
+     * Must be an element of $cache_resource_types.
+     *
+     * @var string
+     */
+    public $caching_type = 'file';
+
+    /**
+     * config type
+     *
+     * @var string
+     */
+    public $default_config_type = 'file';
+
+    /**
+     * check If-Modified-Since headers
+     *
+     * @var boolean
+     */
+    public $cache_modified_check = false;
+
+    /**
+     * registered plugins
+     *
+     * @var array
+     */
+    public $registered_plugins = array();
+
+    /**
+     * registered objects
+     *
+     * @var array
+     */
+    public $registered_objects = array();
+
+    /**
+     * registered classes
+     *
+     * @var array
+     */
+    public $registered_classes = array();
+
+    /**
+     * registered filters
+     *
+     * @var array
+     */
+    public $registered_filters = array();
+
+    /**
+     * registered resources
+     *
+     * @var array
+     */
+    public $registered_resources = array();
+
+    /**
+     * registered cache resources
+     *
+     * @var array
+     */
+    public $registered_cache_resources = array();
+
+    /**
+     * autoload filter
+     *
+     * @var array
+     */
+    public $autoload_filters = array();
+
+    /**
+     * default modifier
+     *
+     * @var array
+     */
+    public $default_modifiers = array();
+
+    /**
+     * autoescape variable output
+     *
+     * @var boolean
+     */
+    public $escape_html = false;
+
+    /**
+     * start time for execution time calculation
+     *
+     * @var int
+     */
+    public $start_time = 0;
+
+    /**
+     * required by the compiler for BC
+     *
+     * @var string
+     */
+    public $_current_file = null;
+
+    /**
+     * internal flag to enable parser debugging
+     *
+     * @var bool
+     */
+    public $_parserdebug = false;
+
+    /**
+     * This object type (Smarty = 1, template = 2, data = 4)
+     *
+     * @var int
+     */
+    public $_objType = 1;
+
+    /**
+     * Debug object
+     *
+     * @var Smarty_Internal_Debug
+     */
+    public $_debug = null;
+
+    /**
+     * removed properties
+     *
+     * @var string[]
+     */
+    private $obsoleteProperties = array('resource_caching', 'template_resource_caching', 'direct_access_security',
+                                        '_dir_perms', '_file_perms', 'plugin_search_order',
+                                        'inheritance_merge_compiled_includes', 'resource_cache_mode',);
+
+    /**
+     * List of private properties which will call getter/setter on a direct access
+     *
+     * @var string[]
+     */
+    private $accessMap = array('template_dir' => 'TemplateDir', 'config_dir' => 'ConfigDir',
+                               'plugins_dir' => 'PluginsDir', 'compile_dir' => 'CompileDir',
+                               'cache_dir' => 'CacheDir',);
+
+    /**#@-*/
+
+    /**
+     * Initialize new Smarty object
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        if (is_callable('mb_internal_encoding')) {
+            mb_internal_encoding(Smarty::$_CHARSET);
+        }
+        $this->start_time = microtime(true);
+
+        if (isset($_SERVER[ 'SCRIPT_NAME' ])) {
+            Smarty::$global_tpl_vars[ 'SCRIPT_NAME' ] = new Smarty_Variable($_SERVER[ 'SCRIPT_NAME' ]);
+        }
+
+        // Check if we're running on windows
+        Smarty::$_IS_WINDOWS = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
+        // let PCRE (preg_*) treat strings as ISO-8859-1 if we're not dealing with UTF-8
+        if (Smarty::$_CHARSET !== 'UTF-8') {
+            Smarty::$_UTF8_MODIFIER = '';
+        }
+    }
+
+    /**
+     * Check if a template resource exists
+     *
+     * @param  string $resource_name template name
+     *
+     * @return boolean status
+     */
+    public function templateExists($resource_name)
+    {
+        // create source object
+        $source = Smarty_Template_Source::load(null, $this, $resource_name);
+        return $source->exists;
+    }
+
+    /**
+     * Loads security class and enables security
+     *
+     * @param  string|Smarty_Security $security_class if a string is used, it must be class-name
+     *
+     * @return Smarty                 current Smarty instance for chaining
+     * @throws SmartyException        when an invalid class name is provided
+     */
+    public function enableSecurity($security_class = null)
+    {
+        Smarty_Security::enableSecurity($this, $security_class);
+        return $this;
+    }
+
+    /**
+     * Disable security
+     *
+     * @return Smarty current Smarty instance for chaining
+     */
+    public function disableSecurity()
+    {
+        $this->security_policy = null;
+
+        return $this;
+    }
+
+    /**
+     * Set template directory
+     *
+     * @param  string|array $template_dir directory(s) of template sources
+     * @param bool          $isConfig     true for config_dir
+     *
+     * @return \Smarty current Smarty instance for chaining
+     */
+    public function setTemplateDir($template_dir, $isConfig = false)
+    {
+        if ($isConfig) {
+            $this->config_dir = array();
+            $this->_processedConfigDir = array();
+        } else {
+            $this->template_dir = array();
+            $this->_processedTemplateDir = array();
+        }
+        $this->addTemplateDir($template_dir, null, $isConfig);
+        return $this;
+    }
+
+    /**
+     * Add template directory(s)
+     *
+     * @param  string|array $template_dir directory(s) of template sources
+     * @param  string       $key          of the array element to assign the template dir to
+     * @param bool          $isConfig     true for config_dir
+     *
+     * @return Smarty          current Smarty instance for chaining
+     */
+    public function addTemplateDir($template_dir, $key = null, $isConfig = false)
+    {
+        if ($isConfig) {
+            $processed = &$this->_processedConfigDir;
+            $dir = &$this->config_dir;
+            $this->_configDirNormalized = false;
+        } else {
+            $processed = &$this->_processedTemplateDir;
+            $dir = &$this->template_dir;
+            $this->_templateDirNormalized = false;
+        }
+        if (is_array($template_dir)) {
+            foreach ($template_dir as $k => $v) {
+                if (is_int($k)) {
+                    // indexes are not merged but appended
+                    $dir[] = $v;
+                } else {
+                    // string indexes are overridden
+                    $dir[ $k ] = $v;
+                    unset($processed[ $key ]);
+                }
+            }
+        } else {
+            if ($key !== null) {
+                // override directory at specified index
+                $dir[ $key ] = $template_dir;
+                unset($processed[ $key ]);
+            } else {
+                // append new directory
+                $dir[] = $template_dir;
+            }
+        }
+        return $this;
+    }
+
+    /**
+     * Get template directories
+     *
+     * @param mixed $index    index of directory to get, null to get all
+     * @param bool  $isConfig true for config_dir
+     *
+     * @return array list of template directories, or directory of $index
+     */
+    public function getTemplateDir($index = null, $isConfig = false)
+    {
+        if ($isConfig) {
+            $dir = &$this->config_dir;
+        } else {
+            $dir = &$this->template_dir;
+        }
+        if ($isConfig ? !$this->_configDirNormalized : !$this->_templateDirNormalized) {
+            $this->_nomalizeTemplateConfig($isConfig);
+        }
+        if ($index !== null) {
+            return isset($dir[ $index ]) ? $dir[ $index ] : null;
+        }
+        return $dir;
+    }
+
+    /**
+     * Set config directory
+     *
+     * @param $config_dir
+     *
+     * @return Smarty       current Smarty instance for chaining
+     */
+    public function setConfigDir($config_dir)
+    {
+        return $this->setTemplateDir($config_dir, true);
+    }
+
+    /**
+     * Add config directory(s)
+     *
+     * @param string|array $config_dir directory(s) of config sources
+     * @param mixed        $key        key of the array element to assign the config dir to
+     *
+     * @return Smarty current Smarty instance for chaining
+     */
+    public function addConfigDir($config_dir, $key = null)
+    {
+        return $this->addTemplateDir($config_dir, $key, true);
+    }
+
+    /**
+     * Get config directory
+     *
+     * @param mixed $index index of directory to get, null to get all
+     *
+     * @return array configuration directory
+     */
+    public function getConfigDir($index = null)
+    {
+        return $this->getTemplateDir($index, true);
+    }
+
+    /**
+     * Set plugins directory
+     *
+     * @param  string|array $plugins_dir directory(s) of plugins
+     *
+     * @return Smarty       current Smarty instance for chaining
+     */
+    public function setPluginsDir($plugins_dir)
+    {
+        $this->plugins_dir = (array) $plugins_dir;
+        $this->_pluginsDirNormalized = false;
+        return $this;
+    }
+
+    /**
+     * Adds directory of plugin files
+     *
+     * @param null|array $plugins_dir
+     *
+     * @return Smarty current Smarty instance for chaining
+     */
+    public function addPluginsDir($plugins_dir)
+    {
+        if (empty($this->plugins_dir)) {
+            $this->plugins_dir[] = SMARTY_PLUGINS_DIR;
+        }
+        $this->plugins_dir = array_merge($this->plugins_dir, (array) $plugins_dir);
+        $this->_pluginsDirNormalized = false;
+        return $this;
+    }
+
+    /**
+     * Get plugin directories
+     *
+     * @return array list of plugin directories
+     */
+    public function getPluginsDir()
+    {
+        if (empty($this->plugins_dir)) {
+            $this->plugins_dir[] = SMARTY_PLUGINS_DIR;
+            $this->_pluginsDirNormalized = false;
+        }
+        if (!$this->_pluginsDirNormalized) {
+            if (!is_array($this->plugins_dir)) {
+                $this->plugins_dir = (array) $this->plugins_dir;
+            }
+            foreach ($this->plugins_dir as $k => $v) {
+                $this->plugins_dir[ $k ] = $this->_realpath(rtrim($v, "/\\") . DS, true);
+            }
+            $this->_cache[ 'plugin_files' ] = array();
+            $this->_pluginsDirNormalized = true;
+        }
+        return $this->plugins_dir;
+    }
+
+    /**
+     *
+     * @param  string $compile_dir directory to store compiled templates in
+     *
+     * @return Smarty current Smarty instance for chaining
+     */
+    public function setCompileDir($compile_dir)
+    {
+        $this->_normalizeDir('compile_dir', $compile_dir);
+        $this->_compileDirNormalized = true;
+        return $this;
+    }
+
+    /**
+     * Get compiled directory
+     *
+     * @return string path to compiled templates
+     */
+    public function getCompileDir()
+    {
+        if (!$this->_compileDirNormalized) {
+            $this->_normalizeDir('compile_dir', $this->compile_dir);
+            $this->_compileDirNormalized = true;
+        }
+        return $this->compile_dir;
+    }
+
+    /**
+     * Set cache directory
+     *
+     * @param  string $cache_dir directory to store cached templates in
+     *
+     * @return Smarty current Smarty instance for chaining
+     */
+    public function setCacheDir($cache_dir)
+    {
+        $this->_normalizeDir('cache_dir', $cache_dir);
+        $this->_cacheDirNormalized = true;
+        return $this;
+    }
+
+    /**
+     * Get cache directory
+     *
+     * @return string path of cache directory
+     */
+    public function getCacheDir()
+    {
+        if (!$this->_cacheDirNormalized) {
+            $this->_normalizeDir('cache_dir', $this->cache_dir);
+            $this->_cacheDirNormalized = true;
+        }
+        return $this->cache_dir;
+    }
+
+    /**
+     * Normalize and set directory string
+     *
+     * @param string $dirName cache_dir or compile_dir
+     * @param string $dir     filepath of folder
+     */
+    private function _normalizeDir($dirName, $dir)
+    {
+        $this->{$dirName} = $this->_realpath(rtrim($dir, "/\\") . DS, true);
+        if (!isset(Smarty::$_muted_directories[ $this->{$dirName} ])) {
+            Smarty::$_muted_directories[ $this->{$dirName} ] = null;
+        }
+    }
+
+    /**
+     * Normalize template_dir or config_dir
+     *
+     * @param bool $isConfig true for config_dir
+     *
+     */
+    private function _nomalizeTemplateConfig($isConfig)
+    {
+        if ($isConfig) {
+            $processed = &$this->_processedConfigDir;
+            $dir = &$this->config_dir;
+        } else {
+            $processed = &$this->_processedTemplateDir;
+            $dir = &$this->template_dir;
+        }
+        if (!is_array($dir)) {
+            $dir = (array) $dir;
+        }
+        foreach ($dir as $k => $v) {
+            if (!isset($processed[ $k ])) {
+                $dir[ $k ] = $v = $this->_realpath(rtrim($v, "/\\") . DS, true);
+                $processed[ $k ] = true;
+            }
+        }
+        $isConfig ? $this->_configDirNormalized = true : $this->_templateDirNormalized = true;
+        $isConfig ? $this->_joined_config_dir = join('#', $this->config_dir) :
+            $this->_joined_template_dir = join('#', $this->template_dir);
+    }
+
+    /**
+     * creates a template object
+     *
+     * @param  string  $template   the resource handle of the template file
+     * @param  mixed   $cache_id   cache id to be used with this template
+     * @param  mixed   $compile_id compile id to be used with this template
+     * @param  object  $parent     next higher level of Smarty variables
+     * @param  boolean $do_clone   flag is Smarty object shall be cloned
+     *
+     * @return object  template object
+     */
+    public function createTemplate($template, $cache_id = null, $compile_id = null, $parent = null, $do_clone = true)
+    {
+        if ($cache_id !== null && (is_object($cache_id) || is_array($cache_id))) {
+            $parent = $cache_id;
+            $cache_id = null;
+        }
+        if ($parent !== null && is_array($parent)) {
+            $data = $parent;
+            $parent = null;
+        } else {
+            $data = null;
+        }
+        $_templateId = $this->_getTemplateId($template, $cache_id, $compile_id);
+        $tpl = null;
+        if ($this->caching && isset($this->_cache[ 'isCached' ][ $_templateId ])) {
+            $tpl = $do_clone ? clone $this->_cache[ 'isCached' ][ $_templateId ] :
+                $this->_cache[ 'isCached' ][ $_templateId ];
+            $tpl->tpl_vars = $tpl->config_vars = array();
+        } else if (!$do_clone && isset($this->_cache[ 'tplObjects' ][ $_templateId ])) {
+            $tpl = clone $this->_cache[ 'tplObjects' ][ $_templateId ];
+        } else {
+            /* @var Smarty_Internal_Template $tpl */
+            $tpl = new $this->template_class($template, $this, null, $cache_id, $compile_id, null, null);
+            $tpl->templateId = $_templateId;
+        }
+        if ($do_clone) {
+            $tpl->smarty = clone $tpl->smarty;
+        }
+        $tpl->parent = $parent ? $parent : $this;
+        // fill data if present
+        if (!empty($data) && is_array($data)) {
+            // set up variable values
+            foreach ($data as $_key => $_val) {
+                $tpl->tpl_vars[ $_key ] = new Smarty_Variable($_val);
+            }
+        }
+        if ($this->debugging || $this->debugging_ctrl == 'URL') {
+            $tpl->smarty->_debug = new Smarty_Internal_Debug();
+            // check URL debugging control
+            if (!$this->debugging && $this->debugging_ctrl == 'URL') {
+                $tpl->smarty->_debug->debugUrl($tpl->smarty);
+            }
+        }
+        return $tpl;
+    }
+
+    /**
+     * Takes unknown classes and loads plugin files for them
+     * class name format: Smarty_PluginType_PluginName
+     * plugin filename format: plugintype.pluginname.php
+     *
+     * @param  string $plugin_name class plugin name to load
+     * @param  bool   $check       check if already loaded
+     *
+     * @throws SmartyException
+     * @return string |boolean filepath of loaded file or false
+     */
+    public function loadPlugin($plugin_name, $check = true)
+    {
+        return $this->ext->loadPlugin->loadPlugin($this, $plugin_name, $check);
+    }
+
+    /**
+     * Get unique template id
+     *
+     * @param string                    $template_name
+     * @param null|mixed                $cache_id
+     * @param null|mixed                $compile_id
+     * @param null                      $caching
+     * @param \Smarty_Internal_Template $template
+     *
+     * @return string
+     */
+    public function _getTemplateId($template_name, $cache_id = null, $compile_id = null, $caching = null,
+                                   Smarty_Internal_Template $template = null)
+    {
+        $template_name = (strpos($template_name, ':') === false) ? "{$this->default_resource_type}:{$template_name}" :
+            $template_name;
+        $cache_id = $cache_id === null ? $this->cache_id : $cache_id;
+        $compile_id = $compile_id === null ? $this->compile_id : $compile_id;
+        $caching = (int) ($caching === null ? $this->caching : $caching);
+
+        if ((isset($template) && strpos($template_name, ':.') !== false) || $this->allow_ambiguous_resources) {
+            $_templateId =
+                Smarty_Resource::getUniqueTemplateName((isset($template) ? $template : $this), $template_name) .
+                "#{$cache_id}#{$compile_id}#{$caching}";
+        } else {
+            $_templateId = $this->_joined_template_dir . "#{$template_name}#{$cache_id}#{$compile_id}#{$caching}";
+        }
+        if (isset($_templateId[ 150 ])) {
+            $_templateId = sha1($_templateId);
+        }
+        return $_templateId;
+    }
+
+    /**
+     * Normalize path
+     *  - remove /./ and /../
+     *  - make it absolute if required
+     *
+     * @param string $path      file path
+     * @param bool   $realpath  if true - convert to absolute
+     *                          false - convert to relative
+     *                          null - keep as it is but remove /./ /../
+     *
+     * @return string
+     */
+    public function _realpath($path, $realpath = null)
+    {
+        $nds = DS == '/' ? '\\' : '/';
+        // normalize DS 
+        $path = str_replace($nds, DS, $path);
+        preg_match('%^(?<root>(?:[[:alpha:]]:[\\\\]|/|[\\\\]{2}[[:alpha:]]+|[[:print:]]{2,}:[/]{2}|[\\\\])?)(?<path>(?:[[:print:]]*))$%',
+                   $path, $parts);
+        $path = $parts[ 'path' ];
+        if ($parts[ 'root' ] == '\\') {
+            $parts[ 'root' ] = substr(getcwd(), 0, 2) . $parts[ 'root' ];
+        } else {
+            if ($realpath !== null && !$parts[ 'root' ]) {
+                $path = getcwd() . DS . $path;
+            }
+        }
+        // remove noop 'DS DS' and 'DS.DS' patterns
+        $path = preg_replace('#([\\\\/]([.]?[\\\\/])+)#', DS, $path);
+        // resolve '..DS' pattern, smallest first
+        if (strpos($path, '..' . DS) != false &&
+            preg_match_all('#(([.]?[\\\\/])*([.][.])[\\\\/]([.]?[\\\\/])*)+#', $path, $match)
+        ) {
+            $counts = array();
+            foreach ($match[ 0 ] as $m) {
+                $counts[] = (int) ((strlen($m) - 1) / 3);
+            }
+            sort($counts);
+            foreach ($counts as $count) {
+                $path = preg_replace('#(([\\\\/]([.]?[\\\\/])*[^\\\\/.]+){' . $count .
+                                     '}[\\\\/]([.]?[\\\\/])*([.][.][\\\\/]([.]?[\\\\/])*){' . $count . '})(?=[^.])#',
+                                     DS, $path);
+            }
+        }
+
+        return $parts[ 'root' ] . $path;
+    }
+
+    /**
+     * Empty template objects cache
+     */
+    public function _clearTemplateCache()
+    {
+        $this->_cache[ 'isCached' ] = array();
+        $this->_cache[ 'tplObjects' ] = array();
+    }
+
+    /**
+     * @param boolean $compile_check
+     */
+    public function setCompileCheck($compile_check)
+    {
+        $this->compile_check = $compile_check;
+    }
+
+    /**
+     * @param boolean $use_sub_dirs
+     */
+    public function setUseSubDirs($use_sub_dirs)
+    {
+        $this->use_sub_dirs = $use_sub_dirs;
+    }
+
+    /**
+     * @param int $error_reporting
+     */
+    public function setErrorReporting($error_reporting)
+    {
+        $this->error_reporting = $error_reporting;
+    }
+
+    /**
+     * @param boolean $escape_html
+     */
+    public function setEscapeHtml($escape_html)
+    {
+        $this->escape_html = $escape_html;
+    }
+
+    /**
+     * @param boolean $auto_literal
+     */
+    public function setAutoLiteral($auto_literal)
+    {
+        $this->auto_literal = $auto_literal;
+    }
+
+    /**
+     * @param boolean $force_compile
+     */
+    public function setForceCompile($force_compile)
+    {
+        $this->force_compile = $force_compile;
+    }
+
+    /**
+     * @param boolean $merge_compiled_includes
+     */
+    public function setMergeCompiledIncludes($merge_compiled_includes)
+    {
+        $this->merge_compiled_includes = $merge_compiled_includes;
+    }
+
+    /**
+     * @param string $left_delimiter
+     */
+    public function setLeftDelimiter($left_delimiter)
+    {
+        $this->left_delimiter = $left_delimiter;
+    }
+
+    /**
+     * @param string $right_delimiter
+     */
+    public function setRightDelimiter($right_delimiter)
+    {
+        $this->right_delimiter = $right_delimiter;
+    }
+
+    /**
+     * @param boolean $debugging
+     */
+    public function setDebugging($debugging)
+    {
+        $this->debugging = $debugging;
+    }
+
+    /**
+     * @param boolean $config_overwrite
+     */
+    public function setConfigOverwrite($config_overwrite)
+    {
+        $this->config_overwrite = $config_overwrite;
+    }
+
+    /**
+     * @param boolean $config_booleanize
+     */
+    public function setConfigBooleanize($config_booleanize)
+    {
+        $this->config_booleanize = $config_booleanize;
+    }
+
+    /**
+     * @param boolean $config_read_hidden
+     */
+    public function setConfigReadHidden($config_read_hidden)
+    {
+        $this->config_read_hidden = $config_read_hidden;
+    }
+
+    /**
+     * @param boolean $compile_locking
+     */
+    public function setCompileLocking($compile_locking)
+    {
+        $this->compile_locking = $compile_locking;
+    }
+
+    /**
+     * @param string $default_resource_type
+     */
+    public function setDefaultResourceType($default_resource_type)
+    {
+        $this->default_resource_type = $default_resource_type;
+    }
+
+    /**
+     * @param string $caching_type
+     */
+    public function setCachingType($caching_type)
+    {
+        $this->caching_type = $caching_type;
+    }
+
+    /**
+     * Test install
+     *
+     * @param null $errors
+     */
+    public function testInstall(&$errors = null)
+    {
+        Smarty_Internal_TestInstall::testInstall($this, $errors);
+    }
+
+    /**
+     * <<magic>> Generic getter.
+     * Calls the appropriate getter function.
+     * Issues an E_USER_NOTICE if no valid getter is found.
+     *
+     * @param  string $name property name
+     *
+     * @return mixed
+     */
+    public function __get($name)
+    {
+        if (isset($this->accessMap[ $name ])) {
+            $method = 'get' . $this->accessMap[ $name ];
+            return $this->{$method}();
+        } elseif (isset($this->_cache[ $name ])) {
+            return $this->_cache[ $name ];
+        } elseif (in_array($name, $this->obsoleteProperties)) {
+            return null;
+        } else {
+            trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE);
+        }
+        return null;
+    }
+
+    /**
+     * <<magic>> Generic setter.
+     * Calls the appropriate setter function.
+     * Issues an E_USER_NOTICE if no valid setter is found.
+     *
+     * @param string $name  property name
+     * @param mixed  $value parameter passed to setter
+     */
+    public function __set($name, $value)
+    {
+        if (isset($this->accessMap[ $name ])) {
+            $method = 'set' . $this->accessMap[ $name ];
+            $this->{$method}($value);
+        } elseif (in_array($name, $this->obsoleteProperties)) {
+            return;
+        } else {
+            if (is_object($value) && method_exists($value, $name)) {
+                $this->$name = $value;
+            } else {
+                trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE);
+            }
+        }
+    }
+
+    /**
+     * Error Handler to mute expected messages
+     *
+     * @link http://php.net/set_error_handler
+     *
+     * @param  integer $errno Error level
+     * @param          $errstr
+     * @param          $errfile
+     * @param          $errline
+     * @param          $errcontext
+     *
+     * @return bool|void
+     */
+    public static function mutingErrorHandler($errno, $errstr, $errfile, $errline, $errcontext)
+    {
+        $_is_muted_directory = false;
+
+        // add the SMARTY_DIR to the list of muted directories
+        if (!isset(Smarty::$_muted_directories[ SMARTY_DIR ])) {
+            $smarty_dir = realpath(SMARTY_DIR);
+            if ($smarty_dir !== false) {
+                Smarty::$_muted_directories[ SMARTY_DIR ] =
+                    array('file' => $smarty_dir, 'length' => strlen($smarty_dir),);
+            }
+        }
+
+        // walk the muted directories and test against $errfile
+        foreach (Smarty::$_muted_directories as $key => &$dir) {
+            if (!$dir) {
+                // resolve directory and length for speedy comparisons
+                $file = realpath($key);
+                if ($file === false) {
+                    // this directory does not exist, remove and skip it
+                    unset(Smarty::$_muted_directories[ $key ]);
+                    continue;
+                }
+                $dir = array('file' => $file, 'length' => strlen($file),);
+            }
+            if (!strncmp($errfile, $dir[ 'file' ], $dir[ 'length' ])) {
+                $_is_muted_directory = true;
+                break;
+            }
+        }
+        // pass to next error handler if this error did not occur inside SMARTY_DIR
+        // or the error was within smarty but masked to be ignored
+        if (!$_is_muted_directory || ($errno && $errno & error_reporting())) {
+            if (Smarty::$_previous_error_handler) {
+                return call_user_func(Smarty::$_previous_error_handler, $errno, $errstr, $errfile, $errline,
+                                      $errcontext);
+            } else {
+                return false;
+            }
+        }
+        return;
+    }
+
+    /**
+     * Enable error handler to mute expected messages
+     *
+     * @return void
+     */
+    public static function muteExpectedErrors()
+    {
+        /*
+            error muting is done because some people implemented custom error_handlers using
+            http://php.net/set_error_handler and for some reason did not understand the following paragraph:
+
+                It is important to remember that the standard PHP error handler is completely bypassed for the
+                error types specified by error_types unless the callback function returns FALSE.
+                error_reporting() settings will have no effect and your error handler will be called regardless -
+                however you are still able to read the current value of error_reporting and act appropriately.
+                Of particular note is that this value will be 0 if the statement that caused the error was
+                prepended by the @ error-control operator.
+
+            Smarty deliberately uses @filemtime() over file_exists() and filemtime() in some places. Reasons include
+                - @filemtime() is almost twice as fast as using an additional file_exists()
+                - between file_exists() and filemtime() a possible race condition is opened,
+                  which does not exist using the simple @filemtime() approach.
+        */
+        $error_handler = array('Smarty', 'mutingErrorHandler');
+        $previous = set_error_handler($error_handler);
+
+        // avoid dead loops
+        if ($previous !== $error_handler) {
+            Smarty::$_previous_error_handler = $previous;
+        }
+    }
+
+    /**
+     * Disable error handler muting expected messages
+     *
+     * @return void
+     */
+    public static function unmuteExpectedErrors()
+    {
+        restore_error_handler();
+    }
+}

+ 455 - 0
Qii/View/smarty/SmartyBC.class.php

@@ -0,0 +1,455 @@
+<?php
+/**
+ * Project:     Smarty: the PHP compiling template engine
+ * File:        SmartyBC.class.php
+ * SVN:         $Id: $
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * For questions, help, comments, discussion, etc., please join the
+ * Smarty mailing list. Send a blank e-mail to
+ * smarty-discussion-subscribe@googlegroups.com
+ *
+ * @link      http://www.smarty.net/
+ * @copyright 2008 New Digital Group, Inc.
+ * @author    Monte Ohrt <monte at ohrt dot com>
+ * @author    Uwe Tews
+ * @author    Rodney Rehm
+ * @package   Smarty
+ */
+/**
+ * @ignore
+ */
+require_once(dirname(__FILE__) . '/Smarty.class.php');
+
+/**
+ * Smarty Backward Compatibility Wrapper Class
+ *
+ * @package Smarty
+ */
+class SmartyBC extends Smarty
+{
+    /**
+     * Smarty 2 BC
+     *
+     * @var string
+     */
+    public $_version = self::SMARTY_VERSION;
+
+    /**
+     * This is an array of directories where trusted php scripts reside.
+     *
+     * @var array
+     */
+    public $trusted_dir = array();
+
+    /**
+     * Initialize new SmartyBC object
+     *
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * wrapper for assign_by_ref
+     *
+     * @param string $tpl_var the template variable name
+     * @param mixed  &$value  the referenced value to assign
+     */
+    public function assign_by_ref($tpl_var, &$value)
+    {
+        $this->assignByRef($tpl_var, $value);
+    }
+
+    /**
+     * wrapper for append_by_ref
+     *
+     * @param string  $tpl_var the template variable name
+     * @param mixed   &$value  the referenced value to append
+     * @param boolean $merge   flag if array elements shall be merged
+     */
+    public function append_by_ref($tpl_var, &$value, $merge = false)
+    {
+        $this->appendByRef($tpl_var, $value, $merge);
+    }
+
+    /**
+     * clear the given assigned template variable.
+     *
+     * @param string $tpl_var the template variable to clear
+     */
+    public function clear_assign($tpl_var)
+    {
+        $this->clearAssign($tpl_var);
+    }
+
+    /**
+     * Registers custom function to be used in templates
+     *
+     * @param string $function      the name of the template function
+     * @param string $function_impl the name of the PHP function to register
+     * @param bool   $cacheable
+     * @param mixed  $cache_attrs
+     */
+    public function register_function($function, $function_impl, $cacheable = true, $cache_attrs = null)
+    {
+        $this->registerPlugin('function', $function, $function_impl, $cacheable, $cache_attrs);
+    }
+
+    /**
+     * Unregister custom function
+     *
+     * @param string $function name of template function
+     */
+    public function unregister_function($function)
+    {
+        $this->unregisterPlugin('function', $function);
+    }
+
+    /**
+     * Registers object to be used in templates
+     *
+     * @param string  $object        name of template object
+     * @param object  $object_impl   the referenced PHP object to register
+     * @param array   $allowed       list of allowed methods (empty = all)
+     * @param boolean $smarty_args   smarty argument format, else traditional
+     * @param array   $block_methods list of methods that are block format
+     *
+     * @throws SmartyException
+     * @internal param array $block_functs list of methods that are block format
+     */
+    public function register_object($object, $object_impl, $allowed = array(), $smarty_args = true,
+                                    $block_methods = array())
+    {
+        settype($allowed, 'array');
+        settype($smarty_args, 'boolean');
+        $this->registerObject($object, $object_impl, $allowed, $smarty_args, $block_methods);
+    }
+
+    /**
+     * Unregister object
+     *
+     * @param string $object name of template object
+     */
+    public function unregister_object($object)
+    {
+        $this->unregisterObject($object);
+    }
+
+    /**
+     * Registers block function to be used in templates
+     *
+     * @param string $block      name of template block
+     * @param string $block_impl PHP function to register
+     * @param bool   $cacheable
+     * @param mixed  $cache_attrs
+     */
+    public function register_block($block, $block_impl, $cacheable = true, $cache_attrs = null)
+    {
+        $this->registerPlugin('block', $block, $block_impl, $cacheable, $cache_attrs);
+    }
+
+    /**
+     * Unregister block function
+     *
+     * @param string $block name of template function
+     */
+    public function unregister_block($block)
+    {
+        $this->unregisterPlugin('block', $block);
+    }
+
+    /**
+     * Registers compiler function
+     *
+     * @param string $function      name of template function
+     * @param string $function_impl name of PHP function to register
+     * @param bool   $cacheable
+     */
+    public function register_compiler_function($function, $function_impl, $cacheable = true)
+    {
+        $this->registerPlugin('compiler', $function, $function_impl, $cacheable);
+    }
+
+    /**
+     * Unregister compiler function
+     *
+     * @param string $function name of template function
+     */
+    public function unregister_compiler_function($function)
+    {
+        $this->unregisterPlugin('compiler', $function);
+    }
+
+    /**
+     * Registers modifier to be used in templates
+     *
+     * @param string $modifier      name of template modifier
+     * @param string $modifier_impl name of PHP function to register
+     */
+    public function register_modifier($modifier, $modifier_impl)
+    {
+        $this->registerPlugin('modifier', $modifier, $modifier_impl);
+    }
+
+    /**
+     * Unregister modifier
+     *
+     * @param string $modifier name of template modifier
+     */
+    public function unregister_modifier($modifier)
+    {
+        $this->unregisterPlugin('modifier', $modifier);
+    }
+
+    /**
+     * Registers a resource to fetch a template
+     *
+     * @param string $type      name of resource
+     * @param array  $functions array of functions to handle resource
+     */
+    public function register_resource($type, $functions)
+    {
+        $this->registerResource($type, $functions);
+    }
+
+    /**
+     * Unregister a resource
+     *
+     * @param string $type name of resource
+     */
+    public function unregister_resource($type)
+    {
+        $this->unregisterResource($type);
+    }
+
+    /**
+     * Registers a prefilter function to apply
+     * to a template before compiling
+     *
+     * @param callable $function
+     */
+    public function register_prefilter($function)
+    {
+        $this->registerFilter('pre', $function);
+    }
+
+    /**
+     * Unregister a prefilter function
+     *
+     * @param callable $function
+     */
+    public function unregister_prefilter($function)
+    {
+        $this->unregisterFilter('pre', $function);
+    }
+
+    /**
+     * Registers a postfilter function to apply
+     * to a compiled template after compilation
+     *
+     * @param callable $function
+     */
+    public function register_postfilter($function)
+    {
+        $this->registerFilter('post', $function);
+    }
+
+    /**
+     * Unregister a postfilter function
+     *
+     * @param callable $function
+     */
+    public function unregister_postfilter($function)
+    {
+        $this->unregisterFilter('post', $function);
+    }
+
+    /**
+     * Registers an output filter function to apply
+     * to a template output
+     *
+     * @param callable $function
+     */
+    public function register_outputfilter($function)
+    {
+        $this->registerFilter('output', $function);
+    }
+
+    /**
+     * Unregister an outputfilter function
+     *
+     * @param callable $function
+     */
+    public function unregister_outputfilter($function)
+    {
+        $this->unregisterFilter('output', $function);
+    }
+
+    /**
+     * load a filter of specified type and name
+     *
+     * @param string $type filter type
+     * @param string $name filter name
+     */
+    public function load_filter($type, $name)
+    {
+        $this->loadFilter($type, $name);
+    }
+
+    /**
+     * clear cached content for the given template and cache id
+     *
+     * @param  string $tpl_file   name of template file
+     * @param  string $cache_id   name of cache_id
+     * @param  string $compile_id name of compile_id
+     * @param  string $exp_time   expiration time
+     *
+     * @return boolean
+     */
+    public function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null)
+    {
+        return $this->clearCache($tpl_file, $cache_id, $compile_id, $exp_time);
+    }
+
+    /**
+     * clear the entire contents of cache (all templates)
+     *
+     * @param  string $exp_time expire time
+     *
+     * @return boolean
+     */
+    public function clear_all_cache($exp_time = null)
+    {
+        return $this->clearCache(null, null, null, $exp_time);
+    }
+
+    /**
+     * test to see if valid cache exists for this template
+     *
+     * @param  string $tpl_file name of template file
+     * @param  string $cache_id
+     * @param  string $compile_id
+     *
+     * @return boolean
+     */
+    public function is_cached($tpl_file, $cache_id = null, $compile_id = null)
+    {
+        return $this->isCached($tpl_file, $cache_id, $compile_id);
+    }
+
+    /**
+     * clear all the assigned template variables.
+     */
+    public function clear_all_assign()
+    {
+        $this->clearAllAssign();
+    }
+
+    /**
+     * clears compiled version of specified template resource,
+     * or all compiled template files if one is not specified.
+     * This function is for advanced use only, not normally needed.
+     *
+     * @param  string $tpl_file
+     * @param  string $compile_id
+     * @param  string $exp_time
+     *
+     * @return boolean results of {@link smarty_core_rm_auto()}
+     */
+    public function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null)
+    {
+        return $this->clearCompiledTemplate($tpl_file, $compile_id, $exp_time);
+    }
+
+    /**
+     * Checks whether requested template exists.
+     *
+     * @param  string $tpl_file
+     *
+     * @return boolean
+     */
+    public function template_exists($tpl_file)
+    {
+        return $this->templateExists($tpl_file);
+    }
+
+    /**
+     * Returns an array containing template variables
+     *
+     * @param  string $name
+     *
+     * @return array
+     */
+    public function get_template_vars($name = null)
+    {
+        return $this->getTemplateVars($name);
+    }
+
+    /**
+     * Returns an array containing config variables
+     *
+     * @param  string $name
+     *
+     * @return array
+     */
+    public function get_config_vars($name = null)
+    {
+        return $this->getConfigVars($name);
+    }
+
+    /**
+     * load configuration values
+     *
+     * @param string $file
+     * @param string $section
+     * @param string $scope
+     */
+    public function config_load($file, $section = null, $scope = 'global')
+    {
+        $this->ConfigLoad($file, $section, $scope);
+    }
+
+    /**
+     * return a reference to a registered object
+     *
+     * @param  string $name
+     *
+     * @return object
+     */
+    public function get_registered_object($name)
+    {
+        return $this->getRegisteredObject($name);
+    }
+
+    /**
+     * clear configuration values
+     *
+     * @param string $var
+     */
+    public function clear_config($var = null)
+    {
+        $this->clearConfig($var);
+    }
+
+    /**
+     * trigger Smarty error
+     *
+     * @param string  $error_msg
+     * @param integer $error_type
+     */
+    public function trigger_error($error_msg, $error_type = E_USER_WARNING)
+    {
+        trigger_error("Smarty error: $error_msg", $error_type);
+    }
+}

+ 160 - 0
Qii/View/smarty/debug.tpl

@@ -0,0 +1,160 @@
+{capture name='_smarty_debug' assign=debug_output}
+    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+    <head>
+        <title>Smarty Debug Console</title>
+        <style type="text/css">
+            {literal}
+            body, h1, h2, h3, td, th, p {
+                font-family: sans-serif;
+                font-weight: normal;
+                font-size: 0.9em;
+                margin: 1px;
+                padding: 0;
+            }
+
+            h1 {
+                margin: 0;
+                text-align: left;
+                padding: 2px;
+                background-color: #f0c040;
+                color: black;
+                font-weight: bold;
+                font-size: 1.2em;
+            }
+
+            h2 {
+                background-color: #9B410E;
+                color: white;
+                text-align: left;
+                font-weight: bold;
+                padding: 2px;
+                border-top: 1px solid black;
+            }
+            h3 {
+                text-align: left;
+                font-weight: bold;
+                color: black;
+                font-size: 0.7em;
+                padding: 2px;
+            }
+
+            body {
+                background: black;
+            }
+
+            p, table, div {
+                background: #f0ead8;
+            }
+
+            p {
+                margin: 0;
+                font-style: italic;
+                text-align: center;
+            }
+
+            table {
+                width: 100%;
+            }
+
+            th, td {
+                font-family: monospace;
+                vertical-align: top;
+                text-align: left;
+            }
+
+            td {
+                color: green;
+            }
+
+            .odd {
+                background-color: #eeeeee;
+            }
+
+            .even {
+                background-color: #fafafa;
+            }
+
+            .exectime {
+                font-size: 0.8em;
+                font-style: italic;
+            }
+
+            #bold div {
+                color: black;
+                font-weight: bold;
+            }
+            #blue h3 {
+                color: blue;
+            }
+            #normal div {
+                color: black;
+                font-weight: normal;
+            }
+            #table_assigned_vars th {
+                color: blue;
+                font-weight: bold;
+            }
+
+            #table_config_vars th {
+                color: maroon;
+            }
+
+            {/literal}
+        </style>
+    </head>
+    <body>
+
+    <h1>Smarty {Smarty::SMARTY_VERSION} Debug Console
+        -  {if isset($template_name)}{$template_name|debug_print_var nofilter} {/if}{if !empty($template_data)}Total Time {$execution_time|string_format:"%.5f"}{/if}</h1>
+
+    {if !empty($template_data)}
+        <h2>included templates &amp; config files (load time in seconds)</h2>
+        <div>
+            {foreach $template_data as $template}
+                <font color=brown>{$template.name}</font>
+                <br>&nbsp;&nbsp;<span class="exectime">
+                (compile {$template['compile_time']|string_format:"%.5f"}) (render {$template['render_time']|string_format:"%.5f"}) (cache {$template['cache_time']|string_format:"%.5f"})
+                 </span>
+                <br>
+            {/foreach}
+        </div>
+    {/if}
+
+    <h2>assigned template variables</h2>
+
+    <table id="table_assigned_vars">
+        {foreach $assigned_vars as $vars}
+            <tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">
+                <td><h3><font color=blue>${$vars@key}</font></h3>
+                    {if isset($vars['nocache'])}<b>Nocache</b></br>{/if}
+                    {if isset($vars['scope'])}<b>Origin:</b> {$vars['scope']|debug_print_var nofilter}{/if}
+                </td>
+                <td><h3>Value</h3>{$vars['value']|debug_print_var:10:80 nofilter}</td>
+                <td>{if isset($vars['attributes'])}<h3>Attributes</h3>{$vars['attributes']|debug_print_var nofilter} {/if}</td>
+         {/foreach}
+    </table>
+
+    <h2>assigned config file variables</h2>
+
+    <table id="table_config_vars">
+        {foreach $config_vars as $vars}
+            <tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">
+                <td><h3><font color=blue>#{$vars@key}#</font></h3>
+                    {if isset($vars['scope'])}<b>Origin:</b> {$vars['scope']|debug_print_var nofilter}{/if}
+                </td>
+                <td>{$vars['value']|debug_print_var:10:80 nofilter}</td>
+            </tr>
+        {/foreach}
+
+    </table>
+    </body>
+    </html>
+{/capture}
+<script type="text/javascript">
+    {$id = '__Smarty__'}
+    {if $display_mode}{$id = "$offset$template_name"|md5}{/if}
+    _smarty_console = window.open("", "console{$id}", "width=1024,height=600,left={$offset},top={$offset},resizable,scrollbars=yes");
+    _smarty_console.document.write("{$debug_output|escape:'javascript' nofilter}");
+    _smarty_console.document.close();
+</script>

+ 112 - 0
Qii/View/smarty/plugins/block.textformat.php

@@ -0,0 +1,112 @@
+<?php
+/**
+ * Smarty plugin to format text blocks
+ *
+ * @package    Smarty
+ * @subpackage PluginsBlock
+ */
+
+/**
+ * Smarty {textformat}{/textformat} block plugin
+ * Type:     block function<br>
+ * Name:     textformat<br>
+ * Purpose:  format text a certain way with preset styles
+ *           or custom wrap/indent settings<br>
+ * Params:
+ * <pre>
+ * - style         - string (email)
+ * - indent        - integer (0)
+ * - wrap          - integer (80)
+ * - wrap_char     - string ("\n")
+ * - indent_char   - string (" ")
+ * - wrap_boundary - boolean (true)
+ * </pre>
+ *
+ * @link   http://www.smarty.net/manual/en/language.function.textformat.php {textformat}
+ *         (Smarty online manual)
+ *
+ * @param array                    $params   parameters
+ * @param string                   $content  contents of the block
+ * @param Smarty_Internal_Template $template template object
+ * @param boolean                  &$repeat  repeat flag
+ *
+ * @return string content re-formatted
+ * @author Monte Ohrt <monte at ohrt dot com>
+ */
+function smarty_block_textformat($params, $content, $template, &$repeat)
+{
+    if (is_null($content)) {
+        return;
+    }
+
+    $style = null;
+    $indent = 0;
+    $indent_first = 0;
+    $indent_char = ' ';
+    $wrap = 80;
+    $wrap_char = "\n";
+    $wrap_cut = false;
+    $assign = null;
+
+    foreach ($params as $_key => $_val) {
+        switch ($_key) {
+            case 'style':
+            case 'indent_char':
+            case 'wrap_char':
+            case 'assign':
+                $$_key = (string) $_val;
+                break;
+
+            case 'indent':
+            case 'indent_first':
+            case 'wrap':
+                $$_key = (int) $_val;
+                break;
+
+            case 'wrap_cut':
+                $$_key = (bool) $_val;
+                break;
+
+            default:
+                trigger_error("textformat: unknown attribute '$_key'");
+        }
+    }
+
+    if ($style == 'email') {
+        $wrap = 72;
+    }
+    // split into paragraphs
+    $_paragraphs = preg_split('![\r\n]{2}!', $content);
+
+    foreach ($_paragraphs as &$_paragraph) {
+        if (!$_paragraph) {
+            continue;
+        }
+        // convert mult. spaces & special chars to single space
+        $_paragraph =
+            preg_replace(array('!\s+!' . Smarty::$_UTF8_MODIFIER, '!(^\s+)|(\s+$)!' . Smarty::$_UTF8_MODIFIER),
+                         array(' ', ''), $_paragraph);
+        // indent first line
+        if ($indent_first > 0) {
+            $_paragraph = str_repeat($indent_char, $indent_first) . $_paragraph;
+        }
+        // wordwrap sentences
+        if (Smarty::$_MBSTRING) {
+            require_once(SMARTY_PLUGINS_DIR . 'shared.mb_wordwrap.php');
+            $_paragraph = smarty_mb_wordwrap($_paragraph, $wrap - $indent, $wrap_char, $wrap_cut);
+        } else {
+            $_paragraph = wordwrap($_paragraph, $wrap - $indent, $wrap_char, $wrap_cut);
+        }
+        // indent lines
+        if ($indent > 0) {
+            $_paragraph = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraph);
+        }
+    }
+    $_output = implode($wrap_char . $wrap_char, $_paragraphs);
+
+    if ($assign) {
+        $template->assign($assign, $_output);
+    } else {
+        return $_output;
+    }
+}

+ 73 - 0
Qii/View/smarty/plugins/function.counter.php

@@ -0,0 +1,73 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * Smarty {counter} function plugin
+ * Type:     function<br>
+ * Name:     counter<br>
+ * Purpose:  print out a counter value
+ *
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @link   http://www.smarty.net/manual/en/language.function.counter.php {counter}
+ *         (Smarty online manual)
+ *
+ * @param array                    $params   parameters
+ * @param Smarty_Internal_Template $template template object
+ *
+ * @return string|null
+ */
+function smarty_function_counter($params, $template)
+{
+    static $counters = array();
+
+    $name = (isset($params[ 'name' ])) ? $params[ 'name' ] : 'default';
+    if (!isset($counters[ $name ])) {
+        $counters[ $name ] = array('start' => 1, 'skip' => 1, 'direction' => 'up', 'count' => 1);
+    }
+    $counter =& $counters[ $name ];
+
+    if (isset($params[ 'start' ])) {
+        $counter[ 'start' ] = $counter[ 'count' ] = (int) $params[ 'start' ];
+    }
+
+    if (!empty($params[ 'assign' ])) {
+        $counter[ 'assign' ] = $params[ 'assign' ];
+    }
+
+    if (isset($counter[ 'assign' ])) {
+        $template->assign($counter[ 'assign' ], $counter[ 'count' ]);
+    }
+
+    if (isset($params[ 'print' ])) {
+        $print = (bool) $params[ 'print' ];
+    } else {
+        $print = empty($counter[ 'assign' ]);
+    }
+
+    if ($print) {
+        $retval = $counter[ 'count' ];
+    } else {
+        $retval = null;
+    }
+
+    if (isset($params[ 'skip' ])) {
+        $counter[ 'skip' ] = $params[ 'skip' ];
+    }
+
+    if (isset($params[ 'direction' ])) {
+        $counter[ 'direction' ] = $params[ 'direction' ];
+    }
+
+    if ($counter[ 'direction' ] == "down") {
+        $counter[ 'count' ] -= $counter[ 'skip' ];
+    } else {
+        $counter[ 'count' ] += $counter[ 'skip' ];
+    }
+
+    return $retval;
+}

+ 105 - 0
Qii/View/smarty/plugins/function.cycle.php

@@ -0,0 +1,105 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * Smarty {cycle} function plugin
+ * Type:     function<br>
+ * Name:     cycle<br>
+ * Date:     May 3, 2002<br>
+ * Purpose:  cycle through given values<br>
+ * Params:
+ * <pre>
+ * - name      - name of cycle (optional)
+ * - values    - comma separated list of values to cycle, or an array of values to cycle
+ *               (this can be left out for subsequent calls)
+ * - reset     - boolean - resets given var to true
+ * - print     - boolean - print var or not. default is true
+ * - advance   - boolean - whether or not to advance the cycle
+ * - delimiter - the value delimiter, default is ","
+ * - assign    - boolean, assigns to template var instead of printed.
+ * </pre>
+ * Examples:<br>
+ * <pre>
+ * {cycle values="#eeeeee,#d0d0d0d"}
+ * {cycle name=row values="one,two,three" reset=true}
+ * {cycle name=row}
+ * </pre>
+ *
+ * @link     http://www.smarty.net/manual/en/language.function.cycle.php {cycle}
+ *           (Smarty online manual)
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @author   credit to Mark Priatel <mpriatel@rogers.com>
+ * @author   credit to Gerard <gerard@interfold.com>
+ * @author   credit to Jason Sweat <jsweat_php@yahoo.com>
+ * @version  1.3
+ *
+ * @param array                    $params   parameters
+ * @param Smarty_Internal_Template $template template object
+ *
+ * @return string|null
+ */
+
+function smarty_function_cycle($params, $template)
+{
+    static $cycle_vars;
+
+    $name = (empty($params[ 'name' ])) ? 'default' : $params[ 'name' ];
+    $print = (isset($params[ 'print' ])) ? (bool) $params[ 'print' ] : true;
+    $advance = (isset($params[ 'advance' ])) ? (bool) $params[ 'advance' ] : true;
+    $reset = (isset($params[ 'reset' ])) ? (bool) $params[ 'reset' ] : false;
+
+    if (!isset($params[ 'values' ])) {
+        if (!isset($cycle_vars[ $name ][ 'values' ])) {
+            trigger_error("cycle: missing 'values' parameter");
+
+            return;
+        }
+    } else {
+        if (isset($cycle_vars[ $name ][ 'values' ]) && $cycle_vars[ $name ][ 'values' ] != $params[ 'values' ]) {
+            $cycle_vars[ $name ][ 'index' ] = 0;
+        }
+        $cycle_vars[ $name ][ 'values' ] = $params[ 'values' ];
+    }
+
+    if (isset($params[ 'delimiter' ])) {
+        $cycle_vars[ $name ][ 'delimiter' ] = $params[ 'delimiter' ];
+    } elseif (!isset($cycle_vars[ $name ][ 'delimiter' ])) {
+        $cycle_vars[ $name ][ 'delimiter' ] = ',';
+    }
+
+    if (is_array($cycle_vars[ $name ][ 'values' ])) {
+        $cycle_array = $cycle_vars[ $name ][ 'values' ];
+    } else {
+        $cycle_array = explode($cycle_vars[ $name ][ 'delimiter' ], $cycle_vars[ $name ][ 'values' ]);
+    }
+
+    if (!isset($cycle_vars[ $name ][ 'index' ]) || $reset) {
+        $cycle_vars[ $name ][ 'index' ] = 0;
+    }
+
+    if (isset($params[ 'assign' ])) {
+        $print = false;
+        $template->assign($params[ 'assign' ], $cycle_array[ $cycle_vars[ $name ][ 'index' ] ]);
+    }
+
+    if ($print) {
+        $retval = $cycle_array[ $cycle_vars[ $name ][ 'index' ] ];
+    } else {
+        $retval = null;
+    }
+
+    if ($advance) {
+        if ($cycle_vars[ $name ][ 'index' ] >= count($cycle_array) - 1) {
+            $cycle_vars[ $name ][ 'index' ] = 0;
+        } else {
+            $cycle_vars[ $name ][ 'index' ] ++;
+        }
+    }
+
+    return $retval;
+}

+ 221 - 0
Qii/View/smarty/plugins/function.fetch.php

@@ -0,0 +1,221 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * Smarty {fetch} plugin
+ * Type:     function<br>
+ * Name:     fetch<br>
+ * Purpose:  fetch file, web or ftp data and display results
+ *
+ * @link   http://www.smarty.net/manual/en/language.function.fetch.php {fetch}
+ *         (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ *
+ * @param array                    $params   parameters
+ * @param Smarty_Internal_Template $template template object
+ *
+ * @throws SmartyException
+ * @return string|null if the assign parameter is passed, Smarty assigns the result to a template variable
+ */
+function smarty_function_fetch($params, $template)
+{
+    if (empty($params[ 'file' ])) {
+        trigger_error("[plugin] fetch parameter 'file' cannot be empty", E_USER_NOTICE);
+
+        return;
+    }
+
+    // strip file protocol
+    if (stripos($params[ 'file' ], 'file://') === 0) {
+        $params[ 'file' ] = substr($params[ 'file' ], 7);
+    }
+
+    $protocol = strpos($params[ 'file' ], '://');
+    if ($protocol !== false) {
+        $protocol = strtolower(substr($params[ 'file' ], 0, $protocol));
+    }
+
+    if (isset($template->smarty->security_policy)) {
+        if ($protocol) {
+            // remote resource (or php stream, …)
+            if (!$template->smarty->security_policy->isTrustedUri($params[ 'file' ])) {
+                return;
+            }
+        } else {
+            // local file
+            if (!$template->smarty->security_policy->isTrustedResourceDir($params[ 'file' ])) {
+                return;
+            }
+        }
+    }
+
+    $content = '';
+    if ($protocol == 'http') {
+        // http fetch
+        if ($uri_parts = parse_url($params[ 'file' ])) {
+            // set defaults
+            $host = $server_name = $uri_parts[ 'host' ];
+            $timeout = 30;
+            $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*";
+            $agent = "Smarty Template Engine " . Smarty::SMARTY_VERSION;
+            $referer = "";
+            $uri = !empty($uri_parts[ 'path' ]) ? $uri_parts[ 'path' ] : '/';
+            $uri .= !empty($uri_parts[ 'query' ]) ? '?' . $uri_parts[ 'query' ] : '';
+            $_is_proxy = false;
+            if (empty($uri_parts[ 'port' ])) {
+                $port = 80;
+            } else {
+                $port = $uri_parts[ 'port' ];
+            }
+            if (!empty($uri_parts[ 'user' ])) {
+                $user = $uri_parts[ 'user' ];
+            }
+            if (!empty($uri_parts[ 'pass' ])) {
+                $pass = $uri_parts[ 'pass' ];
+            }
+            // loop through parameters, setup headers
+            foreach ($params as $param_key => $param_value) {
+                switch ($param_key) {
+                    case "file":
+                    case "assign":
+                    case "assign_headers":
+                        break;
+                    case "user":
+                        if (!empty($param_value)) {
+                            $user = $param_value;
+                        }
+                        break;
+                    case "pass":
+                        if (!empty($param_value)) {
+                            $pass = $param_value;
+                        }
+                        break;
+                    case "accept":
+                        if (!empty($param_value)) {
+                            $accept = $param_value;
+                        }
+                        break;
+                    case "header":
+                        if (!empty($param_value)) {
+                            if (!preg_match('![\w\d-]+: .+!', $param_value)) {
+                                trigger_error("[plugin] invalid header format '" . $param_value . "'", E_USER_NOTICE);
+
+                                return;
+                            } else {
+                                $extra_headers[] = $param_value;
+                            }
+                        }
+                        break;
+                    case "proxy_host":
+                        if (!empty($param_value)) {
+                            $proxy_host = $param_value;
+                        }
+                        break;
+                    case "proxy_port":
+                        if (!preg_match('!\D!', $param_value)) {
+                            $proxy_port = (int) $param_value;
+                        } else {
+                            trigger_error("[plugin] invalid value for attribute '" . $param_key . "'", E_USER_NOTICE);
+
+                            return;
+                        }
+                        break;
+                    case "agent":
+                        if (!empty($param_value)) {
+                            $agent = $param_value;
+                        }
+                        break;
+                    case "referer":
+                        if (!empty($param_value)) {
+                            $referer = $param_value;
+                        }
+                        break;
+                    case "timeout":
+                        if (!preg_match('!\D!', $param_value)) {
+                            $timeout = (int) $param_value;
+                        } else {
+                            trigger_error("[plugin] invalid value for attribute '" . $param_key . "'", E_USER_NOTICE);
+
+                            return;
+                        }
+                        break;
+                    default:
+                        trigger_error("[plugin] unrecognized attribute '" . $param_key . "'", E_USER_NOTICE);
+
+                        return;
+                }
+            }
+            if (!empty($proxy_host) && !empty($proxy_port)) {
+                $_is_proxy = true;
+                $fp = fsockopen($proxy_host, $proxy_port, $errno, $errstr, $timeout);
+            } else {
+                $fp = fsockopen($server_name, $port, $errno, $errstr, $timeout);
+            }
+
+            if (!$fp) {
+                trigger_error("[plugin] unable to fetch: $errstr ($errno)", E_USER_NOTICE);
+
+                return;
+            } else {
+                if ($_is_proxy) {
+                    fputs($fp, 'GET ' . $params[ 'file' ] . " HTTP/1.0\r\n");
+                } else {
+                    fputs($fp, "GET $uri HTTP/1.0\r\n");
+                }
+                if (!empty($host)) {
+                    fputs($fp, "Host: $host\r\n");
+                }
+                if (!empty($accept)) {
+                    fputs($fp, "Accept: $accept\r\n");
+                }
+                if (!empty($agent)) {
+                    fputs($fp, "User-Agent: $agent\r\n");
+                }
+                if (!empty($referer)) {
+                    fputs($fp, "Referer: $referer\r\n");
+                }
+                if (isset($extra_headers) && is_array($extra_headers)) {
+                    foreach ($extra_headers as $curr_header) {
+                        fputs($fp, $curr_header . "\r\n");
+                    }
+                }
+                if (!empty($user) && !empty($pass)) {
+                    fputs($fp, "Authorization: BASIC " . base64_encode("$user:$pass") . "\r\n");
+                }
+
+                fputs($fp, "\r\n");
+                while (!feof($fp)) {
+                    $content .= fgets($fp, 4096);
+                }
+                fclose($fp);
+                $csplit = preg_split("!\r\n\r\n!", $content, 2);
+
+                $content = $csplit[ 1 ];
+
+                if (!empty($params[ 'assign_headers' ])) {
+                    $template->assign($params[ 'assign_headers' ], preg_split("!\r\n!", $csplit[ 0 ]));
+                }
+            }
+        } else {
+            trigger_error("[plugin fetch] unable to parse URL, check syntax", E_USER_NOTICE);
+
+            return;
+        }
+    } else {
+        $content = @file_get_contents($params[ 'file' ]);
+        if ($content === false) {
+            throw new SmartyException("{fetch} cannot read resource '" . $params[ 'file' ] . "'");
+        }
+    }
+
+    if (!empty($params[ 'assign' ])) {
+        $template->assign($params[ 'assign' ], $content);
+    } else {
+        return $content;
+    }
+}

+ 249 - 0
Qii/View/smarty/plugins/function.html_checkboxes.php

@@ -0,0 +1,249 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * Smarty {html_checkboxes} function plugin
+ * File:       function.html_checkboxes.php<br>
+ * Type:       function<br>
+ * Name:       html_checkboxes<br>
+ * Date:       24.Feb.2003<br>
+ * Purpose:    Prints out a list of checkbox input types<br>
+ * Examples:
+ * <pre>
+ * {html_checkboxes values=$ids output=$names}
+ * {html_checkboxes values=$ids name='box' separator='<br>' output=$names}
+ * {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names}
+ * </pre>
+ * Params:
+ * <pre>
+ * - name       (optional) - string default "checkbox"
+ * - values     (required) - array
+ * - options    (optional) - associative array
+ * - checked    (optional) - array default not set
+ * - separator  (optional) - ie <br> or &nbsp;
+ * - output     (optional) - the output next to each checkbox
+ * - assign     (optional) - assign the output as an array to this variable
+ * - escape     (optional) - escape the content (not value), defaults to true
+ * </pre>
+ *
+ * @link       http://www.smarty.net/manual/en/language.function.html.checkboxes.php {html_checkboxes}
+ *             (Smarty online manual)
+ * @author     Christopher Kvarme <christopher.kvarme@flashjab.com>
+ * @author     credits to Monte Ohrt <monte at ohrt dot com>
+ * @version    1.0
+ *
+ * @param array  $params   parameters
+ * @param object $template template object
+ *
+ * @return string
+ * @uses       smarty_function_escape_special_chars()
+ */
+function smarty_function_html_checkboxes($params, $template)
+{
+    require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
+
+    $name = 'checkbox';
+    $values = null;
+    $options = null;
+    $selected = array();
+    $separator = '';
+    $escape = true;
+    $labels = true;
+    $label_ids = false;
+    $output = null;
+
+    $extra = '';
+
+    foreach ($params as $_key => $_val) {
+        switch ($_key) {
+            case 'name':
+            case 'separator':
+                $$_key = (string) $_val;
+                break;
+
+            case 'escape':
+            case 'labels':
+            case 'label_ids':
+                $$_key = (bool) $_val;
+                break;
+
+            case 'options':
+                $$_key = (array) $_val;
+                break;
+
+            case 'values':
+            case 'output':
+                $$_key = array_values((array) $_val);
+                break;
+
+            case 'checked':
+            case 'selected':
+                if (is_array($_val)) {
+                    $selected = array();
+                    foreach ($_val as $_sel) {
+                        if (is_object($_sel)) {
+                            if (method_exists($_sel, "__toString")) {
+                                $_sel = smarty_function_escape_special_chars((string) $_sel->__toString());
+                            } else {
+                                trigger_error("html_checkboxes: selected attribute contains an object of class '" .
+                                              get_class($_sel) . "' without __toString() method", E_USER_NOTICE);
+                                continue;
+                            }
+                        } else {
+                            $_sel = smarty_function_escape_special_chars((string) $_sel);
+                        }
+                        $selected[ $_sel ] = true;
+                    }
+                } elseif (is_object($_val)) {
+                    if (method_exists($_val, "__toString")) {
+                        $selected = smarty_function_escape_special_chars((string) $_val->__toString());
+                    } else {
+                        trigger_error("html_checkboxes: selected attribute is an object of class '" . get_class($_val) .
+                                      "' without __toString() method", E_USER_NOTICE);
+                    }
+                } else {
+                    $selected = smarty_function_escape_special_chars((string) $_val);
+                }
+                break;
+
+            case 'checkboxes':
+                trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead',
+                              E_USER_WARNING);
+                $options = (array) $_val;
+                break;
+
+            case 'assign':
+                break;
+
+            case 'strict':
+                break;
+
+            case 'disabled':
+            case 'readonly':
+                if (!empty($params[ 'strict' ])) {
+                    if (!is_scalar($_val)) {
+                        trigger_error("html_options: $_key attribute must be a scalar, only boolean true or string '$_key' will actually add the attribute",
+                                      E_USER_NOTICE);
+                    }
+
+                    if ($_val === true || $_val === $_key) {
+                        $extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_key) . '"';
+                    }
+
+                    break;
+                }
+            // omit break; to fall through!
+
+            default:
+                if (!is_array($_val)) {
+                    $extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
+                } else {
+                    trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+        }
+    }
+
+    if (!isset($options) && !isset($values)) {
+        return '';
+    } /* raise error here? */
+
+    $_html_result = array();
+
+    if (isset($options)) {
+        foreach ($options as $_key => $_val) {
+            $_html_result[] =
+                smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels,
+                                                       $label_ids, $escape);
+        }
+    } else {
+        foreach ($values as $_i => $_key) {
+            $_val = isset($output[ $_i ]) ? $output[ $_i ] : '';
+            $_html_result[] =
+                smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels,
+                                                       $label_ids, $escape);
+        }
+    }
+
+    if (!empty($params[ 'assign' ])) {
+        $template->assign($params[ 'assign' ], $_html_result);
+    } else {
+        return implode("\n", $_html_result);
+    }
+}
+
+function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels,
+                                                $label_ids, $escape = true)
+{
+    $_output = '';
+
+    if (is_object($value)) {
+        if (method_exists($value, "__toString")) {
+            $value = (string) $value->__toString();
+        } else {
+            trigger_error("html_options: value is an object of class '" . get_class($value) .
+                          "' without __toString() method", E_USER_NOTICE);
+
+            return '';
+        }
+    } else {
+        $value = (string) $value;
+    }
+
+    if (is_object($output)) {
+        if (method_exists($output, "__toString")) {
+            $output = (string) $output->__toString();
+        } else {
+            trigger_error("html_options: output is an object of class '" . get_class($output) .
+                          "' without __toString() method", E_USER_NOTICE);
+
+            return '';
+        }
+    } else {
+        $output = (string) $output;
+    }
+
+    if ($labels) {
+        if ($label_ids) {
+            $_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!' . Smarty::$_UTF8_MODIFIER, '_',
+                                                                     $name . '_' . $value));
+            $_output .= '<label for="' . $_id . '">';
+        } else {
+            $_output .= '<label>';
+        }
+    }
+
+    $name = smarty_function_escape_special_chars($name);
+    $value = smarty_function_escape_special_chars($value);
+    if ($escape) {
+        $output = smarty_function_escape_special_chars($output);
+    }
+
+    $_output .= '<input type="checkbox" name="' . $name . '[]" value="' . $value . '"';
+
+    if ($labels && $label_ids) {
+        $_output .= ' id="' . $_id . '"';
+    }
+
+    if (is_array($selected)) {
+        if (isset($selected[ $value ])) {
+            $_output .= ' checked="checked"';
+        }
+    } elseif ($value === $selected) {
+        $_output .= ' checked="checked"';
+    }
+
+    $_output .= $extra . ' />' . $output;
+    if ($labels) {
+        $_output .= '</label>';
+    }
+
+    $_output .= $separator;
+
+    return $_output;
+}

+ 164 - 0
Qii/View/smarty/plugins/function.html_image.php

@@ -0,0 +1,164 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * Smarty {html_image} function plugin
+ * Type:     function<br>
+ * Name:     html_image<br>
+ * Date:     Feb 24, 2003<br>
+ * Purpose:  format HTML tags for the image<br>
+ * Examples: {html_image file="/images/masthead.gif"}<br>
+ * Output:   <img src="/images/masthead.gif" width=400 height=23><br>
+ * Params:
+ * <pre>
+ * - file        - (required) - file (and path) of image
+ * - height      - (optional) - image height (default actual height)
+ * - width       - (optional) - image width (default actual width)
+ * - basedir     - (optional) - base directory for absolute paths, default is environment variable DOCUMENT_ROOT
+ * - path_prefix - prefix for path output (optional, default empty)
+ * </pre>
+ *
+ * @link    http://www.smarty.net/manual/en/language.function.html.image.php {html_image}
+ *          (Smarty online manual)
+ * @author  Monte Ohrt <monte at ohrt dot com>
+ * @author  credits to Duda <duda@big.hu>
+ * @version 1.0
+ *
+ * @param array                    $params   parameters
+ * @param Smarty_Internal_Template $template template object
+ *
+ * @throws SmartyException
+ * @return string
+ * @uses    smarty_function_escape_special_chars()
+ */
+function smarty_function_html_image($params, $template)
+{
+    require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
+
+    $alt = '';
+    $file = '';
+    $height = '';
+    $width = '';
+    $extra = '';
+    $prefix = '';
+    $suffix = '';
+    $path_prefix = '';
+    $basedir = isset($_SERVER[ 'DOCUMENT_ROOT' ]) ? $_SERVER[ 'DOCUMENT_ROOT' ] : '';
+    foreach ($params as $_key => $_val) {
+        switch ($_key) {
+            case 'file':
+            case 'height':
+            case 'width':
+            case 'dpi':
+            case 'path_prefix':
+            case 'basedir':
+                $$_key = $_val;
+                break;
+
+            case 'alt':
+                if (!is_array($_val)) {
+                    $$_key = smarty_function_escape_special_chars($_val);
+                } else {
+                    throw new SmartyException ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+
+            case 'link':
+            case 'href':
+                $prefix = '<a href="' . $_val . '">';
+                $suffix = '</a>';
+                break;
+
+            default:
+                if (!is_array($_val)) {
+                    $extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
+                } else {
+                    throw new SmartyException ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+        }
+    }
+
+    if (empty($file)) {
+        trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE);
+
+        return;
+    }
+
+    if ($file[ 0 ] == '/') {
+        $_image_path = $basedir . $file;
+    } else {
+        $_image_path = $file;
+    }
+
+    // strip file protocol
+    if (stripos($params[ 'file' ], 'file://') === 0) {
+        $params[ 'file' ] = substr($params[ 'file' ], 7);
+    }
+
+    $protocol = strpos($params[ 'file' ], '://');
+    if ($protocol !== false) {
+        $protocol = strtolower(substr($params[ 'file' ], 0, $protocol));
+    }
+
+    if (isset($template->smarty->security_policy)) {
+        if ($protocol) {
+            // remote resource (or php stream, …)
+            if (!$template->smarty->security_policy->isTrustedUri($params[ 'file' ])) {
+                return;
+            }
+        } else {
+            // local file
+            if (!$template->smarty->security_policy->isTrustedResourceDir($_image_path)) {
+                return;
+            }
+        }
+    }
+
+    if (!isset($params[ 'width' ]) || !isset($params[ 'height' ])) {
+        // FIXME: (rodneyrehm) getimagesize() loads the complete file off a remote resource, use custom [jpg,png,gif]header reader!
+        if (!$_image_data = @getimagesize($_image_path)) {
+            if (!file_exists($_image_path)) {
+                trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE);
+
+                return;
+            } elseif (!is_readable($_image_path)) {
+                trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE);
+
+                return;
+            } else {
+                trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE);
+
+                return;
+            }
+        }
+
+        if (!isset($params[ 'width' ])) {
+            $width = $_image_data[ 0 ];
+        }
+        if (!isset($params[ 'height' ])) {
+            $height = $_image_data[ 1 ];
+        }
+    }
+
+    if (isset($params[ 'dpi' ])) {
+        if (strstr($_SERVER[ 'HTTP_USER_AGENT' ], 'Mac')) {
+            // FIXME: (rodneyrehm) wrong dpi assumption
+            // don't know who thought this up… even if it was true in 1998, it's definitely wrong in 2011.
+            $dpi_default = 72;
+        } else {
+            $dpi_default = 96;
+        }
+        $_resize = $dpi_default / $params[ 'dpi' ];
+        $width = round($width * $_resize);
+        $height = round($height * $_resize);
+    }
+
+    return $prefix . '<img src="' . $path_prefix . $file . '" alt="' . $alt . '" width="' . $width . '" height="' .
+           $height . '"' . $extra . ' />' . $suffix;
+}

+ 204 - 0
Qii/View/smarty/plugins/function.html_options.php

@@ -0,0 +1,204 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * Smarty {html_options} function plugin
+ * Type:     function<br>
+ * Name:     html_options<br>
+ * Purpose:  Prints the list of <option> tags generated from
+ *           the passed parameters<br>
+ * Params:
+ * <pre>
+ * - name       (optional) - string default "select"
+ * - values     (required) - if no options supplied) - array
+ * - options    (required) - if no values supplied) - associative array
+ * - selected   (optional) - string default not set
+ * - output     (required) - if not options supplied) - array
+ * - id         (optional) - string default not set
+ * - class      (optional) - string default not set
+ * </pre>
+ *
+ * @link     http://www.smarty.net/manual/en/language.function.html.options.php {html_image}
+ *           (Smarty online manual)
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @author   Ralf Strehle (minor optimization) <ralf dot strehle at yahoo dot de>
+ *
+ * @param array $params parameters
+ *
+ * @return string
+ * @uses     smarty_function_escape_special_chars()
+ */
+function smarty_function_html_options($params)
+{
+    require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
+
+    $name = null;
+    $values = null;
+    $options = null;
+    $selected = null;
+    $output = null;
+    $id = null;
+    $class = null;
+
+    $extra = '';
+
+    foreach ($params as $_key => $_val) {
+        switch ($_key) {
+            case 'name':
+            case 'class':
+            case 'id':
+                $$_key = (string) $_val;
+                break;
+
+            case 'options':
+                $options = (array) $_val;
+                break;
+
+            case 'values':
+            case 'output':
+                $$_key = array_values((array) $_val);
+                break;
+
+            case 'selected':
+                if (is_array($_val)) {
+                    $selected = array();
+                    foreach ($_val as $_sel) {
+                        if (is_object($_sel)) {
+                            if (method_exists($_sel, "__toString")) {
+                                $_sel = smarty_function_escape_special_chars((string) $_sel->__toString());
+                            } else {
+                                trigger_error("html_options: selected attribute contains an object of class '" .
+                                              get_class($_sel) . "' without __toString() method", E_USER_NOTICE);
+                                continue;
+                            }
+                        } else {
+                            $_sel = smarty_function_escape_special_chars((string) $_sel);
+                        }
+                        $selected[ $_sel ] = true;
+                    }
+                } elseif (is_object($_val)) {
+                    if (method_exists($_val, "__toString")) {
+                        $selected = smarty_function_escape_special_chars((string) $_val->__toString());
+                    } else {
+                        trigger_error("html_options: selected attribute is an object of class '" . get_class($_val) .
+                                      "' without __toString() method", E_USER_NOTICE);
+                    }
+                } else {
+                    $selected = smarty_function_escape_special_chars((string) $_val);
+                }
+                break;
+
+            case 'strict':
+                break;
+
+            case 'disabled':
+            case 'readonly':
+                if (!empty($params[ 'strict' ])) {
+                    if (!is_scalar($_val)) {
+                        trigger_error("html_options: $_key attribute must be a scalar, only boolean true or string '$_key' will actually add the attribute",
+                                      E_USER_NOTICE);
+                    }
+
+                    if ($_val === true || $_val === $_key) {
+                        $extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_key) . '"';
+                    }
+
+                    break;
+                }
+            // omit break; to fall through!
+
+            default:
+                if (!is_array($_val)) {
+                    $extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
+                } else {
+                    trigger_error("html_options: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+        }
+    }
+
+    if (!isset($options) && !isset($values)) {
+        /* raise error here? */
+
+        return '';
+    }
+
+    $_html_result = '';
+    $_idx = 0;
+
+    if (isset($options)) {
+        foreach ($options as $_key => $_val) {
+            $_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected, $id, $class, $_idx);
+        }
+    } else {
+        foreach ($values as $_i => $_key) {
+            $_val = isset($output[ $_i ]) ? $output[ $_i ] : '';
+            $_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected, $id, $class, $_idx);
+        }
+    }
+
+    if (!empty($name)) {
+        $_html_class = !empty($class) ? ' class="' . $class . '"' : '';
+        $_html_id = !empty($id) ? ' id="' . $id . '"' : '';
+        $_html_result =
+            '<select name="' . $name . '"' . $_html_class . $_html_id . $extra . '>' . "\n" . $_html_result .
+            '</select>' . "\n";
+    }
+
+    return $_html_result;
+}
+
+function smarty_function_html_options_optoutput($key, $value, $selected, $id, $class, &$idx)
+{
+    if (!is_array($value)) {
+        $_key = smarty_function_escape_special_chars($key);
+        $_html_result = '<option value="' . $_key . '"';
+        if (is_array($selected)) {
+            if (isset($selected[ $_key ])) {
+                $_html_result .= ' selected="selected"';
+            }
+        } elseif ($_key === $selected) {
+            $_html_result .= ' selected="selected"';
+        }
+        $_html_class = !empty($class) ? ' class="' . $class . ' option"' : '';
+        $_html_id = !empty($id) ? ' id="' . $id . '-' . $idx . '"' : '';
+        if (is_object($value)) {
+            if (method_exists($value, "__toString")) {
+                $value = smarty_function_escape_special_chars((string) $value->__toString());
+            } else {
+                trigger_error("html_options: value is an object of class '" . get_class($value) .
+                              "' without __toString() method", E_USER_NOTICE);
+
+                return '';
+            }
+        } else {
+            $value = smarty_function_escape_special_chars((string) $value);
+        }
+        $_html_result .= $_html_class . $_html_id . '>' . $value . '</option>' . "\n";
+        $idx ++;
+    } else {
+        $_idx = 0;
+        $_html_result =
+            smarty_function_html_options_optgroup($key, $value, $selected, !empty($id) ? ($id . '-' . $idx) : null,
+                                                  $class, $_idx);
+        $idx ++;
+    }
+
+    return $_html_result;
+}
+
+function smarty_function_html_options_optgroup($key, $values, $selected, $id, $class, &$idx)
+{
+    $optgroup_html = '<optgroup label="' . smarty_function_escape_special_chars($key) . '">' . "\n";
+    foreach ($values as $key => $value) {
+        $optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected, $id, $class, $idx);
+    }
+    $optgroup_html .= "</optgroup>\n";
+
+    return $optgroup_html;
+}

+ 232 - 0
Qii/View/smarty/plugins/function.html_radios.php

@@ -0,0 +1,232 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * Smarty {html_radios} function plugin
+ * File:       function.html_radios.php<br>
+ * Type:       function<br>
+ * Name:       html_radios<br>
+ * Date:       24.Feb.2003<br>
+ * Purpose:    Prints out a list of radio input types<br>
+ * Params:
+ * <pre>
+ * - name       (optional) - string default "radio"
+ * - values     (required) - array
+ * - options    (required) - associative array
+ * - checked    (optional) - array default not set
+ * - separator  (optional) - ie <br> or &nbsp;
+ * - output     (optional) - the output next to each radio button
+ * - assign     (optional) - assign the output as an array to this variable
+ * - escape     (optional) - escape the content (not value), defaults to true
+ * </pre>
+ * Examples:
+ * <pre>
+ * {html_radios values=$ids output=$names}
+ * {html_radios values=$ids name='box' separator='<br>' output=$names}
+ * {html_radios values=$ids checked=$checked separator='<br>' output=$names}
+ * </pre>
+ *
+ * @link    http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios}
+ *          (Smarty online manual)
+ * @author  Christopher Kvarme <christopher.kvarme@flashjab.com>
+ * @author  credits to Monte Ohrt <monte at ohrt dot com>
+ * @version 1.0
+ *
+ * @param array                    $params   parameters
+ * @param Smarty_Internal_Template $template template object
+ *
+ * @return string
+ * @uses    smarty_function_escape_special_chars()
+ */
+function smarty_function_html_radios($params, $template)
+{
+    require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
+
+    $name = 'radio';
+    $values = null;
+    $options = null;
+    $selected = null;
+    $separator = '';
+    $escape = true;
+    $labels = true;
+    $label_ids = false;
+    $output = null;
+    $extra = '';
+
+    foreach ($params as $_key => $_val) {
+        switch ($_key) {
+            case 'name':
+            case 'separator':
+                $$_key = (string) $_val;
+                break;
+
+            case 'checked':
+            case 'selected':
+                if (is_array($_val)) {
+                    trigger_error('html_radios: the "' . $_key . '" attribute cannot be an array', E_USER_WARNING);
+                } elseif (is_object($_val)) {
+                    if (method_exists($_val, "__toString")) {
+                        $selected = smarty_function_escape_special_chars((string) $_val->__toString());
+                    } else {
+                        trigger_error("html_radios: selected attribute is an object of class '" . get_class($_val) .
+                                      "' without __toString() method", E_USER_NOTICE);
+                    }
+                } else {
+                    $selected = (string) $_val;
+                }
+                break;
+
+            case 'escape':
+            case 'labels':
+            case 'label_ids':
+                $$_key = (bool) $_val;
+                break;
+
+            case 'options':
+                $$_key = (array) $_val;
+                break;
+
+            case 'values':
+            case 'output':
+                $$_key = array_values((array) $_val);
+                break;
+
+            case 'radios':
+                trigger_error('html_radios: the use of the "radios" attribute is deprecated, use "options" instead',
+                              E_USER_WARNING);
+                $options = (array) $_val;
+                break;
+
+            case 'assign':
+                break;
+
+            case 'strict':
+                break;
+
+            case 'disabled':
+            case 'readonly':
+                if (!empty($params[ 'strict' ])) {
+                    if (!is_scalar($_val)) {
+                        trigger_error("html_options: $_key attribute must be a scalar, only boolean true or string '$_key' will actually add the attribute",
+                                      E_USER_NOTICE);
+                    }
+
+                    if ($_val === true || $_val === $_key) {
+                        $extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_key) . '"';
+                    }
+
+                    break;
+                }
+            // omit break; to fall through!
+
+            default:
+                if (!is_array($_val)) {
+                    $extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
+                } else {
+                    trigger_error("html_radios: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+        }
+    }
+
+    if (!isset($options) && !isset($values)) {
+        /* raise error here? */
+
+        return '';
+    }
+
+    $_html_result = array();
+
+    if (isset($options)) {
+        foreach ($options as $_key => $_val) {
+            $_html_result[] =
+                smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels,
+                                                   $label_ids, $escape);
+        }
+    } else {
+        foreach ($values as $_i => $_key) {
+            $_val = isset($output[ $_i ]) ? $output[ $_i ] : '';
+            $_html_result[] =
+                smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels,
+                                                   $label_ids, $escape);
+        }
+    }
+
+    if (!empty($params[ 'assign' ])) {
+        $template->assign($params[ 'assign' ], $_html_result);
+    } else {
+        return implode("\n", $_html_result);
+    }
+}
+
+function smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels, $label_ids,
+                                            $escape)
+{
+    $_output = '';
+
+    if (is_object($value)) {
+        if (method_exists($value, "__toString")) {
+            $value = (string) $value->__toString();
+        } else {
+            trigger_error("html_options: value is an object of class '" . get_class($value) .
+                          "' without __toString() method", E_USER_NOTICE);
+
+            return '';
+        }
+    } else {
+        $value = (string) $value;
+    }
+
+    if (is_object($output)) {
+        if (method_exists($output, "__toString")) {
+            $output = (string) $output->__toString();
+        } else {
+            trigger_error("html_options: output is an object of class '" . get_class($output) .
+                          "' without __toString() method", E_USER_NOTICE);
+
+            return '';
+        }
+    } else {
+        $output = (string) $output;
+    }
+
+    if ($labels) {
+        if ($label_ids) {
+            $_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!' . Smarty::$_UTF8_MODIFIER, '_',
+                                                                     $name . '_' . $value));
+            $_output .= '<label for="' . $_id . '">';
+        } else {
+            $_output .= '<label>';
+        }
+    }
+
+    $name = smarty_function_escape_special_chars($name);
+    $value = smarty_function_escape_special_chars($value);
+    if ($escape) {
+        $output = smarty_function_escape_special_chars($output);
+    }
+
+    $_output .= '<input type="radio" name="' . $name . '" value="' . $value . '"';
+
+    if ($labels && $label_ids) {
+        $_output .= ' id="' . $_id . '"';
+    }
+
+    if ($value === $selected) {
+        $_output .= ' checked="checked"';
+    }
+
+    $_output .= $extra . ' />' . $output;
+    if ($labels) {
+        $_output .= '</label>';
+    }
+
+    $_output .= $separator;
+
+    return $_output;
+}

+ 391 - 0
Qii/View/smarty/plugins/function.html_select_date.php

@@ -0,0 +1,391 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * @ignore
+ */
+require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
+/**
+ * @ignore
+ */
+require_once(SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php');
+
+/**
+ * Smarty {html_select_date} plugin
+ * Type:     function<br>
+ * Name:     html_select_date<br>
+ * Purpose:  Prints the dropdowns for date selection.
+ * ChangeLog:
+ * <pre>
+ *            - 1.0 initial release
+ *            - 1.1 added support for +/- N syntax for begin
+ *              and end year values. (Monte)
+ *            - 1.2 added support for yyyy-mm-dd syntax for
+ *              time value. (Jan Rosier)
+ *            - 1.3 added support for choosing format for
+ *              month values (Gary Loescher)
+ *            - 1.3.1 added support for choosing format for
+ *              day values (Marcus Bointon)
+ *            - 1.3.2 support negative timestamps, force year
+ *              dropdown to include given date unless explicitly set (Monte)
+ *            - 1.3.4 fix behaviour of 0000-00-00 00:00:00 dates to match that
+ *              of 0000-00-00 dates (cybot, boots)
+ *            - 2.0 complete rewrite for performance,
+ *              added attributes month_names, *_id
+ * </pre>
+ *
+ * @link     http://www.smarty.net/manual/en/language.function.html.select.date.php {html_select_date}
+ *           (Smarty online manual)
+ * @version  2.0
+ * @author   Andrei Zmievski
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @author   Rodney Rehm
+ *
+ * @param array $params parameters
+ *
+ * @return string
+ */
+function smarty_function_html_select_date($params)
+{
+    // generate timestamps used for month names only
+    static $_month_timestamps = null;
+    static $_current_year = null;
+    if ($_month_timestamps === null) {
+        $_current_year = date('Y');
+        $_month_timestamps = array();
+        for ($i = 1; $i <= 12; $i ++) {
+            $_month_timestamps[ $i ] = mktime(0, 0, 0, $i, 1, 2000);
+        }
+    }
+
+    /* Default values. */
+    $prefix = "Date_";
+    $start_year = null;
+    $end_year = null;
+    $display_days = true;
+    $display_months = true;
+    $display_years = true;
+    $month_format = "%B";
+    /* Write months as numbers by default  GL */
+    $month_value_format = "%m";
+    $day_format = "%02d";
+    /* Write day values using this format MB */
+    $day_value_format = "%d";
+    $year_as_text = false;
+    /* Display years in reverse order? Ie. 2000,1999,.... */
+    $reverse_years = false;
+    /* Should the select boxes be part of an array when returned from PHP?
+       e.g. setting it to "birthday", would create "birthday[Day]",
+       "birthday[Month]" & "birthday[Year]". Can be combined with prefix */
+    $field_array = null;
+    /* <select size>'s of the different <select> tags.
+       If not set, uses default dropdown. */
+    $day_size = null;
+    $month_size = null;
+    $year_size = null;
+    /* Unparsed attributes common to *ALL* the <select>/<input> tags.
+       An example might be in the template: all_extra ='class ="foo"'. */
+    $all_extra = null;
+    /* Separate attributes for the tags. */
+    $day_extra = null;
+    $month_extra = null;
+    $year_extra = null;
+    /* Order in which to display the fields.
+       "D" -> day, "M" -> month, "Y" -> year. */
+    $field_order = 'MDY';
+    /* String printed between the different fields. */
+    $field_separator = "\n";
+    $option_separator = "\n";
+    $time = null;
+    // $all_empty = null;
+    // $day_empty = null;
+    // $month_empty = null;
+    // $year_empty = null;
+    $extra_attrs = '';
+    $all_id = null;
+    $day_id = null;
+    $month_id = null;
+    $year_id = null;
+
+    foreach ($params as $_key => $_value) {
+        switch ($_key) {
+            case 'time':
+                if (!is_array($_value) && $_value !== null) {
+                    $time = smarty_make_timestamp($_value);
+                }
+                break;
+
+            case 'month_names':
+                if (is_array($_value) && count($_value) == 12) {
+                    $$_key = $_value;
+                } else {
+                    trigger_error("html_select_date: month_names must be an array of 12 strings", E_USER_NOTICE);
+                }
+                break;
+
+            case 'prefix':
+            case 'field_array':
+            case 'start_year':
+            case 'end_year':
+            case 'day_format':
+            case 'day_value_format':
+            case 'month_format':
+            case 'month_value_format':
+            case 'day_size':
+            case 'month_size':
+            case 'year_size':
+            case 'all_extra':
+            case 'day_extra':
+            case 'month_extra':
+            case 'year_extra':
+            case 'field_order':
+            case 'field_separator':
+            case 'option_separator':
+            case 'all_empty':
+            case 'month_empty':
+            case 'day_empty':
+            case 'year_empty':
+            case 'all_id':
+            case 'month_id':
+            case 'day_id':
+            case 'year_id':
+                $$_key = (string) $_value;
+                break;
+
+            case 'display_days':
+            case 'display_months':
+            case 'display_years':
+            case 'year_as_text':
+            case 'reverse_years':
+                $$_key = (bool) $_value;
+                break;
+
+            default:
+                if (!is_array($_value)) {
+                    $extra_attrs .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_value) . '"';
+                } else {
+                    trigger_error("html_select_date: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+        }
+    }
+
+    // Note: date() is faster than strftime()
+    // Note: explode(date()) is faster than date() date() date()
+    if (isset($params[ 'time' ]) && is_array($params[ 'time' ])) {
+        if (isset($params[ 'time' ][ $prefix . 'Year' ])) {
+            // $_REQUEST[$field_array] given
+            foreach (array('Y' => 'Year', 'm' => 'Month', 'd' => 'Day') as $_elementKey => $_elementName) {
+                $_variableName = '_' . strtolower($_elementName);
+                $$_variableName =
+                    isset($params[ 'time' ][ $prefix . $_elementName ]) ? $params[ 'time' ][ $prefix . $_elementName ] :
+                        date($_elementKey);
+            }
+        } elseif (isset($params[ 'time' ][ $field_array ][ $prefix . 'Year' ])) {
+            // $_REQUEST given
+            foreach (array('Y' => 'Year', 'm' => 'Month', 'd' => 'Day') as $_elementKey => $_elementName) {
+                $_variableName = '_' . strtolower($_elementName);
+                $$_variableName = isset($params[ 'time' ][ $field_array ][ $prefix . $_elementName ]) ?
+                    $params[ 'time' ][ $field_array ][ $prefix . $_elementName ] : date($_elementKey);
+            }
+        } else {
+            // no date found, use NOW
+            list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d'));
+        }
+    } elseif ($time === null) {
+        if (array_key_exists('time', $params)) {
+            $_year = $_month = $_day = $time = null;
+        } else {
+            list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d'));
+        }
+    } else {
+        list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d', $time));
+    }
+
+    // make syntax "+N" or "-N" work with $start_year and $end_year
+    // Note preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match) is slower than trim+substr
+    foreach (array('start', 'end') as $key) {
+        $key .= '_year';
+        $t = $$key;
+        if ($t === null) {
+            $$key = (int) $_current_year;
+        } elseif ($t[ 0 ] == '+') {
+            $$key = (int) ($_current_year + (int) trim(substr($t, 1)));
+        } elseif ($t[ 0 ] == '-') {
+            $$key = (int) ($_current_year - (int) trim(substr($t, 1)));
+        } else {
+            $$key = (int) $$key;
+        }
+    }
+
+    // flip for ascending or descending
+    if (($start_year > $end_year && !$reverse_years) || ($start_year < $end_year && $reverse_years)) {
+        $t = $end_year;
+        $end_year = $start_year;
+        $start_year = $t;
+    }
+
+    // generate year <select> or <input>
+    if ($display_years) {
+        $_extra = '';
+        $_name = $field_array ? ($field_array . '[' . $prefix . 'Year]') : ($prefix . 'Year');
+        if ($all_extra) {
+            $_extra .= ' ' . $all_extra;
+        }
+        if ($year_extra) {
+            $_extra .= ' ' . $year_extra;
+        }
+
+        if ($year_as_text) {
+            $_html_years =
+                '<input type="text" name="' . $_name . '" value="' . $_year . '" size="4" maxlength="4"' . $_extra .
+                $extra_attrs . ' />';
+        } else {
+            $_html_years = '<select name="' . $_name . '"';
+            if ($year_id !== null || $all_id !== null) {
+                $_html_years .= ' id="' . smarty_function_escape_special_chars($year_id !== null ?
+                                                                                   ($year_id ? $year_id : $_name) :
+                                                                                   ($all_id ? ($all_id . $_name) :
+                                                                                       $_name)) . '"';
+            }
+            if ($year_size) {
+                $_html_years .= ' size="' . $year_size . '"';
+            }
+            $_html_years .= $_extra . $extra_attrs . '>' . $option_separator;
+
+            if (isset($year_empty) || isset($all_empty)) {
+                $_html_years .= '<option value="">' . (isset($year_empty) ? $year_empty : $all_empty) . '</option>' .
+                                $option_separator;
+            }
+
+            $op = $start_year > $end_year ? - 1 : 1;
+            for ($i = $start_year; $op > 0 ? $i <= $end_year : $i >= $end_year; $i += $op) {
+                $_html_years .= '<option value="' . $i . '"' . ($_year == $i ? ' selected="selected"' : '') . '>' . $i .
+                                '</option>' . $option_separator;
+            }
+
+            $_html_years .= '</select>';
+        }
+    }
+
+    // generate month <select> or <input>
+    if ($display_months) {
+        $_extra = '';
+        $_name = $field_array ? ($field_array . '[' . $prefix . 'Month]') : ($prefix . 'Month');
+        if ($all_extra) {
+            $_extra .= ' ' . $all_extra;
+        }
+        if ($month_extra) {
+            $_extra .= ' ' . $month_extra;
+        }
+
+        $_html_months = '<select name="' . $_name . '"';
+        if ($month_id !== null || $all_id !== null) {
+            $_html_months .= ' id="' . smarty_function_escape_special_chars($month_id !== null ?
+                                                                                ($month_id ? $month_id : $_name) :
+                                                                                ($all_id ? ($all_id . $_name) :
+                                                                                    $_name)) . '"';
+        }
+        if ($month_size) {
+            $_html_months .= ' size="' . $month_size . '"';
+        }
+        $_html_months .= $_extra . $extra_attrs . '>' . $option_separator;
+
+        if (isset($month_empty) || isset($all_empty)) {
+            $_html_months .= '<option value="">' . (isset($month_empty) ? $month_empty : $all_empty) . '</option>' .
+                             $option_separator;
+        }
+
+        for ($i = 1; $i <= 12; $i ++) {
+            $_val = sprintf('%02d', $i);
+            $_text = isset($month_names) ? smarty_function_escape_special_chars($month_names[ $i ]) :
+                ($month_format == "%m" ? $_val : strftime($month_format, $_month_timestamps[ $i ]));
+            $_value = $month_value_format == "%m" ? $_val : strftime($month_value_format, $_month_timestamps[ $i ]);
+            $_html_months .= '<option value="' . $_value . '"' . ($_val == $_month ? ' selected="selected"' : '') .
+                             '>' . $_text . '</option>' . $option_separator;
+        }
+
+        $_html_months .= '</select>';
+    }
+
+    // generate day <select> or <input>
+    if ($display_days) {
+        $_extra = '';
+        $_name = $field_array ? ($field_array . '[' . $prefix . 'Day]') : ($prefix . 'Day');
+        if ($all_extra) {
+            $_extra .= ' ' . $all_extra;
+        }
+        if ($day_extra) {
+            $_extra .= ' ' . $day_extra;
+        }
+
+        $_html_days = '<select name="' . $_name . '"';
+        if ($day_id !== null || $all_id !== null) {
+            $_html_days .= ' id="' .
+                           smarty_function_escape_special_chars($day_id !== null ? ($day_id ? $day_id : $_name) :
+                                                                    ($all_id ? ($all_id . $_name) : $_name)) . '"';
+        }
+        if ($day_size) {
+            $_html_days .= ' size="' . $day_size . '"';
+        }
+        $_html_days .= $_extra . $extra_attrs . '>' . $option_separator;
+
+        if (isset($day_empty) || isset($all_empty)) {
+            $_html_days .= '<option value="">' . (isset($day_empty) ? $day_empty : $all_empty) . '</option>' .
+                           $option_separator;
+        }
+
+        for ($i = 1; $i <= 31; $i ++) {
+            $_val = sprintf('%02d', $i);
+            $_text = $day_format == '%02d' ? $_val : sprintf($day_format, $i);
+            $_value = $day_value_format == '%02d' ? $_val : sprintf($day_value_format, $i);
+            $_html_days .= '<option value="' . $_value . '"' . ($_val == $_day ? ' selected="selected"' : '') . '>' .
+                           $_text . '</option>' . $option_separator;
+        }
+
+        $_html_days .= '</select>';
+    }
+
+    // order the fields for output
+    $_html = '';
+    for ($i = 0; $i <= 2; $i ++) {
+        switch ($field_order[ $i ]) {
+            case 'Y':
+            case 'y':
+                if (isset($_html_years)) {
+                    if ($_html) {
+                        $_html .= $field_separator;
+                    }
+                    $_html .= $_html_years;
+                }
+                break;
+
+            case 'm':
+            case 'M':
+                if (isset($_html_months)) {
+                    if ($_html) {
+                        $_html .= $field_separator;
+                    }
+                    $_html .= $_html_months;
+                }
+                break;
+
+            case 'd':
+            case 'D':
+                if (isset($_html_days)) {
+                    if ($_html) {
+                        $_html .= $field_separator;
+                    }
+                    $_html .= $_html_days;
+                }
+                break;
+        }
+    }
+
+    return $_html;
+}

+ 366 - 0
Qii/View/smarty/plugins/function.html_select_time.php

@@ -0,0 +1,366 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * @ignore
+ */
+require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php');
+/**
+ * @ignore
+ */
+require_once(SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php');
+
+/**
+ * Smarty {html_select_time} function plugin
+ * Type:     function<br>
+ * Name:     html_select_time<br>
+ * Purpose:  Prints the dropdowns for time selection
+ *
+ * @link     http://www.smarty.net/manual/en/language.function.html.select.time.php {html_select_time}
+ *           (Smarty online manual)
+ * @author   Roberto Berto <roberto@berto.net>
+ * @author   Monte Ohrt <monte AT ohrt DOT com>
+ *
+ * @param array $params parameters
+ *
+ * @return string
+ * @uses     smarty_make_timestamp()
+ */
+function smarty_function_html_select_time($params)
+{
+    $prefix = "Time_";
+    $field_array = null;
+    $field_separator = "\n";
+    $option_separator = "\n";
+    $time = null;
+
+    $display_hours = true;
+    $display_minutes = true;
+    $display_seconds = true;
+    $display_meridian = true;
+
+    $hour_format = '%02d';
+    $hour_value_format = '%02d';
+    $minute_format = '%02d';
+    $minute_value_format = '%02d';
+    $second_format = '%02d';
+    $second_value_format = '%02d';
+
+    $hour_size = null;
+    $minute_size = null;
+    $second_size = null;
+    $meridian_size = null;
+
+    $all_empty = null;
+    $hour_empty = null;
+    $minute_empty = null;
+    $second_empty = null;
+    $meridian_empty = null;
+
+    $all_id = null;
+    $hour_id = null;
+    $minute_id = null;
+    $second_id = null;
+    $meridian_id = null;
+
+    $use_24_hours = true;
+    $minute_interval = 1;
+    $second_interval = 1;
+
+    $extra_attrs = '';
+    $all_extra = null;
+    $hour_extra = null;
+    $minute_extra = null;
+    $second_extra = null;
+    $meridian_extra = null;
+
+    foreach ($params as $_key => $_value) {
+        switch ($_key) {
+            case 'time':
+                if (!is_array($_value) && $_value !== null) {
+                    $time = smarty_make_timestamp($_value);
+                }
+                break;
+
+            case 'prefix':
+            case 'field_array':
+
+            case 'field_separator':
+            case 'option_separator':
+
+            case 'all_extra':
+            case 'hour_extra':
+            case 'minute_extra':
+            case 'second_extra':
+            case 'meridian_extra':
+
+            case 'all_empty':
+            case 'hour_empty':
+            case 'minute_empty':
+            case 'second_empty':
+            case 'meridian_empty':
+
+            case 'all_id':
+            case 'hour_id':
+            case 'minute_id':
+            case 'second_id':
+            case 'meridian_id':
+
+            case 'hour_format':
+            case 'hour_value_format':
+            case 'minute_format':
+            case 'minute_value_format':
+            case 'second_format':
+            case 'second_value_format':
+                $$_key = (string) $_value;
+                break;
+
+            case 'display_hours':
+            case 'display_minutes':
+            case 'display_seconds':
+            case 'display_meridian':
+            case 'use_24_hours':
+                $$_key = (bool) $_value;
+                break;
+
+            case 'minute_interval':
+            case 'second_interval':
+
+            case 'hour_size':
+            case 'minute_size':
+            case 'second_size':
+            case 'meridian_size':
+                $$_key = (int) $_value;
+                break;
+
+            default:
+                if (!is_array($_value)) {
+                    $extra_attrs .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_value) . '"';
+                } else {
+                    trigger_error("html_select_date: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+        }
+    }
+
+    if (isset($params[ 'time' ]) && is_array($params[ 'time' ])) {
+        if (isset($params[ 'time' ][ $prefix . 'Hour' ])) {
+            // $_REQUEST[$field_array] given
+            foreach (array('H' => 'Hour', 'i' => 'Minute', 's' => 'Second') as $_elementKey => $_elementName) {
+                $_variableName = '_' . strtolower($_elementName);
+                $$_variableName =
+                    isset($params[ 'time' ][ $prefix . $_elementName ]) ? $params[ 'time' ][ $prefix . $_elementName ] :
+                        date($_elementKey);
+            }
+            $_meridian =
+                isset($params[ 'time' ][ $prefix . 'Meridian' ]) ? (' ' . $params[ 'time' ][ $prefix . 'Meridian' ]) :
+                    '';
+            $time = strtotime($_hour . ':' . $_minute . ':' . $_second . $_meridian);
+            list($_hour, $_minute, $_second) = $time = explode('-', date('H-i-s', $time));
+        } elseif (isset($params[ 'time' ][ $field_array ][ $prefix . 'Hour' ])) {
+            // $_REQUEST given
+            foreach (array('H' => 'Hour', 'i' => 'Minute', 's' => 'Second') as $_elementKey => $_elementName) {
+                $_variableName = '_' . strtolower($_elementName);
+                $$_variableName = isset($params[ 'time' ][ $field_array ][ $prefix . $_elementName ]) ?
+                    $params[ 'time' ][ $field_array ][ $prefix . $_elementName ] : date($_elementKey);
+            }
+            $_meridian = isset($params[ 'time' ][ $field_array ][ $prefix . 'Meridian' ]) ?
+                (' ' . $params[ 'time' ][ $field_array ][ $prefix . 'Meridian' ]) : '';
+            $time = strtotime($_hour . ':' . $_minute . ':' . $_second . $_meridian);
+            list($_hour, $_minute, $_second) = $time = explode('-', date('H-i-s', $time));
+        } else {
+            // no date found, use NOW
+            list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d'));
+        }
+    } elseif ($time === null) {
+        if (array_key_exists('time', $params)) {
+            $_hour = $_minute = $_second = $time = null;
+        } else {
+            list($_hour, $_minute, $_second) = $time = explode('-', date('H-i-s'));
+        }
+    } else {
+        list($_hour, $_minute, $_second) = $time = explode('-', date('H-i-s', $time));
+    }
+
+    // generate hour <select>
+    if ($display_hours) {
+        $_html_hours = '';
+        $_extra = '';
+        $_name = $field_array ? ($field_array . '[' . $prefix . 'Hour]') : ($prefix . 'Hour');
+        if ($all_extra) {
+            $_extra .= ' ' . $all_extra;
+        }
+        if ($hour_extra) {
+            $_extra .= ' ' . $hour_extra;
+        }
+
+        $_html_hours = '<select name="' . $_name . '"';
+        if ($hour_id !== null || $all_id !== null) {
+            $_html_hours .= ' id="' .
+                            smarty_function_escape_special_chars($hour_id !== null ? ($hour_id ? $hour_id : $_name) :
+                                                                     ($all_id ? ($all_id . $_name) : $_name)) . '"';
+        }
+        if ($hour_size) {
+            $_html_hours .= ' size="' . $hour_size . '"';
+        }
+        $_html_hours .= $_extra . $extra_attrs . '>' . $option_separator;
+
+        if (isset($hour_empty) || isset($all_empty)) {
+            $_html_hours .= '<option value="">' . (isset($hour_empty) ? $hour_empty : $all_empty) . '</option>' .
+                            $option_separator;
+        }
+
+        $start = $use_24_hours ? 0 : 1;
+        $end = $use_24_hours ? 23 : 12;
+        for ($i = $start; $i <= $end; $i ++) {
+            $_val = sprintf('%02d', $i);
+            $_text = $hour_format == '%02d' ? $_val : sprintf($hour_format, $i);
+            $_value = $hour_value_format == '%02d' ? $_val : sprintf($hour_value_format, $i);
+
+            if (!$use_24_hours) {
+                $_hour12 = $_hour == 0 ? 12 : ($_hour <= 12 ? $_hour : $_hour - 12);
+            }
+
+            $selected = $_hour !== null ? ($use_24_hours ? $_hour == $_val : $_hour12 == $_val) : null;
+            $_html_hours .= '<option value="' . $_value . '"' . ($selected ? ' selected="selected"' : '') . '>' .
+                            $_text . '</option>' . $option_separator;
+        }
+
+        $_html_hours .= '</select>';
+    }
+
+    // generate minute <select>
+    if ($display_minutes) {
+        $_html_minutes = '';
+        $_extra = '';
+        $_name = $field_array ? ($field_array . '[' . $prefix . 'Minute]') : ($prefix . 'Minute');
+        if ($all_extra) {
+            $_extra .= ' ' . $all_extra;
+        }
+        if ($minute_extra) {
+            $_extra .= ' ' . $minute_extra;
+        }
+
+        $_html_minutes = '<select name="' . $_name . '"';
+        if ($minute_id !== null || $all_id !== null) {
+            $_html_minutes .= ' id="' . smarty_function_escape_special_chars($minute_id !== null ?
+                                                                                 ($minute_id ? $minute_id : $_name) :
+                                                                                 ($all_id ? ($all_id . $_name) :
+                                                                                     $_name)) . '"';
+        }
+        if ($minute_size) {
+            $_html_minutes .= ' size="' . $minute_size . '"';
+        }
+        $_html_minutes .= $_extra . $extra_attrs . '>' . $option_separator;
+
+        if (isset($minute_empty) || isset($all_empty)) {
+            $_html_minutes .= '<option value="">' . (isset($minute_empty) ? $minute_empty : $all_empty) . '</option>' .
+                              $option_separator;
+        }
+
+        $selected = $_minute !== null ? ($_minute - $_minute % $minute_interval) : null;
+        for ($i = 0; $i <= 59; $i += $minute_interval) {
+            $_val = sprintf('%02d', $i);
+            $_text = $minute_format == '%02d' ? $_val : sprintf($minute_format, $i);
+            $_value = $minute_value_format == '%02d' ? $_val : sprintf($minute_value_format, $i);
+            $_html_minutes .= '<option value="' . $_value . '"' . ($selected === $i ? ' selected="selected"' : '') .
+                              '>' . $_text . '</option>' . $option_separator;
+        }
+
+        $_html_minutes .= '</select>';
+    }
+
+    // generate second <select>
+    if ($display_seconds) {
+        $_html_seconds = '';
+        $_extra = '';
+        $_name = $field_array ? ($field_array . '[' . $prefix . 'Second]') : ($prefix . 'Second');
+        if ($all_extra) {
+            $_extra .= ' ' . $all_extra;
+        }
+        if ($second_extra) {
+            $_extra .= ' ' . $second_extra;
+        }
+
+        $_html_seconds = '<select name="' . $_name . '"';
+        if ($second_id !== null || $all_id !== null) {
+            $_html_seconds .= ' id="' . smarty_function_escape_special_chars($second_id !== null ?
+                                                                                 ($second_id ? $second_id : $_name) :
+                                                                                 ($all_id ? ($all_id . $_name) :
+                                                                                     $_name)) . '"';
+        }
+        if ($second_size) {
+            $_html_seconds .= ' size="' . $second_size . '"';
+        }
+        $_html_seconds .= $_extra . $extra_attrs . '>' . $option_separator;
+
+        if (isset($second_empty) || isset($all_empty)) {
+            $_html_seconds .= '<option value="">' . (isset($second_empty) ? $second_empty : $all_empty) . '</option>' .
+                              $option_separator;
+        }
+
+        $selected = $_second !== null ? ($_second - $_second % $second_interval) : null;
+        for ($i = 0; $i <= 59; $i += $second_interval) {
+            $_val = sprintf('%02d', $i);
+            $_text = $second_format == '%02d' ? $_val : sprintf($second_format, $i);
+            $_value = $second_value_format == '%02d' ? $_val : sprintf($second_value_format, $i);
+            $_html_seconds .= '<option value="' . $_value . '"' . ($selected === $i ? ' selected="selected"' : '') .
+                              '>' . $_text . '</option>' . $option_separator;
+        }
+
+        $_html_seconds .= '</select>';
+    }
+
+    // generate meridian <select>
+    if ($display_meridian && !$use_24_hours) {
+        $_html_meridian = '';
+        $_extra = '';
+        $_name = $field_array ? ($field_array . '[' . $prefix . 'Meridian]') : ($prefix . 'Meridian');
+        if ($all_extra) {
+            $_extra .= ' ' . $all_extra;
+        }
+        if ($meridian_extra) {
+            $_extra .= ' ' . $meridian_extra;
+        }
+
+        $_html_meridian = '<select name="' . $_name . '"';
+        if ($meridian_id !== null || $all_id !== null) {
+            $_html_meridian .= ' id="' . smarty_function_escape_special_chars($meridian_id !== null ?
+                                                                                  ($meridian_id ? $meridian_id :
+                                                                                      $_name) :
+                                                                                  ($all_id ? ($all_id . $_name) :
+                                                                                      $_name)) . '"';
+        }
+        if ($meridian_size) {
+            $_html_meridian .= ' size="' . $meridian_size . '"';
+        }
+        $_html_meridian .= $_extra . $extra_attrs . '>' . $option_separator;
+
+        if (isset($meridian_empty) || isset($all_empty)) {
+            $_html_meridian .= '<option value="">' . (isset($meridian_empty) ? $meridian_empty : $all_empty) .
+                               '</option>' . $option_separator;
+        }
+
+        $_html_meridian .= '<option value="am"' . ($_hour > 0 && $_hour < 12 ? ' selected="selected"' : '') .
+                           '>AM</option>' . $option_separator . '<option value="pm"' .
+                           ($_hour < 12 ? '' : ' selected="selected"') . '>PM</option>' . $option_separator .
+                           '</select>';
+    }
+
+    $_html = '';
+    foreach (array('_html_hours', '_html_minutes', '_html_seconds', '_html_meridian') as $k) {
+        if (isset($$k)) {
+            if ($_html) {
+                $_html .= $field_separator;
+            }
+            $_html .= $$k;
+        }
+    }
+
+    return $_html;
+}

+ 176 - 0
Qii/View/smarty/plugins/function.html_table.php

@@ -0,0 +1,176 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * Smarty {html_table} function plugin
+ * Type:     function<br>
+ * Name:     html_table<br>
+ * Date:     Feb 17, 2003<br>
+ * Purpose:  make an html table from an array of data<br>
+ * Params:
+ * <pre>
+ * - loop       - array to loop through
+ * - cols       - number of columns, comma separated list of column names
+ *                or array of column names
+ * - rows       - number of rows
+ * - table_attr - table attributes
+ * - th_attr    - table heading attributes (arrays are cycled)
+ * - tr_attr    - table row attributes (arrays are cycled)
+ * - td_attr    - table cell attributes (arrays are cycled)
+ * - trailpad   - value to pad trailing cells with
+ * - caption    - text for caption element
+ * - vdir       - vertical direction (default: "down", means top-to-bottom)
+ * - hdir       - horizontal direction (default: "right", means left-to-right)
+ * - inner      - inner loop (default "cols": print $loop line by line,
+ *                $loop will be printed column by column otherwise)
+ * </pre>
+ * Examples:
+ * <pre>
+ * {table loop=$data}
+ * {table loop=$data cols=4 tr_attr='"bgcolor=red"'}
+ * {table loop=$data cols="first,second,third" tr_attr=$colors}
+ * </pre>
+ *
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @author   credit to Messju Mohr <messju at lammfellpuschen dot de>
+ * @author   credit to boots <boots dot smarty at yahoo dot com>
+ * @version  1.1
+ * @link     http://www.smarty.net/manual/en/language.function.html.table.php {html_table}
+ *           (Smarty online manual)
+ *
+ * @param array $params parameters
+ *
+ * @return string
+ */
+function smarty_function_html_table($params)
+{
+    $table_attr = 'border="1"';
+    $tr_attr = '';
+    $th_attr = '';
+    $td_attr = '';
+    $cols = $cols_count = 3;
+    $rows = 3;
+    $trailpad = '&nbsp;';
+    $vdir = 'down';
+    $hdir = 'right';
+    $inner = 'cols';
+    $caption = '';
+    $loop = null;
+
+    if (!isset($params[ 'loop' ])) {
+        trigger_error("html_table: missing 'loop' parameter", E_USER_WARNING);
+
+        return;
+    }
+
+    foreach ($params as $_key => $_value) {
+        switch ($_key) {
+            case 'loop':
+                $$_key = (array) $_value;
+                break;
+
+            case 'cols':
+                if (is_array($_value) && !empty($_value)) {
+                    $cols = $_value;
+                    $cols_count = count($_value);
+                } elseif (!is_numeric($_value) && is_string($_value) && !empty($_value)) {
+                    $cols = explode(',', $_value);
+                    $cols_count = count($cols);
+                } elseif (!empty($_value)) {
+                    $cols_count = (int) $_value;
+                } else {
+                    $cols_count = $cols;
+                }
+                break;
+
+            case 'rows':
+                $$_key = (int) $_value;
+                break;
+
+            case 'table_attr':
+            case 'trailpad':
+            case 'hdir':
+            case 'vdir':
+            case 'inner':
+            case 'caption':
+                $$_key = (string) $_value;
+                break;
+
+            case 'tr_attr':
+            case 'td_attr':
+            case 'th_attr':
+                $$_key = $_value;
+                break;
+        }
+    }
+
+    $loop_count = count($loop);
+    if (empty($params[ 'rows' ])) {
+        /* no rows specified */
+        $rows = ceil($loop_count / $cols_count);
+    } elseif (empty($params[ 'cols' ])) {
+        if (!empty($params[ 'rows' ])) {
+            /* no cols specified, but rows */
+            $cols_count = ceil($loop_count / $rows);
+        }
+    }
+
+    $output = "<table $table_attr>\n";
+
+    if (!empty($caption)) {
+        $output .= '<caption>' . $caption . "</caption>\n";
+    }
+
+    if (is_array($cols)) {
+        $cols = ($hdir == 'right') ? $cols : array_reverse($cols);
+        $output .= "<thead><tr>\n";
+
+        for ($r = 0; $r < $cols_count; $r ++) {
+            $output .= '<th' . smarty_function_html_table_cycle('th', $th_attr, $r) . '>';
+            $output .= $cols[ $r ];
+            $output .= "</th>\n";
+        }
+        $output .= "</tr></thead>\n";
+    }
+
+    $output .= "<tbody>\n";
+    for ($r = 0; $r < $rows; $r ++) {
+        $output .= "<tr" . smarty_function_html_table_cycle('tr', $tr_attr, $r) . ">\n";
+        $rx = ($vdir == 'down') ? $r * $cols_count : ($rows - 1 - $r) * $cols_count;
+
+        for ($c = 0; $c < $cols_count; $c ++) {
+            $x = ($hdir == 'right') ? $rx + $c : $rx + $cols_count - 1 - $c;
+            if ($inner != 'cols') {
+                /* shuffle x to loop over rows*/
+                $x = floor($x / $cols_count) + ($x % $cols_count) * $rows;
+            }
+
+            if ($x < $loop_count) {
+                $output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">" . $loop[ $x ] . "</td>\n";
+            } else {
+                $output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">$trailpad</td>\n";
+            }
+        }
+        $output .= "</tr>\n";
+    }
+    $output .= "</tbody>\n";
+    $output .= "</table>\n";
+
+    return $output;
+}
+
+function smarty_function_html_table_cycle($name, $var, $no)
+{
+    if (!is_array($var)) {
+        $ret = $var;
+    } else {
+        $ret = $var[ $no % count($var) ];
+    }
+
+    return ($ret) ? ' ' . $ret : '';
+}

+ 153 - 0
Qii/View/smarty/plugins/function.mailto.php

@@ -0,0 +1,153 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * Smarty {mailto} function plugin
+ * Type:     function<br>
+ * Name:     mailto<br>
+ * Date:     May 21, 2002
+ * Purpose:  automate mailto address link creation, and optionally encode them.<br>
+ * Params:
+ * <pre>
+ * - address    - (required) - e-mail address
+ * - text       - (optional) - text to display, default is address
+ * - encode     - (optional) - can be one of:
+ *                             * none : no encoding (default)
+ *                             * javascript : encode with javascript
+ *                             * javascript_charcode : encode with javascript charcode
+ *                             * hex : encode with hexidecimal (no javascript)
+ * - cc         - (optional) - address(es) to carbon copy
+ * - bcc        - (optional) - address(es) to blind carbon copy
+ * - subject    - (optional) - e-mail subject
+ * - newsgroups - (optional) - newsgroup(s) to post to
+ * - followupto - (optional) - address(es) to follow up to
+ * - extra      - (optional) - extra tags for the href link
+ * </pre>
+ * Examples:
+ * <pre>
+ * {mailto address="me@domain.com"}
+ * {mailto address="me@domain.com" encode="javascript"}
+ * {mailto address="me@domain.com" encode="hex"}
+ * {mailto address="me@domain.com" subject="Hello to you!"}
+ * {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"}
+ * {mailto address="me@domain.com" extra='class="mailto"'}
+ * </pre>
+ *
+ * @link     http://www.smarty.net/manual/en/language.function.mailto.php {mailto}
+ *           (Smarty online manual)
+ * @version  1.2
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @author   credits to Jason Sweat (added cc, bcc and subject functionality)
+ *
+ * @param array $params parameters
+ *
+ * @return string
+ */
+function smarty_function_mailto($params)
+{
+    static $_allowed_encoding =
+        array('javascript' => true, 'javascript_charcode' => true, 'hex' => true, 'none' => true);
+    $extra = '';
+
+    if (empty($params[ 'address' ])) {
+        trigger_error("mailto: missing 'address' parameter", E_USER_WARNING);
+
+        return;
+    } else {
+        $address = $params[ 'address' ];
+    }
+
+    $text = $address;
+    // netscape and mozilla do not decode %40 (@) in BCC field (bug?)
+    // so, don't encode it.
+    $search = array('%40', '%2C');
+    $replace = array('@', ',');
+    $mail_parms = array();
+    foreach ($params as $var => $value) {
+        switch ($var) {
+            case 'cc':
+            case 'bcc':
+            case 'followupto':
+                if (!empty($value)) {
+                    $mail_parms[] = $var . '=' . str_replace($search, $replace, rawurlencode($value));
+                }
+                break;
+
+            case 'subject':
+            case 'newsgroups':
+                $mail_parms[] = $var . '=' . rawurlencode($value);
+                break;
+
+            case 'extra':
+            case 'text':
+                $$var = $value;
+
+            default:
+        }
+    }
+
+    if ($mail_parms) {
+        $address .= '?' . join('&', $mail_parms);
+    }
+
+    $encode = (empty($params[ 'encode' ])) ? 'none' : $params[ 'encode' ];
+    if (!isset($_allowed_encoding[ $encode ])) {
+        trigger_error("mailto: 'encode' parameter must be none, javascript, javascript_charcode or hex",
+                      E_USER_WARNING);
+
+        return;
+    }
+    // FIXME: (rodneyrehm) document.write() excues me what? 1998 has passed!
+    if ($encode == 'javascript') {
+        $string = 'document.write(\'<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>\');';
+
+        $js_encode = '';
+        for ($x = 0, $_length = strlen($string); $x < $_length; $x ++) {
+            $js_encode .= '%' . bin2hex($string[ $x ]);
+        }
+
+        return '<script type="text/javascript">eval(unescape(\'' . $js_encode . '\'))</script>';
+    } elseif ($encode == 'javascript_charcode') {
+        $string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
+
+        for ($x = 0, $y = strlen($string); $x < $y; $x ++) {
+            $ord[] = ord($string[ $x ]);
+        }
+
+        $_ret = "<script type=\"text/javascript\" language=\"javascript\">\n" . "{document.write(String.fromCharCode(" .
+                implode(',', $ord) . "))" . "}\n" . "</script>\n";
+
+        return $_ret;
+    } elseif ($encode == 'hex') {
+        preg_match('!^(.*)(\?.*)$!', $address, $match);
+        if (!empty($match[ 2 ])) {
+            trigger_error("mailto: hex encoding does not work with extra attributes. Try javascript.", E_USER_WARNING);
+
+            return;
+        }
+        $address_encode = '';
+        for ($x = 0, $_length = strlen($address); $x < $_length; $x ++) {
+            if (preg_match('!\w!' . Smarty::$_UTF8_MODIFIER, $address[ $x ])) {
+                $address_encode .= '%' . bin2hex($address[ $x ]);
+            } else {
+                $address_encode .= $address[ $x ];
+            }
+        }
+        $text_encode = '';
+        for ($x = 0, $_length = strlen($text); $x < $_length; $x ++) {
+            $text_encode .= '&#x' . bin2hex($text[ $x ]) . ';';
+        }
+
+        $mailto = "&#109;&#97;&#105;&#108;&#116;&#111;&#58;";
+
+        return '<a href="' . $mailto . $address_encode . '" ' . $extra . '>' . $text_encode . '</a>';
+    } else {
+        // no encoding
+        return '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>';
+    }
+}

+ 104 - 0
Qii/View/smarty/plugins/function.math.php

@@ -0,0 +1,104 @@
+<?php
+/**
+ * Smarty plugin
+ * This plugin is only for Smarty2 BC
+ *
+ * @package    Smarty
+ * @subpackage PluginsFunction
+ */
+
+/**
+ * Smarty {math} function plugin
+ * Type:     function<br>
+ * Name:     math<br>
+ * Purpose:  handle math computations in template
+ *
+ * @link     http://www.smarty.net/manual/en/language.function.math.php {math}
+ *           (Smarty online manual)
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ *
+ * @param array                    $params   parameters
+ * @param Smarty_Internal_Template $template template object
+ *
+ * @return string|null
+ */
+function smarty_function_math($params, $template)
+{
+    static $_allowed_funcs =
+        array('int' => true, 'abs' => true, 'ceil' => true, 'cos' => true, 'exp' => true, 'floor' => true,
+              'log' => true, 'log10' => true, 'max' => true, 'min' => true, 'pi' => true, 'pow' => true, 'rand' => true,
+              'round' => true, 'sin' => true, 'sqrt' => true, 'srand' => true, 'tan' => true);
+    // be sure equation parameter is present
+    if (empty($params[ 'equation' ])) {
+        trigger_error("math: missing equation parameter", E_USER_WARNING);
+
+        return;
+    }
+
+    $equation = $params[ 'equation' ];
+
+    // make sure parenthesis are balanced
+    if (substr_count($equation, "(") != substr_count($equation, ")")) {
+        trigger_error("math: unbalanced parenthesis", E_USER_WARNING);
+
+        return;
+    }
+
+    // disallow backticks
+    if (strpos($equation, '`') !== false) {
+        trigger_error("math: backtick character not allowed in equation", E_USER_WARNING);
+
+        return;
+    }
+
+    // also disallow dollar signs
+    if (strpos($equation, '$') !== false) {
+        trigger_error("math: dollar signs not allowed in equation", E_USER_WARNING);
+
+        return;
+    }
+
+    // match all vars in equation, make sure all are passed
+    preg_match_all('!(?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)!', $equation, $match);
+
+    foreach ($match[ 1 ] as $curr_var) {
+        if ($curr_var && !isset($params[ $curr_var ]) && !isset($_allowed_funcs[ $curr_var ])) {
+            trigger_error("math: function call $curr_var not allowed", E_USER_WARNING);
+
+            return;
+        }
+    }
+
+    foreach ($params as $key => $val) {
+        if ($key != "equation" && $key != "format" && $key != "assign") {
+            // make sure value is not empty
+            if (strlen($val) == 0) {
+                trigger_error("math: parameter $key is empty", E_USER_WARNING);
+
+                return;
+            }
+            if (!is_numeric($val)) {
+                trigger_error("math: parameter $key: is not numeric", E_USER_WARNING);
+
+                return;
+            }
+            $equation = preg_replace("/\b$key\b/", " \$params['$key'] ", $equation);
+        }
+    }
+    $smarty_math_result = null;
+    eval("\$smarty_math_result = " . $equation . ";");
+
+    if (empty($params[ 'format' ])) {
+        if (empty($params[ 'assign' ])) {
+            return $smarty_math_result;
+        } else {
+            $template->assign($params[ 'assign' ], $smarty_math_result);
+        }
+    } else {
+        if (empty($params[ 'assign' ])) {
+            printf($params[ 'format' ], $smarty_math_result);
+        } else {
+            $template->assign($params[ 'assign' ], sprintf($params[ 'format' ], $smarty_math_result));
+        }
+    }
+}

+ 101 - 0
Qii/View/smarty/plugins/modifier.capitalize.php

@@ -0,0 +1,101 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifier
+ */
+
+/**
+ * Smarty capitalize modifier plugin
+ * Type:     modifier<br>
+ * Name:     capitalize<br>
+ * Purpose:  capitalize words in the string
+ * {@internal {$string|capitalize:true:true} is the fastest option for MBString enabled systems }}
+ *
+ * @param string  $string    string to capitalize
+ * @param boolean $uc_digits also capitalize "x123" to "X123"
+ * @param boolean $lc_rest   capitalize first letters, lowercase all following letters "aAa" to "Aaa"
+ *
+ * @return string capitalized string
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author Rodney Rehm
+ */
+function smarty_modifier_capitalize($string, $uc_digits = false, $lc_rest = false)
+{
+    if (Smarty::$_MBSTRING) {
+        if ($lc_rest) {
+            // uppercase (including hyphenated words)
+            $upper_string = mb_convert_case($string, MB_CASE_TITLE, Smarty::$_CHARSET);
+        } else {
+            // uppercase word breaks
+            $upper_string = preg_replace_callback("!(^|[^\p{L}'])([\p{Ll}])!S" . Smarty::$_UTF8_MODIFIER,
+                                                  'smarty_mod_cap_mbconvert_cb', $string);
+        }
+        // check uc_digits case
+        if (!$uc_digits) {
+            if (preg_match_all("!\b([\p{L}]*[\p{N}]+[\p{L}]*)\b!" . Smarty::$_UTF8_MODIFIER, $string, $matches,
+                               PREG_OFFSET_CAPTURE)) {
+                foreach ($matches[ 1 ] as $match) {
+                    $upper_string =
+                        substr_replace($upper_string, mb_strtolower($match[ 0 ], Smarty::$_CHARSET), $match[ 1 ],
+                                       strlen($match[ 0 ]));
+                }
+            }
+        }
+        $upper_string =
+            preg_replace_callback("!((^|\s)['\"])(\w)!" . Smarty::$_UTF8_MODIFIER, 'smarty_mod_cap_mbconvert2_cb',
+                                  $upper_string);
+        return $upper_string;
+    }
+
+    // lowercase first
+    if ($lc_rest) {
+        $string = strtolower($string);
+    }
+    // uppercase (including hyphenated words)
+    $upper_string =
+        preg_replace_callback("!(^|[^\p{L}'])([\p{Ll}])!S" . Smarty::$_UTF8_MODIFIER, 'smarty_mod_cap_ucfirst_cb',
+                              $string);
+    // check uc_digits case
+    if (!$uc_digits) {
+        if (preg_match_all("!\b([\p{L}]*[\p{N}]+[\p{L}]*)\b!" . Smarty::$_UTF8_MODIFIER, $string, $matches,
+                           PREG_OFFSET_CAPTURE)) {
+            foreach ($matches[ 1 ] as $match) {
+                $upper_string =
+                    substr_replace($upper_string, strtolower($match[ 0 ]), $match[ 1 ], strlen($match[ 0 ]));
+            }
+        }
+    }
+    $upper_string = preg_replace_callback("!((^|\s)['\"])(\w)!" . Smarty::$_UTF8_MODIFIER, 'smarty_mod_cap_ucfirst2_cb',
+                                          $upper_string);
+    return $upper_string;
+}
+
+/* 
+ *
+ * Bug: create_function() use exhausts memory when used in long loops
+ * Fix: use declared functions for callbacks instead of using create_function()
+ * Note: This can be fixed using anonymous functions instead, but that requires PHP >= 5.3
+ *
+ * @author Kyle Renfrow
+ */
+function smarty_mod_cap_mbconvert_cb($matches)
+{
+    return stripslashes($matches[ 1 ]) . mb_convert_case(stripslashes($matches[ 2 ]), MB_CASE_UPPER, Smarty::$_CHARSET);
+}
+
+function smarty_mod_cap_mbconvert2_cb($matches)
+{
+    return stripslashes($matches[ 1 ]) . mb_convert_case(stripslashes($matches[ 3 ]), MB_CASE_UPPER, Smarty::$_CHARSET);
+}
+
+function smarty_mod_cap_ucfirst_cb($matches)
+{
+    return stripslashes($matches[ 1 ]) . ucfirst(stripslashes($matches[ 2 ]));
+}
+
+function smarty_mod_cap_ucfirst2_cb($matches)
+{
+    return stripslashes($matches[ 1 ]) . ucfirst(stripslashes($matches[ 3 ]));
+}

+ 65 - 0
Qii/View/smarty/plugins/modifier.date_format.php

@@ -0,0 +1,65 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifier
+ */
+
+/**
+ * Smarty date_format modifier plugin
+ * Type:     modifier<br>
+ * Name:     date_format<br>
+ * Purpose:  format datestamps via strftime<br>
+ * Input:<br>
+ *          - string: input date string
+ *          - format: strftime format for output
+ *          - default_date: default date if $string is empty
+ *
+ * @link   http://www.smarty.net/manual/en/language.modifier.date.format.php date_format (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ *
+ * @param string $string       input date string
+ * @param string $format       strftime format for output
+ * @param string $default_date default date if $string is empty
+ * @param string $formatter    either 'strftime' or 'auto'
+ *
+ * @return string |void
+ * @uses   smarty_make_timestamp()
+ */
+function smarty_modifier_date_format($string, $format = null, $default_date = '', $formatter = 'auto')
+{
+    if ($format === null) {
+        $format = Smarty::$_DATE_FORMAT;
+    }
+    /**
+     * require_once the {@link shared.make_timestamp.php} plugin
+     */
+    require_once(SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php');
+    if ($string != '' && $string != '0000-00-00' && $string != '0000-00-00 00:00:00') {
+        $timestamp = smarty_make_timestamp($string);
+    } elseif ($default_date != '') {
+        $timestamp = smarty_make_timestamp($default_date);
+    } else {
+        return;
+    }
+    if ($formatter == 'strftime' || ($formatter == 'auto' && strpos($format, '%') !== false)) {
+        if (DS == '\\') {
+            $_win_from = array('%D', '%h', '%n', '%r', '%R', '%t', '%T');
+            $_win_to = array('%m/%d/%y', '%b', "\n", '%I:%M:%S %p', '%H:%M', "\t", '%H:%M:%S');
+            if (strpos($format, '%e') !== false) {
+                $_win_from[] = '%e';
+                $_win_to[] = sprintf('%\' 2d', date('j', $timestamp));
+            }
+            if (strpos($format, '%l') !== false) {
+                $_win_from[] = '%l';
+                $_win_to[] = sprintf('%\' 2d', date('h', $timestamp));
+            }
+            $format = str_replace($_win_from, $_win_to, $format);
+        }
+
+        return strftime($format, $timestamp);
+    } else {
+        return date($format, $timestamp);
+    }
+}

+ 112 - 0
Qii/View/smarty/plugins/modifier.debug_print_var.php

@@ -0,0 +1,112 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage Debug
+ */
+
+/**
+ * Smarty debug_print_var modifier plugin
+ * Type:     modifier<br>
+ * Name:     debug_print_var<br>
+ * Purpose:  formats variable contents for display in the console
+ *
+ * @author Monte Ohrt <monte at ohrt dot com>
+ *
+ * @param array|object $var     variable to be formatted
+ * @param int          $max     maximum recursion depth if $var is an array or object
+ * @param int          $length  maximum string length if $var is a string
+ * @param int          $depth   actual recursion depth
+ * @param array        $objects processed objects in actual depth to prevent recursive object processing
+ *
+ * @return string
+ */
+function smarty_modifier_debug_print_var($var, $max = 10, $length = 40, $depth = 0, $objects = array())
+{
+    $_replace = array("\n" => '\n', "\r" => '\r', "\t" => '\t');
+    switch (gettype($var)) {
+        case 'array' :
+            $results = '<b>Array (' . count($var) . ')</b>';
+            if ($depth == $max) {
+                break;
+            }
+            foreach ($var as $curr_key => $curr_val) {
+                $results .= '<br>' . str_repeat('&nbsp;', $depth * 2) . '<b>' . strtr($curr_key, $_replace) .
+                            '</b> =&gt; ' .
+                            smarty_modifier_debug_print_var($curr_val, $max, $length, ++ $depth, $objects);
+                $depth --;
+            }
+            break;
+
+        case 'object' :
+            $object_vars = get_object_vars($var);
+            $results = '<b>' . get_class($var) . ' Object (' . count($object_vars) . ')</b>';
+            if (in_array($var, $objects)) {
+                $results .= ' called recursive';
+                break;
+            }
+            if ($depth == $max) {
+                break;
+            }
+            $objects[] = $var;
+            foreach ($object_vars as $curr_key => $curr_val) {
+                $results .= '<br>' . str_repeat('&nbsp;', $depth * 2) . '<b> -&gt;' . strtr($curr_key, $_replace) .
+                            '</b> = ' . smarty_modifier_debug_print_var($curr_val, $max, $length, ++ $depth, $objects);
+                $depth --;
+            }
+            break;
+
+        case 'boolean' :
+        case 'NULL' :
+        case 'resource' :
+            if (true === $var) {
+                $results = 'true';
+            } elseif (false === $var) {
+                $results = 'false';
+            } elseif (null === $var) {
+                $results = 'null';
+            } else {
+                $results = htmlspecialchars((string) $var);
+            }
+            $results = '<i>' . $results . '</i>';
+            break;
+
+        case 'integer' :
+        case 'float' :
+            $results = htmlspecialchars((string) $var);
+            break;
+
+        case 'string' :
+            $results = strtr($var, $_replace);
+            if (Smarty::$_MBSTRING) {
+                if (mb_strlen($var, Smarty::$_CHARSET) > $length) {
+                    $results = mb_substr($var, 0, $length - 3, Smarty::$_CHARSET) . '...';
+                }
+            } else {
+                if (isset($var[ $length ])) {
+                    $results = substr($var, 0, $length - 3) . '...';
+                }
+            }
+
+            $results = htmlspecialchars('"' . $results . '"', ENT_QUOTES, Smarty::$_CHARSET);
+            break;
+
+        case 'unknown type' :
+        default :
+            $results = strtr((string) $var, $_replace);
+            if (Smarty::$_MBSTRING) {
+                if (mb_strlen($results, Smarty::$_CHARSET) > $length) {
+                    $results = mb_substr($results, 0, $length - 3, Smarty::$_CHARSET) . '...';
+                }
+            } else {
+                if (strlen($results) > $length) {
+                    $results = substr($results, 0, $length - 3) . '...';
+                }
+            }
+
+            $results = htmlspecialchars($results, ENT_QUOTES, Smarty::$_CHARSET);
+    }
+
+    return $results;
+}

+ 200 - 0
Qii/View/smarty/plugins/modifier.escape.php

@@ -0,0 +1,200 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifier
+ */
+
+/**
+ * Smarty escape modifier plugin
+ * Type:     modifier<br>
+ * Name:     escape<br>
+ * Purpose:  escape string for output
+ *
+ * @link   http://www.smarty.net/docs/en/language.modifier.escape
+ * @author Monte Ohrt <monte at ohrt dot com>
+ *
+ * @param string  $string        input string
+ * @param string  $esc_type      escape type
+ * @param string  $char_set      character set, used for htmlspecialchars() or htmlentities()
+ * @param boolean $double_encode encode already encoded entitites again, used for htmlspecialchars() or htmlentities()
+ *
+ * @return string escaped input string
+ */
+function smarty_modifier_escape($string, $esc_type = 'html', $char_set = null, $double_encode = true)
+{
+    static $_double_encode = null;
+    if ($_double_encode === null) {
+        $_double_encode = version_compare(PHP_VERSION, '5.2.3', '>=');
+    }
+
+    if (!$char_set) {
+        $char_set = Smarty::$_CHARSET;
+    }
+
+    switch ($esc_type) {
+        case 'html':
+            if ($_double_encode) {
+                // php >=5.3.2 - go native
+                return htmlspecialchars($string, ENT_QUOTES, $char_set, $double_encode);
+            } else {
+                if ($double_encode) {
+                    // php <5.2.3 - only handle double encoding
+                    return htmlspecialchars($string, ENT_QUOTES, $char_set);
+                } else {
+                    // php <5.2.3 - prevent double encoding
+                    $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
+                    $string = htmlspecialchars($string, ENT_QUOTES, $char_set);
+                    $string = str_replace(array('%%%SMARTY_START%%%', '%%%SMARTY_END%%%'), array('&', ';'), $string);
+
+                    return $string;
+                }
+            }
+
+        case 'htmlall':
+            if (Smarty::$_MBSTRING) {
+                // mb_convert_encoding ignores htmlspecialchars()
+                if ($_double_encode) {
+                    // php >=5.3.2 - go native
+                    $string = htmlspecialchars($string, ENT_QUOTES, $char_set, $double_encode);
+                } else {
+                    if ($double_encode) {
+                        // php <5.2.3 - only handle double encoding
+                        $string = htmlspecialchars($string, ENT_QUOTES, $char_set);
+                    } else {
+                        // php <5.2.3 - prevent double encoding
+                        $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
+                        $string = htmlspecialchars($string, ENT_QUOTES, $char_set);
+                        $string =
+                            str_replace(array('%%%SMARTY_START%%%', '%%%SMARTY_END%%%'), array('&', ';'), $string);
+
+                        return $string;
+                    }
+                }
+
+                // htmlentities() won't convert everything, so use mb_convert_encoding
+                return mb_convert_encoding($string, 'HTML-ENTITIES', $char_set);
+            }
+
+            // no MBString fallback
+            if ($_double_encode) {
+                return htmlentities($string, ENT_QUOTES, $char_set, $double_encode);
+            } else {
+                if ($double_encode) {
+                    return htmlentities($string, ENT_QUOTES, $char_set);
+                } else {
+                    $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
+                    $string = htmlentities($string, ENT_QUOTES, $char_set);
+                    $string = str_replace(array('%%%SMARTY_START%%%', '%%%SMARTY_END%%%'), array('&', ';'), $string);
+
+                    return $string;
+                }
+            }
+
+        case 'url':
+            return rawurlencode($string);
+
+        case 'urlpathinfo':
+            return str_replace('%2F', '/', rawurlencode($string));
+
+        case 'quotes':
+            // escape unescaped single quotes
+            return preg_replace("%(?<!\\\\)'%", "\\'", $string);
+
+        case 'hex':
+            // escape every byte into hex
+            // Note that the UTF-8 encoded character ä will be represented as %c3%a4
+            $return = '';
+            $_length = strlen($string);
+            for ($x = 0; $x < $_length; $x ++) {
+                $return .= '%' . bin2hex($string[ $x ]);
+            }
+
+            return $return;
+
+        case 'hexentity':
+            $return = '';
+            if (Smarty::$_MBSTRING) {
+                require_once(SMARTY_PLUGINS_DIR . 'shared.mb_unicode.php');
+                $return = '';
+                foreach (smarty_mb_to_unicode($string, Smarty::$_CHARSET) as $unicode) {
+                    $return .= '&#x' . strtoupper(dechex($unicode)) . ';';
+                }
+
+                return $return;
+            }
+            // no MBString fallback
+            $_length = strlen($string);
+            for ($x = 0; $x < $_length; $x ++) {
+                $return .= '&#x' . bin2hex($string[ $x ]) . ';';
+            }
+
+            return $return;
+
+        case 'decentity':
+            $return = '';
+            if (Smarty::$_MBSTRING) {
+                require_once(SMARTY_PLUGINS_DIR . 'shared.mb_unicode.php');
+                $return = '';
+                foreach (smarty_mb_to_unicode($string, Smarty::$_CHARSET) as $unicode) {
+                    $return .= '&#' . $unicode . ';';
+                }
+
+                return $return;
+            }
+            // no MBString fallback
+            $_length = strlen($string);
+            for ($x = 0; $x < $_length; $x ++) {
+                $return .= '&#' . ord($string[ $x ]) . ';';
+            }
+
+            return $return;
+
+        case 'javascript':
+            // escape quotes and backslashes, newlines, etc.
+            return strtr($string, array('\\' => '\\\\', "'" => "\\'", '"' => '\\"', "\r" => '\\r', "\n" => '\\n',
+                                        '</' => '<\/'));
+
+        case 'mail':
+            if (Smarty::$_MBSTRING) {
+                require_once(SMARTY_PLUGINS_DIR . 'shared.mb_str_replace.php');
+
+                return smarty_mb_str_replace(array('@', '.'), array(' [AT] ', ' [DOT] '), $string);
+            }
+            // no MBString fallback
+            return str_replace(array('@', '.'), array(' [AT] ', ' [DOT] '), $string);
+
+        case 'nonstd':
+            // escape non-standard chars, such as ms document quotes
+            $return = '';
+            if (Smarty::$_MBSTRING) {
+                require_once(SMARTY_PLUGINS_DIR . 'shared.mb_unicode.php');
+                foreach (smarty_mb_to_unicode($string, Smarty::$_CHARSET) as $unicode) {
+                    if ($unicode >= 126) {
+                        $return .= '&#' . $unicode . ';';
+                    } else {
+                        $return .= chr($unicode);
+                    }
+                }
+
+                return $return;
+            }
+
+            $_length = strlen($string);
+            for ($_i = 0; $_i < $_length; $_i ++) {
+                $_ord = ord(substr($string, $_i, 1));
+                // non-standard char, escape it
+                if ($_ord >= 126) {
+                    $return .= '&#' . $_ord . ';';
+                } else {
+                    $return .= substr($string, $_i, 1);
+                }
+            }
+
+            return $return;
+
+        default:
+            return $string;
+    }
+}

+ 58 - 0
Qii/View/smarty/plugins/modifier.regex_replace.php

@@ -0,0 +1,58 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifier
+ */
+
+/**
+ * Smarty regex_replace modifier plugin
+ * Type:     modifier<br>
+ * Name:     regex_replace<br>
+ * Purpose:  regular expression search/replace
+ *
+ * @link    http://smarty.php.net/manual/en/language.modifier.regex.replace.php
+ *          regex_replace (Smarty online manual)
+ * @author  Monte Ohrt <monte at ohrt dot com>
+ *
+ * @param string       $string  input string
+ * @param string|array $search  regular expression(s) to search for
+ * @param string|array $replace string(s) that should be replaced
+ * @param int          $limit   the maximum number of replacements
+ *
+ * @return string
+ */
+function smarty_modifier_regex_replace($string, $search, $replace, $limit = - 1)
+{
+    if (is_array($search)) {
+        foreach ($search as $idx => $s) {
+            $search[ $idx ] = _smarty_regex_replace_check($s);
+        }
+    } else {
+        $search = _smarty_regex_replace_check($search);
+    }
+
+    return preg_replace($search, $replace, $string, $limit);
+}
+
+/**
+ * @param  string $search string(s) that should be replaced
+ *
+ * @return string
+ * @ignore
+ */
+function _smarty_regex_replace_check($search)
+{
+    // null-byte injection detection
+    // anything behind the first null-byte is ignored
+    if (($pos = strpos($search, "\0")) !== false) {
+        $search = substr($search, 0, $pos);
+    }
+    // remove eval-modifier from $search
+    if (preg_match('!([a-zA-Z\s]+)$!s', $search, $match) && (strpos($match[ 1 ], 'e') !== false)) {
+        $search = substr($search, 0, - strlen($match[ 1 ])) . preg_replace('![e\s]+!', '', $match[ 1 ]);
+    }
+
+    return $search;
+}

+ 34 - 0
Qii/View/smarty/plugins/modifier.replace.php

@@ -0,0 +1,34 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifier
+ */
+
+/**
+ * Smarty replace modifier plugin
+ * Type:     modifier<br>
+ * Name:     replace<br>
+ * Purpose:  simple search/replace
+ *
+ * @link   http://smarty.php.net/manual/en/language.modifier.replace.php replace (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author Uwe Tews
+ *
+ * @param string $string  input string
+ * @param string $search  text to search for
+ * @param string $replace replacement text
+ *
+ * @return string
+ */
+function smarty_modifier_replace($string, $search, $replace)
+{
+    if (Smarty::$_MBSTRING) {
+        require_once(SMARTY_PLUGINS_DIR . 'shared.mb_str_replace.php');
+
+        return smarty_mb_str_replace($search, $replace, $string);
+    }
+
+    return str_replace($search, $replace, $string);
+}

+ 27 - 0
Qii/View/smarty/plugins/modifier.spacify.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifier
+ */
+
+/**
+ * Smarty spacify modifier plugin
+ * Type:     modifier<br>
+ * Name:     spacify<br>
+ * Purpose:  add spaces between characters in a string
+ *
+ * @link   http://smarty.php.net/manual/en/language.modifier.spacify.php spacify (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ *
+ * @param string $string       input string
+ * @param string $spacify_char string to insert between characters.
+ *
+ * @return string
+ */
+function smarty_modifier_spacify($string, $spacify_char = ' ')
+{
+    // well… what about charsets besides latin and UTF-8?
+    return implode($spacify_char, preg_split('//' . Smarty::$_UTF8_MODIFIER, $string, - 1, PREG_SPLIT_NO_EMPTY));
+}

+ 66 - 0
Qii/View/smarty/plugins/modifier.truncate.php

@@ -0,0 +1,66 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifier
+ */
+
+/**
+ * Smarty truncate modifier plugin
+ * Type:     modifier<br>
+ * Name:     truncate<br>
+ * Purpose:  Truncate a string to a certain length if necessary,
+ *               optionally splitting in the middle of a word, and
+ *               appending the $etc string or inserting $etc into the middle.
+ *
+ * @link   http://smarty.php.net/manual/en/language.modifier.truncate.php truncate (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ *
+ * @param string  $string      input string
+ * @param integer $length      length of truncated text
+ * @param string  $etc         end string
+ * @param boolean $break_words truncate at word boundary
+ * @param boolean $middle      truncate in the middle of text
+ *
+ * @return string truncated string
+ */
+function smarty_modifier_truncate($string, $length = 80, $etc = '...', $break_words = false, $middle = false)
+{
+    if ($length == 0) {
+        return '';
+    }
+
+    if (Smarty::$_MBSTRING) {
+        if (mb_strlen($string, Smarty::$_CHARSET) > $length) {
+            $length -= min($length, mb_strlen($etc, Smarty::$_CHARSET));
+            if (!$break_words && !$middle) {
+                $string = preg_replace('/\s+?(\S+)?$/' . Smarty::$_UTF8_MODIFIER, '',
+                                       mb_substr($string, 0, $length + 1, Smarty::$_CHARSET));
+            }
+            if (!$middle) {
+                return mb_substr($string, 0, $length, Smarty::$_CHARSET) . $etc;
+            }
+
+            return mb_substr($string, 0, $length / 2, Smarty::$_CHARSET) . $etc .
+                   mb_substr($string, - $length / 2, $length, Smarty::$_CHARSET);
+        }
+
+        return $string;
+    }
+
+    // no MBString fallback
+    if (isset($string[ $length ])) {
+        $length -= min($length, strlen($etc));
+        if (!$break_words && !$middle) {
+            $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length + 1));
+        }
+        if (!$middle) {
+            return substr($string, 0, $length) . $etc;
+        }
+
+        return substr($string, 0, $length / 2) . $etc . substr($string, - $length / 2);
+    }
+
+    return $string;
+}

+ 29 - 0
Qii/View/smarty/plugins/modifiercompiler.cat.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty cat modifier plugin
+ * Type:     modifier<br>
+ * Name:     cat<br>
+ * Date:     Feb 24, 2003<br>
+ * Purpose:  catenate a value to a variable<br>
+ * Input:    string to catenate<br>
+ * Example:  {$var|cat:"foo"}
+ *
+ * @link     http://smarty.php.net/manual/en/language.modifier.cat.php cat
+ *           (Smarty online manual)
+ * @author   Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_cat($params)
+{
+    return '(' . implode(').(', $params) . ')';
+}

+ 32 - 0
Qii/View/smarty/plugins/modifiercompiler.count_characters.php

@@ -0,0 +1,32 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty count_characters modifier plugin
+ * Type:     modifier<br>
+ * Name:     count_characteres<br>
+ * Purpose:  count the number of characters in a text
+ *
+ * @link   http://www.smarty.net/manual/en/language.modifier.count.characters.php count_characters (Smarty online manual)
+ * @author Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_count_characters($params)
+{
+    if (!isset($params[ 1 ]) || $params[ 1 ] != 'true') {
+        return 'preg_match_all(\'/[^\s]/' . Smarty::$_UTF8_MODIFIER . '\',' . $params[ 0 ] . ', $tmp)';
+    }
+    if (Smarty::$_MBSTRING) {
+        return 'mb_strlen(' . $params[ 0 ] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')';
+    }
+    // no MBString fallback
+    return 'strlen(' . $params[ 0 ] . ')';
+}

+ 27 - 0
Qii/View/smarty/plugins/modifiercompiler.count_paragraphs.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty count_paragraphs modifier plugin
+ * Type:     modifier<br>
+ * Name:     count_paragraphs<br>
+ * Purpose:  count the number of paragraphs in a text
+ *
+ * @link    http://www.smarty.net/manual/en/language.modifier.count.paragraphs.php
+ *          count_paragraphs (Smarty online manual)
+ * @author  Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_count_paragraphs($params)
+{
+    // count \r or \n characters
+    return '(preg_match_all(\'#[\r\n]+#\', ' . $params[ 0 ] . ', $tmp)+1)';
+}

+ 27 - 0
Qii/View/smarty/plugins/modifiercompiler.count_sentences.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty count_sentences modifier plugin
+ * Type:     modifier<br>
+ * Name:     count_sentences
+ * Purpose:  count the number of sentences in a text
+ *
+ * @link    http://www.smarty.net/manual/en/language.modifier.count.paragraphs.php
+ *          count_sentences (Smarty online manual)
+ * @author  Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_count_sentences($params)
+{
+    // find periods, question marks, exclamation marks with a word before but not after.
+    return 'preg_match_all("#\w[\.\?\!](\W|$)#S' . Smarty::$_UTF8_MODIFIER . '", ' . $params[ 0 ] . ', $tmp)';
+}

+ 32 - 0
Qii/View/smarty/plugins/modifiercompiler.count_words.php

@@ -0,0 +1,32 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty count_words modifier plugin
+ * Type:     modifier<br>
+ * Name:     count_words<br>
+ * Purpose:  count the number of words in a text
+ *
+ * @link   http://www.smarty.net/manual/en/language.modifier.count.words.php count_words (Smarty online manual)
+ * @author Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_count_words($params)
+{
+    if (Smarty::$_MBSTRING) {
+        // return 'preg_match_all(\'#[\w\pL]+#' . Smarty::$_UTF8_MODIFIER . '\', ' . $params[0] . ', $tmp)';
+        // expression taken from http://de.php.net/manual/en/function.str-word-count.php#85592
+        return 'preg_match_all(\'/\p{L}[\p{L}\p{Mn}\p{Pd}\\\'\x{2019}]*/' . Smarty::$_UTF8_MODIFIER . '\', ' .
+               $params[ 0 ] . ', $tmp)';
+    }
+    // no MBString fallback
+    return 'str_word_count(' . $params[ 0 ] . ')';
+}

+ 35 - 0
Qii/View/smarty/plugins/modifiercompiler.default.php

@@ -0,0 +1,35 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty default modifier plugin
+ * Type:     modifier<br>
+ * Name:     default<br>
+ * Purpose:  designate default value for empty variables
+ *
+ * @link   http://www.smarty.net/manual/en/language.modifier.default.php default (Smarty online manual)
+ * @author Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_default($params)
+{
+    $output = $params[ 0 ];
+    if (!isset($params[ 1 ])) {
+        $params[ 1 ] = "''";
+    }
+
+    array_shift($params);
+    foreach ($params as $param) {
+        $output = '(($tmp = @' . $output . ')===null||$tmp===\'\' ? ' . $param . ' : $tmp)';
+    }
+
+    return $output;
+}

+ 117 - 0
Qii/View/smarty/plugins/modifiercompiler.escape.php

@@ -0,0 +1,117 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * @ignore
+ */
+require_once(SMARTY_PLUGINS_DIR . 'shared.literal_compiler_param.php');
+
+/**
+ * Smarty escape modifier plugin
+ * Type:     modifier<br>
+ * Name:     escape<br>
+ * Purpose:  escape string for output
+ *
+ * @link   http://www.smarty.net/docsv2/en/language.modifier.escape count_characters (Smarty online manual)
+ * @author Rodney Rehm
+ *
+ * @param array $params parameters
+ * @param       $compiler
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_escape($params, $compiler)
+{
+    static $_double_encode = null;
+    if ($_double_encode === null) {
+        $_double_encode = version_compare(PHP_VERSION, '5.2.3', '>=');
+    }
+
+    try {
+        $esc_type = smarty_literal_compiler_param($params, 1, 'html');
+        $char_set = smarty_literal_compiler_param($params, 2, Smarty::$_CHARSET);
+        $double_encode = smarty_literal_compiler_param($params, 3, true);
+
+        if (!$char_set) {
+            $char_set = Smarty::$_CHARSET;
+        }
+
+        switch ($esc_type) {
+            case 'html':
+                if ($_double_encode) {
+                    return 'htmlspecialchars(' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ', ' .
+                           var_export($double_encode, true) . ')';
+                } elseif ($double_encode) {
+                    return 'htmlspecialchars(' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ')';
+                } else {
+                    // fall back to modifier.escape.php
+                }
+
+            case 'htmlall':
+                if (Smarty::$_MBSTRING) {
+                    if ($_double_encode) {
+                        // php >=5.2.3 - go native
+                        return 'mb_convert_encoding(htmlspecialchars(' . $params[ 0 ] . ', ENT_QUOTES, ' .
+                               var_export($char_set, true) . ', ' . var_export($double_encode, true) .
+                               '), "HTML-ENTITIES", ' . var_export($char_set, true) . ')';
+                    } elseif ($double_encode) {
+                        // php <5.2.3 - only handle double encoding
+                        return 'mb_convert_encoding(htmlspecialchars(' . $params[ 0 ] . ', ENT_QUOTES, ' .
+                               var_export($char_set, true) . '), "HTML-ENTITIES", ' . var_export($char_set, true) . ')';
+                    } else {
+                        // fall back to modifier.escape.php
+                    }
+                }
+
+                // no MBString fallback
+                if ($_double_encode) {
+                    // php >=5.2.3 - go native
+                    return 'htmlentities(' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ', ' .
+                           var_export($double_encode, true) . ')';
+                } elseif ($double_encode) {
+                    // php <5.2.3 - only handle double encoding
+                    return 'htmlentities(' . $params[ 0 ] . ', ENT_QUOTES, ' . var_export($char_set, true) . ')';
+                } else {
+                    // fall back to modifier.escape.php
+                }
+
+            case 'url':
+                return 'rawurlencode(' . $params[ 0 ] . ')';
+
+            case 'urlpathinfo':
+                return 'str_replace("%2F", "/", rawurlencode(' . $params[ 0 ] . '))';
+
+            case 'quotes':
+                // escape unescaped single quotes
+                return 'preg_replace("%(?<!\\\\\\\\)\'%", "\\\'",' . $params[ 0 ] . ')';
+
+            case 'javascript':
+                // escape quotes and backslashes, newlines, etc.
+                return 'strtr(' . $params[ 0 ] .
+                       ', array("\\\\" => "\\\\\\\\", "\'" => "\\\\\'", "\"" => "\\\\\"", "\\r" => "\\\\r", "\\n" => "\\\n", "</" => "<\/" ))';
+        }
+    }
+    catch (SmartyException $e) {
+        // pass through to regular plugin fallback
+    }
+
+    // could not optimize |escape call, so fallback to regular plugin
+    if ($compiler->template->caching && ($compiler->tag_nocache | $compiler->nocache)) {
+        $compiler->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ 'escape' ][ 'modifier' ][ 'file' ] =
+            SMARTY_PLUGINS_DIR . 'modifier.escape.php';
+        $compiler->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ 'escape' ][ 'modifier' ][ 'function' ] =
+            'smarty_modifier_escape';
+    } else {
+        $compiler->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ 'escape' ][ 'modifier' ][ 'file' ] =
+            SMARTY_PLUGINS_DIR . 'modifier.escape.php';
+        $compiler->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ 'escape' ][ 'modifier' ][ 'function' ] =
+            'smarty_modifier_escape';
+    }
+
+    return 'smarty_modifier_escape(' . join(', ', $params) . ')';
+}

+ 33 - 0
Qii/View/smarty/plugins/modifiercompiler.from_charset.php

@@ -0,0 +1,33 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty from_charset modifier plugin
+ * Type:     modifier<br>
+ * Name:     from_charset<br>
+ * Purpose:  convert character encoding from $charset to internal encoding
+ *
+ * @author Rodney Rehm
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_from_charset($params)
+{
+    if (!Smarty::$_MBSTRING) {
+        // FIXME: (rodneyrehm) shouldn't this throw an error?
+        return $params[ 0 ];
+    }
+
+    if (!isset($params[ 1 ])) {
+        $params[ 1 ] = '"ISO-8859-1"';
+    }
+
+    return 'mb_convert_encoding(' . $params[ 0 ] . ', "' . addslashes(Smarty::$_CHARSET) . '", ' . $params[ 1 ] . ')';
+}

+ 33 - 0
Qii/View/smarty/plugins/modifiercompiler.indent.php

@@ -0,0 +1,33 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty indent modifier plugin
+ * Type:     modifier<br>
+ * Name:     indent<br>
+ * Purpose:  indent lines of text
+ *
+ * @link   http://www.smarty.net/manual/en/language.modifier.indent.php indent (Smarty online manual)
+ * @author Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+
+function smarty_modifiercompiler_indent($params)
+{
+    if (!isset($params[ 1 ])) {
+        $params[ 1 ] = 4;
+    }
+    if (!isset($params[ 2 ])) {
+        $params[ 2 ] = "' '";
+    }
+
+    return 'preg_replace(\'!^!m\',str_repeat(' . $params[ 2 ] . ',' . $params[ 1 ] . '),' . $params[ 0 ] . ')';
+}

+ 31 - 0
Qii/View/smarty/plugins/modifiercompiler.lower.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty lower modifier plugin
+ * Type:     modifier<br>
+ * Name:     lower<br>
+ * Purpose:  convert string to lowercase
+ *
+ * @link   http://www.smarty.net/manual/en/language.modifier.lower.php lower (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+
+function smarty_modifiercompiler_lower($params)
+{
+    if (Smarty::$_MBSTRING) {
+        return 'mb_strtolower(' . $params[ 0 ] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')';
+    }
+    // no MBString fallback
+    return 'strtolower(' . $params[ 0 ] . ')';
+}

+ 21 - 0
Qii/View/smarty/plugins/modifiercompiler.noprint.php

@@ -0,0 +1,21 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty noprint modifier plugin
+ * Type:     modifier<br>
+ * Name:     noprint<br>
+ * Purpose:  return an empty string
+ *
+ * @author   Uwe Tews
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_noprint()
+{
+    return "''";
+}

+ 25 - 0
Qii/View/smarty/plugins/modifiercompiler.string_format.php

@@ -0,0 +1,25 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty string_format modifier plugin
+ * Type:     modifier<br>
+ * Name:     string_format<br>
+ * Purpose:  format strings via sprintf
+ *
+ * @link   http://www.smarty.net/manual/en/language.modifier.string.format.php string_format (Smarty online manual)
+ * @author Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_string_format($params)
+{
+    return 'sprintf(' . $params[ 1 ] . ',' . $params[ 0 ] . ')';
+}

+ 33 - 0
Qii/View/smarty/plugins/modifiercompiler.strip.php

@@ -0,0 +1,33 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty strip modifier plugin
+ * Type:     modifier<br>
+ * Name:     strip<br>
+ * Purpose:  Replace all repeated spaces, newlines, tabs
+ *              with a single space or supplied replacement string.<br>
+ * Example:  {$var|strip} {$var|strip:"&nbsp;"}<br>
+ * Date:     September 25th, 2002
+ *
+ * @link   http://www.smarty.net/manual/en/language.modifier.strip.php strip (Smarty online manual)
+ * @author Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+
+function smarty_modifiercompiler_strip($params)
+{
+    if (!isset($params[ 1 ])) {
+        $params[ 1 ] = "' '";
+    }
+
+    return "preg_replace('!\s+!" . Smarty::$_UTF8_MODIFIER . "', {$params[1]},{$params[0]})";
+}

+ 29 - 0
Qii/View/smarty/plugins/modifiercompiler.strip_tags.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty strip_tags modifier plugin
+ * Type:     modifier<br>
+ * Name:     strip_tags<br>
+ * Purpose:  strip html tags from text
+ *
+ * @link   http://www.smarty.net/docs/en/language.modifier.strip.tags.tpl strip_tags (Smarty online manual)
+ * @author Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_strip_tags($params)
+{
+    if (!isset($params[ 1 ]) || $params[ 1 ] === true || trim($params[ 1 ], '"') == 'true') {
+        return "preg_replace('!<[^>]*?>!', ' ', {$params[0]})";
+    } else {
+        return 'strip_tags(' . $params[ 0 ] . ')';
+    }
+}

+ 33 - 0
Qii/View/smarty/plugins/modifiercompiler.to_charset.php

@@ -0,0 +1,33 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty to_charset modifier plugin
+ * Type:     modifier<br>
+ * Name:     to_charset<br>
+ * Purpose:  convert character encoding from internal encoding to $charset
+ *
+ * @author Rodney Rehm
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_to_charset($params)
+{
+    if (!Smarty::$_MBSTRING) {
+        // FIXME: (rodneyrehm) shouldn't this throw an error?
+        return $params[ 0 ];
+    }
+
+    if (!isset($params[ 1 ])) {
+        $params[ 1 ] = '"ISO-8859-1"';
+    }
+
+    return 'mb_convert_encoding(' . $params[ 0 ] . ', ' . $params[ 1 ] . ', "' . addslashes(Smarty::$_CHARSET) . '")';
+}

+ 50 - 0
Qii/View/smarty/plugins/modifiercompiler.unescape.php

@@ -0,0 +1,50 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty unescape modifier plugin
+ * Type:     modifier<br>
+ * Name:     unescape<br>
+ * Purpose:  unescape html entities
+ *
+ * @author Rodney Rehm
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_unescape($params)
+{
+    if (!isset($params[ 1 ])) {
+        $params[ 1 ] = 'html';
+    }
+    if (!isset($params[ 2 ])) {
+        $params[ 2 ] = '\'' . addslashes(Smarty::$_CHARSET) . '\'';
+    } else {
+        $params[ 2 ] = "'" . $params[ 2 ] . "'";
+    }
+
+    switch (trim($params[ 1 ], '"\'')) {
+        case 'entity':
+        case 'htmlall':
+            if (Smarty::$_MBSTRING) {
+                return 'mb_convert_encoding(' . $params[ 0 ] . ', ' . $params[ 2 ] . ', \'HTML-ENTITIES\')';
+            }
+
+            return 'html_entity_decode(' . $params[ 0 ] . ', ENT_NOQUOTES, ' . $params[ 2 ] . ')';
+
+        case 'html':
+            return 'htmlspecialchars_decode(' . $params[ 0 ] . ', ENT_QUOTES)';
+
+        case 'url':
+            return 'rawurldecode(' . $params[ 0 ] . ')';
+
+        default:
+            return $params[ 0 ];
+    }
+}

+ 29 - 0
Qii/View/smarty/plugins/modifiercompiler.upper.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty upper modifier plugin
+ * Type:     modifier<br>
+ * Name:     lower<br>
+ * Purpose:  convert string to uppercase
+ *
+ * @link   http://smarty.php.net/manual/en/language.modifier.upper.php lower (Smarty online manual)
+ * @author Uwe Tews
+ *
+ * @param array $params parameters
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_upper($params)
+{
+    if (Smarty::$_MBSTRING) {
+        return 'mb_strtoupper(' . $params[ 0 ] . ', \'' . addslashes(Smarty::$_CHARSET) . '\')';
+    }
+    // no MBString fallback
+    return 'strtoupper(' . $params[ 0 ] . ')';
+}

+ 51 - 0
Qii/View/smarty/plugins/modifiercompiler.wordwrap.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsModifierCompiler
+ */
+
+/**
+ * Smarty wordwrap modifier plugin
+ * Type:     modifier<br>
+ * Name:     wordwrap<br>
+ * Purpose:  wrap a string of text at a given length
+ *
+ * @link   http://smarty.php.net/manual/en/language.modifier.wordwrap.php wordwrap (Smarty online manual)
+ * @author Uwe Tews
+ *
+ * @param array $params parameters
+ * @param       $compiler
+ *
+ * @return string with compiled code
+ */
+function smarty_modifiercompiler_wordwrap($params, $compiler)
+{
+    if (!isset($params[ 1 ])) {
+        $params[ 1 ] = 80;
+    }
+    if (!isset($params[ 2 ])) {
+        $params[ 2 ] = '"\n"';
+    }
+    if (!isset($params[ 3 ])) {
+        $params[ 3 ] = 'false';
+    }
+    $function = 'wordwrap';
+    if (Smarty::$_MBSTRING) {
+        if ($compiler->template->caching && ($compiler->tag_nocache | $compiler->nocache)) {
+            $compiler->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ 'wordwrap' ][ 'modifier' ][ 'file' ] =
+                SMARTY_PLUGINS_DIR . 'shared.mb_wordwrap.php';
+            $compiler->template->required_plugins[ 'nocache' ][ 'wordwrap' ][ 'modifier' ][ 'function' ] =
+                'smarty_mb_wordwrap';
+        } else {
+            $compiler->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ 'wordwrap' ][ 'modifier' ][ 'file' ] =
+                SMARTY_PLUGINS_DIR . 'shared.mb_wordwrap.php';
+            $compiler->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ 'wordwrap' ][ 'modifier' ][ 'function' ] =
+                'smarty_mb_wordwrap';
+        }
+        $function = 'smarty_mb_wordwrap';
+    }
+
+    return $function . '(' . $params[ 0 ] . ',' . $params[ 1 ] . ',' . $params[ 2 ] . ',' . $params[ 3 ] . ')';
+}

+ 89 - 0
Qii/View/smarty/plugins/outputfilter.trimwhitespace.php

@@ -0,0 +1,89 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFilter
+ */
+
+/**
+ * Smarty trimwhitespace outputfilter plugin
+ * Trim unnecessary whitespace from HTML markup.
+ *
+ * @author   Rodney Rehm
+ *
+ * @param string $source input string
+ *
+ * @return string filtered output
+ * @todo     substr_replace() is not overloaded by mbstring.func_overload - so this function might fail!
+ */
+function smarty_outputfilter_trimwhitespace($source)
+{
+    $store = array();
+    $_store = 0;
+    $_offset = 0;
+
+    // Unify Line-Breaks to \n
+    $source = preg_replace("/\015\012|\015|\012/", "\n", $source);
+
+    // capture Internet Explorer and KnockoutJS Conditional Comments
+    if (preg_match_all('#<!--((\[[^\]]+\]>.*?<!\[[^\]]+\])|(\s*/?ko\s+.+))-->#is', $source, $matches,
+                       PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
+        foreach ($matches as $match) {
+            $store[] = $match[ 0 ][ 0 ];
+            $_length = strlen($match[ 0 ][ 0 ]);
+            $replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
+            $source = substr_replace($source, $replace, $match[ 0 ][ 1 ] - $_offset, $_length);
+
+            $_offset += $_length - strlen($replace);
+            $_store ++;
+        }
+    }
+
+    // Strip all HTML-Comments
+    // yes, even the ones in <script> - see http://stackoverflow.com/a/808850/515124
+    $source = preg_replace('#<!--.*?-->#ms', '', $source);
+
+    // capture html elements not to be messed with
+    $_offset = 0;
+    if (preg_match_all('#(<script[^>]*>.*?</script[^>]*>)|(<textarea[^>]*>.*?</textarea[^>]*>)|(<pre[^>]*>.*?</pre[^>]*>)#is',
+                       $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
+        foreach ($matches as $match) {
+            $store[] = $match[ 0 ][ 0 ];
+            $_length = strlen($match[ 0 ][ 0 ]);
+            $replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
+            $source = substr_replace($source, $replace, $match[ 0 ][ 1 ] - $_offset, $_length);
+
+            $_offset += $_length - strlen($replace);
+            $_store ++;
+        }
+    }
+
+    $expressions = array(// replace multiple spaces between tags by a single space
+                         // can't remove them entirely, becaue that might break poorly implemented CSS display:inline-block elements
+                         '#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1 \2',
+                         // remove spaces between attributes (but not in attribute values!)
+                         '#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5',
+                         // note: for some very weird reason trim() seems to remove spaces inside attributes.
+                         // maybe a \0 byte or something is interfering?
+                         '#^\s+<#Ss' => '<', '#>\s+$#Ss' => '>',);
+
+    $source = preg_replace(array_keys($expressions), array_values($expressions), $source);
+    // note: for some very weird reason trim() seems to remove spaces inside attributes.
+    // maybe a \0 byte or something is interfering?
+    // $source = trim( $source );
+
+    $_offset = 0;
+    if (preg_match_all('#@!@SMARTY:([0-9]+):SMARTY@!@#is', $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
+        foreach ($matches as $match) {
+            $_length = strlen($match[ 0 ][ 0 ]);
+            $replace = $store[ $match[ 1 ][ 0 ] ];
+            $source = substr_replace($source, $replace, $match[ 0 ][ 1 ] + $_offset, $_length);
+
+            $_offset += strlen($replace) - $_length;
+            $_store ++;
+        }
+    }
+
+    return $source;
+}

+ 34 - 0
Qii/View/smarty/plugins/shared.escape_special_chars.php

@@ -0,0 +1,34 @@
+<?php
+/**
+ * Smarty shared plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsShared
+ */
+
+/**
+ * escape_special_chars common function
+ * Function: smarty_function_escape_special_chars<br>
+ * Purpose:  used by other smarty functions to escape
+ *           special chars except for already escaped ones
+ *
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ *
+ * @param  string $string text that should by escaped
+ *
+ * @return string
+ */
+function smarty_function_escape_special_chars($string)
+{
+    if (!is_array($string)) {
+        if (version_compare(PHP_VERSION, '5.2.3', '>=')) {
+            $string = htmlspecialchars($string, ENT_COMPAT, Smarty::$_CHARSET, false);
+        } else {
+            $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
+            $string = htmlspecialchars($string);
+            $string = str_replace(array('%%%SMARTY_START%%%', '%%%SMARTY_END%%%'), array('&', ';'), $string);
+        }
+    }
+
+    return $string;
+}

+ 36 - 0
Qii/View/smarty/plugins/shared.literal_compiler_param.php

@@ -0,0 +1,36 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsShared
+ */
+
+/**
+ * evaluate compiler parameter
+ *
+ * @param array   $params  parameter array as given to the compiler function
+ * @param integer $index   array index of the parameter to convert
+ * @param mixed   $default value to be returned if the parameter is not present
+ *
+ * @return mixed evaluated value of parameter or $default
+ * @throws SmartyException if parameter is not a literal (but an expression, variable, …)
+ * @author Rodney Rehm
+ */
+function smarty_literal_compiler_param($params, $index, $default = null)
+{
+    // not set, go default
+    if (!isset($params[ $index ])) {
+        return $default;
+    }
+    // test if param is a literal
+    if (!preg_match('/^([\'"]?)[a-zA-Z0-9-]+(\\1)$/', $params[ $index ])) {
+        throw new SmartyException('$param[' . $index .
+                                  '] is not a literal and is thus not evaluatable at compile time');
+    }
+
+    $t = null;
+    eval("\$t = " . $params[ $index ] . ";");
+
+    return $t;
+}

+ 45 - 0
Qii/View/smarty/plugins/shared.make_timestamp.php

@@ -0,0 +1,45 @@
+<?php
+/**
+ * Smarty shared plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsShared
+ */
+
+/**
+ * Function: smarty_make_timestamp<br>
+ * Purpose:  used by other smarty functions to make a timestamp from a string.
+ *
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ *
+ * @param DateTime|int|string $string date object, timestamp or string that can be converted using strtotime()
+ *
+ * @return int
+ */
+function smarty_make_timestamp($string)
+{
+    if (empty($string)) {
+        // use "now":
+        return time();
+    } elseif ($string instanceof DateTime ||
+              (interface_exists('DateTimeInterface', false) && $string instanceof DateTimeInterface)
+    ) {
+        return (int) $string->format('U'); // PHP 5.2 BC
+    } elseif (strlen($string) == 14 && ctype_digit($string)) {
+        // it is mysql timestamp format of YYYYMMDDHHMMSS?
+        return mktime(substr($string, 8, 2), substr($string, 10, 2), substr($string, 12, 2), substr($string, 4, 2),
+                      substr($string, 6, 2), substr($string, 0, 4));
+    } elseif (is_numeric($string)) {
+        // it is a numeric string, we handle it as timestamp
+        return (int) $string;
+    } else {
+        // strtotime should handle it
+        $time = strtotime($string);
+        if ($time == - 1 || $time === false) {
+            // strtotime() was not able to parse $string, use "now":
+            return time();
+        }
+
+        return $time;
+    }
+}

+ 55 - 0
Qii/View/smarty/plugins/shared.mb_str_replace.php

@@ -0,0 +1,55 @@
+<?php
+/**
+ * Smarty shared plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsShared
+ */
+if (!function_exists('smarty_mb_str_replace')) {
+
+    /**
+     * Multibyte string replace
+     *
+     * @param  string $search  the string to be searched
+     * @param  string $replace the replacement string
+     * @param  string $subject the source string
+     * @param  int    &$count  number of matches found
+     *
+     * @return string replaced string
+     * @author Rodney Rehm
+     */
+    function smarty_mb_str_replace($search, $replace, $subject, &$count = 0)
+    {
+        if (!is_array($search) && is_array($replace)) {
+            return false;
+        }
+        if (is_array($subject)) {
+            // call mb_replace for each single string in $subject
+            foreach ($subject as &$string) {
+                $string = smarty_mb_str_replace($search, $replace, $string, $c);
+                $count += $c;
+            }
+        } elseif (is_array($search)) {
+            if (!is_array($replace)) {
+                foreach ($search as &$string) {
+                    $subject = smarty_mb_str_replace($string, $replace, $subject, $c);
+                    $count += $c;
+                }
+            } else {
+                $n = max(count($search), count($replace));
+                while ($n --) {
+                    $subject = smarty_mb_str_replace(current($search), current($replace), $subject, $c);
+                    $count += $c;
+                    next($search);
+                    next($replace);
+                }
+            }
+        } else {
+            $parts = mb_split(preg_quote($search), $subject);
+            $count = count($parts) - 1;
+            $subject = implode($replace, $parts);
+        }
+
+        return $subject;
+    }
+}

+ 54 - 0
Qii/View/smarty/plugins/shared.mb_unicode.php

@@ -0,0 +1,54 @@
+<?php
+/**
+ * Smarty shared plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsShared
+ */
+
+/**
+ * convert characters to their decimal unicode equivalents
+ *
+ * @link   http://www.ibm.com/developerworks/library/os-php-unicode/index.html#listing3 for inspiration
+ *
+ * @param string $string   characters to calculate unicode of
+ * @param string $encoding encoding of $string, if null mb_internal_encoding() is used
+ *
+ * @return array sequence of unicodes
+ * @author Rodney Rehm
+ */
+function smarty_mb_to_unicode($string, $encoding = null)
+{
+    if ($encoding) {
+        $expanded = mb_convert_encoding($string, "UTF-32BE", $encoding);
+    } else {
+        $expanded = mb_convert_encoding($string, "UTF-32BE");
+    }
+
+    return unpack("N*", $expanded);
+}
+
+/**
+ * convert unicodes to the character of given encoding
+ *
+ * @link   http://www.ibm.com/developerworks/library/os-php-unicode/index.html#listing3 for inspiration
+ *
+ * @param integer|array $unicode  single unicode or list of unicodes to convert
+ * @param string        $encoding encoding of returned string, if null mb_internal_encoding() is used
+ *
+ * @return string unicode as character sequence in given $encoding
+ * @author Rodney Rehm
+ */
+function smarty_mb_from_unicode($unicode, $encoding = null)
+{
+    $t = '';
+    if (!$encoding) {
+        $encoding = mb_internal_encoding();
+    }
+    foreach ((array) $unicode as $utf32be) {
+        $character = pack("N*", $utf32be);
+        $t .= mb_convert_encoding($character, $encoding, "UTF-32BE");
+    }
+
+    return $t;
+}

+ 75 - 0
Qii/View/smarty/plugins/shared.mb_wordwrap.php

@@ -0,0 +1,75 @@
+<?php
+/**
+ * Smarty shared plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsShared
+ */
+
+if (!function_exists('smarty_mb_wordwrap')) {
+
+    /**
+     * Wrap a string to a given number of characters
+     *
+     * @link   http://php.net/manual/en/function.wordwrap.php for similarity
+     *
+     * @param  string  $str   the string to wrap
+     * @param  int     $width the width of the output
+     * @param  string  $break the character used to break the line
+     * @param  boolean $cut   ignored parameter, just for the sake of
+     *
+     * @return string  wrapped string
+     * @author Rodney Rehm
+     */
+    function smarty_mb_wordwrap($str, $width = 75, $break = "\n", $cut = false)
+    {
+        // break words into tokens using white space as a delimiter
+        $tokens =
+            preg_split('!(\s)!S' . Smarty::$_UTF8_MODIFIER, $str, - 1, PREG_SPLIT_NO_EMPTY + PREG_SPLIT_DELIM_CAPTURE);
+        $length = 0;
+        $t = '';
+        $_previous = false;
+        $_space = false;
+
+        foreach ($tokens as $_token) {
+            $token_length = mb_strlen($_token, Smarty::$_CHARSET);
+            $_tokens = array($_token);
+            if ($token_length > $width) {
+                if ($cut) {
+                    $_tokens = preg_split('!(.{' . $width . '})!S' . Smarty::$_UTF8_MODIFIER, $_token, - 1,
+                                          PREG_SPLIT_NO_EMPTY + PREG_SPLIT_DELIM_CAPTURE);
+                }
+            }
+
+            foreach ($_tokens as $token) {
+                $_space = !!preg_match('!^\s$!S' . Smarty::$_UTF8_MODIFIER, $token);
+                $token_length = mb_strlen($token, Smarty::$_CHARSET);
+                $length += $token_length;
+
+                if ($length > $width) {
+                    // remove space before inserted break
+                    if ($_previous) {
+                        $t = mb_substr($t, 0, - 1, Smarty::$_CHARSET);
+                    }
+
+                    if (!$_space) {
+                        // add the break before the token
+                        if (!empty($t)) {
+                            $t .= $break;
+                        }
+                        $length = $token_length;
+                    }
+                } elseif ($token == "\n") {
+                    // hard break must reset counters
+                    $_previous = 0;
+                    $length = 0;
+                }
+                $_previous = $_space;
+                // add the token
+                $t .= $token;
+            }
+        }
+
+        return $t;
+    }
+}

+ 19 - 0
Qii/View/smarty/plugins/variablefilter.htmlspecialchars.php

@@ -0,0 +1,19 @@
+<?php
+/**
+ * Smarty plugin
+ *
+ * @package    Smarty
+ * @subpackage PluginsFilter
+ */
+
+/**
+ * Smarty htmlspecialchars variablefilter plugin
+ *
+ * @param string $source input string
+ *
+ * @return string filtered output
+ */
+function smarty_variablefilter_htmlspecialchars($source)
+{
+    return htmlspecialchars($source, ENT_QUOTES, Smarty::$_CHARSET);
+}

+ 220 - 0
Qii/View/smarty/sysplugins/smarty_cacheresource.php

@@ -0,0 +1,220 @@
+<?php
+/**
+ * Smarty Internal Plugin
+ *
+ * @package    Smarty
+ * @subpackage Cacher
+ */
+
+/**
+ * Cache Handler API
+ *
+ * @package    Smarty
+ * @subpackage Cacher
+ * @author     Rodney Rehm
+ */
+abstract class Smarty_CacheResource
+{
+    /**
+     * resource types provided by the core
+     *
+     * @var array
+     */
+    protected static $sysplugins = array('file' => '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}'");
+    }
+}

+ 275 - 0
Qii/View/smarty/sysplugins/smarty_cacheresource_custom.php

@@ -0,0 +1,275 @@
+<?php
+/**
+ * Smarty Internal Plugin
+ *
+ * @package    Smarty
+ * @subpackage Cacher
+ */
+
+/**
+ * Cache Handler API
+ *
+ * @package    Smarty
+ * @subpackage Cacher
+ * @author     Rodney Rehm
+ */
+abstract class Smarty_CacheResource_Custom extends Smarty_CacheResource
+{
+    /**
+     * fetch cached content and its modification time from data source
+     *
+     * @param  string  $id         unique cache content identifier
+     * @param  string  $name       template name
+     * @param  string  $cache_id   cache id
+     * @param  string  $compile_id compile id
+     * @param  string  $content    cached content
+     * @param  integer $mtime      cache modification timestamp (epoch)
+     *
+     * @return void
+     */
+    abstract protected function fetch($id, $name, $cache_id, $compile_id, &$content, &$mtime);
+
+    /**
+     * Fetch cached content's modification timestamp from data source
+     * {@internal implementing this method is optional.
+     *  Only implement it if modification times can be accessed faster than loading the complete cached content.}}
+     *
+     * @param  string $id         unique cache content identifier
+     * @param  string $name       template name
+     * @param  string $cache_id   cache id
+     * @param  string $compile_id compile id
+     *
+     * @return integer|boolean timestamp (epoch) the template was modified, or false if not found
+     */
+    protected function fetchTimestamp($id, $name, $cache_id, $compile_id)
+    {
+        return false;
+    }
+
+    /**
+     * Save content to cache
+     *
+     * @param  string       $id         unique cache content identifier
+     * @param  string       $name       template name
+     * @param  string       $cache_id   cache id
+     * @param  string       $compile_id compile id
+     * @param  integer|null $exp_time   seconds till expiration or null
+     * @param  string       $content    content to cache
+     *
+     * @return boolean      success
+     */
+    abstract protected function save($id, $name, $cache_id, $compile_id, $exp_time, $content);
+
+    /**
+     * Delete content from cache
+     *
+     * @param  string|null  $name       template name
+     * @param  string|null  $cache_id   cache id
+     * @param  string|null  $compile_id compile id
+     * @param  integer|null $exp_time   seconds till expiration time in seconds or null
+     *
+     * @return integer      number of deleted caches
+     */
+    abstract protected function delete($name, $cache_id, $compile_id, $exp_time);
+
+    /**
+     * populate Cached Object with meta data from Resource
+     *
+     * @param  Smarty_Template_Cached   $cached    cached object
+     * @param  Smarty_Internal_Template $_template template object
+     *
+     * @return void
+     */
+    public function populate(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template)
+    {
+        $_cache_id = isset($cached->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);
+    }
+}

+ 507 - 0
Qii/View/smarty/sysplugins/smarty_cacheresource_keyvaluestore.php

@@ -0,0 +1,507 @@
+<?php
+/**
+ * Smarty Internal Plugin
+ *
+ * @package    Smarty
+ * @subpackage Cacher
+ */
+
+/**
+ * Smarty Cache Handler Base for Key/Value Storage Implementations
+ * This class implements the functionality required to use simple key/value stores
+ * for hierarchical cache groups. key/value stores like memcache or APC do not support
+ * wildcards in keys, therefore a cache group cannot be cleared like "a|*" - which
+ * is no problem to filesystem and RDBMS implementations.
+ * This implementation is based on the concept of invalidation. While one specific cache
+ * can be identified and cleared, any range of caches cannot be identified. For this reason
+ * each level of the cache group hierarchy can have its own value in the store. These values
+ * are nothing but microtimes, telling us when a particular cache group was cleared for the
+ * last time. These keys are evaluated for every cache read to determine if the cache has
+ * been invalidated since it was created and should hence be treated as inexistent.
+ * Although deep hierarchies are possible, they are not recommended. Try to keep your
+ * cache groups as shallow as possible. Anything up 3-5 parents should be ok. So
+ * »a|b|c« is a good depth where »a|b|c|d|e|f|g|h|i|j|k« isn't. Try to join correlating
+ * cache groups: if your cache groups look somewhat like »a|b|$page|$items|$whatever«
+ * consider using »a|b|c|$page-$items-$whatever« instead.
+ *
+ * @package    Smarty
+ * @subpackage Cacher
+ * @author     Rodney Rehm
+ */
+abstract class Smarty_CacheResource_KeyValueStore extends Smarty_CacheResource
+{
+    /**
+     * cache for contents
+     *
+     * @var array
+     */
+    protected $contents = array();
+
+    /**
+     * cache for timestamps
+     *
+     * @var array
+     */
+    protected $timestamps = array();
+
+    /**
+     * populate Cached Object with meta data from Resource
+     *
+     * @param  Smarty_Template_Cached   $cached    cached object
+     * @param  Smarty_Internal_Template $_template template object
+     *
+     * @return void
+     */
+    public function populate(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template)
+    {
+        $cached->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;
+    }
+}

+ 68 - 0
Qii/View/smarty/sysplugins/smarty_data.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * Smarty Plugin Data
+ * This file contains the data object
+ *
+ * @package    Smarty
+ * @subpackage Template
+ * @author     Uwe Tews
+ */
+
+/**
+ * class for the Smarty data object
+ * The Smarty data object will hold Smarty variables in the current scope
+ *
+ * @package    Smarty
+ * @subpackage Template
+ */
+class Smarty_Data extends Smarty_Internal_Data
+{
+    /**
+     * Counter
+     *
+     * @var int
+     */
+    static $count = 0;
+
+    /**
+     * Data block name
+     *
+     * @var string
+     */
+    public $dataObjectName = '';
+
+    /**
+     * Smarty object
+     *
+     * @var Smarty
+     */
+    public $smarty = null;
+
+    /**
+     * create Smarty data object
+     *
+     * @param Smarty|array                    $_parent parent template
+     * @param Smarty|Smarty_Internal_Template $smarty  global smarty instance
+     * @param string                          $name    optional data block name
+     *
+     * @throws SmartyException
+     */
+    public function __construct($_parent = null, $smarty = null, $name = null)
+    {
+        parent::__construct();
+        self::$count ++;
+        $this->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");
+        }
+    }
+}

+ 90 - 0
Qii/View/smarty/sysplugins/smarty_internal_block.php

@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * Smarty {block} tag class
+ *
+ * @package    Smarty
+ * @subpackage PluginsInternal
+ * @author     Uwe Tews
+ */
+class Smarty_Internal_Block
+{
+    /**
+     * Block name
+     *
+     * @var string
+     */
+    public $name = '';
+
+    /**
+     * Hide attribute
+     *
+     * @var bool
+     */
+    public $hide = false;
+
+    /**
+     * Append attribute
+     *
+     * @var bool
+     */
+    public $append = false;
+
+    /**
+     * prepend attribute
+     *
+     * @var bool
+     */
+    public $prepend = false;
+
+    /**
+     * Block calls {$smarty.block.child}
+     *
+     * @var bool
+     */
+    public $callsChild = false;
+
+    /**
+     * Inheritance child block
+     *
+     * @var Smarty_Internal_Block|null
+     */
+    public $child = null;
+
+    /**
+     * Inheritance calling parent block
+     *
+     * @var Smarty_Internal_Block|null
+     */
+    public $parent = null;
+
+    /**
+     * Inheritance Template index
+     *
+     * @var int
+     */
+    public $tplIndex = 0;
+
+    /**
+     * Smarty_Internal_Block constructor.
+     * - if outer level {block} of child template ($state == 1) save it as child root block
+     * - otherwise process inheritance and render
+     *
+     * @param string   $name     block name
+     * @param int|null $tplIndex index of outer level {block} if nested
+     */
+    public function __construct($name, $tplIndex)
+    {
+        $this->name = $name;
+        $this->tplIndex = $tplIndex;
+    }
+
+    /**
+     * Compiled block code overloaded by {block} class
+     *
+     * @param \Smarty_Internal_Template $tpl
+     */
+    public function callBlock(Smarty_Internal_Template $tpl)
+    {
+    }
+}

+ 220 - 0
Qii/View/smarty/sysplugins/smarty_internal_cacheresource_file.php

@@ -0,0 +1,220 @@
+<?php
+/**
+ * Smarty Internal Plugin CacheResource File
+ *
+ * @package    Smarty
+ * @subpackage Cacher
+ * @author     Uwe Tews
+ * @author     Rodney Rehm
+ */
+
+/**
+ * This class does contain all necessary methods for the HTML cache on file system
+ * Implements the file system as resource for the HTML cache Version ussing nocache inserts.
+ *
+ * @package    Smarty
+ * @subpackage Cacher
+ */
+class Smarty_Internal_CacheResource_File extends Smarty_CacheResource
+{
+    /**
+     * populate Cached Object with meta data from Resource
+     *
+     * @param Smarty_Template_Cached   $cached    cached object
+     * @param Smarty_Internal_Template $_template template object
+     *
+     * @return void
+     */
+    public function populate(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template)
+    {
+        $source = &$_template->source;
+        $smarty = &$_template->smarty;
+        $_compile_dir_sep = $smarty->use_sub_dirs ? 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 ] . DS . $_filepath[ 2 ] . $_filepath[ 3 ] . DS .
+                                 $_filepath[ 4 ] . $_filepath[ 5 ] . 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') && 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_Internal_Extension_Clear::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_Internal_Extension_Clear::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);
+    }
+}

+ 51 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_append.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Append
+ * Compiles the {append} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Append Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Append extends Smarty_Internal_Compile_Assign
+{
+    /**
+     * Compiles code for the {append} 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)
+    {
+        // the following must be assigned at runtime because it will be overwritten in parent class
+        $this->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);
+    }
+}

+ 94 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_assign.php

@@ -0,0 +1,94 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Assign
+ * Compiles the {assign} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Assign Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $option_flags = array('nocache', 'noscope');
+
+   /**
+     * Valid scope names
+     *
+     * @var array
+     */
+    public $valid_scopes = array('local' => 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 =
+                "<?php \$_tmp_array = isset(\$_smarty_tpl->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 = "<?php \$_smarty_tpl->_assignInScope({$_var}, {$_attr['value']}{$_params});\n?>";
+        }
+        return $output;
+    }
+}

+ 247 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_block.php

@@ -0,0 +1,247 @@
+<?php
+/*
+ * This file is part of Smarty.
+ *
+ * (c) 2015 Uwe Tews
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Smarty Internal Plugin Compile Block Class
+ *
+ * @author Uwe Tews <uwe.tews@googlemail.com>
+ */
+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');
+
+    /**
+     * nesting level of block tags
+     *
+     * @var int
+     */
+    public static $blockTagNestingLevel = 0;
+
+    /**
+     * 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' ] ++;
+        $compiler->_cache[ 'blockName' ][ $compiler->_cache[ 'blockNesting' ] ] = $_attr[ 'name' ];
+        $compiler->_cache[ 'blockParams' ][ $compiler->_cache[ 'blockNesting' ] ] = array();
+        $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;
+    }
+
+    /**
+     * Compile saved child block source
+     *
+     * @param \Smarty_Internal_TemplateCompilerBase compiler object
+     * @param string                                $_name   optional name of child block
+     *
+     * @return string   compiled code of child block
+     */
+    static function compileChildBlock(Smarty_Internal_TemplateCompilerBase $compiler, $_name = null)
+    {
+        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 = "<?php \n\$_smarty_tpl->inheritance->callChild(\$_smarty_tpl, \$this);\n?>\n";
+        return $output;
+    }
+
+    /**
+     * Compile $smarty.block.parent
+     *
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
+     * @param string                                $_name    optional name of child block
+     *
+     * @return string   compiled code of child block
+     */
+    static function compileParentBlock(Smarty_Internal_TemplateCompilerBase $compiler, $_name = null)
+    {
+        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 = "<?php \n\$_smarty_tpl->inheritance->callParent(\$_smarty_tpl, \$this);\n?>\n";
+        return $output;
+    }
+}
+
+/**
+ * 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 = 'Block_' . preg_replace('![^\w]+!', '_', uniqid(rand(), true));
+        // 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 = "<?php\n";
+        $output .= "/* {block {$_name}} */\n";
+        $output .= "class {$_className} extends Smarty_Internal_Block\n";
+        $output .= "{\n";
+        foreach ($_block as $property => $value) {
+            $output .= "public \${$property} = {$value};\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 = "<?php\n";
+        if (isset($_assign)) {
+            $output .= "\$_smarty_tpl->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 = "<?php \n";
+        if ($compiler->_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;
+    }
+}

+ 77 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_break.php

@@ -0,0 +1,77 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Break
+ * Compiles the {break} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Break Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Break extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('levels');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $shorttag_order = array('levels');
+
+    /**
+     * Compiles code for the {break} 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)
+    {
+        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;
+        while ($level_count > 0 && $stack_count >= 0) {
+            if (isset($_is_loopy[ $compiler->_tag_stack[ $stack_count ][ 0 ] ])) {
+                $level_count --;
+            }
+            $stack_count --;
+        }
+        if ($level_count != 0) {
+            $compiler->trigger_template_error("cannot break {$_levels} level(s)", null, true);
+        }
+
+        return "<?php break {$_levels};?>";
+    }
+}

+ 89 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_call.php

@@ -0,0 +1,89 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Function_Call
+ * Compiles the calls of user defined tags defined by {function}
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Function_Call Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Call extends Smarty_Internal_CompileBase
+{
+    /**
+     * 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 $optional_attributes = array('_any');
+
+    /**
+     * Compiles the calls of user defined tags defined by {function}
+     *
+     * @param  array  $args     array with attributes from parser
+     * @param  object $compiler compiler object
+     *
+     * @return string compiled code
+     */
+    public function compile($args, $compiler)
+    {
+        // check and get attributes
+        $_attr = $this->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 =
+                "<?php ob_start();\n\$_smarty_tpl->ext->_tplFunction->callTemplateFunction(\$_smarty_tpl, {$_name}, {$_params}, {$_nocache});\n\$_smarty_tpl->assign({$_assign}, ob_get_clean());?>\n";
+        } else {
+            $_output =
+                "<?php \$_smarty_tpl->ext->_tplFunction->callTemplateFunction(\$_smarty_tpl, {$_name}, {$_params}, {$_nocache});?>\n";
+        }
+        return $_output;
+    }
+}

+ 112 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_capture.php

@@ -0,0 +1,112 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Capture
+ * Compiles the {capture} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Capture Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Capture extends Smarty_Internal_CompileBase
+{
+    /**
+     * 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 $optional_attributes = array('name', 'assign', 'append');
+
+    /**
+     * Compiles code for the {$smarty.capture.xxx}
+     *
+     * @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 static function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter = null)
+    {
+        $tag = 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);
+        }
+        return "\$_smarty_tpl->smarty->ext->_capture->getBuffer(\$_smarty_tpl, '{$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 = "<?php \$_smarty_tpl->smarty->ext->_capture->open(\$_smarty_tpl, $buffer, $assign, $append);\n?>\n";
+
+        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 "<?php \$_smarty_tpl->smarty->ext->_capture->close(\$_smarty_tpl);\n?>\n";
+    }
+}

+ 98 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_config_load.php

@@ -0,0 +1,98 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Config Load
+ * Compiles the {config load} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Config Load Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Config_Load extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $required_attributes = array('file');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $shorttag_order = array('file', 'section');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('section', 'scope');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $option_flags = array('nocache', 'noscope');
+
+    /**
+     * Valid scope names
+     *
+     * @var array
+     */
+    public $valid_scopes = array('local' => Smarty::SCOPE_LOCAL, 'parent' => Smarty::SCOPE_PARENT,
+                                 'root' => Smarty::SCOPE_ROOT, 'tpl_root' => Smarty::SCOPE_TPL_ROOT,
+                                 'smarty' => 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 =
+            "<?php\n\$_smarty_tpl->smarty->ext->configLoad->_loadConfigFile(\$_smarty_tpl, {$conf_file}, {$section}, {$_scope});\n?>\n";
+
+        return $_output;
+    }
+}

+ 77 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_continue.php

@@ -0,0 +1,77 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Continue
+ * Compiles the {continue} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Continue Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Continue extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('levels');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $shorttag_order = array('levels');
+
+    /**
+     * Compiles code for the {continue} 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)
+    {
+        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;
+        while ($level_count > 0 && $stack_count >= 0) {
+            if (isset($_is_loopy[ $compiler->_tag_stack[ $stack_count ][ 0 ] ])) {
+                $level_count --;
+            }
+            $stack_count --;
+        }
+        if ($level_count != 0) {
+            $compiler->trigger_template_error("cannot continue {$_levels} level(s)", null, true);
+        }
+
+        return "<?php continue {$_levels};?>";
+    }
+}

+ 42 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_debug.php

@@ -0,0 +1,42 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Debug
+ * Compiles the {debug} tag.
+ * It opens a window the the Smarty Debugging Console.
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Debug Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Debug extends Smarty_Internal_CompileBase
+{
+    /**
+     * Compiles code for the {debug} tag
+     *
+     * @param  array  $args     array with attributes from parser
+     * @param  object $compiler compiler object
+     *
+     * @return string compiled code
+     */
+    public function compile($args, $compiler)
+    {
+        // check and get attributes
+        $_attr = $this->getAttributes($compiler, $args);
+
+        // compile always as nocache
+        $compiler->tag_nocache = true;
+
+        // display debug template
+        $_output =
+            "<?php \$_smarty_debug = new Smarty_Internal_Debug;\n \$_smarty_debug->display_debug(\$_smarty_tpl);\n";
+        $_output .= "unset(\$_smarty_debug);\n?>";
+        return $_output;
+    }
+}

+ 72 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_eval.php

@@ -0,0 +1,72 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Eval
+ * Compiles the {eval} tag.
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Eval Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Eval extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $required_attributes = array('var');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('assign');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $shorttag_order = array('var', 'assign');
+
+    /**
+     * Compiles code for the {eval} tag
+     *
+     * @param  array  $args     array with attributes from parser
+     * @param  object $compiler compiler object
+     *
+     * @return string compiled code
+     */
+    public function compile($args, $compiler)
+    {
+        // check and get attributes
+        $_attr = $this->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 "<?php $_output ?>";
+    }
+}

+ 134 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_extends.php

@@ -0,0 +1,134 @@
+<?php
+
+/**
+ * Smarty Internal Plugin Compile extend
+ * Compiles the {extends} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile extend Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Extends extends Smarty_Internal_Compile_Shared_Inheritance
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $required_attributes = array('file');
+
+    /**
+     * Array of names of optional attribute required by tag
+     * use array('_any') if there is no restriction of attributes names
+     *
+     * @var array
+     */
+    public $optional_attributes = array('extends_resource');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $shorttag_order = array('file');
+
+    /**
+     * Compiles code for the {extends} tag extends: resource
+     *
+     * @param array                                 $args     array with attributes from parser
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
+     *
+     * @return string compiled code
+     * @throws \SmartyCompilerException
+     * @throws \SmartyException
+     */
+    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', $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);
+            $this->compileInclude($compiler, $_attr[ 'file' ]);
+        }
+        $compiler->has_code = false;
+        return '';
+    }
+
+    /**
+     * Add code for inheritance endChild() method to end of template
+     *
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler
+     */
+    private function compileEndChild(Smarty_Internal_TemplateCompilerBase $compiler)
+    {
+        $compiler->parser->template_postfix[] = new Smarty_Internal_ParseTree_Tag($compiler->parser,
+                                                                                  "<?php \$_smarty_tpl->inheritance->endChild();\n?>\n");
+    }
+
+    /**
+     * Add code for including subtemplate to end of template
+     *
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler
+     * @param  string                               $file subtemplate name
+     */
+    private function compileInclude(Smarty_Internal_TemplateCompilerBase $compiler, $file)
+    {
+        $compiler->parser->template_postfix[] = new Smarty_Internal_ParseTree_Tag($compiler->parser,
+                                                                                  $compiler->compileTag('include',
+                                                                                                        array($file,
+                                                                                                              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}';
+    }
+}

+ 170 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_for.php

@@ -0,0 +1,170 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile For
+ * Compiles the {for} {forelse} {/for} tags
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile For Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_For extends Smarty_Internal_CompileBase
+{
+    /**
+     * Compiles code for the {for} tag
+     * Smarty 3 does implement two different syntax's:
+     * - {for $var in $array}
+     * For looping over arrays or iterators
+     * - {for $x=0; $x<$y; $x++}
+     * For general loops
+     * The parser is generating different sets of attribute by which this compiler can
+     * determine which syntax is used.
+     *
+     * @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 ++;
+        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 = "<?php\n";
+        if ($parameter == 1) {
+            foreach ($_attr[ 'start' ] as $_statement) {
+                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);\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 "<?php }} else { ?>";
+    }
+}
+
+/**
+ * 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 = "<?php }\n";
+        if ($openTag != 'forelse') {
+            $output .= "}\n";
+        }
+        $output .= "?>\n";
+        return $output;
+    }
+}

+ 330 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_foreach.php

@@ -0,0 +1,330 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Foreach
+ * Compiles the {foreach} {foreachelse} {/foreach} tags
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Foreach Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Foreach extends Smarty_Internal_Compile_Private_ForeachSection
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $required_attributes = array('from', 'item');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('name', 'key', 'properties');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $shorttag_order = array('from', 'item', 'key', 'name');
+
+    /**
+     * counter
+     *
+     * @var int
+     */
+    public $counter = 0;
+
+    /**
+     * Name of this tag
+     *
+     * @var string
+     */
+    public $tagName = 'foreach';
+
+    /**
+     * Valid properties of $smarty.foreach.name.xxx variable
+     *
+     * @var array
+     */
+    public $nameProperties = array('first', 'last', 'index', 'iteration', 'show', 'total');
+
+    /**
+     * Valid properties of $item@xxx variable
+     *
+     * @var array
+     */
+    public $itemProperties = array('first', 'last', 'index', 'iteration', 'show', 'total', 'key');
+
+    /**
+     * Flag if tag had name attribute
+     *
+     * @var bool
+     */
+    public $isNamed = false;
+
+    /**
+     * 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
+     * @throws \SmartyCompilerException
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
+    {
+        $compiler->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 = "<?php\n";
+        $output .= "\$_from = \$_smarty_tpl->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 ($this->isNamed) {
+            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;
+    }
+}
+
+/**
+ * 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 = "<?php\n";
+        if ($restore == 2) {
+            $output .= "{$itemVar} = {$local}saved;\n";
+        }
+        $output .= "}\n} else {\n?>\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 = "<?php\n";
+
+        if ($restore == 2) {
+            $output .= "{$itemVar} = {$local}saved;\n";
+        }
+        if ($restore > 0) {
+            $output .= "}\n";
+        }
+        $output .= "}\n";
+        $output .= "\$_smarty_tpl->smarty->ext->_foreach->restore(\$_smarty_tpl);\n";
+        $output .= "?>\n";
+        return $output;
+    }
+}

+ 216 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_function.php

@@ -0,0 +1,216 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Function
+ * Compiles the {function} {/function} tags
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Function Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase
+{
+
+    /**
+     * 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 $optional_attributes = array('_any');
+
+    /**
+     * Compiles code for the {function} 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
+     * @throws \SmartyCompilerException
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
+    {
+        // check and get attributes
+        $_attr = $this->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 = "<?php\n";
+            $output .= "/* {$_funcNameCaching} */\n";
+            $output .= "if (!function_exists('{$_funcNameCaching}')) {\n";
+            $output .= "function {$_funcNameCaching} (\$_smarty_tpl,\$params) {\n";
+            $output .= "ob_start();\n";
+            $output .= "\$_smarty_tpl->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}%%*/<?php ";
+            $output .= "\\\$_smarty_tpl->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 = "<?php echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php ";
+            $output .= "\\\$_smarty_tpl->ext->_tplFunction->restoreTemplateVariables(\\\$_smarty_tpl, '{$_name}');?>\n";
+            $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";\n?>";
+            $output .= "<?php echo str_replace('{$compiler->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 = "<?php\n";
+        $output .= "/* {$_funcName} */\n";
+        $output .= "if (!function_exists('{$_funcName}')) {\n";
+        $output .= "function {$_funcName}(\$_smarty_tpl,\$params) {\n";
+        $output .= $_paramsCode;
+        $output .= "foreach (\$params as \$key => \$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 = "<?php\n}}\n";
+        $output .= "/*/ {$_funcName} */\n\n";
+        $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;
+    }
+}

+ 208 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_if.php

@@ -0,0 +1,208 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile If
+ * Compiles the {if} {else} {elseif} {/if} tags
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile If Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_If 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
+     * @throws \SmartyCompilerException
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
+    {
+        // check and get attributes
+        $_attr = $this->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 ($compiler->nocache) {
+                // create nocache var to make it know for further compiling
+                if (is_array($parameter[ 'if condition' ][ 'var' ])) {
+                    $var = $parameter[ 'if condition' ][ 'var' ][ 'var' ];
+                } else {
+                    $var = $parameter[ 'if condition' ][ 'var' ];
+                }
+                $compiler->setNocacheInVariable($var);
+            }
+            $assignCompiler = new Smarty_Internal_Compile_Assign();
+            $assignAttr = array();
+            $assignAttr[][ 'value' ] = $parameter[ 'if condition' ][ 'value' ];
+            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 .= "<?php if (" . $parameter[ 'if condition' ][ 'value' ] . ") {?>";
+            return $_output;
+        } else {
+            return "<?php if ({$parameter['if condition']}) {?>";
+        }
+    }
+}
+
+/**
+ * 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 "<?php } else { ?>";
+    }
+}
+
+/**
+ * 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 = '';
+        if (is_array($parameter[ 'if condition' ])) {
+            $condition_by_assign = true;
+            if ($compiler->nocache) {
+                // create nocache var to make it know for further compiling
+                if (is_array($parameter[ 'if condition' ][ 'var' ])) {
+                    $var = $parameter[ 'if condition' ][ 'var' ][ 'var' ];
+                } else {
+                    $var = $parameter[ 'if condition' ][ 'var' ];
+                }
+                $compiler->setNocacheInVariable($var);
+            }
+            $assignCompiler = new Smarty_Internal_Compile_Assign();
+            $assignAttr = array();
+            $assignAttr[][ 'value' ] = $parameter[ 'if condition' ][ 'value' ];
+            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("<?php } else {\n?>", $assignCode);
+                return $compiler->appendCode($_output,
+                                             "<?php if (" . $parameter[ 'if condition' ][ 'value' ] . ") {\n?>");
+            } else {
+                $this->openTag($compiler, 'elseif', array($nesting, $compiler->tag_nocache));
+                return "<?php } elseif ({$parameter['if condition']}) {?>";
+            }
+        } else {
+            $_output = $compiler->appendCode("<?php } else {\n?>", $prefixCode);
+            $this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache));
+            if ($condition_by_assign) {
+                $_output = $compiler->appendCode($_output, $assignCode);
+                return $compiler->appendCode($_output,
+                                             "<?php if (" . $parameter[ 'if condition' ][ 'value' ] . ") {\n?>");
+            } else {
+                return $compiler->appendCode($_output, "<?php if ({$parameter['if condition']}) {?>");
+            }
+        }
+    }
+}
+
+/**
+ * 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 "<?php {$tmp}?>";
+    }
+}

+ 345 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_include.php

@@ -0,0 +1,345 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Include
+ * Compiles the {include} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Include Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
+{
+    /**
+     * caching mode to create nocache code but no cache file
+     */
+    const CACHING_NOCACHE_CODE = 9999;
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $required_attributes = array('file');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $shorttag_order = array('file');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $option_flags = array('nocache', 'inline', 'caching');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('_any');
+
+    /**
+     * Valid scope names
+     *
+     * @var array
+     */
+    public $valid_scopes = array('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 {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 = '"' . $fullResourceName . '"';
+                }
+            }
+            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 = "<?php\n";
+            if ($update_compile_id) {
+                $_output .= $compiler->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('<?php ' . $_vars_nc . "?>\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 = "<?php ";
+        if ($update_compile_id) {
+            $_output .= "\$_compile_id_save[] = \$_smarty_tpl->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 = "<?php\n\n";
+            $compiled_code .= "/* Start inline template \"{$sourceInfo}\" =============================*/\n";
+            $compiled_code .= "function {$tpl->compiled->unifunc} (\$_smarty_tpl) {\n";
+            $compiled_code .= "?>\n" . $tpl->compiler->compileTemplateSource($tpl, null, $compiler->parent_compiler);
+            $compiled_code .= "<?php\n";
+            $compiled_code .= "}\n?>\n";
+            $compiled_code .= $tpl->compiler->postFilter($tpl->compiler->blockOrFunctionCode);
+            $compiled_code .= "<?php\n\n";
+            $compiled_code .= "/* End inline template \"{$sourceInfo}\" =============================*/\n";
+            $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;
+        }
+    }
+}

+ 111 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_include_php.php

@@ -0,0 +1,111 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Include PHP
+ * Compiles the {include_php} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Insert Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Include_Php extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $required_attributes = array('file');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $shorttag_order = array('file');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('once', 'assign');
+
+    /**
+     * Compiles code for the {include_php} tag
+     *
+     * @param  array                                $args     array with attributes from parser
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
+     *
+     * @return string
+     * @throws \SmartyCompilerException
+     * @throws \SmartyException
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
+    {
+        if (!($compiler->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 . 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 "<?php ob_start();\ninclude{$_once} ('{$_filepath}');\n\$_smarty_tpl->assign({$_assign},ob_get_clean());\n?>";
+        } else {
+            return "<?php include{$_once} ('{$_filepath}');?>\n";
+        }
+    }
+}

+ 155 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_insert.php

@@ -0,0 +1,155 @@
+<?php
+
+/**
+ * Smarty Internal Plugin Compile Insert
+ * Compiles the {insert} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Insert Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Insert extends Smarty_Internal_CompileBase
+{
+    /**
+     * 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 $optional_attributes = array('_any');
+
+    /**
+     * Compiles code for the {insert} 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);
+        //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 = '<?php ';
+        // save possible attributes
+        eval('$_name = @' . $_attr[ 'name' ] . ';');
+        if (isset($_attr[ 'assign' ])) {
+            // output will be stored in a smarty variable instead of being displayed
+            $_assign = $_attr[ 'assign' ];
+            // create variable to make sure that the compiler knows about its nocache status
+            $var = trim($_attr[ 'assign' ], "'");
+            if (isset($compiler->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, '/\\') . 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;
+    }
+}

+ 40 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_ldelim.php

@@ -0,0 +1,40 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Ldelim
+ * Compiles the {ldelim} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Ldelim Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Ldelim extends Smarty_Internal_CompileBase
+{
+    /**
+     * Compiles code for the {ldelim} tag
+     * This tag does output the left delimiter
+     *
+     * @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)
+    {
+        $_attr = $this->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;
+    }
+}

+ 64 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_make_nocache.php

@@ -0,0 +1,64 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Make_Nocache
+ * Compiles the {make_nocache} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Make_Nocache Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Make_Nocache extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $option_flags = array();
+
+    /**
+     * Array of names of required attribute required by tag
+     *
+     * @var array
+     */
+    public $required_attributes = array('var');
+
+    /**
+     * Shorttag attribute order defined by its names
+     *
+     * @var array
+     */
+    public $shorttag_order = array('var');
+
+    /**
+     * Compiles code for the {make_nocache} 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);
+        if ($compiler->template->caching) {
+            $output = "<?php \$_smarty_tpl->smarty->ext->_make_nocache->save(\$_smarty_tpl, {$_attr[ 'var' ]});\n?>\n";
+            $compiler->has_code = true;
+            $compiler->suppressNocacheProcessing = true;
+            return $output;
+        } else {
+            return true;
+        }
+    }
+}

+ 75 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_nocache.php

@@ -0,0 +1,75 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Nocache
+ * Compiles the {nocache} {/nocache} tags.
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Nocache Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Nocache extends Smarty_Internal_CompileBase
+{
+    /**
+     * Array of names of valid option flags
+     *
+     * @var array
+     */
+    public $option_flags = array();
+
+    /**
+     * 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);
+        $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;
+    }
+}

+ 123 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_private_block_plugin.php

@@ -0,0 +1,123 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Block Plugin
+ * Compiles code for the execution of block plugin
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Block Plugin Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Private_Block_Plugin extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('_any');
+
+    /**
+     * nesting level
+     *
+     * @var int
+     */
+    public $nesting = 0;
+
+    /**
+     * Compiles code for the execution of block plugin
+     *
+     * @param  array                                $args      array with attributes from parser
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler  compiler object
+     * @param  array                                $parameter array with compilation parameter
+     * @param  string                               $tag       name of block plugin
+     * @param  string                               $function  PHP function name
+     *
+     * @return string compiled code
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag, $function = null)
+    {
+        if (!isset($tag[ 5 ]) || substr($tag, - 5) != 'close') {
+            // opening tag of block plugin
+            // check and get attributes
+            $_attr = $this->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 = "<?php ";
+            if (is_array($callback)) {
+                $output .= "\$_block_plugin{$this->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{$this->nesting}=true;\necho {$callback}({$_params}, null, \$_smarty_tpl, \$_block_repeat{$this->nesting});\nwhile (\$_block_repeat{$this->nesting}) {\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 = "<?php " . $mod_content . "\$_block_repeat{$this->nesting}=false;\n" . $mod_pre .
+                      "echo {$callback}({$_params}, " . $mod_content2 .
+                      ", \$_smarty_tpl, \$_block_repeat{$this->nesting});\n" . $mod_post . "}\n";
+            $output .= "array_pop(\$_smarty_tpl->smarty->_cache['_tag_stack']);";
+            $output .= "?>";
+            $this->nesting --;
+        }
+        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);
+    }
+}

+ 221 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_private_foreachsection.php

@@ -0,0 +1,221 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile ForeachSection
+ * Shared methods for {foreach} {section} tags
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile ForeachSection Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Private_ForeachSection extends Smarty_Internal_CompileBase
+{
+
+    /**
+     * Preg search pattern
+     *
+     * @var string
+     */
+    private $propertyPreg = '';
+
+    /**
+     * Offsets in preg match result
+     *
+     * @var array
+     */
+    private $resultOffsets = array();
+
+    /**
+     * Start offset
+     *
+     * @var int
+     */
+    private $startOffset = 0;
+
+    /**
+     * Name of this tag
+     *
+     * @var string
+     */
+    public $tagName = '';
+
+    /**
+     * Valid properties of $smarty.xxx variable
+     *
+     * @var array
+     */
+    public $nameProperties = array();
+
+    /**
+     * {section} tag has no item properties
+     *
+     * @var array
+     */
+    public $itemProperties = null;
+
+    /**
+     * {section} tag has always name attribute
+     *
+     * @var bool
+     */
+    public $isNamed = true;
+
+    /**
+     * @var array
+     */
+    public $matchResults = array();
+
+    /**
+     * Scan sources for used tag attributes
+     *
+     * @param  array                                $attributes
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler
+     */
+    public function scanForProperties($attributes, Smarty_Internal_TemplateCompilerBase $compiler)
+    {
+        $this->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)";
+    }
+}

+ 74 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_private_function_plugin.php

@@ -0,0 +1,74 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Function Plugin
+ * Compiles code for the execution of function plugin
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Function Plugin Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Private_Function_Plugin extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $required_attributes = array();
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('_any');
+
+    /**
+     * Compiles code for the execution of function plugin
+     *
+     * @param  array                                $args      array with attributes from parser
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler  compiler object
+     * @param  array                                $parameter array with compilation parameter
+     * @param  string                               $tag       name of function plugin
+     * @param  string                               $function  PHP function name
+     *
+     * @return string compiled code
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag, $function)
+    {
+        // check and get attributes
+        $_attr = $this->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 = isset($_attr[ 'assign' ]) ? false : true;
+        $output = "<?php " . ($compiler->has_output ? "echo " : '') . "{$output};?>\n";
+        return $output;
+    }
+}

+ 157 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_private_modifier.php

@@ -0,0 +1,157 @@
+<?php
+
+/**
+ * Smarty Internal Plugin Compile Modifier
+ * Compiles code for modifier execution
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Modifier Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Private_Modifier extends Smarty_Internal_CompileBase
+{
+    /**
+     * Compiles code for modifier execution
+     *
+     * @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);
+        $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 ])) {
+                            $function =
+                                $compiler->smarty->registered_plugins[ Smarty::PLUGIN_MODIFIER ][ $modifier ][ 0 ];
+                            if (!is_array($function)) {
+                                $output = "{$function}({$params})";
+                            } else {
+                                if (is_object($function[ 0 ])) {
+                                    $output = '$_smarty_tpl->smarty->registered_plugins[Smarty::PLUGIN_MODIFIER][\'' .
+                                              $modifier . '\'][0][0]->' . $function[ 1 ] . '(' . $params . ')';
+                                } else {
+                                    $output = $function[ 0 ] . '::' . $function[ 1 ] . '(' . $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;
+    }
+}

+ 42 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_private_object_block_function.php

@@ -0,0 +1,42 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Object Block Function
+ * Compiles code for registered objects as block function
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Object Block Function Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Private_Object_Block_Function extends Smarty_Internal_Compile_Private_Block_Plugin
+{
+    /**
+     * Setup callback and parameter array
+     *
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler
+     * @param  array                                $_attr attributes
+     * @param  string                               $tag
+     * @param  string                               $method
+     *
+     * @return array
+     */
+    public function setup(Smarty_Internal_TemplateCompilerBase $compiler, $_attr, $tag, $method)
+    {
+        $_paramsArray = array();
+        foreach ($_attr as $_key => $_value) {
+            if (is_int($_key)) {
+                $_paramsArray[] = "$_key=>$_value";
+            } else {
+                $_paramsArray[] = "'$_key'=>$_value";
+            }
+        }
+        $callback = array("\$_smarty_tpl->smarty->registered_objects['{$tag}'][0]", "->{$method}");
+        return array($callback, $_paramsArray, "array(\$_block_plugin{$this->nesting}, '{$method}')");
+    }
+}

+ 86 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_private_object_function.php

@@ -0,0 +1,86 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Object Function
+ * Compiles code for registered objects as function
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Object Function Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Private_Object_Function extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('_any');
+
+    /**
+     * Compiles code for the execution of function plugin
+     *
+     * @param  array                                $args      array with attributes from parser
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler  compiler object
+     * @param  array                                $parameter array with compilation parameter
+     * @param  string                               $tag       name of function
+     * @param  string                               $method    name of method to call
+     *
+     * @return string compiled code
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag, $method)
+    {
+        // check and get attributes
+        $_attr = $this->getAttributes($compiler, $args);
+        //Does tag create output
+        $compiler->has_output = isset($_attr[ 'assign' ]) ? false : true;
+
+        unset($_attr[ 'nocache' ]);
+        $_assign = null;
+        if (isset($_attr[ 'assign' ])) {
+            $_assign = $_attr[ 'assign' ];
+            unset($_attr[ 'assign' ]);
+        }
+        // method or property ?
+        if (is_callable(array($compiler->smarty->registered_objects[ $tag ][ 0 ], $method))) {
+            // convert attributes into parameter array string
+            if ($compiler->smarty->registered_objects[ $tag ][ 2 ]) {
+                $_paramsArray = array();
+                foreach ($_attr as $_key => $_value) {
+                    if (is_int($_key)) {
+                        $_paramsArray[] = "$_key=>$_value";
+                    } else {
+                        $_paramsArray[] = "'$_key'=>$_value";
+                    }
+                }
+                $_params = 'array(' . implode(",", $_paramsArray) . ')';
+                $output = "\$_smarty_tpl->smarty->registered_objects['{$tag}'][0]->{$method}({$_params},\$_smarty_tpl)";
+            } else {
+                $_params = implode(",", $_attr);
+                $output = "\$_smarty_tpl->smarty->registered_objects['{$tag}'][0]->{$method}({$_params})";
+            }
+        } else {
+            // object property
+            $output = "\$_smarty_tpl->smarty->registered_objects['{$tag}'][0]->{$method}";
+        }
+        if (!empty($parameter[ 'modifierlist' ])) {
+            $output = $compiler->compileTag('private_modifier', array(),
+                                            array('modifierlist' => $parameter[ 'modifierlist' ], 'value' => $output));
+        }
+        //Does tag create output
+        $compiler->has_output = isset($_attr[ 'assign' ]) ? false : true;
+
+        if (empty($_assign)) {
+            return "<?php echo {$output};?>\n";
+        } else {
+            return "<?php \$_smarty_tpl->assign({$_assign},{$output});?>\n";
+        }
+    }
+}

+ 220 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_private_php.php

@@ -0,0 +1,220 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile PHP Expression
+ * Compiles any tag which will output an expression or variable
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile PHP Expression Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Private_Php extends Smarty_Internal_CompileBase
+{
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $required_attributes = array('code', 'type');
+
+    /**
+     * Compiles code for generating output from any expression
+     *
+     * @param array                                 $args      array with attributes from parser
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler  compiler object
+     * @param array                                 $parameter array with compilation parameter
+     *
+     * @return string
+     * @throws \SmartyException
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
+    {
+        // check and get attributes
+        $_attr = $this->getAttributes($compiler, $args);
+        $compiler->has_code = false;
+        if ($_attr[ 'type' ] == 'xml') {
+            $compiler->tag_nocache = true;
+            $save = $compiler->template->compiled->has_nocache_code;
+            $output = addcslashes($_attr[ 'code' ], "'\\");
+            $compiler->parser->current_buffer->append_subtree($compiler->parser,
+                                                              new Smarty_Internal_ParseTree_Tag($compiler->parser,
+                                                                                                $compiler->processNocacheCode("<?php echo '" .
+                                                                                                                              $output .
+                                                                                                                              "';?>",
+                                                                                                                              true)));
+            $compiler->template->compiled->has_nocache_code = $save;
+            return '';
+        }
+        if ($_attr[ 'type' ] != 'tag') {
+            if ($compiler->php_handling == Smarty::PHP_REMOVE) {
+                return '';
+            } elseif ($compiler->php_handling == Smarty::PHP_QUOTE) {
+                $output =
+                    preg_replace_callback('#(<\?(?:php|=)?)|(<%)|(<script\s+language\s*=\s*["\']?\s*php\s*["\']?\s*>)|(\?>)|(%>)|(<\/script>)#i',
+                                          array($this, 'quote'), $_attr[ 'code' ]);
+                $compiler->parser->current_buffer->append_subtree($compiler->parser,
+                                                                  new Smarty_Internal_ParseTree_Text($output));
+                return '';
+            } elseif ($compiler->php_handling == Smarty::PHP_PASSTHRU || $_attr[ 'type' ] == 'unmatched') {
+                $compiler->tag_nocache = true;
+                $save = $compiler->template->compiled->has_nocache_code;
+                $output = addcslashes($_attr[ 'code' ], "'\\");
+                $compiler->parser->current_buffer->append_subtree($compiler->parser,
+                                                                  new Smarty_Internal_ParseTree_Tag($compiler->parser,
+                                                                                                    $compiler->processNocacheCode("<?php echo '" .
+                                                                                                                                  $output .
+                                                                                                                                  "';?>",
+                                                                                                                                  true)));
+                $compiler->template->compiled->has_nocache_code = $save;
+                return '';
+            } elseif ($compiler->php_handling == Smarty::PHP_ALLOW) {
+                if (!($compiler->smarty instanceof SmartyBC)) {
+                    $compiler->trigger_template_error('$smarty->php_handling PHP_ALLOW not allowed. Use SmartyBC to enable it',
+                                                      null, true);
+                }
+                $compiler->has_code = true;
+                return $_attr[ 'code' ];
+            } else {
+                $compiler->trigger_template_error('Illegal $smarty->php_handling value', null, true);
+            }
+        } else {
+            $compiler->has_code = true;
+            if (!($compiler->smarty instanceof SmartyBC)) {
+                $compiler->trigger_template_error('{php}{/php} tags not allowed. Use SmartyBC to enable them', null,
+                                                  true);
+            }
+            $ldel = preg_quote($compiler->smarty->left_delimiter, '#');
+            $rdel = preg_quote($compiler->smarty->right_delimiter, '#');
+            preg_match("#^({$ldel}php\\s*)((.)*?)({$rdel})#", $_attr[ 'code' ], $match);
+            if (!empty($match[ 2 ])) {
+                if ('nocache' == trim($match[ 2 ])) {
+                    $compiler->tag_nocache = true;
+                } else {
+                    $compiler->trigger_template_error("illegal value of option flag \"{$match[2]}\"", null, true);
+                }
+            }
+            return preg_replace(array("#^{$ldel}\\s*php\\s*(.)*?{$rdel}#", "#{$ldel}\\s*/\\s*php\\s*{$rdel}$#"),
+                                array('<?php ', '?>'), $_attr[ 'code' ]);
+        }
+    }
+
+    /**
+     * Lexer code for PHP tags
+     *
+     * This code has been moved from lexer here fo easier debugging and maintenance
+     *
+     * @param $lex
+     */
+    public function parsePhp($lex)
+    {
+        $lex->token = Smarty_Internal_Templateparser::TP_PHP;
+        $close = 0;
+        $lex->taglineno = $lex->line;
+        $closeTag = '?>';
+        if (strpos($lex->value, '<?xml') === 0) {
+            $lex->is_xml = true;
+            $lex->token = Smarty_Internal_Templateparser::TP_NOCACHE;
+            return;
+        } elseif (strpos($lex->value, '<?') === 0) {
+            $lex->phpType = 'php';
+        } elseif (strpos($lex->value, '<%') === 0) {
+            $lex->phpType = 'asp';
+            $closeTag = '%>';
+        } elseif (strpos($lex->value, '%>') === 0) {
+            $lex->phpType = 'unmatched';
+        } elseif (strpos($lex->value, '?>') === 0) {
+            if ($lex->is_xml) {
+                $lex->is_xml = false;
+                $lex->token = Smarty_Internal_Templateparser::TP_NOCACHE;
+                return;
+            }
+            $lex->phpType = 'unmatched';
+        } elseif (strpos($lex->value, '<s') === 0) {
+            $lex->phpType = 'script';
+            $closeTag = '</script>';
+        } elseif (strpos($lex->value, $lex->smarty->left_delimiter) === 0) {
+            if ($lex->isAutoLiteral()) {
+                $lex->token = Smarty_Internal_Templateparser::TP_TEXT;
+                return;
+            }
+            $closeTag = "{$lex->smarty->left_delimiter}/php{$lex->smarty->right_delimiter}";
+            if ($lex->value == $closeTag) {
+                $lex->compiler->trigger_template_error("unexpected closing tag '{$closeTag}'");
+            }
+            $lex->phpType = 'tag';
+        }
+        if ($lex->phpType == 'unmatched') {
+            return;
+        }
+        if (($lex->phpType == 'php' || $lex->phpType == 'asp') &&
+            ($lex->compiler->php_handling == Smarty::PHP_PASSTHRU || $lex->compiler->php_handling == Smarty::PHP_QUOTE)
+        ) {
+            return;
+        }
+        $start = $lex->counter + strlen($lex->value);
+        $body = true;
+        if (preg_match('~' . preg_quote($closeTag, '~') . '~i', $lex->data, $match, PREG_OFFSET_CAPTURE, $start)) {
+            $close = $match[ 0 ][ 1 ];
+        } else {
+            $lex->compiler->trigger_template_error("missing closing tag '{$closeTag}'");
+        }
+        while ($body) {
+            if (preg_match('~([/][*])|([/][/][^\n]*)|(\'[^\'\\\\]*(?:\\.[^\'\\\\]*)*\')|("[^"\\\\]*(?:\\.[^"\\\\]*)*")~',
+                           $lex->data, $match, PREG_OFFSET_CAPTURE, $start)) {
+                $value = $match[ 0 ][ 0 ];
+                $from = $pos = $match[ 0 ][ 1 ];
+                if ($pos > $close) {
+                    $body = false;
+                } else {
+                    $start = $pos + strlen($value);
+                    $phpCommentStart = $value == '/*';
+                    if ($phpCommentStart) {
+                        $phpCommentEnd = preg_match('~([*][/])~', $lex->data, $match, PREG_OFFSET_CAPTURE, $start);
+                        if ($phpCommentEnd) {
+                            $pos2 = $match[ 0 ][ 1 ];
+                            $start = $pos2 + strlen($match[ 0 ][ 0 ]);
+                        }
+                    }
+                    while ($close > $pos && $close < $start) {
+                        if (preg_match('~' . preg_quote($closeTag, '~') . '~i', $lex->data, $match, PREG_OFFSET_CAPTURE,
+                                       $from)) {
+                            $close = $match[ 0 ][ 1 ];
+                            $from = $close + strlen($match[ 0 ][ 0 ]);
+                        } else {
+                            $lex->compiler->trigger_template_error("missing closing tag '{$closeTag}'");
+                        }
+                    }
+                    if ($phpCommentStart && (!$phpCommentEnd || $pos2 > $close)) {
+                        $lex->taglineno = $lex->line + substr_count(substr($lex->data, $lex->counter, $start), "\n");
+                        $lex->compiler->trigger_template_error("missing PHP comment closing tag '*/'");
+                    }
+                }
+            } else {
+                $body = false;
+            }
+        }
+        $lex->value = substr($lex->data, $lex->counter, $close + strlen($closeTag) - $lex->counter);
+    }
+
+    /*
+     * Call back function for $php_handling = PHP_QUOTE
+     *
+     */
+    /**
+     * @param $match
+     *
+     * @return string
+     */
+    private function quote($match)
+    {
+        return htmlspecialchars($match[ 0 ], ENT_QUOTES);
+    }
+}

+ 162 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_private_print_expression.php

@@ -0,0 +1,162 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Print Expression
+ * Compiles any tag which will output an expression or variable
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Print Expression Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Private_Print_Expression extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('assign');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $option_flags = array('nocache', 'nofilter');
+
+    /**
+     * Compiles code for generating output from any expression
+     *
+     * @param array                                 $args      array with attributes from parser
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler  compiler object
+     * @param array                                 $parameter array with compilation parameter
+     *
+     * @return string
+     * @throws \SmartyException
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
+    {
+        // check and get attributes
+        $_attr = $this->getAttributes($compiler, $args);
+        $output = $parameter[ 'value' ];
+        // tag modifier
+        if (!empty($parameter[ 'modifierlist' ])) {
+            $output = $compiler->compileTag('private_modifier', array(),
+                                            array('modifierlist' => $parameter[ 'modifierlist' ],
+                                                  'value' => $output));
+        }
+        if (isset($_attr[ 'assign' ])) {
+            // assign output to variable
+            return "<?php \$_smarty_tpl->assign({$_attr['assign']},{$output});?>";
+        } else {
+            // display value
+            if (!$_attr[ 'nofilter' ]) {
+                // default modifier
+                if (!empty($compiler->smarty->default_modifiers)) {
+                    if (empty($compiler->default_modifier_list)) {
+                        $modifierlist = array();
+                        foreach ($compiler->smarty->default_modifiers as $key => $single_default_modifier) {
+                            preg_match_all('/(\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'|"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|:|[^:]+)/',
+                                           $single_default_modifier, $mod_array);
+                            for ($i = 0, $count = count($mod_array[ 0 ]); $i < $count; $i ++) {
+                                if ($mod_array[ 0 ][ $i ] != ':') {
+                                    $modifierlist[ $key ][] = $mod_array[ 0 ][ $i ];
+                                }
+                            }
+                        }
+                        $compiler->default_modifier_list = $modifierlist;
+                    }
+                    $output = $compiler->compileTag('private_modifier', array(),
+                                                    array('modifierlist' => $compiler->default_modifier_list,
+                                                          'value' => $output));
+                }
+                // autoescape html
+                if ($compiler->template->smarty->escape_html) {
+                    $output = "htmlspecialchars({$output}, ENT_QUOTES, '" . addslashes(Smarty::$_CHARSET) . "')";
+                }
+                // loop over registered filters
+                if (!empty($compiler->template->smarty->registered_filters[ Smarty::FILTER_VARIABLE ])) {
+                    foreach ($compiler->template->smarty->registered_filters[ Smarty::FILTER_VARIABLE ] as $key =>
+                             $function) {
+                        if (!is_array($function)) {
+                            $output = "{$function}({$output},\$_smarty_tpl)";
+                        } elseif (is_object($function[ 0 ])) {
+                            $output =
+                                "\$_smarty_tpl->smarty->registered_filters[Smarty::FILTER_VARIABLE]['{$key}'][0]->{$function[1]}({$output},\$_smarty_tpl)";
+                        } else {
+                            $output = "{$function[0]}::{$function[1]}({$output},\$_smarty_tpl)";
+                        }
+                    }
+                }
+                // auto loaded filters
+                if (isset($compiler->smarty->autoload_filters[ Smarty::FILTER_VARIABLE ])) {
+                    foreach ((array) $compiler->template->smarty->autoload_filters[ Smarty::FILTER_VARIABLE ] as $name)
+                    {
+                        $result = $this->compile_output_filter($compiler, $name, $output);
+                        if ($result !== false) {
+                            $output = $result;
+                        } else {
+                            // not found, throw exception
+                            throw new SmartyException("Unable to load filter '{$name}'");
+                        }
+                    }
+                }
+                foreach ($compiler->variable_filters as $filter) {
+                    if (count($filter) == 1 &&
+                        ($result = $this->compile_output_filter($compiler, $filter[ 0 ], $output)) !== false
+                    ) {
+                        $output = $result;
+                    } else {
+                        $output = $compiler->compileTag('private_modifier', array(),
+                                                        array('modifierlist' => array($filter), 'value' => $output));
+                    }
+                }
+            }
+
+            $compiler->has_output = true;
+            $output = "<?php echo {$output};?>";
+        }
+
+        return $output;
+    }
+
+    /**
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
+     * @param string                                $name     name of variable filter
+     * @param string                                $output   embedded output
+     *
+     * @return string
+     */
+    private function compile_output_filter(Smarty_Internal_TemplateCompilerBase $compiler, $name, $output)
+    {
+        $plugin_name = "smarty_variablefilter_{$name}";
+        $path = $compiler->smarty->loadPlugin($plugin_name);
+        if ($path) {
+            /**
+            if ($compiler->template->caching) {
+                $compiler->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $name ][ Smarty::FILTER_VARIABLE ][ 'file' ] =
+                    $path;
+                $compiler->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $name ][ Smarty::FILTER_VARIABLE ][ 'function' ] =
+                    $plugin_name;
+            } else {
+                $compiler->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $name ][ Smarty::FILTER_VARIABLE ][ 'file' ] =
+                    $path;
+                $compiler->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $name ][ Smarty::FILTER_VARIABLE ][ 'function' ] =
+                    $plugin_name;
+            }
+             * */
+            return "{$plugin_name}({$output},\$_smarty_tpl)";
+        } else {
+            // not found
+            return false;
+        }
+    }
+}

+ 72 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_private_registered_block.php

@@ -0,0 +1,72 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Registered Block
+ * Compiles code for the execution of a registered block function
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Registered Block Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Private_Registered_Block extends Smarty_Internal_Compile_Private_Block_Plugin
+{
+    /**
+     * Setup callback, parameter array and nocache mode
+     *
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler
+     * @param  array                                $_attr attributes
+     * @param  string                               $tag
+     * @param  null                                 $function
+     *
+     * @return array
+     */
+    public function setup(Smarty_Internal_TemplateCompilerBase $compiler, $_attr, $tag, $function)
+    {
+        if (isset($compiler->smarty->registered_plugins[ Smarty::PLUGIN_BLOCK ][ $tag ])) {
+            $tag_info = $compiler->smarty->registered_plugins[ Smarty::PLUGIN_BLOCK ][ $tag ];
+            $callback = $tag_info[ 0 ];
+            if (is_array($callback)) {
+                if (is_object($callback[ 0 ])) {
+                    $callable = "array(\$_block_plugin{$this->nesting}, '{$callback[1]}')";
+                    $callback =
+                        array("\$_smarty_tpl->smarty->registered_plugins['block']['{$tag}'][0][0]", "->{$callback[1]}");
+                } else {
+                    $callable = "array(\$_block_plugin{$this->nesting}, '{$callback[1]}')";
+                    $callback =
+                        array("\$_smarty_tpl->smarty->registered_plugins['block']['{$tag}'][0][0]", "::{$callback[1]}");
+                }
+            } else {
+                $callable = "\$_block_plugin{$this->nesting}";
+                $callback = array("\$_smarty_tpl->smarty->registered_plugins['block']['{$tag}'][0]", '');
+            }
+        } else {
+            $tag_info = $compiler->default_handler_plugins[ Smarty::PLUGIN_BLOCK ][ $tag ];
+            $callback = $tag_info[ 0 ];
+            if (is_array($callback)) {
+                $callable = "array('{$callback[0]}', '{$callback[1]}')";
+                $callback = "{$callback[1]}::{$callback[1]}";
+            } else {
+                $callable = null;
+            }
+        }
+        $compiler->tag_nocache = !$tag_info[ 1 ] | $compiler->tag_nocache;
+        $_paramsArray = array();
+        foreach ($_attr as $_key => $_value) {
+            if (is_int($_key)) {
+                $_paramsArray[] = "$_key=>$_value";
+            } elseif ($compiler->template->caching && in_array($_key, $tag_info[ 2 ])) {
+                $_value = str_replace("'", "^#^", $_value);
+                $_paramsArray[] = "'$_key'=>^#^.var_export($_value,true).^#^";
+            } else {
+                $_paramsArray[] = "'$_key'=>$_value";
+            }
+        }
+        return array($callback, $_paramsArray, $callable);
+    }
+}

+ 82 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_private_registered_function.php

@@ -0,0 +1,82 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Registered Function
+ * Compiles code for the execution of a registered function
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Registered Function Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Private_Registered_Function extends Smarty_Internal_CompileBase
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('_any');
+
+    /**
+     * Compiles code for the execution of a registered function
+     *
+     * @param  array                                $args      array with attributes from parser
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler  compiler object
+     * @param  array                                $parameter array with compilation parameter
+     * @param  string                               $tag       name of function
+     *
+     * @return string compiled code
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag)
+    {
+        // check and get attributes
+        $_attr = $this->getAttributes($compiler, $args);
+        unset($_attr[ 'nocache' ]);
+        if (isset($compiler->smarty->registered_plugins[ Smarty::PLUGIN_FUNCTION ][ $tag ])) {
+            $tag_info = $compiler->smarty->registered_plugins[ Smarty::PLUGIN_FUNCTION ][ $tag ];
+        } else {
+            $tag_info = $compiler->default_handler_plugins[ Smarty::PLUGIN_FUNCTION ][ $tag ];
+        }
+        // not cachable?
+        $compiler->tag_nocache = $compiler->tag_nocache || !$tag_info[ 1 ];
+        // convert attributes into parameter array string
+        $_paramsArray = array();
+        foreach ($_attr as $_key => $_value) {
+            if (is_int($_key)) {
+                $_paramsArray[] = "$_key=>$_value";
+            } elseif ($compiler->template->caching && in_array($_key, $tag_info[ 2 ])) {
+                $_value = str_replace("'", "^#^", $_value);
+                $_paramsArray[] = "'$_key'=>^#^.var_export($_value,true).^#^";
+            } else {
+                $_paramsArray[] = "'$_key'=>$_value";
+            }
+        }
+        $_params = 'array(' . implode(",", $_paramsArray) . ')';
+        $function = $tag_info[ 0 ];
+        // compile code
+        if (!is_array($function)) {
+            $output = "{$function}({$_params},\$_smarty_tpl)";
+        } elseif (is_object($function[ 0 ])) {
+            $output =
+                "\$_smarty_tpl->smarty->registered_plugins[Smarty::PLUGIN_FUNCTION]['{$tag}'][0][0]->{$function[1]}({$_params},\$_smarty_tpl)";
+        } else {
+            $output = "{$function[0]}::{$function[1]}({$_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 = isset($_attr[ 'assign' ]) ? false : true;
+        $output = "<?php " . ($compiler->has_output ? "echo " : '') . "{$output};?>\n";
+        return $output;
+    }
+}

+ 126 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_private_special_variable.php

@@ -0,0 +1,126 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Special Smarty Variable
+ * Compiles the special $smarty variables
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile special Smarty Variable Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_CompileBase
+{
+    /**
+     * Compiles code for the special $smarty variables
+     *
+     * @param  array                                       $args     array with attributes from parser
+     * @param \Smarty_Internal_TemplateCompilerBase        $compiler compiler object
+     * @param                                              $parameter
+     *
+     * @return string compiled code
+     * @throws \SmartyCompilerException
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
+    {
+        $_index = preg_split("/\]\[/", substr($parameter, 1, strlen($parameter) - 2));
+        $variable = strtolower($compiler->getId($_index[ 0 ]));
+        if ($variable === false) {
+            $compiler->trigger_template_error("special \$Smarty variable name index can not be variable", null, true);
+        }
+        if (!isset($compiler->smarty->security_policy) ||
+            $compiler->smarty->security_policy->isTrustedSpecialSmartyVar($variable, $compiler)
+        ) {
+            switch ($variable) {
+                case 'foreach':
+                case 'section':
+                    if (!isset(Smarty_Internal_TemplateCompilerBase::$_tag_objects[ $variable ])) {
+                        $class = 'Smarty_Internal_Compile_' . ucfirst($variable);
+                        Smarty_Internal_TemplateCompilerBase::$_tag_objects[ $variable ] = new $class;
+                    }
+                    return Smarty_Internal_TemplateCompilerBase::$_tag_objects[ $variable ]->compileSpecialVariable(array(), $compiler, $_index);
+                case 'capture':
+                    if (class_exists('Smarty_Internal_Compile_Capture')) {
+                        return Smarty_Internal_Compile_Capture::compileSpecialVariable(array(), $compiler, $_index);
+                    }
+                    return '';
+                case 'now':
+                    return 'time()';
+                case 'cookies':
+                    if (isset($compiler->smarty->security_policy) &&
+                        !$compiler->smarty->security_policy->allow_super_globals
+                    ) {
+                        $compiler->trigger_template_error("(secure mode) super globals not permitted");
+                        break;
+                    }
+                    $compiled_ref = '$_COOKIE';
+                    break;
+                case 'get':
+                case 'post':
+                case 'env':
+                case 'server':
+                case 'session':
+                case 'request':
+                    if (isset($compiler->smarty->security_policy) &&
+                        !$compiler->smarty->security_policy->allow_super_globals
+                    ) {
+                        $compiler->trigger_template_error("(secure mode) super globals not permitted");
+                        break;
+                    }
+                    $compiled_ref = '$_' . strtoupper($variable);
+                    break;
+
+                case 'template':
+                    return 'basename($_smarty_tpl->source->filepath)';
+
+                case 'template_object':
+                    return '$_smarty_tpl';
+
+                case 'current_dir':
+                    return 'dirname($_smarty_tpl->source->filepath)';
+
+                case 'version':
+                    return "Smarty::SMARTY_VERSION";
+
+                case 'const':
+                    if (isset($compiler->smarty->security_policy) &&
+                        !$compiler->smarty->security_policy->allow_constants
+                    ) {
+                        $compiler->trigger_template_error("(secure mode) constants not permitted");
+                        break;
+                    }
+                    if (strpos($_index[ 1 ], '$') === false && strpos($_index[ 1 ], '\'') === false) {
+                        return "@constant('{$_index[1]}')";
+                    } else {
+                        return "@constant({$_index[1]})";
+                    }
+
+                case 'config':
+                    if (isset($_index[ 2 ])) {
+                        return "(is_array(\$tmp = \$_smarty_tpl->smarty->ext->configload->_getConfigVariable(\$_smarty_tpl, $_index[1])) ? \$tmp[$_index[2]] : null)";
+                    } else {
+                        return "\$_smarty_tpl->smarty->ext->configload->_getConfigVariable(\$_smarty_tpl, $_index[1])";
+                    }
+                case 'ldelim':
+                    return "\$_smarty_tpl->smarty->left_delimiter";
+                case 'rdelim':
+                    return "\$_smarty_tpl->smarty->right_delimiter";
+                default:
+                    $compiler->trigger_template_error('$smarty.' . trim($_index[ 0 ], "'") . ' is not defined');
+                    break;
+            }
+            if (isset($_index[ 1 ])) {
+                array_shift($_index);
+                foreach ($_index as $_ind) {
+                    $compiled_ref = $compiled_ref . "[$_ind]";
+                }
+            }
+            return $compiled_ref;
+        }
+    }
+}

+ 40 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_rdelim.php

@@ -0,0 +1,40 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Rdelim
+ * Compiles the {rdelim} tag
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Rdelim Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Rdelim extends Smarty_Internal_CompileBase
+{
+    /**
+     * Compiles code for the {rdelim} tag
+     * This tag does output the right delimiter.
+     *
+     * @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)
+    {
+        $_attr = $this->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->right_delimiter;
+    }
+}

+ 469 - 0
Qii/View/smarty/sysplugins/smarty_internal_compile_section.php

@@ -0,0 +1,469 @@
+<?php
+/**
+ * Smarty Internal Plugin Compile Section
+ * Compiles the {section} {sectionelse} {/section} tags
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ * @author     Uwe Tews
+ */
+
+/**
+ * Smarty Internal Plugin Compile Section Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Section extends Smarty_Internal_Compile_Private_ForeachSection
+{
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $required_attributes = array('name', 'loop');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $shorttag_order = array('name', 'loop');
+
+    /**
+     * Attribute definition: Overwrites base class.
+     *
+     * @var array
+     * @see Smarty_Internal_CompileBase
+     */
+    public $optional_attributes = array('start', 'step', 'max', 'show', 'properties');
+
+    /**
+     * counter
+     *
+     * @var int
+     */
+    public $counter = 0;
+
+    /**
+     * Name of this tag
+     *
+     * @var string
+     */
+    public $tagName = 'section';
+
+    /**
+     * Valid properties of $smarty.section.name.xxx variable
+     *
+     * @var array
+     */
+    public $nameProperties = array('first', 'last', 'index', 'iteration', 'show', 'total', 'rownum', 'index_prev',
+                                   'index_next', 'loop');
+
+    /**
+     * {section} tag has no item properties
+     *
+     * @var array
+     */
+    public $itemProperties = null;
+
+    /**
+     * {section} tag has always name attribute
+     *
+     * @var bool
+     */
+    public $isNamed = true;
+
+    /**
+     * Compiles code for the {section} 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)
+    {
+        $compiler->loopNesting ++;
+        // check and get attributes
+        $_attr = $this->getAttributes($compiler, $args);
+        $attributes = array('name' => $compiler->getId($_attr[ 'name' ]));
+        unset($_attr[ 'name' ]);
+        foreach ($attributes as $a => $v) {
+            if ($v === false) {
+                $compiler->trigger_template_error("'{$a}' attribute/variable has illegal value", null, true);
+            }
+        }
+        $local = "\$__section_{$attributes['name']}_" . $this->counter ++ . '_';
+        $sectionVar = "\$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}']";
+        $this->openTag($compiler, 'section', array('section', $compiler->nocache, $local, $sectionVar));
+        // maybe nocache because of nocache variables
+        $compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
+
+        $initLocal =
+            array('saved' => "isset(\$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}']) ? \$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}'] : false",);
+        $initNamedProperty = array();
+        $initFor = array();
+        $incFor = array();
+        $cmpFor = array();
+        $propValue = array('index' => "{$sectionVar}->value['index']", 'show' => 'true', 'step' => 1,
+                           'iteration' => "{$local}iteration",
+
+        );
+        $propType = array('index' => 2, 'iteration' => 2, 'show' => 0, 'step' => 0,);
+        // search for used tag attributes
+        $this->scanForProperties($attributes, $compiler);
+        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->nameProperties)) {
+                    $namedAttr[ $prop ] = true;
+                } else {
+                    $compiler->trigger_template_error("Invalid property '{$prop}'", null, true);
+                }
+            }
+        }
+        $namedAttr[ 'index' ] = true;
+        $output = "<?php\n";
+        foreach ($_attr as $attr_name => $attr_value) {
+            switch ($attr_name) {
+                case 'loop':
+                    if (is_numeric($attr_value)) {
+                        $v = (int) $attr_value;
+                        $t = 0;
+                    } else {
+                        $v = "(is_array(@\$_loop=$attr_value) ? count(\$_loop) : max(0, (int) \$_loop))";
+                        $t = 1;
+                    }
+                    if (isset($namedAttr[ 'loop' ])) {
+                        $initNamedProperty[ 'loop' ] = "'loop' => {$v}";
+                        if ($t == 1) {
+                            $v = "{$sectionVar}->value['loop']";
+                        }
+                    } elseif ($t == 1) {
+                        $initLocal[ 'loop' ] = $v;
+                        $v = "{$local}loop";
+                    }
+                    break;
+                case 'show':
+                    if (is_bool($attr_value)) {
+                        $v = $attr_value ? 'true' : 'false';
+                        $t = 0;
+                    } else {
+                        $v = "(bool) $attr_value";
+                        $t = 3;
+                    }
+                    break;
+                case 'step':
+                    if (is_numeric($attr_value)) {
+                        $v = (int) $attr_value;
+                        $v = ($v == 0) ? 1 : $v;
+                        $t = 0;
+                        break;
+                    }
+                    $initLocal[ 'step' ] = "((int)@$attr_value) == 0 ? 1 : (int)@$attr_value";
+                    $v = "{$local}step";
+                    $t = 2;
+                    break;
+
+                case 'max':
+                case 'start':
+                    if (is_numeric($attr_value)) {
+                        $v = (int) $attr_value;
+                        $t = 0;
+                        break;
+                    }
+                    $v = "(int)@$attr_value";
+                    $t = 3;
+                    break;
+            }
+            if ($t == 3 && $compiler->getId($attr_value)) {
+                $t = 1;
+            }
+            $propValue[ $attr_name ] = $v;
+            $propType[ $attr_name ] = $t;
+        }
+
+        if (isset($namedAttr[ 'step' ])) {
+            $initNamedProperty[ 'step' ] = $propValue[ 'step' ];
+        }
+        if (isset($namedAttr[ 'iteration' ])) {
+            $propValue[ 'iteration' ] = "{$sectionVar}->value['iteration']";
+        }
+        $incFor[ 'iteration' ] = "{$propValue['iteration']}++";
+        $initFor[ 'iteration' ] = "{$propValue['iteration']} = 1";
+
+        if ($propType[ 'step' ] == 0) {
+            if ($propValue[ 'step' ] == 1) {
+                $incFor[ 'index' ] = "{$sectionVar}->value['index']++";
+            } elseif ($propValue[ 'step' ] > 1) {
+                $incFor[ 'index' ] = "{$sectionVar}->value['index'] += {$propValue['step']}";
+            } else {
+                $incFor[ 'index' ] = "{$sectionVar}->value['index'] -= " . - $propValue[ 'step' ];
+            }
+        } else {
+            $incFor[ 'index' ] = "{$sectionVar}->value['index'] += {$propValue['step']}";
+        }
+
+        if (!isset($propValue[ 'max' ])) {
+            $propValue[ 'max' ] = $propValue[ 'loop' ];
+            $propType[ 'max' ] = $propType[ 'loop' ];
+        } elseif ($propType[ 'max' ] != 0) {
+            $propValue[ 'max' ] = "{$propValue['max']} < 0 ? {$propValue['loop']} : {$propValue['max']}";
+            $propType[ 'max' ] = 1;
+        } else {
+            if ($propValue[ 'max' ] < 0) {
+                $propValue[ 'max' ] = $propValue[ 'loop' ];
+                $propType[ 'max' ] = $propType[ 'loop' ];
+            }
+        }
+
+        if (!isset($propValue[ 'start' ])) {
+            $start_code =
+                array(1 => "{$propValue['step']} > 0 ? ", 2 => '0', 3 => ' : ', 4 => $propValue[ 'loop' ], 5 => ' - 1');
+            if ($propType[ 'loop' ] == 0) {
+                $start_code[ 5 ] = '';
+                $start_code[ 4 ] = $propValue[ 'loop' ] - 1;
+            }
+            if ($propType[ 'step' ] == 0) {
+                if ($propValue[ 'step' ] > 0) {
+                    $start_code = array(1 => '0');
+                    $propType[ 'start' ] = 0;
+                } else {
+                    $start_code[ 1 ] = $start_code[ 2 ] = $start_code[ 3 ] = '';
+                    $propType[ 'start' ] = $propType[ 'loop' ];
+                }
+            } else {
+                $propType[ 'start' ] = 1;
+            }
+            $propValue[ 'start' ] = join('', $start_code);
+        } else {
+            $start_code =
+                array(1 => "{$propValue['start']} < 0 ? ", 2 => 'max(', 3 => "{$propValue['step']} > 0 ? ", 4 => '0',
+                      5 => ' : ', 6 => '-1', 7 => ', ', 8 => "{$propValue['start']} + {$propValue['loop']}", 10 => ')',
+                      11 => ' : ', 12 => 'min(', 13 => $propValue[ 'start' ], 14 => ', ',
+                      15 => "{$propValue['step']} > 0 ? ", 16 => $propValue[ 'loop' ], 17 => ' : ',
+                      18 => $propType[ 'loop' ] == 0 ? $propValue[ 'loop' ] - 1 : "{$propValue['loop']} - 1",
+                      19 => ')');
+            if ($propType[ 'step' ] == 0) {
+                $start_code[ 3 ] = $start_code[ 5 ] = $start_code[ 15 ] = $start_code[ 17 ] = '';
+                if ($propValue[ 'step' ] > 0) {
+                    $start_code[ 6 ] = $start_code[ 18 ] = '';
+                } else {
+                    $start_code[ 4 ] = $start_code[ 16 ] = '';
+                }
+            }
+            if ($propType[ 'start' ] == 0) {
+                if ($propType[ 'loop' ] == 0) {
+                    $start_code[ 8 ] = $propValue[ 'start' ] + $propValue[ 'loop' ];
+                }
+                $propType[ 'start' ] = $propType[ 'step' ] + $propType[ 'loop' ];
+                $start_code[ 1 ] = '';
+                if ($propValue[ 'start' ] < 0) {
+                    for ($i = 11; $i <= 19; $i ++) {
+                        $start_code[ $i ] = '';
+                    }
+                    if ($propType[ 'start' ] == 0) {
+                        $start_code = array(max($propValue[ 'step' ] > 0 ? 0 : - 1,
+                                                $propValue[ 'start' ] + $propValue[ 'loop' ]));
+                    }
+                } else {
+                    for ($i = 1; $i <= 11; $i ++) {
+                        $start_code[ $i ] = '';
+                    }
+                    if ($propType[ 'start' ] == 0) {
+                        $start_code =
+                            array(min($propValue[ 'step' ] > 0 ? $propValue[ 'loop' ] : $propValue[ 'loop' ] - 1,
+                                      $propValue[ 'start' ]));
+                    }
+                }
+            }
+            $propValue[ 'start' ] = join('', $start_code);
+        }
+        if ($propType[ 'start' ] != 0) {
+            $initLocal[ 'start' ] = $propValue[ 'start' ];
+            $propValue[ 'start' ] = "{$local}start";
+        }
+
+        $initFor[ 'index' ] = "{$sectionVar}->value['index'] = {$propValue['start']}";
+
+        if (!isset($_attr[ 'start' ]) && !isset($_attr[ 'step' ]) && !isset($_attr[ 'max' ])) {
+            $propValue[ 'total' ] = $propValue[ 'loop' ];
+            $propType[ 'total' ] = $propType[ 'loop' ];
+        } else {
+            $propType[ 'total' ] =
+                $propType[ 'start' ] + $propType[ 'loop' ] + $propType[ 'step' ] + $propType[ 'max' ];
+            if ($propType[ 'total' ] == 0) {
+                $propValue[ 'total' ] =
+                    min(ceil(($propValue[ 'step' ] > 0 ? $propValue[ 'loop' ] - $propValue[ 'start' ] :
+                                 (int) $propValue[ 'start' ] + 1) / abs($propValue[ 'step' ])), $propValue[ 'max' ]);
+            } else {
+                $total_code = array(1 => 'min(', 2 => 'ceil(', 3 => '(', 4 => "{$propValue['step']} > 0 ? ",
+                                    5 => $propValue[ 'loop' ], 6 => ' - ', 7 => $propValue[ 'start' ], 8 => ' : ',
+                                    9 => $propValue[ 'start' ], 10 => '+ 1', 11 => ')', 12 => '/ ', 13 => 'abs(',
+                                    14 => $propValue[ 'step' ], 15 => ')', 16 => ')', 17 => ", {$propValue['max']})",);
+                if (!isset($propValue[ 'max' ])) {
+                    $total_code[ 1 ] = $total_code[ 17 ] = '';
+                }
+                if ($propType[ 'loop' ] + $propType[ 'start' ] == 0) {
+                    $total_code[ 5 ] = $propValue[ 'loop' ] - $propValue[ 'start' ];
+                    $total_code[ 6 ] = $total_code[ 7 ] = '';
+                }
+                if ($propType[ 'start' ] == 0) {
+                    $total_code[ 9 ] = (int) $propValue[ 'start' ] + 1;
+                    $total_code[ 10 ] = '';
+                }
+                if ($propType[ 'step' ] == 0) {
+                    $total_code[ 13 ] = $total_code[ 15 ] = '';
+                    if ($propValue[ 'step' ] == 1 || $propValue[ 'step' ] == - 1) {
+                        $total_code[ 2 ] = $total_code[ 12 ] = $total_code[ 14 ] = $total_code[ 16 ] = '';
+                    } elseif ($propValue[ 'step' ] < 0) {
+                        $total_code[ 14 ] = - $propValue[ 'step' ];
+                    }
+                    $total_code[ 4 ] = '';
+                    if ($propValue[ 'step' ] > 0) {
+                        $total_code[ 8 ] = $total_code[ 9 ] = $total_code[ 10 ] = '';
+                    } else {
+                        $total_code[ 5 ] = $total_code[ 6 ] = $total_code[ 7 ] = $total_code[ 8 ] = '';
+                    }
+                }
+                $propValue[ 'total' ] = join('', $total_code);
+            }
+        }
+
+        if (isset($namedAttr[ 'loop' ])) {
+            $initNamedProperty[ 'loop' ] = "'loop' => {$propValue['total']}";
+        }
+        if (isset($namedAttr[ 'total' ])) {
+            $initNamedProperty[ 'total' ] = "'total' => {$propValue['total']}";
+            if ($propType[ 'total' ] > 0) {
+                $propValue[ 'total' ] = "{$sectionVar}->value['total']";
+            }
+        } elseif ($propType[ 'total' ] > 0) {
+            $initLocal[ 'total' ] = $propValue[ 'total' ];
+            $propValue[ 'total' ] = "{$local}total";
+        }
+
+        $cmpFor[ 'iteration' ] = "{$propValue['iteration']} <= {$propValue['total']}";
+
+        foreach ($initLocal as $key => $code) {
+            $output .= "{$local}{$key} = {$code};\n";
+        }
+
+        $_vars = 'array(' . join(', ', $initNamedProperty) . ')';
+        $output .= "{$sectionVar} = new Smarty_Variable({$_vars});\n";
+        $cond_code = "{$propValue['total']} != 0";
+        if ($propType[ 'total' ] == 0) {
+            if ($propValue[ 'total' ] == 0) {
+                $cond_code = 'false';
+            } else {
+                $cond_code = 'true';
+            }
+        }
+        if ($propType[ 'show' ] > 0) {
+            $output .= "{$local}show = {$propValue['show']} ? {$cond_code} : false;\n";
+            $output .= "if ({$local}show) {\n";
+        } elseif ($propValue[ 'show' ] == 'true') {
+            $output .= "if ({$cond_code}) {\n";
+        } else {
+            $output .= "if (false) {\n";
+        }
+        $jinit = join(', ', $initFor);
+        $jcmp = join(', ', $cmpFor);
+        $jinc = join(', ', $incFor);
+        $output .= "for ({$jinit}; {$jcmp}; {$jinc}){\n";
+        if (isset($namedAttr[ 'rownum' ])) {
+            $output .= "{$sectionVar}->value['rownum'] = {$propValue['iteration']};\n";
+        }
+        if (isset($namedAttr[ 'index_prev' ])) {
+            $output .= "{$sectionVar}->value['index_prev'] = {$propValue['index']} - {$propValue['step']};\n";
+        }
+        if (isset($namedAttr[ 'index_next' ])) {
+            $output .= "{$sectionVar}->value['index_next'] = {$propValue['index']} + {$propValue['step']};\n";
+        }
+        if (isset($namedAttr[ 'first' ])) {
+            $output .= "{$sectionVar}->value['first'] = ({$propValue['iteration']} == 1);\n";
+        }
+        if (isset($namedAttr[ 'last' ])) {
+            $output .= "{$sectionVar}->value['last'] = ({$propValue['iteration']} == {$propValue['total']});\n";
+        }
+        $output .= "?>";
+
+        return $output;
+    }
+}
+
+/**
+ * Smarty Internal Plugin Compile Sectionelse Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Sectionelse extends Smarty_Internal_CompileBase
+{
+    /**
+     * Compiles code for the {sectionelse} tag
+     *
+     * @param  array                                $args     array with attributes from parser
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
+     *
+     * @return string compiled code
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
+    {
+        // check and get attributes
+        $_attr = $this->getAttributes($compiler, $args);
+
+        list($openTag, $nocache, $local, $sectionVar) = $this->closeTag($compiler, array('section'));
+        $this->openTag($compiler, 'sectionelse', array('sectionelse', $nocache, $local, $sectionVar));
+
+        return "<?php }} else {\n ?>";
+    }
+}
+
+/**
+ * Smarty Internal Plugin Compile Sectionclose Class
+ *
+ * @package    Smarty
+ * @subpackage Compiler
+ */
+class Smarty_Internal_Compile_Sectionclose extends Smarty_Internal_CompileBase
+{
+    /**
+     * Compiles code for the {/section} tag
+     *
+     * @param  array                                $args     array with attributes from parser
+     * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
+     *
+     * @return string compiled code
+     */
+    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
+    {
+        $compiler->loopNesting --;
+        // must endblock be nocache?
+        if ($compiler->nocache) {
+            $compiler->tag_nocache = true;
+        }
+
+        list($openTag, $compiler->nocache, $local, $sectionVar) =
+            $this->closeTag($compiler, array('section', 'sectionelse'));
+
+        $output = "<?php\n";
+        if ($openTag == 'sectionelse') {
+            $output .= "}\n";
+        } else {
+            $output .= "}\n}\n";
+        }
+        $output .= "if ({$local}saved) {\n";
+        $output .= "{$sectionVar} = {$local}saved;\n";
+        $output .= "}\n";
+        $output .= "?>";
+
+        return $output;
+    }
+}

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor