/thirdparts/smarty/sysplugins/smarty_internal_template.php

https://github.com/laurentc/NApf · PHP · 1003 lines · 695 code · 39 blank · 269 comment · 229 complexity · 585bf3d6a8551eef01c614bb9e795f0e MD5 · raw file

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