/core/model/smarty/sysplugins/smarty_internal_template.php

https://github.com/hatone/revolution · PHP · 972 lines · 670 code · 38 blank · 264 comment · 224 complexity · ef55bdc338994e87b650e2cf0f87df45 MD5 · raw file

  1. <?php
  2. /**
  3. * Smarty Internal Plugin Template
  4. *
  5. * This file contains the Smarty template engine
  6. *
  7. * @package Smarty
  8. * @subpackage Templates
  9. * @author Uwe Tews
  10. */
  11. /**
  12. * Main class with template data structures and methods
  13. */
  14. class Smarty_Internal_Template extends Smarty_Internal_Data {
  15. // object cache
  16. public $compiler_object = null;
  17. public $cacher_object = null;
  18. // Smarty parameter
  19. public $cache_id = null;
  20. public $compile_id = null;
  21. public $caching = null;
  22. public $cache_lifetime = null;
  23. public $cacher_class = null;
  24. public $caching_type = null;
  25. public $forceNocache = false;
  26. // Template resource
  27. public $template_resource = null;
  28. public $resource_type = null;
  29. public $resource_name = null;
  30. // public $resource_object = null;
  31. private $isExisting = null;
  32. public $templateUid = '';
  33. // Template source
  34. public $template_filepath = null;
  35. public $template_source = null;
  36. private $template_timestamp = null;
  37. // Compiled template
  38. private $compiled_filepath = null;
  39. public $compiled_template = null;
  40. private $compiled_timestamp = null;
  41. public $mustCompile = null;
  42. public $suppressHeader = false;
  43. public $suppressFileDependency = false;
  44. public $has_nocache_code = false;
  45. public $write_compiled_code = true;
  46. // Rendered content
  47. public $rendered_content = null;
  48. // Cache file
  49. private $cached_filepath = null;
  50. public $cached_timestamp = null;
  51. private $isCached = null;
  52. // private $cache_resource_object = null;
  53. private $cacheFileChecked = false;
  54. // template variables
  55. public $tpl_vars = array();
  56. public $parent = null;
  57. public $config_vars = array();
  58. // storage for plugin
  59. public $plugin_data = array();
  60. // special properties
  61. public $properties = array ('file_dependency' => array(),
  62. 'nocache_hash' => '',
  63. 'function' => array());
  64. // required plugins
  65. public $required_plugins = array('compiled' => array(), 'nocache' => array());
  66. public $saved_modifier = null;
  67. public $smarty = null;
  68. // blocks for template inheritance
  69. public $block_data = array();
  70. /**
  71. * Create template data object
  72. *
  73. * Some of the global Smarty settings copied to template scope
  74. * It load the required template resources and cacher plugins
  75. *
  76. * @param string $template_resource template resource string
  77. * @param object $_parent back pointer to parent object with variables or null
  78. * @param mixed $_cache_id cache id or null
  79. * @param mixed $_compile_id compile id or null
  80. */
  81. public function __construct($template_resource, $smarty, $_parent = null, $_cache_id = null, $_compile_id = null, $_caching = null, $_cache_lifetime = null)
  82. {
  83. $this->smarty = &$smarty;
  84. // Smarty parameter
  85. $this->cache_id = $_cache_id === null ? $this->smarty->cache_id : $_cache_id;
  86. $this->compile_id = $_compile_id === null ? $this->smarty->compile_id : $_compile_id;
  87. $this->caching = $_caching === null ? $this->smarty->caching : $_caching;
  88. if ($this->caching === true) $this->caching = Smarty::CACHING_LIFETIME_CURRENT;
  89. $this->cache_lifetime = $_cache_lifetime === null ?$this->smarty->cache_lifetime : $_cache_lifetime;
  90. $this->parent = $_parent;
  91. // dummy local smarty variable
  92. $this->tpl_vars['smarty'] = new Smarty_Variable;
  93. // Template resource
  94. $this->template_resource = $template_resource;
  95. // copy block data of template inheritance
  96. if ($this->parent instanceof Smarty_Internal_Template) {
  97. $this->block_data = $this->parent->block_data;
  98. }
  99. }
  100. /**
  101. * Returns the template filepath
  102. *
  103. * The template filepath is determined by the actual resource handler
  104. *
  105. * @return string the template filepath
  106. */
  107. public function getTemplateFilepath ()
  108. {
  109. return $this->template_filepath === null ?
  110. $this->template_filepath = $this->resource_object->getTemplateFilepath($this) :
  111. $this->template_filepath;
  112. }
  113. /**
  114. * Returns the timpestamp of the template source
  115. *
  116. * The template timestamp is determined by the actual resource handler
  117. *
  118. * @return integer the template timestamp
  119. */
  120. public function getTemplateTimestamp ()
  121. {
  122. return $this->template_timestamp === null ?
  123. $this->template_timestamp = $this->resource_object->getTemplateTimestamp($this) :
  124. $this->template_timestamp;
  125. }
  126. /**
  127. * Returns the template source code
  128. *
  129. * The template source is being read by the actual resource handler
  130. *
  131. * @return string the template source
  132. */
  133. public function getTemplateSource ()
  134. {
  135. if ($this->template_source === null) {
  136. if (!$this->resource_object->getTemplateSource($this)) {
  137. throw new SmartyException("Unable to read template {$this->resource_type} '{$this->resource_name}'");
  138. }
  139. }
  140. return $this->template_source;
  141. }
  142. /**
  143. * Returns if the template is existing
  144. *
  145. * The status is determined by the actual resource handler
  146. *
  147. * @return boolean true if the template exists
  148. */
  149. public function isExisting ($error = false)
  150. {
  151. if ($this->isExisting === null) {
  152. $this->isExisting = $this->resource_object->isExisting($this);
  153. }
  154. if (!$this->isExisting && $error) {
  155. throw new SmartyException("Unable to load template {$this->resource_type} '{$this->resource_name}'");
  156. }
  157. return $this->isExisting;
  158. }
  159. /**
  160. * Returns if the current template must be compiled by the Smarty compiler
  161. *
  162. * It does compare the timestamps of template source and the compiled templates and checks the force compile configuration
  163. *
  164. * @return boolean true if the template must be compiled
  165. */
  166. public function mustCompile ()
  167. {
  168. $this->isExisting(true);
  169. if ($this->mustCompile === null) {
  170. $this->mustCompile = ($this->resource_object->usesCompiler && ($this->smarty->force_compile || $this->resource_object->isEvaluated || $this->getCompiledTimestamp () === false ||
  171. // ($this->smarty->compile_check && $this->getCompiledTimestamp () !== $this->getTemplateTimestamp ())));
  172. ($this->smarty->compile_check && $this->getCompiledTimestamp () < $this->getTemplateTimestamp ())));
  173. }
  174. return $this->mustCompile;
  175. }
  176. /**
  177. * Returns the compiled template filepath
  178. *
  179. * @return string the template filepath
  180. */
  181. public function getCompiledFilepath ()
  182. {
  183. return $this->compiled_filepath === null ?
  184. ($this->compiled_filepath = !$this->resource_object->isEvaluated ? $this->resource_object->getCompiledFilepath($this) : false) :
  185. $this->compiled_filepath;
  186. }
  187. /**
  188. * Returns the timpestamp of the compiled template
  189. *
  190. * @return integer the template timestamp
  191. */
  192. public function getCompiledTimestamp ()
  193. {
  194. return $this->compiled_timestamp === null ?
  195. ($this->compiled_timestamp = (!$this->resource_object->isEvaluated && file_exists($this->getCompiledFilepath())) ? filemtime($this->getCompiledFilepath()) : false) :
  196. $this->compiled_timestamp;
  197. }
  198. /**
  199. * Returns the compiled template
  200. *
  201. * It checks if the template must be compiled or just read from the template resource
  202. *
  203. * @return string the compiled template
  204. */
  205. public function getCompiledTemplate ()
  206. {
  207. if ($this->compiled_template === null) {
  208. // see if template needs compiling.
  209. if ($this->mustCompile()) {
  210. $this->compileTemplateSource();
  211. } else {
  212. if ($this->compiled_template === null) {
  213. $this->compiled_template = !$this->resource_object->isEvaluated && $this->resource_object->usesCompiler ? file_get_contents($this->getCompiledFilepath()) : false;
  214. }
  215. }
  216. }
  217. return $this->compiled_template;
  218. }
  219. /**
  220. * Compiles the template
  221. *
  222. * If the template is not evaluated the compiled template is saved on disk
  223. */
  224. public function compileTemplateSource ()
  225. {
  226. if (!$this->resource_object->isEvaluated) {
  227. $this->properties['file_dependency'] = array();
  228. $this->properties['file_dependency'][$this->templateUid] = array($this->getTemplateFilepath(), $this->getTemplateTimestamp(),$this->resource_type);
  229. }
  230. if ($this->smarty->debugging) {
  231. Smarty_Internal_Debug::start_compile($this);
  232. }
  233. // compile template
  234. if (!is_object($this->compiler_object)) {
  235. // load compiler
  236. $this->smarty->loadPlugin($this->resource_object->compiler_class);
  237. $this->compiler_object = new $this->resource_object->compiler_class($this->resource_object->template_lexer_class, $this->resource_object->template_parser_class, $this->smarty);
  238. }
  239. // compile locking
  240. if ($this->smarty->compile_locking && !$this->resource_object->isEvaluated) {
  241. if ($saved_timestamp = $this->getCompiledTimestamp()) {
  242. touch($this->getCompiledFilepath());
  243. }
  244. }
  245. // call compiler
  246. try {
  247. $this->compiler_object->compileTemplate($this);
  248. }
  249. catch (Exception $e) {
  250. // restore old timestamp in case of error
  251. if ($this->smarty->compile_locking && !$this->resource_object->isEvaluated && $saved_timestamp) {
  252. touch($this->getCompiledFilepath(), $saved_timestamp);
  253. }
  254. throw $e;
  255. }
  256. // compiling succeded
  257. if (!$this->resource_object->isEvaluated && $this->write_compiled_code) {
  258. // write compiled template
  259. Smarty_Internal_Write_File::writeFile($this->getCompiledFilepath(), $this->compiled_template, $this->smarty);
  260. }
  261. if ($this->smarty->debugging) {
  262. Smarty_Internal_Debug::end_compile($this);
  263. }
  264. }
  265. /**
  266. * Returns the filepath of the cached template output
  267. *
  268. * The filepath is determined by the actual cache resource
  269. *
  270. * @return string the cache filepath
  271. */
  272. public function getCachedFilepath ()
  273. {
  274. return $this->cached_filepath === null ?
  275. $this->cached_filepath = ($this->resource_object->isEvaluated || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) ? false : $this->cache_resource_object->getCachedFilepath($this) :
  276. $this->cached_filepath;
  277. }
  278. /**
  279. * Returns the timpestamp of the cached template output
  280. *
  281. * The timestamp is determined by the actual cache resource
  282. *
  283. * @return integer the template timestamp
  284. */
  285. public function getCachedTimestamp ()
  286. {
  287. return $this->cached_timestamp === null ?
  288. $this->cached_timestamp = ($this->resource_object->isEvaluated || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) ? false : $this->cache_resource_object->getCachedTimestamp($this) :
  289. $this->cached_timestamp;
  290. }
  291. /**
  292. * Returns the cached template output
  293. *
  294. * @return string |booelan the template content or false if the file does not exist
  295. */
  296. public function getCachedContent ()
  297. {
  298. return $this->rendered_content === null ?
  299. $this->rendered_content = ($this->resource_object->isEvaluated || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) ? false : $this->cache_resource_object->getCachedContents($this) :
  300. $this->rendered_content;
  301. }
  302. /**
  303. * Writes the cached template output
  304. */
  305. public function writeCachedContent ($content)
  306. {
  307. if ($this->resource_object->isEvaluated || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) {
  308. // don't write cache file
  309. return false;
  310. }
  311. $this->properties['cache_lifetime'] = $this->cache_lifetime;
  312. return $this->cache_resource_object->writeCachedContent($this, $this->createPropertyHeader(true) .$content);
  313. }
  314. /**
  315. * Checks of a valid version redered HTML output is in the cache
  316. *
  317. * If the cache is valid the contents is stored in the template object
  318. *
  319. * @return boolean true if cache is valid
  320. */
  321. public function isCached ($template = null, $cache_id = null, $compile_id = null, $parent = null)
  322. {
  323. if ($template === null) {
  324. $no_render = true;
  325. } elseif ($template === false) {
  326. $no_render = false;
  327. } else {
  328. if ($parent === null) {
  329. $parent = $this;
  330. }
  331. $this->smarty->isCached ($template, $cache_id, $compile_id, $parent);
  332. }
  333. if ($this->isCached === null) {
  334. $this->isCached = false;
  335. if (($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED) && !$this->resource_object->isEvaluated) {
  336. $cachedTimestamp = $this->getCachedTimestamp();
  337. if ($cachedTimestamp === false || $this->smarty->force_compile || $this->smarty->force_cache) {
  338. return $this->isCached;
  339. }
  340. if ($this->caching === Smarty::CACHING_LIFETIME_SAVED || ($this->caching == Smarty::CACHING_LIFETIME_CURRENT && (time() <= ($cachedTimestamp + $this->cache_lifetime) || $this->cache_lifetime < 0))) {
  341. if ($this->smarty->debugging) {
  342. Smarty_Internal_Debug::start_cache($this);
  343. }
  344. $this->rendered_content = $this->cache_resource_object->getCachedContents($this, $no_render);
  345. if ($this->smarty->debugging) {
  346. Smarty_Internal_Debug::end_cache($this);
  347. }
  348. if ($this->cacheFileChecked) {
  349. $this->isCached = true;
  350. return $this->isCached;
  351. }
  352. $this->cacheFileChecked = true;
  353. if ($this->caching === Smarty::CACHING_LIFETIME_SAVED && $this->properties['cache_lifetime'] >= 0 && (time() > ($this->getCachedTimestamp() + $this->properties['cache_lifetime']))) {
  354. $this->tpl_vars = array();
  355. $this->rendered_content = null;
  356. return $this->isCached;
  357. }
  358. if (!empty($this->properties['file_dependency']) && $this->smarty->compile_check) {
  359. $resource_type = null;
  360. $resource_name = null;
  361. foreach ($this->properties['file_dependency'] as $_file_to_check) {
  362. If ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'extends' || $_file_to_check[2] == 'php') {
  363. $mtime = filemtime($_file_to_check[0]);
  364. } else {
  365. $this->getResourceTypeName($_file_to_check[0], $resource_type, $resource_name);
  366. $resource_handler = $this->loadTemplateResourceHandler($resource_type);
  367. $mtime = $resource_handler->getTemplateTimestampTypeName($resource_type, $resource_name);
  368. }
  369. // If ($mtime > $this->getCachedTimestamp()) {
  370. If ($mtime > $_file_to_check[1]) {
  371. $this->tpl_vars = array();
  372. $this->rendered_content = null;
  373. return $this->isCached;
  374. }
  375. }
  376. }
  377. $this->isCached = true;
  378. }
  379. }
  380. }
  381. return $this->isCached;
  382. }
  383. /**
  384. * Render the output using the compiled template or the PHP template source
  385. *
  386. * The rendering process is accomplished by just including the PHP files.
  387. * The only exceptions are evaluated templates (string template). Their code has
  388. * to be evaluated
  389. */
  390. public function renderTemplate ()
  391. {
  392. if ($this->resource_object->usesCompiler) {
  393. if ($this->mustCompile() && $this->compiled_template === null) {
  394. $this->compileTemplateSource();
  395. }
  396. if ($this->smarty->debugging) {
  397. Smarty_Internal_Debug::start_render($this);
  398. }
  399. $_smarty_tpl = $this;
  400. ob_start();
  401. if ($this->resource_object->isEvaluated) {
  402. eval("?>" . $this->compiled_template);
  403. } else {
  404. include($this->getCompiledFilepath ());
  405. // check file dependencies at compiled code
  406. if ($this->smarty->compile_check) {
  407. if (!empty($this->properties['file_dependency'])) {
  408. $this->mustCompile = false;
  409. $resource_type = null;
  410. $resource_name = null;
  411. foreach ($this->properties['file_dependency'] as $_file_to_check) {
  412. If ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'extends' || $_file_to_check[2] == 'php') {
  413. $mtime = filemtime($_file_to_check[0]);
  414. } else {
  415. $this->getResourceTypeName($_file_to_check[0], $resource_type, $resource_name);
  416. $resource_handler = $this->loadTemplateResourceHandler($resource_type);
  417. $mtime = $resource_handler->getTemplateTimestampTypeName($resource_type, $resource_name);
  418. }
  419. // If ($mtime != $_file_to_check[1]) {
  420. If ($mtime > $_file_to_check[1]) {
  421. $this->mustCompile = true;
  422. break;
  423. }
  424. }
  425. if ($this->mustCompile) {
  426. // recompile and render again
  427. ob_get_clean();
  428. $this->compileTemplateSource();
  429. ob_start();
  430. include($this->getCompiledFilepath ());
  431. }
  432. }
  433. }
  434. }
  435. } else {
  436. if (is_callable(array($this->resource_object, 'renderUncompiled'))) {
  437. if ($this->smarty->debugging) {
  438. Smarty_Internal_Debug::start_render($this);
  439. }
  440. ob_start();
  441. $this->resource_object->renderUncompiled($this);
  442. } else {
  443. throw new SmartyException("Resource '$this->resource_type' must have 'renderUncompiled' methode");
  444. }
  445. }
  446. $this->rendered_content = ob_get_clean();
  447. if (!$this->resource_object->isEvaluated && empty($this->properties['file_dependency'][$this->templateUid])) {
  448. $this->properties['file_dependency'][$this->templateUid] = array($this->getTemplateFilepath(), $this->getTemplateTimestamp(),$this->resource_type);
  449. }
  450. if ($this->parent instanceof Smarty_Internal_Template) {
  451. $this->parent->properties['file_dependency'] = array_merge($this->parent->properties['file_dependency'], $this->properties['file_dependency']);
  452. foreach($this->required_plugins as $code => $tmp1) {
  453. foreach($tmp1 as $name => $tmp) {
  454. foreach($tmp as $type => $data) {
  455. $this->parent->required_plugins[$code][$name][$type] = $data;
  456. }
  457. }
  458. }
  459. }
  460. if ($this->smarty->debugging) {
  461. Smarty_Internal_Debug::end_render($this);
  462. }
  463. // write to cache when nessecary
  464. if (!$this->resource_object->isEvaluated && ($this->caching == Smarty::CACHING_LIFETIME_SAVED || $this->caching == Smarty::CACHING_LIFETIME_CURRENT)) {
  465. if ($this->smarty->debugging) {
  466. Smarty_Internal_Debug::start_cache($this);
  467. }
  468. $this->properties['has_nocache_code'] = false;
  469. // get text between non-cached items
  470. $cache_split = preg_split("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content);
  471. // get non-cached items
  472. preg_match_all("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content, $cache_parts);
  473. $output = '';
  474. // loop over items, stitch back together
  475. foreach($cache_split as $curr_idx => $curr_split) {
  476. // escape PHP tags in template content
  477. $output .= preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php echo \'$1\'; ?>', $curr_split);
  478. if (isset($cache_parts[0][$curr_idx])) {
  479. $this->properties['has_nocache_code'] = true;
  480. // remove nocache tags from cache output
  481. $output .= preg_replace("!/\*/?%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!", '', $cache_parts[0][$curr_idx]);
  482. }
  483. }
  484. // rendering (must be done before writing cache file because of {function} nocache handling)
  485. $_smarty_tpl = $this;
  486. ob_start();
  487. eval("?>" . $output);
  488. $this->rendered_content = ob_get_clean();
  489. // write cache file content
  490. $this->writeCachedContent('<?php if (!$no_render) {?>'. $output. '<?php } ?>');
  491. if ($this->smarty->debugging) {
  492. Smarty_Internal_Debug::end_cache($this);
  493. }
  494. } else {
  495. // var_dump('renderTemplate', $this->has_nocache_code, $this->template_resource, $this->properties['nocache_hash'], $this->parent->properties['nocache_hash'], $this->rendered_content);
  496. if ($this->has_nocache_code && !empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) {
  497. // replace nocache_hash
  498. $this->rendered_content = preg_replace("/{$this->properties['nocache_hash']}/", $this->parent->properties['nocache_hash'], $this->rendered_content);
  499. $this->parent->has_nocache_code = $this->has_nocache_code;
  500. }
  501. }
  502. }
  503. /**
  504. * Returns the rendered HTML output
  505. *
  506. * If the cache is valid the cached content is used, otherwise
  507. * the output is rendered from the compiled template or PHP template source
  508. *
  509. * @return string rendered HTML output
  510. */
  511. public function getRenderedTemplate ()
  512. {
  513. // disable caching for evaluated code
  514. if ($this->resource_object->isEvaluated) {
  515. $this->caching = false;
  516. }
  517. // checks if template exists
  518. $this->isExisting(true);
  519. // read from cache or render
  520. if ($this->rendered_content === null) {
  521. if ($this->isCached) {
  522. if ($this->smarty->debugging) {
  523. Smarty_Internal_Debug::start_cache($this);
  524. }
  525. $this->rendered_content = $this->cache_resource_object->getCachedContents($this, false);
  526. if ($this->smarty->debugging) {
  527. Smarty_Internal_Debug::end_cache($this);
  528. }
  529. }
  530. if ($this->isCached === null) {
  531. $this->isCached(false);
  532. }
  533. if (!$this->isCached) {
  534. // render template (not loaded and not in cache)
  535. $this->renderTemplate();
  536. }
  537. }
  538. $this->updateParentVariables();
  539. $this->isCached = null;
  540. return $this->rendered_content;
  541. }
  542. /**
  543. * Parse a template resource in its name and type
  544. * Load required resource handler
  545. *
  546. * @param string $template_resource template resource specification
  547. * @param string $resource_type return resource type
  548. * @param string $resource_name return resource name
  549. * @param object $resource_handler return resource handler object
  550. */
  551. public function parseResourceName($template_resource, &$resource_type, &$resource_name, &$resource_handler)
  552. {
  553. if (empty($template_resource))
  554. return false;
  555. $this->getResourceTypeName($template_resource, $resource_type, $resource_name);
  556. $resource_handler = $this->loadTemplateResourceHandler($resource_type);
  557. // cache template object under a unique ID
  558. // do not cache eval resources
  559. if ($resource_type != 'eval') {
  560. $this->smarty->template_objects[sha1($this->template_resource . $this->cache_id . $this->compile_id)] = $this;
  561. }
  562. return true;
  563. }
  564. /**
  565. * get system filepath to template
  566. */
  567. public function buildTemplateFilepath ($file = null)
  568. {
  569. if ($file == null) {
  570. $file = $this->resource_name;
  571. }
  572. foreach((array)$this->smarty->template_dir as $_template_dir) {
  573. if (strpos('/\\', substr($_template_dir, -1)) === false) {
  574. $_template_dir .= DS;
  575. }
  576. $_filepath = $_template_dir . $file;
  577. if (file_exists($_filepath))
  578. return $_filepath;
  579. }
  580. if (file_exists($file)) return $file;
  581. // no tpl file found
  582. if (!empty($this->smarty->default_template_handler_func)) {
  583. if (!is_callable($this->smarty->default_template_handler_func)) {
  584. throw new SmartyException("Default template handler not callable");
  585. } else {
  586. $_return = call_user_func_array($this->smarty->default_template_handler_func,
  587. array($this->resource_type, $this->resource_name, &$this->template_source, &$this->template_timestamp, $this));
  588. if (is_string($_return)) {
  589. return $_return;
  590. } elseif ($_return === true) {
  591. return $file;
  592. }
  593. }
  594. }
  595. return false;
  596. }
  597. /**
  598. * Update Smarty variables in other scopes
  599. */
  600. public function updateParentVariables ($scope = Smarty::SCOPE_LOCAL)
  601. {
  602. $has_root = false;
  603. foreach ($this->tpl_vars as $_key => $_variable) {
  604. $_variable_scope = $this->tpl_vars[$_key]->scope;
  605. if ($scope == Smarty::SCOPE_LOCAL && $_variable_scope == Smarty::SCOPE_LOCAL) {
  606. continue;
  607. }
  608. if (isset($this->parent) && ($scope == Smarty::SCOPE_PARENT || $_variable_scope == Smarty::SCOPE_PARENT)) {
  609. if (isset($this->parent->tpl_vars[$_key])) {
  610. // variable is already defined in parent, copy value
  611. $this->parent->tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
  612. } else {
  613. // create variable in parent
  614. $this->parent->tpl_vars[$_key] = clone $_variable;
  615. $this->parent->tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
  616. }
  617. }
  618. if ($scope == Smarty::SCOPE_ROOT || $_variable_scope == Smarty::SCOPE_ROOT) {
  619. if ($this->parent == null) {
  620. continue;
  621. }
  622. if (!$has_root) {
  623. // find root
  624. $root_ptr = $this;
  625. while ($root_ptr->parent != null) {
  626. $root_ptr = $root_ptr->parent;
  627. $has_root = true;
  628. }
  629. }
  630. if (isset($root_ptr->tpl_vars[$_key])) {
  631. // variable is already defined in root, copy value
  632. $root_ptr->tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
  633. } else {
  634. // create variable in root
  635. $root_ptr->tpl_vars[$_key] = clone $_variable;
  636. $root_ptr->tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
  637. }
  638. }
  639. if ($scope == Smarty::SCOPE_GLOBAL || $_variable_scope == Smarty::SCOPE_GLOBAL) {
  640. if (isset(Smarty::$global_tpl_vars[$_key])) {
  641. // variable is already defined in root, copy value
  642. Smarty::$global_tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
  643. } else {
  644. // create global variable
  645. Smarty::$global_tpl_vars[$_key] = clone $_variable;
  646. }
  647. Smarty::$global_tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
  648. }
  649. }
  650. }
  651. /**
  652. * Split a template resource in its name and type
  653. *
  654. * @param string $template_resource template resource specification
  655. * @param string $resource_type return resource type
  656. * @param string $resource_name return resource name
  657. */
  658. protected function getResourceTypeName ($template_resource, &$resource_type, &$resource_name)
  659. {
  660. if (strpos($template_resource, ':') === false) {
  661. // no resource given, use default
  662. $resource_type = $this->smarty->default_resource_type;
  663. $resource_name = $template_resource;
  664. } else {
  665. // get type and name from path
  666. list($resource_type, $resource_name) = explode(':', $template_resource, 2);
  667. if (strlen($resource_type) == 1) {
  668. // 1 char is not resource type, but part of filepath
  669. $resource_type = 'file';
  670. $resource_name = $template_resource;
  671. }
  672. }
  673. }
  674. /**
  675. * Load template resource handler by type
  676. *
  677. * @param string $resource_type template resource type
  678. * @return object resource handler object
  679. */
  680. protected function loadTemplateResourceHandler ($resource_type)
  681. {
  682. // try registered resource
  683. if (isset($this->smarty->registered_resources[$resource_type])) {
  684. return new Smarty_Internal_Resource_Registered($this);
  685. } else {
  686. // try sysplugins dir
  687. if (in_array($resource_type, array('file', 'string', 'extends', 'php', 'stream', 'eval'))) {
  688. $_resource_class = 'Smarty_Internal_Resource_' . ucfirst($resource_type);
  689. return new $_resource_class($this->smarty);
  690. } else {
  691. // try plugins dir
  692. $_resource_class = 'Smarty_Resource_' . ucfirst($resource_type);
  693. if ($this->smarty->loadPlugin($_resource_class)) {
  694. if (class_exists($_resource_class, false)) {
  695. return new $_resource_class($this->smarty);
  696. } else {
  697. return new Smarty_Internal_Resource_Registered($this, $resource_type);
  698. }
  699. } else {
  700. // try streams
  701. $_known_stream = stream_get_wrappers();
  702. if (in_array($resource_type, $_known_stream)) {
  703. // is known stream
  704. if (is_object($this->smarty->security_policy)) {
  705. $this->smarty->security_policy->isTrustedStream($resource_type);
  706. }
  707. return new Smarty_Internal_Resource_Stream($this->smarty);
  708. } else {
  709. throw new SmartyException('Unkown resource type \'' . $resource_type . '\'');
  710. }
  711. }
  712. }
  713. }
  714. }
  715. /**
  716. * Create property header
  717. */
  718. public function createPropertyHeader ($cache = false)
  719. {
  720. $plugins_string = '';
  721. // include code for plugins
  722. if (!$cache) {
  723. if (!empty($this->required_plugins['compiled'])) {
  724. $plugins_string = '<?php ';
  725. foreach($this->required_plugins['compiled'] as $tmp) {
  726. foreach($tmp as $data) {
  727. $plugins_string .= "if (!is_callable('{$data['function']}')) include '{$data['file']}';\n";
  728. }
  729. }
  730. $plugins_string .= '?>';
  731. }
  732. if (!empty($this->required_plugins['nocache'])) {
  733. $this->has_nocache_code = true;
  734. $plugins_string .= "<?php echo '/*%%SmartyNocache:{$this->properties['nocache_hash']}%%*/<?php ";
  735. foreach($this->required_plugins['nocache'] as $tmp) {
  736. foreach($tmp as $data) {
  737. $plugins_string .= "if (!is_callable(\'{$data['function']}\')) include \'{$data['file']}\';\n";
  738. }
  739. }
  740. $plugins_string .= "?>/*/%%SmartyNocache:{$this->properties['nocache_hash']}%%*/';?>\n";
  741. }
  742. }
  743. // build property code
  744. $this->properties['has_nocache_code'] = $this->has_nocache_code;
  745. $properties_string = "<?php /*%%SmartyHeaderCode:{$this->properties['nocache_hash']}%%*/" ;
  746. if ($this->smarty->direct_access_security) {
  747. $properties_string .= "if(!defined('SMARTY_DIR')) exit('no direct access allowed');\n";
  748. }
  749. if ($cache) {
  750. // remove compiled code of{function} definition
  751. unset($this->properties['function']);
  752. if (!empty($this->smarty->template_functions)) {
  753. // copy code of {function} tags called in nocache mode
  754. foreach ($this->smarty->template_functions as $name => $function_data) {
  755. if (isset($function_data['called_nocache'])) {
  756. unset($function_data['called_nocache'], $this->smarty->template_functions[$name]['called_nocache']);
  757. $this->properties['function'][$name] = $function_data;
  758. }
  759. }
  760. }
  761. }
  762. $properties_string .= "\$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . "); /*/%%SmartyHeaderCode%%*/?>\n";
  763. return $properties_string . $plugins_string;
  764. }
  765. /**
  766. * Decode saved properties from compiled template and cache files
  767. */
  768. public function decodeProperties ($properties)
  769. {
  770. $this->has_nocache_code = $properties['has_nocache_code'];
  771. $this->properties['nocache_hash'] = $properties['nocache_hash'];
  772. if (isset($properties['cache_lifetime'])) {
  773. $this->properties['cache_lifetime'] = $properties['cache_lifetime'];
  774. }
  775. if (isset($properties['file_dependency'])) {
  776. $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']);
  777. }
  778. if (!empty($properties['function'])) {
  779. $this->properties['function'] = array_merge($this->properties['function'], $properties['function']);
  780. $this->smarty->template_functions = array_merge($this->smarty->template_functions, $properties['function']);
  781. }
  782. }
  783. /**
  784. * creates a loacal Smarty variable for array assignments
  785. */
  786. public function createLocalArrayVariable($tpl_var, $nocache = false, $scope = Smarty::SCOPE_LOCAL)
  787. {
  788. if (!isset($this->tpl_vars[$tpl_var])) {
  789. $tpl_var_inst = $this->getVariable($tpl_var, null, true, false);
  790. if ($tpl_var_inst instanceof Undefined_Smarty_Variable) {
  791. $this->tpl_vars[$tpl_var] = new Smarty_variable(array(), $nocache, $scope);
  792. } else {
  793. $this->tpl_vars[$tpl_var] = clone $tpl_var_inst;
  794. if ($scope != Smarty::SCOPE_LOCAL) {
  795. $this->tpl_vars[$tpl_var]->scope = $scope;
  796. }
  797. }
  798. }
  799. if (!(is_array($this->tpl_vars[$tpl_var]->value) || $this->tpl_vars[$tpl_var]->value instanceof ArrayAccess)) {
  800. settype($this->tpl_vars[$tpl_var]->value, 'array');
  801. }
  802. }
  803. /**
  804. * [util function] counts an array, arrayaccess/traversable or PDOStatement object
  805. * @param mixed $value
  806. * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0 for empty elements
  807. */
  808. public function _count($value)
  809. {
  810. if (is_array($value) === true || $value instanceof Countable) {
  811. return count($value);
  812. } elseif ($value instanceof ArrayAccess) {
  813. if ($value->offsetExists(0)) {
  814. return 1;
  815. }
  816. } elseif ($value instanceof Iterator) {
  817. $value->rewind();
  818. if ($value->valid()) {
  819. return 1;
  820. }
  821. } elseif ($value instanceof PDOStatement) {
  822. return $value->rowCount();
  823. } elseif ($value instanceof Traversable) {
  824. return iterator_count($value);
  825. } elseif ($value instanceof ArrayAccess) {
  826. if ($value->offsetExists(0)) {
  827. return 1;
  828. }
  829. } elseif (is_object($value)) {
  830. return count($value);
  831. }
  832. return 0;
  833. }
  834. /**
  835. * wrapper for fetch
  836. */
  837. public function fetch ($template = null, $cache_id = null, $compile_id = null, $parent = null, $display = false)
  838. {
  839. if ($template == null) {
  840. return $this->smarty->fetch($this);
  841. } else {
  842. if (!isset($parent)) {
  843. $parent = $this;
  844. }
  845. return $this->smarty->fetch($template, $cache_id, $compile_id, $parent, $display);
  846. }
  847. }
  848. /**
  849. * wrapper for display
  850. */
  851. public function display ($template = null, $cache_id = null, $compile_id = null, $parent = null)
  852. {
  853. if ($template == null) {
  854. return $this->smarty->display($this);
  855. } else {
  856. if (!isset($parent)) {
  857. $parent = $this;
  858. }
  859. return $this->smarty->display($template, $cache_id, $compile_id, $parent);
  860. }
  861. }
  862. /**
  863. * set Smarty property in template context
  864. * @param string $property_name property name
  865. * @param mixed $value value
  866. */
  867. public function __set($property_name, $value)
  868. {
  869. if ($property_name == 'resource_object' || $property_name == 'cache_resource_object') {
  870. $this->$property_name = $value;
  871. } elseif (property_exists($this->smarty, $property_name)) {
  872. $this->smarty->$property_name = $value;
  873. } else {
  874. throw new SmartyException("invalid template property '$property_name'.");
  875. }
  876. }
  877. /**
  878. * get Smarty property in template context
  879. * @param string $property_name property name
  880. */
  881. public function __get($property_name)
  882. {
  883. if ($property_name == 'resource_object') {
  884. // load template resource
  885. $this->resource_object = null;
  886. if (!$this->parseResourceName ($this->template_resource, $this->resource_type, $this->resource_name, $this->resource_object)) {
  887. throw new SmartyException ("Unable to parse resource name \"{$template_resource}\"");
  888. }
  889. return $this->resource_object;
  890. }
  891. if ($property_name == 'cache_resource_object') {
  892. // load cache resource
  893. $this->cache_resource_object = $this->loadCacheResource();
  894. return $this->cache_resource_object;
  895. }
  896. if (property_exists($this->smarty, $property_name)) {
  897. return $this->smarty->$property_name;
  898. } else {
  899. throw new SmartyException("template property '$property_name' does not exist.");
  900. }
  901. }
  902. /**
  903. * Takes unknown class methods and lazy loads sysplugin files for them
  904. * class name format: Smarty_Method_MethodName
  905. * plugin filename format: method.methodname.php
  906. *
  907. * @param string $name unknown methode name
  908. * @param array $args aurgument array
  909. */
  910. public function __call($name, $args)
  911. {
  912. static $camel_func;
  913. if (!isset($camel_func))
  914. $camel_func = create_function('$c', 'return "_" . strtolower($c[1]);');
  915. // see if this is a set/get for a property
  916. $first3 = strtolower(substr($name, 0, 3));
  917. if (in_array($first3, array('set', 'get')) && substr($name, 3, 1) !== '_') {
  918. // try to keep case correct for future PHP 6.0 case-sensitive class methods
  919. // lcfirst() not available < PHP 5.3.0, so improvise
  920. $property_name = strtolower(substr($name, 3, 1)) . substr($name, 4);
  921. // convert camel case to underscored name
  922. $property_name = preg_replace_callback('/([A-Z])/', $camel_func, $property_name);
  923. if (property_exists($this, $property_name)) {
  924. if ($first3 == 'get')
  925. return $this->$property_name;
  926. else
  927. return $this->$property_name = $args[0];
  928. }
  929. }
  930. // pass call to Smarty object
  931. return call_user_func_array(array($this->smarty,$name),$args);
  932. }
  933. }
  934. ?>