/lib/smarty/sysplugins/smarty_internal_template.php

https://github.com/Alex8452/Kurogo-Mobile-Web-Doc-Translation · PHP · 998 lines · 692 code · 37 blank · 269 comment · 230 complexity · 55d603f9c3e8bab280119348672830c1 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. $this->compiler_object
  273. );
  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->rendered_content = null;
  366. return $this->isCached;
  367. }
  368. if (!empty($this->properties['file_dependency']) && $this->smarty->compile_check) {
  369. $resource_type = null;
  370. $resource_name = null;
  371. foreach ($this->properties['file_dependency'] as $_file_to_check) {
  372. If ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'extends' || $_file_to_check[2] == 'php') {
  373. $mtime = filemtime($_file_to_check[0]);
  374. } else {
  375. $this->getResourceTypeName($_file_to_check[0], $resource_type, $resource_name);
  376. $resource_handler = $this->loadTemplateResourceHandler($resource_type);
  377. $mtime = $resource_handler->getTemplateTimestampTypeName($resource_type, $resource_name);
  378. }
  379. // If ($mtime > $this->getCachedTimestamp()) {
  380. If ($mtime > $_file_to_check[1]) {
  381. $this->tpl_vars = array();
  382. $this->rendered_content = null;
  383. return $this->isCached;
  384. }
  385. }
  386. }
  387. $this->isCached = true;
  388. }
  389. }
  390. }
  391. return $this->isCached;
  392. }
  393. /**
  394. * Render the output using the compiled template or the PHP template source
  395. *
  396. * The rendering process is accomplished by just including the PHP files.
  397. * The only exceptions are evaluated templates (string template). Their code has
  398. * to be evaluated
  399. */
  400. public function renderTemplate ()
  401. {
  402. if ($this->resource_object->usesCompiler) {
  403. if ($this->mustCompile() && $this->compiled_template === null) {
  404. $this->compileTemplateSource();
  405. }
  406. if ($this->smarty->debugging) {
  407. Smarty_Internal_Debug::start_render($this);
  408. }
  409. $_smarty_tpl = $this;
  410. ob_start();
  411. if ($this->resource_object->isEvaluated) {
  412. eval("?>" . $this->compiled_template);
  413. } else {
  414. include($this->getCompiledFilepath ());
  415. // check file dependencies at compiled code
  416. if ($this->smarty->compile_check) {
  417. if (!empty($this->properties['file_dependency'])) {
  418. $this->mustCompile = false;
  419. $resource_type = null;
  420. $resource_name = null;
  421. foreach ($this->properties['file_dependency'] as $_file_to_check) {
  422. If ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'extends' || $_file_to_check[2] == 'php') {
  423. $mtime = filemtime($_file_to_check[0]);
  424. } else {
  425. $this->getResourceTypeName($_file_to_check[0], $resource_type, $resource_name);
  426. $resource_handler = $this->loadTemplateResourceHandler($resource_type);
  427. $mtime = $resource_handler->getTemplateTimestampTypeName($resource_type, $resource_name);
  428. }
  429. // If ($mtime != $_file_to_check[1]) {
  430. If ($mtime > $_file_to_check[1]) {
  431. $this->mustCompile = true;
  432. break;
  433. }
  434. }
  435. if ($this->mustCompile) {
  436. // recompile and render again
  437. ob_get_clean();
  438. $this->compileTemplateSource();
  439. ob_start();
  440. include($this->getCompiledFilepath ());
  441. }
  442. }
  443. }
  444. }
  445. } else {
  446. if (is_callable(array($this->resource_object, 'renderUncompiled'))) {
  447. if ($this->smarty->debugging) {
  448. Smarty_Internal_Debug::start_render($this);
  449. }
  450. ob_start();
  451. $this->resource_object->renderUncompiled($this);
  452. } else {
  453. throw new SmartyException("Resource '$this->resource_type' must have 'renderUncompiled' methode");
  454. }
  455. }
  456. $this->rendered_content = ob_get_clean();
  457. if (!$this->resource_object->isEvaluated && empty($this->properties['file_dependency'][$this->templateUid])) {
  458. $this->properties['file_dependency'][$this->templateUid] = array($this->getTemplateFilepath(), $this->getTemplateTimestamp(),$this->resource_type);
  459. }
  460. if ($this->parent instanceof Smarty_Internal_Template) {
  461. $this->parent->properties['file_dependency'] = array_merge($this->parent->properties['file_dependency'], $this->properties['file_dependency']);
  462. foreach($this->required_plugins as $code => $tmp1) {
  463. foreach($tmp1 as $name => $tmp) {
  464. foreach($tmp as $type => $data) {
  465. $this->parent->required_plugins[$code][$name][$type] = $data;
  466. }
  467. }
  468. }
  469. }
  470. if ($this->smarty->debugging) {
  471. Smarty_Internal_Debug::end_render($this);
  472. }
  473. // write to cache when nessecary
  474. if (!$this->resource_object->isEvaluated && ($this->caching == Smarty::CACHING_LIFETIME_SAVED || $this->caching == Smarty::CACHING_LIFETIME_CURRENT)) {
  475. if ($this->smarty->debugging) {
  476. Smarty_Internal_Debug::start_cache($this);
  477. }
  478. $this->properties['has_nocache_code'] = false;
  479. // get text between non-cached items
  480. $cache_split = preg_split("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content);
  481. // get non-cached items
  482. preg_match_all("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content, $cache_parts);
  483. $output = '';
  484. // loop over items, stitch back together
  485. foreach($cache_split as $curr_idx => $curr_split) {
  486. // escape PHP tags in template content
  487. $output .= preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php echo \'$1\'; ?>', $curr_split);
  488. if (isset($cache_parts[0][$curr_idx])) {
  489. $this->properties['has_nocache_code'] = true;
  490. // remove nocache tags from cache output
  491. $output .= preg_replace("!/\*/?%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!", '', $cache_parts[0][$curr_idx]);
  492. }
  493. }
  494. if (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output'])) {
  495. $output = Smarty_Internal_Filter_Handler::runFilter('output', $output, $this);
  496. }
  497. // rendering (must be done before writing cache file because of {function} nocache handling)
  498. $_smarty_tpl = $this;
  499. ob_start();
  500. eval("?>" . $output);
  501. $this->rendered_content = ob_get_clean();
  502. // write cache file content
  503. $this->writeCachedContent('<?php if (!$no_render) {?>'. $output. '<?php } ?>');
  504. if ($this->smarty->debugging) {
  505. Smarty_Internal_Debug::end_cache($this);
  506. }
  507. } else {
  508. // var_dump('renderTemplate', $this->has_nocache_code, $this->template_resource, $this->properties['nocache_hash'], $this->parent->properties['nocache_hash'], $this->rendered_content);
  509. if ($this->has_nocache_code && !empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) {
  510. // replace nocache_hash
  511. $this->rendered_content = preg_replace("/{$this->properties['nocache_hash']}/", $this->parent->properties['nocache_hash'], $this->rendered_content);
  512. $this->parent->has_nocache_code = $this->has_nocache_code;
  513. }
  514. }
  515. }
  516. /**
  517. * Returns the rendered HTML output
  518. *
  519. * If the cache is valid the cached content is used, otherwise
  520. * the output is rendered from the compiled template or PHP template source
  521. *
  522. * @return string rendered HTML output
  523. */
  524. public function getRenderedTemplate ()
  525. {
  526. // disable caching for evaluated code
  527. if ($this->resource_object->isEvaluated) {
  528. $this->caching = false;
  529. }
  530. // checks if template exists
  531. $this->isExisting(true);
  532. // read from cache or render
  533. if ($this->rendered_content === null) {
  534. if ($this->isCached) {
  535. if ($this->smarty->debugging) {
  536. Smarty_Internal_Debug::start_cache($this);
  537. }
  538. $this->rendered_content = $this->cache_resource_object->getCachedContents($this, false);
  539. if ($this->smarty->debugging) {
  540. Smarty_Internal_Debug::end_cache($this);
  541. }
  542. }
  543. if ($this->isCached === null) {
  544. $this->isCached(false);
  545. }
  546. if (!$this->isCached) {
  547. // render template (not loaded and not in cache)
  548. $this->renderTemplate();
  549. }
  550. }
  551. $this->updateParentVariables();
  552. $this->isCached = null;
  553. return $this->rendered_content;
  554. }
  555. /**
  556. * Parse a template resource in its name and type
  557. * Load required resource handler
  558. *
  559. * @param string $template_resource template resource specification
  560. * @param string $resource_type return resource type
  561. * @param string $resource_name return resource name
  562. * @param object $resource_handler return resource handler object
  563. */
  564. public function parseResourceName($template_resource, &$resource_type, &$resource_name, &$resource_handler)
  565. {
  566. if (empty($template_resource))
  567. return false;
  568. $this->getResourceTypeName($template_resource, $resource_type, $resource_name);
  569. $resource_handler = $this->loadTemplateResourceHandler($resource_type);
  570. // cache template object under a unique ID
  571. // do not cache eval resources
  572. if ($resource_type != 'eval') {
  573. $this->smarty->template_objects[sha1($this->template_resource . $this->cache_id . $this->compile_id)] = $this;
  574. }
  575. return true;
  576. }
  577. /**
  578. * get system filepath to template
  579. */
  580. public function buildTemplateFilepath ($file = null)
  581. {
  582. if ($file == null) {
  583. $file = $this->resource_name;
  584. }
  585. // relative file name?
  586. if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) {
  587. foreach((array)$this->smarty->template_dir as $_template_dir) {
  588. if (strpos('/\\', substr($_template_dir, -1)) === false) {
  589. $_template_dir .= DS;
  590. }
  591. $_filepath = $_template_dir . $file;
  592. if (file_exists($_filepath)) {
  593. return $_filepath;
  594. }
  595. if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_template_dir)) {
  596. // try PHP include_path
  597. if (($_filepath = Smarty_Internal_Get_Include_Path::getIncludePath($_filepath)) !== false) {
  598. return $_filepath;
  599. }
  600. }
  601. }
  602. }
  603. // try absolute filepath
  604. if (file_exists($file)) return $file;
  605. // no tpl file found
  606. if (!empty($this->smarty->default_template_handler_func)) {
  607. if (!is_callable($this->smarty->default_template_handler_func)) {
  608. throw new SmartyException("Default template handler not callable");
  609. } else {
  610. $_return = call_user_func_array($this->smarty->default_template_handler_func,
  611. array($this->resource_type, $this->resource_name, &$this->template_source, &$this->template_timestamp, $this));
  612. if (is_string($_return)) {
  613. return $_return;
  614. } elseif ($_return === true) {
  615. return $file;
  616. }
  617. }
  618. }
  619. return false;
  620. }
  621. /**
  622. * Update Smarty variables in other scopes
  623. */
  624. public function updateParentVariables ($scope = Smarty::SCOPE_LOCAL)
  625. {
  626. $has_root = false;
  627. foreach ($this->tpl_vars as $_key => $_variable) {
  628. $_variable_scope = $this->tpl_vars[$_key]->scope;
  629. if ($scope == Smarty::SCOPE_LOCAL && $_variable_scope == Smarty::SCOPE_LOCAL) {
  630. continue;
  631. }
  632. if (isset($this->parent) && ($scope == Smarty::SCOPE_PARENT || $_variable_scope == Smarty::SCOPE_PARENT)) {
  633. if (isset($this->parent->tpl_vars[$_key])) {
  634. // variable is already defined in parent, copy value
  635. $this->parent->tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
  636. } else {
  637. // create variable in parent
  638. $this->parent->tpl_vars[$_key] = clone $_variable;
  639. $this->parent->tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
  640. }
  641. }
  642. if ($scope == Smarty::SCOPE_ROOT || $_variable_scope == Smarty::SCOPE_ROOT) {
  643. if ($this->parent == null) {
  644. continue;
  645. }
  646. if (!$has_root) {
  647. // find root
  648. $root_ptr = $this;
  649. while ($root_ptr->parent != null) {
  650. $root_ptr = $root_ptr->parent;
  651. $has_root = true;
  652. }
  653. }
  654. if (isset($root_ptr->tpl_vars[$_key])) {
  655. // variable is already defined in root, copy value
  656. $root_ptr->tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
  657. } else {
  658. // create variable in root
  659. $root_ptr->tpl_vars[$_key] = clone $_variable;
  660. $root_ptr->tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
  661. }
  662. }
  663. if ($scope == Smarty::SCOPE_GLOBAL || $_variable_scope == Smarty::SCOPE_GLOBAL) {
  664. if (isset(Smarty::$global_tpl_vars[$_key])) {
  665. // variable is already defined in root, copy value
  666. Smarty::$global_tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
  667. } else {
  668. // create global variable
  669. Smarty::$global_tpl_vars[$_key] = clone $_variable;
  670. }
  671. Smarty::$global_tpl_vars[$_key]->scope = Smarty::SCOPE_LOCAL;
  672. }
  673. }
  674. }
  675. /**
  676. * Split a template resource in its name and type
  677. *
  678. * @param string $template_resource template resource specification
  679. * @param string $resource_type return resource type
  680. * @param string $resource_name return resource name
  681. */
  682. protected function getResourceTypeName ($template_resource, &$resource_type, &$resource_name)
  683. {
  684. if (strpos($template_resource, ':') === false) {
  685. // no resource given, use default
  686. $resource_type = $this->smarty->default_resource_type;
  687. $resource_name = $template_resource;
  688. } else {
  689. // get type and name from path
  690. list($resource_type, $resource_name) = explode(':', $template_resource, 2);
  691. if (strlen($resource_type) == 1) {
  692. // 1 char is not resource type, but part of filepath
  693. $resource_type = 'file';
  694. $resource_name = $template_resource;
  695. }
  696. }
  697. }
  698. /**
  699. * Load template resource handler by type
  700. *
  701. * @param string $resource_type template resource type
  702. * @return object resource handler object
  703. */
  704. protected function loadTemplateResourceHandler ($resource_type)
  705. {
  706. // try registered resource
  707. if (isset($this->smarty->registered_resources[$resource_type])) {
  708. return new Smarty_Internal_Resource_Registered($this);
  709. } else {
  710. // try sysplugins dir
  711. if (in_array($resource_type, array('file', 'string', 'extends', 'php', 'stream', 'eval'))) {
  712. $_resource_class = 'Smarty_Internal_Resource_' . ucfirst($resource_type);
  713. return new $_resource_class($this->smarty);
  714. } else {
  715. // try plugins dir
  716. $_resource_class = 'Smarty_Resource_' . ucfirst($resource_type);
  717. if ($this->smarty->loadPlugin($_resource_class)) {
  718. if (class_exists($_resource_class, false)) {
  719. return new $_resource_class($this->smarty);
  720. } else {
  721. return new Smarty_Internal_Resource_Registered($this, $resource_type);
  722. }
  723. } else {
  724. // try streams
  725. $_known_stream = stream_get_wrappers();
  726. if (in_array($resource_type, $_known_stream)) {
  727. // is known stream
  728. if (is_object($this->smarty->security_policy)) {
  729. $this->smarty->security_policy->isTrustedStream($resource_type);
  730. }
  731. return new Smarty_Internal_Resource_Stream($this->smarty);
  732. } else {
  733. throw new SmartyException('Unkown resource type \'' . $resource_type . '\'');
  734. }
  735. }
  736. }
  737. }
  738. }
  739. /**
  740. * Create property header
  741. */
  742. public function createPropertyHeader ($cache = false)
  743. {
  744. $plugins_string = '';
  745. // include code for plugins
  746. if (!$cache) {
  747. if (!empty($this->required_plugins['compiled'])) {
  748. $plugins_string = '<?php ';
  749. foreach($this->required_plugins['compiled'] as $tmp) {
  750. foreach($tmp as $data) {
  751. $plugins_string .= "if (!is_callable('{$data['function']}')) include '{$data['file']}';\n";
  752. }
  753. }
  754. $plugins_string .= '?>';
  755. }
  756. if (!empty($this->required_plugins['nocache'])) {
  757. $this->has_nocache_code = true;
  758. $plugins_string .= "<?php echo '/*%%SmartyNocache:{$this->properties['nocache_hash']}%%*/<?php ";
  759. foreach($this->required_plugins['nocache'] as $tmp) {
  760. foreach($tmp as $data) {
  761. $plugins_string .= "if (!is_callable(\'{$data['function']}\')) include \'{$data['file']}\';\n";
  762. }
  763. }
  764. $plugins_string .= "?>/*/%%SmartyNocache:{$this->properties['nocache_hash']}%%*/';?>\n";
  765. }
  766. }
  767. // build property code
  768. $this->properties['has_nocache_code'] = $this->has_nocache_code;
  769. $properties_string = "<?php /*%%SmartyHeaderCode:{$this->properties['nocache_hash']}%%*/" ;
  770. if ($this->smarty->direct_access_security) {
  771. $properties_string .= "if(!defined('SMARTY_DIR')) exit('no direct access allowed');\n";
  772. }
  773. if ($cache) {
  774. // remove compiled code of{function} definition
  775. unset($this->properties['function']);
  776. if (!empty($this->smarty->template_functions)) {
  777. // copy code of {function} tags called in nocache mode
  778. foreach ($this->smarty->template_functions as $name => $function_data) {
  779. if (isset($function_data['called_nocache'])) {
  780. unset($function_data['called_nocache'], $this->smarty->template_functions[$name]['called_nocache']);
  781. $this->properties['function'][$name] = $function_data;
  782. }
  783. }
  784. }
  785. }
  786. $properties_string .= "\$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . "); /*/%%SmartyHeaderCode%%*/?>\n";
  787. return $properties_string . $plugins_string;
  788. }
  789. /**
  790. * Decode saved properties from compiled template and cache files
  791. */
  792. public function decodeProperties ($properties)
  793. {
  794. $this->has_nocache_code = $properties['has_nocache_code'];
  795. $this->properties['nocache_hash'] = $properties['nocache_hash'];
  796. if (isset($properties['cache_lifetime'])) {
  797. $this->properties['cache_lifetime'] = $properties['cache_lifetime'];
  798. }
  799. if (isset($properties['file_dependency'])) {
  800. $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']);
  801. }
  802. if (!empty($properties['function'])) {
  803. $this->properties['function'] = array_merge($this->properties['function'], $properties['function']);
  804. $this->smarty->template_functions = array_merge($this->smarty->template_functions, $properties['function']);
  805. }
  806. }
  807. /**
  808. * creates a local Smarty variable for array assignments
  809. */
  810. public function createLocalArrayVariable($tpl_var, $nocache = false, $scope = Smarty::SCOPE_LOCAL)
  811. {
  812. if (!isset($this->tpl_vars[$tpl_var])) {
  813. $tpl_var_inst = $this->getVariable($tpl_var, null, true, false);
  814. if ($tpl_var_inst instanceof Undefined_Smarty_Variable) {
  815. $this->tpl_vars[$tpl_var] = new Smarty_variable(array(), $nocache, $scope);
  816. } else {
  817. $this->tpl_vars[$tpl_var] = clone $tpl_var_inst;
  818. if ($scope != Smarty::SCOPE_LOCAL) {
  819. $this->tpl_vars[$tpl_var]->scope = $scope;
  820. }
  821. }
  822. }
  823. if (!(is_array($this->tpl_vars[$tpl_var]->value) || $this->tpl_vars[$tpl_var]->value instanceof ArrayAccess)) {
  824. settype($this->tpl_vars[$tpl_var]->value, 'array');
  825. }
  826. }
  827. /**
  828. * [util function] counts an array, arrayaccess/traversable or PDOStatement object
  829. * @param mixed $value
  830. * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0 for empty elements
  831. */
  832. public function _count($value)
  833. {
  834. if (is_array($value) === true || $value instanceof Countable) {
  835. return count($value);
  836. } elseif ($value instanceof Iterator) {
  837. $value->rewind();
  838. if ($value->valid()) {
  839. return iterator_count($value);
  840. }
  841. } elseif ($value instanceof PDOStatement) {
  842. return $value->rowCount();
  843. } elseif ($value instanceof Traversable) {
  844. return iterator_count($value);
  845. } elseif ($value instanceof ArrayAccess) {
  846. if ($value->offsetExists(0)) {
  847. return 1;
  848. }
  849. } elseif (is_object($value)) {
  850. return count($value);
  851. }
  852. return 0;
  853. }
  854. /**
  855. * wrapper for fetch
  856. */
  857. public function fetch ($template = null, $cache_id = null, $compile_id = null, $parent = null, $display = false)
  858. {
  859. if ($template == null) {
  860. return $this->smarty->fetch($this);
  861. } else {
  862. if (!isset($parent)) {
  863. $parent = $this;
  864. }
  865. return $this->smarty->fetch($template, $cache_id, $compile_id, $parent, $display);
  866. }
  867. }
  868. /**
  869. * wrapper for display
  870. */
  871. public function display ($template = null, $cache_id = null, $compile_id = null, $parent = null)
  872. {
  873. if ($template == null) {
  874. return $this->smarty->display($this);
  875. } else {
  876. if (!isset($parent)) {
  877. $parent = $this;
  878. }
  879. return $this->smarty->display($template, $cache_id, $compile_id, $parent);
  880. }
  881. }
  882. /**
  883. * set Smarty property in template context
  884. * @param string $property_name property name
  885. * @param mixed $value value
  886. */
  887. public function __set($property_name, $value)
  888. {
  889. if ($property_name == 'resource_object' || $property_name == 'cache_resource_object') {
  890. $this->$property_name = $value;
  891. } elseif (property_exists($this->smarty, $property_name)) {
  892. $this->smarty->$property_name = $value;
  893. } else {
  894. throw new SmartyException("invalid template property '$property_name'.");
  895. }
  896. }
  897. /**
  898. * get Smarty property in template context
  899. * @param string $property_name property name
  900. */
  901. public function __get($property_name)
  902. {
  903. if ($property_name == 'resource_object') {
  904. // load template resource
  905. $this->resource_object = null;
  906. if (!$this->parseResourceName ($this->template_resource, $this->resource_type, $this->resource_name, $this->resource_object)) {
  907. throw new SmartyException ("Unable to parse resource name \"{$template_resource}\"");
  908. }
  909. return $this->resource_object;
  910. }
  911. if ($property_name == 'cache_resource_object') {
  912. // load cache resource
  913. $this->cache_resource_object = $this->loadCacheResource();
  914. return $this->cache_resource_object;
  915. }
  916. if (property_exists($this->smarty, $property_name)) {
  917. return $this->smarty->$property_name;
  918. } else {
  919. throw new SmartyException("template property '$property_name' does not exist.");
  920. }
  921. }
  922. /**
  923. * Takes unknown class methods and lazy loads sysplugin files for them
  924. * class name format: Smarty_Method_MethodName
  925. * plugin filename format: method.methodname.php
  926. *
  927. * @param string $name unknown methode name
  928. * @param array $args aurgument array
  929. */
  930. public function __call($name, $args)
  931. {
  932. static $camel_func;
  933. if (!isset($camel_func))
  934. $camel_func = create_function('$c', 'return "_" . strtolower($c[1]);');
  935. // see if this is a set/get for a property
  936. $first3 = strtolower(substr($name, 0, 3));
  937. if (in_array($first3, array('set', 'get')) && substr($name, 3, 1) !== '_') {
  938. // try to keep case correct for future PHP 6.0 case-sensitive class methods
  939. // lcfirst() not available < PHP 5.3.0, so improvise
  940. $property_name = strtolower(substr($name, 3, 1)) . substr($name, 4);
  941. // convert camel case to underscored name
  942. $property_name = preg_replace_callback('/([A-Z])/', $camel_func, $property_name);
  943. if (property_exists($this, $property_name)) {
  944. if ($first3 == 'get')
  945. return $this->$property_name;
  946. else
  947. return $this->$property_name = $args[0];
  948. }
  949. }
  950. // Smarty Backward Compatible wrapper
  951. if (strpos($name,'_') !== false) {
  952. if (!isset($this->wrapper)) {
  953. $this->wrapper = new Smarty_Internal_Wrapper($this);
  954. }
  955. return $this->wrapper->convert($name, $args);
  956. }
  957. // pass call to Smarty object
  958. return call_user_func_array(array($this->smarty,$name),$args);
  959. }
  960. }
  961. ?>