/smarty/sysplugins/smarty_internal_template.php

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