Code

Updated smarty
[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     // storage for block data
69     public $block_data = array(); 
70     // required plugins
71     public $required_plugins = array('compiled' => array(), 'nocache' => array());
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         // call compiler
259         if ($this->compiler_object->compileTemplate($this)) {
260             // compiling succeded
261             if (!$this->resource_object->isEvaluated) {
262                 // write compiled template
263                 Smarty_Internal_Write_File::writeFile($this->getCompiledFilepath(), $this->compiled_template, $this->smarty);
264             } 
265         } else {
266             // error compiling template
267             throw new Exception("Error compiling template {$this->getTemplateFilepath ()}");
268             return false;
269         } 
270         if ($this->smarty->debugging) {
271             Smarty_Internal_Debug::end_compile($this);
272         } 
273     } 
275     /**
276     * Returns the filepath of the cached template output
277     * 
278     * The filepath is determined by the actual cache resource
279     * 
280     * @return string the cache filepath
281     */
282     public function getCachedFilepath ()
283     {
284         return $this->cached_filepath === null ?
285         $this->cached_filepath = ($this->resource_object->isEvaluated || !($this->caching == SMARTY_CACHING_LIFETIME_CURRENT || $this->caching == SMARTY_CACHING_LIFETIME_SAVED)) ? false : $this->cache_resource_object->getCachedFilepath($this) :
286         $this->cached_filepath;
287     } 
289     /**
290     * Returns the timpestamp of the cached template output
291     * 
292     * The timestamp is determined by the actual cache resource
293     * 
294     * @return integer the template timestamp
295     */
296     public function getCachedTimestamp ()
297     {
298         return $this->cached_timestamp === null ?
299         $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) :
300         $this->cached_timestamp;
301     } 
303     /**
304     * Returns the cached template output
305     * 
306     * @return string |booelan the template content or false if the file does not exist
307     */
308     public function getCachedContent ()
309     {
310         return $this->rendered_content === null ?
311         $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) :
312         $this->rendered_content;
313     } 
315     /**
316     * Writes the cached template output
317     */
318     public function writeCachedContent ($content)
319     {
320         if ($this->resource_object->isEvaluated || !($this->caching == SMARTY_CACHING_LIFETIME_CURRENT || $this->caching == SMARTY_CACHING_LIFETIME_SAVED)) {
321             // don't write cache file
322             return false;
323         } 
324         $this->properties['cache_lifetime'] = $this->cache_lifetime;
325         return $this->cache_resource_object->writeCachedContent($this, $this->createPropertyHeader(true) . $content);
326     } 
328     /**
329     * Checks of a valid version redered HTML output is in the cache
330     * 
331     * If the cache is valid the contents is stored in the template object
332     * 
333     * @return boolean true if cache is valid
334     */
335     public function isCached ()
336     {
337         if ($this->isCached === null) {
338             $this->isCached = false;
339             if (($this->caching == SMARTY_CACHING_LIFETIME_CURRENT || $this->caching == SMARTY_CACHING_LIFETIME_SAVED) && !$this->resource_object->isEvaluated) {
340                 if (!isset($this->cache_resource_object)) {
341                     $this->cache_resource_object = $this->smarty->loadCacheResource();
342                 } 
343                 $cachedTimestamp = $this->getCachedTimestamp();
344                 if ($cachedTimestamp === false || $this->force_compile || $this->force_cache) {
345                     return $this->isCached;
346                 } 
347                 if ($this->caching === SMARTY_CACHING_LIFETIME_SAVED || ($this->caching == SMARTY_CACHING_LIFETIME_CURRENT && (time() <= ($cachedTimestamp + $this->cache_lifetime) || $this->cache_lifetime < 0))) {
348                     if ($this->smarty->debugging) {
349                         Smarty_Internal_Debug::start_cache($this);
350                     } 
351                     $this->rendered_content = $this->cache_resource_object->getCachedContents($this);
352                     if ($this->smarty->debugging) {
353                         Smarty_Internal_Debug::end_cache($this);
354                     } 
355                     if ($this->cacheFileChecked) {
356                         $this->isCached = true;
357                         return $this->isCached;
358                     } 
359                     $this->cacheFileChecked = true;
360                     if ($this->caching === SMARTY_CACHING_LIFETIME_SAVED && $this->properties['cache_lifetime'] > 0 && (time() > ($this->getCachedTimestamp() + $this->properties['cache_lifetime']))) {
361                         $this->rendered_content = null;
362                         return $this->isCached;
363                     } 
364                     if (!empty($this->properties['file_dependency']) && $this->smarty->compile_check) {
365                         foreach ($this->properties['file_dependency'] as $_file_to_check) {
366                             $this->getResourceTypeName($_file_to_check[0], $resource_type, $resource_name);
367                             If ($resource_type == 'file') {
368                                 $mtime = filemtime($_file_to_check[0]);
369                             } else {
370                                 $resource_handler = $this->loadTemplateResourceHandler($resource_type);
371                                 $mtime = $resource_handler->getTemplateTimestampTypeName($resource_type, $resource_name);
372                             } 
373                             // If ($mtime > $this->getCachedTimestamp()) {
374                             If ($mtime > $_file_to_check[1]) {
375                                 $this->rendered_content = null;
376                                 return $this->isCached;
377                             } 
378                         } 
379                     } 
380                     $this->isCached = true;
381                 } 
382             } 
383         } 
384         return $this->isCached;
385     } 
387     /**
388     * Render the output using the compiled template or the PHP template source
389     * 
390     * The rendering process is accomplished by just including the PHP files.
391     * The only exceptions are evaluated templates (string template). Their code has 
392     * to be evaluated
393     */
394     public function renderTemplate ()
395     {
396         if ($this->resource_object->usesCompiler) {
397             if ($this->mustCompile() && $this->compiled_template === null) {
398                 $this->compileTemplateSource();
399             } 
400             if ($this->smarty->debugging) {
401                 Smarty_Internal_Debug::start_render($this);
402             } 
403             $_smarty_tpl = $this;
404             ob_start();
405             if ($this->resource_object->isEvaluated) {
406                 eval("?>" . $this->compiled_template);
407             } else {
408                 include($this->getCompiledFilepath ()); 
409                 // check file dependencies at compiled code
410                 if ($this->smarty->compile_check) {
411                     if (!empty($this->properties['file_dependency'])) {
412                         $this->mustCompile = false;
413                         foreach ($this->properties['file_dependency'] as $_file_to_check) {
414                             $this->getResourceTypeName($_file_to_check[0], $resource_type, $resource_name);
415                             If ($resource_type == 'file') {
416                                 $mtime = filemtime($_file_to_check[0]);
417                             } else {
418                                 $resource_handler = $this->loadTemplateResourceHandler($resource_type);
419                                 $mtime = $resource_handler->getTemplateTimestampTypeName($resource_type, $resource_name);
420                             } 
421                             // If ($mtime != $_file_to_check[1]) {
422                             If ($mtime > $_file_to_check[1]) {
423                                 $this->mustCompile = true;
424                                 break;
425                             } 
426                         } 
427                         if ($this->mustCompile) {
428                             // recompile and render again
429                             ob_get_clean();
430                             $this->compileTemplateSource();
431                             ob_start();
432                             include($this->getCompiledFilepath ());
433                         } 
434                     } 
435                 } 
436             } 
437         } else {
438             if (is_callable(array($this->resource_object, 'renderUncompiled'))) {
439                 if ($this->smarty->debugging) {
440                     Smarty_Internal_Debug::start_render($this);
441                 } 
442                 ob_start();
443                 $this->resource_object->renderUncompiled($this);
444             } else {
445                 throw new Exception("Resource '$this->resource_type' must have 'renderUncompiled' methode");
446             } 
447         } 
448         $this->rendered_content = ob_get_clean();
449         if (!$this->resource_object->isEvaluated && empty($this->properties['file_dependency'][$this->templateUid])) {
450             $this->properties['file_dependency'][$this->templateUid] = array($this->getTemplateFilepath(), $this->getTemplateTimestamp());
451         } 
452         if ($this->parent instanceof Smarty_Template or $this->parent instanceof Smarty_Internal_Template) {
453             $this->parent->properties['file_dependency'] = array_merge($this->parent->properties['file_dependency'], $this->properties['file_dependency']);
454             foreach($this->required_plugins as $code => $tmp1) {
455                 foreach($tmp1 as $name => $tmp) {
456                     foreach($tmp as $type => $data) {
457                         $this->parent->required_plugins[$code][$name][$type] = $data;
458                     } 
459                 } 
460             } 
461         } 
462         if ($this->smarty->debugging) {
463             Smarty_Internal_Debug::end_render($this);
464         } 
465         // write to cache when nessecary
466         if (!$this->resource_object->isEvaluated && ($this->caching == SMARTY_CACHING_LIFETIME_SAVED || $this->caching == SMARTY_CACHING_LIFETIME_CURRENT)) {
467             if ($this->smarty->debugging) {
468                 Smarty_Internal_Debug::start_cache($this);
469             } 
470             $this->properties['has_nocache_code'] = false; 
471             // get text between non-cached items
472             $cache_split = preg_split("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content); 
473             // get non-cached items
474             preg_match_all("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content, $cache_parts);
475             $output = ''; 
476             // loop over items, stitch back together
477             foreach($cache_split as $curr_idx => $curr_split) {
478                 // escape PHP tags in template content
479                 $output .= preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php echo \'$1\'; ?>', $curr_split);
480                 if (isset($cache_parts[0][$curr_idx])) {
481                     $this->properties['has_nocache_code'] = true; 
482                     // remove nocache tags from cache output
483                     $output .= preg_replace("!/\*/?%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!", '', $cache_parts[0][$curr_idx]);
484                 } 
485             } 
486             // rendering (must be done before writing cache file because of {function} nocache handling)
487             $_smarty_tpl = $this;
488             ob_start();
489             eval("?>" . $output);
490             $this->rendered_content = ob_get_clean(); 
491             // write cache file content
492             $this->writeCachedContent($output);
493             if ($this->smarty->debugging) {
494                 Smarty_Internal_Debug::end_cache($this);
495             } 
496         } else {
497             // var_dump('renderTemplate', $this->has_nocache_code, $this->template_resource, $this->properties['nocache_hash'], $this->parent->properties['nocache_hash'], $this->rendered_content);
498             if ($this->has_nocache_code && !empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) {
499                 // replace nocache_hash
500                 $this->rendered_content = preg_replace("/{$this->properties['nocache_hash']}/", $this->parent->properties['nocache_hash'], $this->rendered_content);
501                 $this->parent->has_nocache_code = $this->has_nocache_code;
502             } 
503         } 
504     } 
506     /**
507     * Returns the rendered HTML output 
508     * 
509     * If the cache is valid the cached content is used, otherwise
510     * the output is rendered from the compiled template or PHP template source
511     * 
512     * @return string rendered HTML output
513     */
514     public function getRenderedTemplate ()
515     { 
516         // disable caching for evaluated code
517         if ($this->resource_object->isEvaluated) {
518             $this->caching = false;
519         } 
520         // checks if template exists
521         $this->isExisting(true); 
522         // read from cache or render
523         if ($this->rendered_content === null && !$this->isCached()) {
524             // render template (not loaded and not in cache)
525             $this->renderTemplate();
526         } 
527         $this->updateParentVariables();
528         $this->isCached = null;
529         return $this->rendered_content;
530     } 
532     /**
533     * Parse a template resource in its name and type
534     * Load required resource handler
535     * 
536     * @param string $template_resource template resource specification
537     * @param string $resource_type return resource type
538     * @param string $resource_name return resource name
539     * @param object $resource_handler return resource handler object
540     */
541     public function parseResourceName($template_resource, &$resource_type, &$resource_name, &$resource_handler)
542     {
543         if (empty($template_resource))
544             return false;
545         $this->getResourceTypeName($template_resource, $resource_type, $resource_name);
546         $resource_handler = $this->loadTemplateResourceHandler($resource_type); 
547         // cache template object under a unique ID
548         // do not cache string resources
549         // *****        if ($resource_type != 'string' && $this->smarty->caching) {
550         if ($resource_type != 'string') {
551             $this->smarty->template_objects[crc32($this->template_resource . $this->cache_id . $this->compile_id)] = $this;
552         } 
553         return true;
554     } 
556     /**
557     * get system filepath to template
558     */
559     public function buildTemplateFilepath ($file = null)
560     {
561         if ($file == null) {
562             $file = $this->resource_name;
563         } 
564         foreach((array)$this->smarty->template_dir as $_template_dir) {
565             if (strpos('/\\', substr($_template_dir, -1)) === false) {
566                 $_template_dir .= DS;
567             } 
569             $_filepath = $_template_dir . $file;
570             if (file_exists($_filepath))
571                 return $_filepath;
572         } 
573         if (file_exists($file)) return $file; 
574         // no tpl file found
575         if (!empty($this->smarty->default_template_handler_func)) {
576             if (!is_callable($this->smarty->default_template_handler_func)) {
577                 throw new Exception("Default template handler not callable");
578             } else {
579                 $_return = call_user_func_array($this->smarty->default_template_handler_func,
580                     array($this->resource_type, $this->resource_name, &$this->template_source, &$this->template_timestamp, $this));
581                 if (is_string($_return)) {
582                     return $_return;
583                 } elseif ($_return === true) {
584                     return $file;
585                 } 
586             } 
587         } 
588         // throw new Exception("Unable to load template \"{$file}\"");
589         return false;
590     } 
592     /**
593     * Update Smarty variables in other scopes
594     */
595     public function updateParentVariables ($scope = SMARTY_LOCAL_SCOPE)
596     {
597         $has_root = false;
598         foreach ($this->tpl_vars as $_key => $_variable) {
599             $_variable_scope = $this->tpl_vars[$_key]->scope;
600             if ($scope == SMARTY_LOCAL_SCOPE && $_variable_scope == SMARTY_LOCAL_SCOPE) {
601                 continue;
602             } 
603             if (isset($this->parent) && ($scope == SMARTY_PARENT_SCOPE || $_variable_scope == SMARTY_PARENT_SCOPE)) {
604                 if (isset($this->parent->tpl_vars[$_key])) {
605                     // variable is already defined in parent, copy value
606                     $this->parent->tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
607                 } else {
608                     // create variable in parent
609                     $this->parent->tpl_vars[$_key] = clone $_variable;
610                     $this->parent->tpl_vars[$_key]->scope = SMARTY_LOCAL_SCOPE;
611                 } 
612             } 
613             if ($scope == SMARTY_ROOT_SCOPE || $_variable_scope == SMARTY_ROOT_SCOPE) {
614                 if ($this->parent == null) {
615                     continue;
616                 } 
617                 if (!$has_root) {
618                     // find  root
619                     $root_ptr = $this;
620                     while ($root_ptr->parent != null) {
621                         $root_ptr = $root_ptr->parent;
622                         $has_root = true;
623                     } 
624                 } 
625                 if (isset($root_ptr->tpl_vars[$_key])) {
626                     // variable is already defined in root, copy value
627                     $root_ptr->tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
628                 } else {
629                     // create variable in root
630                     $root_ptr->tpl_vars[$_key] = clone $_variable;
631                     $root_ptr->tpl_vars[$_key]->scope = SMARTY_LOCAL_SCOPE;
632                 } 
633             } 
634             if ($scope == SMARTY_GLOBAL_SCOPE || $_variable_scope == SMARTY_GLOBAL_SCOPE) {
635                 if (isset($this->smarty->global_tpl_vars[$_key])) {
636                     // variable is already defined in root, copy value
637                     $this->smarty->global_tpl_vars[$_key]->value = $this->tpl_vars[$_key]->value;
638                 } else {
639                     // create variable in root
640                     $this->smarty->global_tpl_vars[$_key] = clone $_variable;
641                 } 
642                 $this->smarty->global_tpl_vars[$_key]->scope = SMARTY_LOCAL_SCOPE;
643             } 
644         } 
645     } 
647     /**
648     * Split a template resource in its name and type
649     * 
650     * @param string $template_resource template resource specification
651     * @param string $resource_type return resource type
652     * @param string $resource_name return resource name
653     */
654     protected function getResourceTypeName ($template_resource, &$resource_type, &$resource_name)
655     {
656         if (strpos($template_resource, ':') === false) {
657             // no resource given, use default
658             $resource_type = $this->smarty->default_resource_type;
659             $resource_name = $template_resource;
660         } else {
661             // get type and name from path
662             list($resource_type, $resource_name) = explode(':', $template_resource, 2);
663             if (strlen($resource_type) == 1) {
664                 // 1 char is not resource type, but part of filepath
665                 $resource_type = 'file';
666                 $resource_name = $template_resource;
667             } else {
668                 $resource_type = $resource_type;
669             } 
670         } 
671     } 
673     /**
674     * Load template resource handler by type
675     * 
676     * @param string $resource_type template resource type
677     * @return object resource handler object
678     */
679     protected function loadTemplateResourceHandler ($resource_type)
680     { 
681         // try registered resource
682         if (isset($this->smarty->_plugins['resource'][$resource_type])) {
683             return new Smarty_Internal_Resource_Registered($this->smarty);
684         } else {
685             // try sysplugins dir
686             if (in_array($resource_type, array('file', 'string', 'extends', 'php', 'registered', 'stream'))) {
687                 $_resource_class = 'Smarty_Internal_Resource_' . $resource_type;
688                 return new $_resource_class($this->smarty);
689             } else {
690                 // try plugins dir
691                 $_resource_class = 'Smarty_Resource_' . $resource_type;
692                 if ($this->smarty->loadPlugin($_resource_class)) {
693                     if (class_exists($_resource_class, false)) {
694                         return new $_resource_class($this->smarty);
695                     } else {
696                         $this->smarty->register_resource($resource_type,
697                             array("smarty_resource_{$resource_type}_source",
698                                 "smarty_resource_{$resource_type}_timestamp",
699                                 "smarty_resource_{$resource_type}_secure",
700                                 "smarty_resource_{$resource_type}_trusted"));
701                         return new Smarty_Internal_Resource_Registered($this->smarty);
702                     } 
703                 } else {
704                     // try streams
705                     $_known_stream = stream_get_wrappers();
706                     if (in_array($resource_type, $_known_stream)) {
707                         // is known stream
708                         if ($this->smarty->security) {
709                             $this->smarty->security_handler->isTrustedStream($resource_type);
710                         } 
711                         return new Smarty_Internal_Resource_Stream($this->smarty);
712                     } else {
713                         throw new Exception('Unkown resource type \'' . $resource_type . '\'');
714                     } 
715                 } 
716             } 
717         } 
718     } 
720     /**
721     * Create property header
722     */
723     public function createPropertyHeader ($cache = false)
724     {
725         $plugins_string = ''; 
726         // include code for plugins
727         if (!$cache) {
728             if (!empty($this->required_plugins['compiled'])) {
729                 $plugins_string = '<?php ';
730                 foreach($this->required_plugins['compiled'] as $tmp) {
731                     foreach($tmp as $data) {
732                         $plugins_string .= "if (!is_callable('{$data['function']}')) include '{$data['file']}';\n";
733                     } 
734                 } 
735                 $plugins_string .= '?>';
736             } 
737             if (!empty($this->required_plugins['nocache'])) {
738                 $this->has_nocache_code = true;
739                 $plugins_string .= "<?php echo '/*%%SmartyNocache:{$this->properties['nocache_hash']}%%*/<?php ";
740                 foreach($this->required_plugins['nocache'] as $tmp) {
741                     foreach($tmp as $data) {
742                         $plugins_string .= "if (!is_callable(\'{$data['function']}\')) include \'{$data['file']}\';\n";
743                     } 
744                 } 
745                 $plugins_string .= "?>/*/%%SmartyNocache:{$this->properties['nocache_hash']}%%*/';?>\n";
746             } 
747         } 
748         // build property code
749         $this->properties['has_nocache_code'] = $this->has_nocache_code;
750         $properties_string = "<?php /*%%SmartyHeaderCode:{$this->properties['nocache_hash']}%%*/" ;
751         if ($this->smarty->direct_access_security) {
752             $properties_string .= "if(!defined('SMARTY_DIR')) exit('no direct access allowed');\n";
753         } 
754         if ($cache) {
755             // remove compiled code of{function} definition
756             unset($this->properties['function']);
757             if (!empty($this->smarty->template_functions)) {
758                 // copy code of {function} tags called in nocache mode
759                 foreach ($this->smarty->template_functions as $name => $function_data) {
760                     if (isset($function_data['called_nocache'])) {
761                         unset($function_data['called_nocache'], $this->smarty->template_functions[$name]['called_nocache']);
762                         $this->properties['function'][$name] = $function_data;
763                     } 
764                 } 
765             } 
766         } 
767         $properties_string .= "\$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . "); /*/%%SmartyHeaderCode%%*/?>\n";
768         return $properties_string . $plugins_string;
769     } 
771     /**
772     * Decode saved properties from compiled template and cache files
773     */
774     public function decodeProperties ($properties)
775     {
776         $this->has_nocache_code = $properties['has_nocache_code'];
777         $this->properties['nocache_hash'] = $properties['nocache_hash'];
778         if (isset($properties['cache_lifetime'])) {
779             $this->properties['cache_lifetime'] = $properties['cache_lifetime'];
780         } 
781         if (isset($properties['file_dependency'])) {
782             $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']);
783         } 
784         if (!empty($properties['function'])) {
785             $this->properties['function'] = array_merge($this->properties['function'], $properties['function']);
786             $this->smarty->template_functions = array_merge($this->smarty->template_functions, $properties['function']);
787         } 
788     } 
790     /**
791     * wrapper for display
792     */
793     public function display ()
794     {
795         return $this->smarty->display($this);
796     } 
798     /**
799     * wrapper for fetch
800     */
801     public function fetch ()
802     {
803         return $this->smarty->fetch($this);
804     } 
805
807 /**
808 * wrapper for template class
809 */
810 class Smarty_Template extends Smarty_Internal_Template {
811
813 ?>