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