smarty_internal_template.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. <?php
  2. /**
  3. * Smarty Internal Plugin Template
  4. * This file contains the Smarty template engine
  5. *
  6. * @package Smarty
  7. * @subpackage Template
  8. * @author Uwe Tews
  9. */
  10. /**
  11. * Main class with template data structures and methods
  12. *
  13. * @package Smarty
  14. * @subpackage Template
  15. * @property Smarty_Template_Source $source
  16. * @property Smarty_Template_Compiled $compiled
  17. * @property Smarty_Template_Cached $cached
  18. */
  19. class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
  20. {
  21. /**
  22. * cache_id
  23. *
  24. * @var string
  25. */
  26. public $cache_id = null;
  27. /**
  28. * $compile_id
  29. * @var string
  30. */
  31. public $compile_id = null;
  32. /**
  33. * caching enabled
  34. *
  35. * @var boolean
  36. */
  37. public $caching = null;
  38. /**
  39. * cache lifetime in seconds
  40. *
  41. * @var integer
  42. */
  43. public $cache_lifetime = null;
  44. /**
  45. * Template resource
  46. *
  47. * @var string
  48. */
  49. public $template_resource = null;
  50. /**
  51. * flag if compiled template is invalid and must be (re)compiled
  52. *
  53. * @var bool
  54. */
  55. public $mustCompile = null;
  56. /**
  57. * flag if template does contain nocache code sections
  58. *
  59. * @var bool
  60. */
  61. public $has_nocache_code = false;
  62. /**
  63. * special compiled and cached template properties
  64. *
  65. * @var array
  66. */
  67. public $properties = array('file_dependency' => array(),
  68. 'nocache_hash' => '',
  69. 'function' => array());
  70. /**
  71. * required plugins
  72. *
  73. * @var array
  74. */
  75. public $required_plugins = array('compiled' => array(), 'nocache' => array());
  76. /**
  77. * Global smarty instance
  78. *
  79. * @var Smarty
  80. */
  81. public $smarty = null;
  82. /**
  83. * blocks for template inheritance
  84. *
  85. * @var array
  86. */
  87. public $block_data = array();
  88. /**
  89. * variable filters
  90. *
  91. * @var array
  92. */
  93. public $variable_filters = array();
  94. /**
  95. * optional log of tag/attributes
  96. *
  97. * @var array
  98. */
  99. public $used_tags = array();
  100. /**
  101. * internal flag to allow relative path in child template blocks
  102. *
  103. * @var bool
  104. */
  105. public $allow_relative_path = false;
  106. /**
  107. * internal capture runtime stack
  108. *
  109. * @var array
  110. */
  111. public $_capture_stack = array(0 => array());
  112. /**
  113. * Create template data object
  114. * Some of the global Smarty settings copied to template scope
  115. * It load the required template resources and cacher plugins
  116. *
  117. * @param string $template_resource template resource string
  118. * @param Smarty $smarty Smarty instance
  119. * @param Smarty_Internal_Template $_parent back pointer to parent object with variables or null
  120. * @param mixed $_cache_id cache id or null
  121. * @param mixed $_compile_id compile id or null
  122. * @param bool $_caching use caching?
  123. * @param int $_cache_lifetime cache life-time in seconds
  124. */
  125. public function __construct($template_resource, $smarty, $_parent = null, $_cache_id = null, $_compile_id = null, $_caching = null, $_cache_lifetime = null)
  126. {
  127. $this->smarty = & $smarty;
  128. // Smarty parameter
  129. $this->cache_id = $_cache_id === null ? $this->smarty->cache_id : $_cache_id;
  130. $this->compile_id = $_compile_id === null ? $this->smarty->compile_id : $_compile_id;
  131. $this->caching = $_caching === null ? $this->smarty->caching : $_caching;
  132. if ($this->caching === true) {
  133. $this->caching = Smarty::CACHING_LIFETIME_CURRENT;
  134. }
  135. $this->cache_lifetime = $_cache_lifetime === null ? $this->smarty->cache_lifetime : $_cache_lifetime;
  136. $this->parent = $_parent;
  137. // Template resource
  138. $this->template_resource = $template_resource;
  139. // copy block data of template inheritance
  140. if ($this->parent instanceof Smarty_Internal_Template) {
  141. $this->block_data = $this->parent->block_data;
  142. }
  143. }
  144. /**
  145. * Returns if the current template must be compiled by the Smarty compiler
  146. * It does compare the timestamps of template source and the compiled templates and checks the force compile configuration
  147. *
  148. * @throws SmartyException
  149. * @return boolean true if the template must be compiled
  150. */
  151. public function mustCompile()
  152. {
  153. if (!$this->source->exists) {
  154. if ($this->parent instanceof Smarty_Internal_Template) {
  155. $parent_resource = " in '$this->parent->template_resource}'";
  156. } else {
  157. $parent_resource = '';
  158. }
  159. throw new SmartyException("Unable to load template {$this->source->type} '{$this->source->name}'{$parent_resource}");
  160. }
  161. if ($this->mustCompile === null) {
  162. $this->mustCompile = (!$this->source->uncompiled && ($this->smarty->force_compile || $this->source->recompiled || $this->compiled->timestamp === false ||
  163. ($this->smarty->compile_check && $this->compiled->timestamp < $this->source->timestamp)));
  164. }
  165. return $this->mustCompile;
  166. }
  167. /**
  168. * Compiles the template
  169. * If the template is not evaluated the compiled template is saved on disk
  170. */
  171. public function compileTemplateSource()
  172. {
  173. if (!$this->source->recompiled) {
  174. $this->properties['file_dependency'] = array();
  175. if ($this->source->components) {
  176. // for the extends resource the compiler will fill it
  177. // uses real resource for file dependency
  178. // $source = end($this->source->components);
  179. // $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $source->type);
  180. } else {
  181. $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $this->source->type);
  182. }
  183. }
  184. // compile locking
  185. if ($this->smarty->compile_locking && !$this->source->recompiled) {
  186. if ($saved_timestamp = $this->compiled->timestamp) {
  187. touch($this->compiled->filepath);
  188. }
  189. }
  190. // call compiler
  191. try {
  192. $code = $this->compiler->compileTemplate($this);
  193. }
  194. catch (Exception $e) {
  195. // restore old timestamp in case of error
  196. if ($this->smarty->compile_locking && !$this->source->recompiled && $saved_timestamp) {
  197. touch($this->compiled->filepath, $saved_timestamp);
  198. }
  199. throw $e;
  200. }
  201. // compiling succeded
  202. if (!$this->source->recompiled && $this->compiler->write_compiled_code) {
  203. // write compiled template
  204. $_filepath = $this->compiled->filepath;
  205. if ($_filepath === false) {
  206. throw new SmartyException('getCompiledFilepath() did not return a destination to save the compiled template to');
  207. }
  208. Smarty_Internal_Write_File::writeFile($_filepath, $code, $this->smarty);
  209. $this->compiled->exists = true;
  210. $this->compiled->isCompiled = true;
  211. }
  212. // release compiler object to free memory
  213. unset($this->compiler);
  214. }
  215. /**
  216. * Writes the cached template output
  217. *
  218. * @param string $content
  219. *
  220. * @return bool
  221. */
  222. public function writeCachedContent($content)
  223. {
  224. if ($this->source->recompiled || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) {
  225. // don't write cache file
  226. return false;
  227. }
  228. $this->properties['cache_lifetime'] = $this->cache_lifetime;
  229. $this->properties['unifunc'] = 'content_' . str_replace(array('.', ','), '_', uniqid('', true));
  230. $content = $this->createTemplateCodeFrame($content, true);
  231. /** @var Smarty_Internal_Template $_smarty_tpl
  232. * used in evaluated code
  233. */
  234. $_smarty_tpl = $this;
  235. eval("?>" . $content);
  236. $this->cached->valid = true;
  237. $this->cached->processed = true;
  238. return $this->cached->write($this, $content);
  239. }
  240. /**
  241. * Template code runtime function to get subtemplate content
  242. *
  243. * @param string $template the resource handle of the template file
  244. * @param mixed $cache_id cache id to be used with this template
  245. * @param mixed $compile_id compile id to be used with this template
  246. * @param integer $caching cache mode
  247. * @param integer $cache_lifetime life time of cache data
  248. * @param $data
  249. * @param int $parent_scope scope in which {include} should execute
  250. *
  251. * @returns string template content
  252. */
  253. public function getSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope)
  254. {
  255. // already in template cache?
  256. if ($this->smarty->allow_ambiguous_resources) {
  257. $_templateId = Smarty_Resource::getUniqueTemplateName($this, $template) . $cache_id . $compile_id;
  258. } else {
  259. $_templateId = $this->smarty->joined_template_dir . '#' . $template . $cache_id . $compile_id;
  260. }
  261. if (isset($_templateId[150])) {
  262. $_templateId = sha1($_templateId);
  263. }
  264. if (isset($this->smarty->template_objects[$_templateId])) {
  265. // clone cached template object because of possible recursive call
  266. $tpl = clone $this->smarty->template_objects[$_templateId];
  267. $tpl->parent = $this;
  268. $tpl->caching = $caching;
  269. $tpl->cache_lifetime = $cache_lifetime;
  270. } else {
  271. $tpl = new $this->smarty->template_class($template, $this->smarty, $this, $cache_id, $compile_id, $caching, $cache_lifetime);
  272. }
  273. // get variables from calling scope
  274. if ($parent_scope == Smarty::SCOPE_LOCAL) {
  275. $tpl->tpl_vars = $this->tpl_vars;
  276. $tpl->tpl_vars['smarty'] = clone $this->tpl_vars['smarty'];
  277. } elseif ($parent_scope == Smarty::SCOPE_PARENT) {
  278. $tpl->tpl_vars = & $this->tpl_vars;
  279. } elseif ($parent_scope == Smarty::SCOPE_GLOBAL) {
  280. $tpl->tpl_vars = & Smarty::$global_tpl_vars;
  281. } elseif (($scope_ptr = $this->getScopePointer($parent_scope)) == null) {
  282. $tpl->tpl_vars = & $this->tpl_vars;
  283. } else {
  284. $tpl->tpl_vars = & $scope_ptr->tpl_vars;
  285. }
  286. $tpl->config_vars = $this->config_vars;
  287. if (!empty($data)) {
  288. // set up variable values
  289. foreach ($data as $_key => $_val) {
  290. $tpl->tpl_vars[$_key] = new Smarty_variable($_val);
  291. }
  292. }
  293. return $tpl->fetch(null, null, null, null, false, false, true);
  294. }
  295. /**
  296. * Template code runtime function to set up an inline subtemplate
  297. *
  298. * @param string $template the resource handle of the template file
  299. * @param mixed $cache_id cache id to be used with this template
  300. * @param mixed $compile_id compile id to be used with this template
  301. * @param integer $caching cache mode
  302. * @param integer $cache_lifetime life time of cache data
  303. * @param $data
  304. * @param int $parent_scope scope in which {include} should execute
  305. * @param string $hash nocache hash code
  306. *
  307. * @returns string template content
  308. */
  309. public function setupInlineSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope, $hash)
  310. {
  311. $tpl = new $this->smarty->template_class($template, $this->smarty, $this, $cache_id, $compile_id, $caching, $cache_lifetime);
  312. $tpl->properties['nocache_hash'] = $hash;
  313. // get variables from calling scope
  314. if ($parent_scope == Smarty::SCOPE_LOCAL) {
  315. $tpl->tpl_vars = $this->tpl_vars;
  316. $tpl->tpl_vars['smarty'] = clone $this->tpl_vars['smarty'];
  317. } elseif ($parent_scope == Smarty::SCOPE_PARENT) {
  318. $tpl->tpl_vars = & $this->tpl_vars;
  319. } elseif ($parent_scope == Smarty::SCOPE_GLOBAL) {
  320. $tpl->tpl_vars = & Smarty::$global_tpl_vars;
  321. } elseif (($scope_ptr = $this->getScopePointer($parent_scope)) == null) {
  322. $tpl->tpl_vars = & $this->tpl_vars;
  323. } else {
  324. $tpl->tpl_vars = & $scope_ptr->tpl_vars;
  325. }
  326. $tpl->config_vars = $this->config_vars;
  327. if (!empty($data)) {
  328. // set up variable values
  329. foreach ($data as $_key => $_val) {
  330. $tpl->tpl_vars[$_key] = new Smarty_variable($_val);
  331. }
  332. }
  333. return $tpl;
  334. }
  335. /**
  336. * Create code frame for compiled and cached templates
  337. *
  338. * @param string $content optional template content
  339. * @param bool $cache flag for cache file
  340. *
  341. * @return string
  342. */
  343. public function createTemplateCodeFrame($content = '', $cache = false)
  344. {
  345. $plugins_string = '';
  346. // include code for plugins
  347. if (!$cache) {
  348. if (!empty($this->required_plugins['compiled'])) {
  349. $plugins_string = '<?php ';
  350. foreach ($this->required_plugins['compiled'] as $tmp) {
  351. foreach ($tmp as $data) {
  352. $file = addslashes($data['file']);
  353. if (is_Array($data['function'])) {
  354. $plugins_string .= "if (!is_callable(array('{$data['function'][0]}','{$data['function'][1]}'))) include '{$file}';\n";
  355. } else {
  356. $plugins_string .= "if (!is_callable('{$data['function']}')) include '{$file}';\n";
  357. }
  358. }
  359. }
  360. $plugins_string .= '?>';
  361. }
  362. if (!empty($this->required_plugins['nocache'])) {
  363. $this->has_nocache_code = true;
  364. $plugins_string .= "<?php echo '/*%%SmartyNocache:{$this->properties['nocache_hash']}%%*/<?php \$_smarty = \$_smarty_tpl->smarty; ";
  365. foreach ($this->required_plugins['nocache'] as $tmp) {
  366. foreach ($tmp as $data) {
  367. $file = addslashes($data['file']);
  368. if (is_Array($data['function'])) {
  369. $plugins_string .= addslashes("if (!is_callable(array('{$data['function'][0]}','{$data['function'][1]}'))) include '{$file}';\n");
  370. } else {
  371. $plugins_string .= addslashes("if (!is_callable('{$data['function']}')) include '{$file}';\n");
  372. }
  373. }
  374. }
  375. $plugins_string .= "?>/*/%%SmartyNocache:{$this->properties['nocache_hash']}%%*/';?>\n";
  376. }
  377. }
  378. // build property code
  379. $this->properties['has_nocache_code'] = $this->has_nocache_code;
  380. $output = '';
  381. if (!$this->source->recompiled) {
  382. $output = "<?php /*%%SmartyHeaderCode:{$this->properties['nocache_hash']}%%*/";
  383. if ($this->smarty->direct_access_security) {
  384. $output .= "if(!defined('SMARTY_DIR')) exit('no direct access allowed');\n";
  385. }
  386. }
  387. if ($cache) {
  388. // remove compiled code of{function} definition
  389. unset($this->properties['function']);
  390. if (!empty($this->smarty->template_functions)) {
  391. // copy code of {function} tags called in nocache mode
  392. foreach ($this->smarty->template_functions as $name => $function_data) {
  393. if (isset($function_data['called_nocache'])) {
  394. foreach ($function_data['called_functions'] as $func_name) {
  395. $this->smarty->template_functions[$func_name]['called_nocache'] = true;
  396. }
  397. }
  398. }
  399. foreach ($this->smarty->template_functions as $name => $function_data) {
  400. if (isset($function_data['called_nocache'])) {
  401. unset($function_data['called_nocache'], $function_data['called_functions'], $this->smarty->template_functions[$name]['called_nocache']);
  402. $this->properties['function'][$name] = $function_data;
  403. }
  404. }
  405. }
  406. }
  407. $this->properties['version'] = Smarty::SMARTY_VERSION;
  408. if (!isset($this->properties['unifunc'])) {
  409. $this->properties['unifunc'] = 'content_' . str_replace(array('.', ','), '_', uniqid('', true));
  410. }
  411. if (!$this->source->recompiled) {
  412. $output .= "\$_valid = \$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . ',' . ($cache ? 'true' : 'false') . "); /*/%%SmartyHeaderCode%%*/?>\n";
  413. $output .= '<?php if ($_valid && !is_callable(\'' . $this->properties['unifunc'] . '\')) {function ' . $this->properties['unifunc'] . '($_smarty_tpl) {?>';
  414. }
  415. $output .= $plugins_string;
  416. $output .= $content;
  417. if (!$this->source->recompiled) {
  418. $output .= "<?php }} ?>\n";
  419. }
  420. return $output;
  421. }
  422. /**
  423. * This function is executed automatically when a compiled or cached template file is included
  424. * - Decode saved properties from compiled template and cache files
  425. * - Check if compiled or cache file is valid
  426. *
  427. * @param array $properties special template properties
  428. * @param bool $cache flag if called from cache file
  429. *
  430. * @return bool flag if compiled or cache file is valid
  431. */
  432. public function decodeProperties($properties, $cache = false)
  433. {
  434. $this->has_nocache_code = $properties['has_nocache_code'];
  435. $this->properties['nocache_hash'] = $properties['nocache_hash'];
  436. if (isset($properties['cache_lifetime'])) {
  437. $this->properties['cache_lifetime'] = $properties['cache_lifetime'];
  438. }
  439. if (isset($properties['file_dependency'])) {
  440. $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']);
  441. }
  442. if (!empty($properties['function'])) {
  443. $this->properties['function'] = array_merge($this->properties['function'], $properties['function']);
  444. $this->smarty->template_functions = array_merge($this->smarty->template_functions, $properties['function']);
  445. }
  446. $this->properties['version'] = (isset($properties['version'])) ? $properties['version'] : '';
  447. $this->properties['unifunc'] = $properties['unifunc'];
  448. // check file dependencies at compiled code
  449. $is_valid = true;
  450. if ($this->properties['version'] != Smarty::SMARTY_VERSION) {
  451. $is_valid = false;
  452. } elseif (((!$cache && $this->smarty->compile_check && empty($this->compiled->_properties) && !$this->compiled->isCompiled) || $cache && ($this->smarty->compile_check === true || $this->smarty->compile_check === Smarty::COMPILECHECK_ON)) && !empty($this->properties['file_dependency'])) {
  453. foreach ($this->properties['file_dependency'] as $_file_to_check) {
  454. if ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'php') {
  455. if ($this->source->filepath == $_file_to_check[0] && isset($this->source->timestamp)) {
  456. // do not recheck current template
  457. $mtime = $this->source->timestamp;
  458. } else {
  459. // file and php types can be checked without loading the respective resource handlers
  460. $mtime = @filemtime($_file_to_check[0]);
  461. }
  462. } elseif ($_file_to_check[2] == 'string') {
  463. continue;
  464. } else {
  465. $source = Smarty_Resource::source(null, $this->smarty, $_file_to_check[0]);
  466. $mtime = $source->timestamp;
  467. }
  468. if (!$mtime || $mtime > $_file_to_check[1]) {
  469. $is_valid = false;
  470. break;
  471. }
  472. }
  473. }
  474. if ($cache) {
  475. // CACHING_LIFETIME_SAVED cache expiry has to be validated here since otherwise we'd define the unifunc
  476. if ($this->caching === Smarty::CACHING_LIFETIME_SAVED &&
  477. $this->properties['cache_lifetime'] >= 0 &&
  478. (time() > ($this->cached->timestamp + $this->properties['cache_lifetime']))
  479. ) {
  480. $is_valid = false;
  481. }
  482. $this->cached->valid = $is_valid;
  483. } else {
  484. $this->mustCompile = !$is_valid;
  485. }
  486. // store data in reusable Smarty_Template_Compiled
  487. if (!$cache) {
  488. $this->compiled->_properties = $properties;
  489. }
  490. return $is_valid;
  491. }
  492. /**
  493. * Template code runtime function to create a local Smarty variable for array assignments
  494. *
  495. * @param string $tpl_var tempate variable name
  496. * @param bool $nocache cache mode of variable
  497. * @param int $scope scope of variable
  498. */
  499. public function createLocalArrayVariable($tpl_var, $nocache = false, $scope = Smarty::SCOPE_LOCAL)
  500. {
  501. if (!isset($this->tpl_vars[$tpl_var])) {
  502. $this->tpl_vars[$tpl_var] = new Smarty_variable(array(), $nocache, $scope);
  503. } else {
  504. $this->tpl_vars[$tpl_var] = clone $this->tpl_vars[$tpl_var];
  505. if ($scope != Smarty::SCOPE_LOCAL) {
  506. $this->tpl_vars[$tpl_var]->scope = $scope;
  507. }
  508. if (!(is_array($this->tpl_vars[$tpl_var]->value) || $this->tpl_vars[$tpl_var]->value instanceof ArrayAccess)) {
  509. settype($this->tpl_vars[$tpl_var]->value, 'array');
  510. }
  511. }
  512. }
  513. /**
  514. * Template code runtime function to get pointer to template variable array of requested scope
  515. *
  516. * @param int $scope requested variable scope
  517. *
  518. * @return array array of template variables
  519. */
  520. public function &getScope($scope)
  521. {
  522. if ($scope == Smarty::SCOPE_PARENT && !empty($this->parent)) {
  523. return $this->parent->tpl_vars;
  524. } elseif ($scope == Smarty::SCOPE_ROOT && !empty($this->parent)) {
  525. $ptr = $this->parent;
  526. while (!empty($ptr->parent)) {
  527. $ptr = $ptr->parent;
  528. }
  529. return $ptr->tpl_vars;
  530. } elseif ($scope == Smarty::SCOPE_GLOBAL) {
  531. return Smarty::$global_tpl_vars;
  532. }
  533. $null = null;
  534. return $null;
  535. }
  536. /**
  537. * Get parent or root of template parent chain
  538. *
  539. * @param int $scope pqrent or root scope
  540. *
  541. * @return mixed object
  542. */
  543. public function getScopePointer($scope)
  544. {
  545. if ($scope == Smarty::SCOPE_PARENT && !empty($this->parent)) {
  546. return $this->parent;
  547. } elseif ($scope == Smarty::SCOPE_ROOT && !empty($this->parent)) {
  548. $ptr = $this->parent;
  549. while (!empty($ptr->parent)) {
  550. $ptr = $ptr->parent;
  551. }
  552. return $ptr;
  553. }
  554. return null;
  555. }
  556. /**
  557. * [util function] counts an array, arrayaccess/traversable or PDOStatement object
  558. *
  559. * @param mixed $value
  560. *
  561. * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0 for empty elements
  562. */
  563. public function _count($value)
  564. {
  565. if (is_array($value) === true || $value instanceof Countable) {
  566. return count($value);
  567. } elseif ($value instanceof IteratorAggregate) {
  568. // Note: getIterator() returns a Traversable, not an Iterator
  569. // thus rewind() and valid() methods may not be present
  570. return iterator_count($value->getIterator());
  571. } elseif ($value instanceof Iterator) {
  572. return iterator_count($value);
  573. } elseif ($value instanceof PDOStatement) {
  574. return $value->rowCount();
  575. } elseif ($value instanceof Traversable) {
  576. return iterator_count($value);
  577. } elseif ($value instanceof ArrayAccess) {
  578. if ($value->offsetExists(0)) {
  579. return 1;
  580. }
  581. } elseif (is_object($value)) {
  582. return count($value);
  583. }
  584. return 0;
  585. }
  586. /**
  587. * runtime error not matching capture tags
  588. */
  589. public function capture_error()
  590. {
  591. throw new SmartyException("Not matching {capture} open/close in \"{$this->template_resource}\"");
  592. }
  593. /**
  594. * Empty cache for this template
  595. *
  596. * @param integer $exp_time expiration time
  597. *
  598. * @return integer number of cache files deleted
  599. */
  600. public function clearCache($exp_time = null)
  601. {
  602. Smarty_CacheResource::invalidLoadedCache($this->smarty);
  603. return $this->cached->handler->clear($this->smarty, $this->template_name, $this->cache_id, $this->compile_id, $exp_time);
  604. }
  605. /**
  606. * set Smarty property in template context
  607. *
  608. * @param string $property_name property name
  609. * @param mixed $value value
  610. *
  611. * @throws SmartyException
  612. */
  613. public function __set($property_name, $value)
  614. {
  615. switch ($property_name) {
  616. case 'source':
  617. case 'compiled':
  618. case 'cached':
  619. case 'compiler':
  620. $this->$property_name = $value;
  621. return;
  622. // FIXME: routing of template -> smarty attributes
  623. default:
  624. if (property_exists($this->smarty, $property_name)) {
  625. $this->smarty->$property_name = $value;
  626. return;
  627. }
  628. }
  629. throw new SmartyException("invalid template property '$property_name'.");
  630. }
  631. /**
  632. * get Smarty property in template context
  633. *
  634. * @param string $property_name property name
  635. *
  636. * @throws SmartyException
  637. */
  638. public function __get($property_name)
  639. {
  640. switch ($property_name) {
  641. case 'source':
  642. if (strlen($this->template_resource) == 0) {
  643. throw new SmartyException('Missing template name');
  644. }
  645. $this->source = Smarty_Resource::source($this);
  646. // cache template object under a unique ID
  647. // do not cache eval resources
  648. if ($this->source->type != 'eval') {
  649. if ($this->smarty->allow_ambiguous_resources) {
  650. $_templateId = $this->source->unique_resource . $this->cache_id . $this->compile_id;
  651. } else {
  652. $_templateId = $this->smarty->joined_template_dir . '#' . $this->template_resource . $this->cache_id . $this->compile_id;
  653. }
  654. if (isset($_templateId[150])) {
  655. $_templateId = sha1($_templateId);
  656. }
  657. $this->smarty->template_objects[$_templateId] = $this;
  658. }
  659. return $this->source;
  660. case 'compiled':
  661. $this->compiled = $this->source->getCompiled($this);
  662. return $this->compiled;
  663. case 'cached':
  664. if (!class_exists('Smarty_Template_Cached')) {
  665. include SMARTY_SYSPLUGINS_DIR . 'smarty_cacheresource.php';
  666. }
  667. $this->cached = new Smarty_Template_Cached($this);
  668. return $this->cached;
  669. case 'compiler':
  670. $this->smarty->loadPlugin($this->source->compiler_class);
  671. $this->compiler = new $this->source->compiler_class($this->source->template_lexer_class, $this->source->template_parser_class, $this->smarty);
  672. return $this->compiler;
  673. // FIXME: routing of template -> smarty attributes
  674. default:
  675. if (property_exists($this->smarty, $property_name)) {
  676. return $this->smarty->$property_name;
  677. }
  678. }
  679. throw new SmartyException("template property '$property_name' does not exist.");
  680. }
  681. /**
  682. * Template data object destructor
  683. */
  684. public function __destruct()
  685. {
  686. if ($this->smarty->cache_locking && isset($this->cached) && $this->cached->is_locked) {
  687. $this->cached->handler->releaseLock($this->smarty, $this->cached);
  688. }
  689. }
  690. }