Code

fixed property
[gosa.git] / gosa-core / include / smarty / sysplugins / smarty_internal_template.php
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 ?>