smarty_internal_template.php 38 KB

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