]> git.mxchange.org Git - friendica.git/blob - library/Smarty/libs/sysplugins/smarty_resource.php
Add Smarty to Composer
[friendica.git] / library / Smarty / libs / sysplugins / smarty_resource.php
1 <?php
2 /**
3  * Smarty Resource Plugin
4  *
5  * @package    Smarty
6  * @subpackage TemplateResources
7  * @author     Rodney Rehm
8  */
9
10 /**
11  * Smarty Resource Plugin
12  * Base implementation for resource plugins
13  *
14  * @package    Smarty
15  * @subpackage TemplateResources
16  */
17 abstract class Smarty_Resource
18 {
19     /**
20      * cache for Smarty_Template_Source instances
21      *
22      * @var array
23      */
24     public static $sources = array();
25     /**
26      * cache for Smarty_Template_Compiled instances
27      *
28      * @var array
29      */
30     public static $compileds = array();
31     /**
32      * cache for Smarty_Resource instances
33      *
34      * @var array
35      */
36     public static $resources = array();
37     /**
38      * resource types provided by the core
39      *
40      * @var array
41      */
42     protected static $sysplugins = array(
43         'file'    => true,
44         'string'  => true,
45         'extends' => true,
46         'stream'  => true,
47         'eval'    => true,
48         'php'     => true
49     );
50
51     /**
52      * Name of the Class to compile this resource's contents with
53      *
54      * @var string
55      */
56     public $compiler_class = 'Smarty_Internal_SmartyTemplateCompiler';
57
58     /**
59      * Name of the Class to tokenize this resource's contents with
60      *
61      * @var string
62      */
63     public $template_lexer_class = 'Smarty_Internal_Templatelexer';
64
65     /**
66      * Name of the Class to parse this resource's contents with
67      *
68      * @var string
69      */
70     public $template_parser_class = 'Smarty_Internal_Templateparser';
71
72     /**
73      * Load template's source into current template object
74      * {@internal The loaded source is assigned to $_template->source->content directly.}}
75      *
76      * @param  Smarty_Template_Source $source source object
77      *
78      * @return string                 template source
79      * @throws SmartyException        if source cannot be loaded
80      */
81     abstract public function getContent(Smarty_Template_Source $source);
82
83     /**
84      * populate Source Object with meta data from Resource
85      *
86      * @param Smarty_Template_Source   $source    source object
87      * @param Smarty_Internal_Template $_template template object
88      */
89     abstract public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null);
90
91     /**
92      * populate Source Object with timestamp and exists from Resource
93      *
94      * @param Smarty_Template_Source $source source object
95      */
96     public function populateTimestamp(Smarty_Template_Source $source)
97     {
98         // intentionally left blank
99     }
100
101     /**
102      * modify resource_name according to resource handlers specifications
103      *
104      * @param  Smarty  $smarty        Smarty instance
105      * @param  string  $resource_name resource_name to make unique
106      * @param  boolean $is_config     flag for config resource
107      *
108      * @return string unique resource name
109      */
110     protected function buildUniqueResourceName(Smarty $smarty, $resource_name, $is_config = false)
111     {
112         if ($is_config) {
113             return get_class($this) . '#' . $smarty->joined_config_dir . '#' . $resource_name;
114         } else {
115             return get_class($this) . '#' . $smarty->joined_template_dir . '#' . $resource_name;
116         }
117     }
118
119     /**
120      * populate Compiled Object with compiled filepath
121      *
122      * @param Smarty_Template_Compiled $compiled  compiled object
123      * @param Smarty_Internal_Template $_template template object
124      */
125     public function populateCompiledFilepath(Smarty_Template_Compiled $compiled, Smarty_Internal_Template $_template)
126     {
127         $_compile_id = isset($_template->compile_id) ? preg_replace('![^\w\|]+!', '_', $_template->compile_id) : null;
128         $_filepath = $compiled->source->uid;
129         // if use_sub_dirs, break file into directories
130         if ($_template->smarty->use_sub_dirs) {
131             $_filepath = substr($_filepath, 0, 2) . DS
132                 . substr($_filepath, 2, 2) . DS
133                 . substr($_filepath, 4, 2) . DS
134                 . $_filepath;
135         }
136         $_compile_dir_sep = $_template->smarty->use_sub_dirs ? DS : '^';
137         if (isset($_compile_id)) {
138             $_filepath = $_compile_id . $_compile_dir_sep . $_filepath;
139         }
140         // caching token
141         if ($_template->caching) {
142             $_cache = '.cache';
143         } else {
144             $_cache = '';
145         }
146         $_compile_dir = $_template->smarty->getCompileDir();
147         // set basename if not specified
148         $_basename = $this->getBasename($compiled->source);
149         if ($_basename === null) {
150             $_basename = basename(preg_replace('![^\w\/]+!', '_', $compiled->source->name));
151         }
152         // separate (optional) basename by dot
153         if ($_basename) {
154             $_basename = '.' . $_basename;
155         }
156
157         $compiled->filepath = $_compile_dir . $_filepath . '.' . $compiled->source->type . $_basename . $_cache . '.php';
158     }
159
160     /**
161      * Normalize Paths "foo/../bar" to "bar"
162      *
163      * @param  string  $_path path to normalize
164      * @param  boolean $ds    respect windows directory separator
165      *
166      * @return string  normalized path
167      */
168     protected function normalizePath($_path, $ds = true)
169     {
170         if ($ds) {
171             // don't we all just love windows?
172             $_path = str_replace('\\', '/', $_path);
173         }
174
175         $offset = 0;
176
177         // resolve simples
178         $_path = preg_replace('#/\./(\./)*#', '/', $_path);
179         // resolve parents
180         while (true) {
181             $_parent = strpos($_path, '/../', $offset);
182             if (!$_parent) {
183                 break;
184             } elseif ($_path[$_parent - 1] === '.') {
185                 $offset = $_parent + 3;
186                 continue;
187             }
188
189             $_pos = strrpos($_path, '/', $_parent - strlen($_path) - 1);
190             if ($_pos === false) {
191                 // don't we all just love windows?
192                 $_pos = $_parent;
193             }
194
195             $_path = substr_replace($_path, '', $_pos, $_parent + 3 - $_pos);
196         }
197
198         if ($ds && DS != '/') {
199             // don't we all just love windows?
200             $_path = str_replace('/', '\\', $_path);
201         }
202
203         return $_path;
204     }
205
206     /**
207      * build template filepath by traversing the template_dir array
208      *
209      * @param  Smarty_Template_Source   $source    source object
210      * @param  Smarty_Internal_Template $_template template object
211      *
212      * @return string                   fully qualified filepath
213      * @throws SmartyException          if default template handler is registered but not callable
214      */
215     protected function buildFilepath(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null)
216     {
217         $file = $source->name;
218         if ($source instanceof Smarty_Config_Source) {
219             $_directories = $source->smarty->getConfigDir();
220             $_default_handler = $source->smarty->default_config_handler_func;
221         } else {
222             $_directories = $source->smarty->getTemplateDir();
223             $_default_handler = $source->smarty->default_template_handler_func;
224         }
225
226         // go relative to a given template?
227         $_file_is_dotted = $file[0] == '.' && ($file[1] == '.' || $file[1] == '/' || $file[1] == "\\");
228         if ($_template && $_template->parent instanceof Smarty_Internal_Template && $_file_is_dotted) {
229             if ($_template->parent->source->type != 'file' && $_template->parent->source->type != 'extends' && !$_template->parent->allow_relative_path) {
230                 throw new SmartyException("Template '{$file}' cannot be relative to template of resource type '{$_template->parent->source->type}'");
231             }
232             $file = dirname($_template->parent->source->filepath) . DS . $file;
233             $_file_exact_match = true;
234             if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) {
235                 // the path gained from the parent template is relative to the current working directory
236                 // as expansions (like include_path) have already been done
237                 $file = getcwd() . DS . $file;
238             }
239         }
240
241         // resolve relative path
242         if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) {
243             // don't we all just love windows?
244             $_path = DS . trim($file, '/');
245             $_was_relative = true;
246         } else {
247             // don't we all just love windows?
248             $_path = str_replace('\\', '/', $file);
249         }
250         $_path = $this->normalizePath($_path, false);
251         if (DS != '/') {
252             // don't we all just love windows?
253             $_path = str_replace('/', '\\', $_path);
254         }
255         // revert to relative
256         if (isset($_was_relative)) {
257             $_path = substr($_path, 1);
258         }
259
260         // this is only required for directories
261         $file = rtrim($_path, '/\\');
262
263         // files relative to a template only get one shot
264         if (isset($_file_exact_match)) {
265             return $this->fileExists($source, $file) ? $file : false;
266         }
267
268         // template_dir index?
269         if (preg_match('#^\[(?P<key>[^\]]+)\](?P<file>.+)$#', $file, $match)) {
270             $_directory = null;
271             // try string indexes
272             if (isset($_directories[$match['key']])) {
273                 $_directory = $_directories[$match['key']];
274             } elseif (is_numeric($match['key'])) {
275                 // try numeric index
276                 $match['key'] = (int) $match['key'];
277                 if (isset($_directories[$match['key']])) {
278                     $_directory = $_directories[$match['key']];
279                 } else {
280                     // try at location index
281                     $keys = array_keys($_directories);
282                     $_directory = $_directories[$keys[$match['key']]];
283                 }
284             }
285
286             if ($_directory) {
287                 $_file = substr($file, strpos($file, ']') + 1);
288                 $_filepath = $_directory . $_file;
289                 if ($this->fileExists($source, $_filepath)) {
290                     return $_filepath;
291                 }
292             }
293         }
294
295         $_stream_resolve_include_path = function_exists('stream_resolve_include_path');
296
297         // relative file name?
298         if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) {
299             foreach ($_directories as $_directory) {
300                 $_filepath = $_directory . $file;
301                 if ($this->fileExists($source, $_filepath)) {
302                     return $this->normalizePath($_filepath);
303                 }
304                 if ($source->smarty->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_directory)) {
305                     // try PHP include_path
306                     if ($_stream_resolve_include_path) {
307                         $_filepath = stream_resolve_include_path($_filepath);
308                     } else {
309                         $_filepath = Smarty_Internal_Get_Include_Path::getIncludePath($_filepath);
310                     }
311
312                     if ($_filepath !== false) {
313                         if ($this->fileExists($source, $_filepath)) {
314                             return $this->normalizePath($_filepath);
315                         }
316                     }
317                 }
318             }
319         }
320
321         // try absolute filepath
322         if ($this->fileExists($source, $file)) {
323             return $file;
324         }
325
326         // no tpl file found
327         if ($_default_handler) {
328             if (!is_callable($_default_handler)) {
329                 if ($source instanceof Smarty_Config_Source) {
330                     throw new SmartyException("Default config handler not callable");
331                 } else {
332                     throw new SmartyException("Default template handler not callable");
333                 }
334             }
335             $_return = call_user_func_array($_default_handler,
336                                             array($source->type, $source->name, &$_content, &$_timestamp, $source->smarty));
337             if (is_string($_return)) {
338                 $source->timestamp = @filemtime($_return);
339                 $source->exists = !!$source->timestamp;
340
341                 return $_return;
342             } elseif ($_return === true) {
343                 $source->content = $_content;
344                 $source->timestamp = $_timestamp;
345                 $source->exists = true;
346
347                 return $_filepath;
348             }
349         }
350
351         // give up
352         return false;
353     }
354
355     /**
356      * test is file exists and save timestamp
357      *
358      * @param  Smarty_Template_Source $source source object
359      * @param  string                 $file   file name
360      *
361      * @return bool                   true if file exists
362      */
363     protected function fileExists(Smarty_Template_Source $source, $file)
364     {
365         $source->timestamp = is_file($file) ? @filemtime($file) : false;
366
367         return $source->exists = !!$source->timestamp;
368     }
369
370     /**
371      * Determine basename for compiled filename
372      *
373      * @param  Smarty_Template_Source $source source object
374      *
375      * @return string                 resource's basename
376      */
377     protected function getBasename(Smarty_Template_Source $source)
378     {
379         return null;
380     }
381
382     /**
383      * Load Resource Handler
384      *
385      * @param  Smarty $smarty smarty object
386      * @param  string $type   name of the resource
387      *
388      * @throws SmartyException
389      * @return Smarty_Resource Resource Handler
390      */
391     public static function load(Smarty $smarty, $type)
392     {
393         // try smarty's cache
394         if (isset($smarty->_resource_handlers[$type])) {
395             return $smarty->_resource_handlers[$type];
396         }
397
398         // try registered resource
399         if (isset($smarty->registered_resources[$type])) {
400             if ($smarty->registered_resources[$type] instanceof Smarty_Resource) {
401                 $smarty->_resource_handlers[$type] = $smarty->registered_resources[$type];
402                 // note registered to smarty is not kept unique!
403                 return $smarty->_resource_handlers[$type];
404             }
405
406             if (!isset(self::$resources['registered'])) {
407                 self::$resources['registered'] = new Smarty_Internal_Resource_Registered();
408             }
409             if (!isset($smarty->_resource_handlers[$type])) {
410                 $smarty->_resource_handlers[$type] = self::$resources['registered'];
411             }
412
413             return $smarty->_resource_handlers[$type];
414         }
415
416         // try sysplugins dir
417         if (isset(self::$sysplugins[$type])) {
418             if (!isset(self::$resources[$type])) {
419                 $_resource_class = 'Smarty_Internal_Resource_' . ucfirst($type);
420                 self::$resources[$type] = new $_resource_class();
421             }
422
423             return $smarty->_resource_handlers[$type] = self::$resources[$type];
424         }
425
426         // try plugins dir
427         $_resource_class = 'Smarty_Resource_' . ucfirst($type);
428         if ($smarty->loadPlugin($_resource_class)) {
429             if (isset(self::$resources[$type])) {
430                 return $smarty->_resource_handlers[$type] = self::$resources[$type];
431             }
432
433             if (class_exists($_resource_class, false)) {
434                 self::$resources[$type] = new $_resource_class();
435
436                 return $smarty->_resource_handlers[$type] = self::$resources[$type];
437             } else {
438                 $smarty->registerResource($type, array(
439                     "smarty_resource_{$type}_source",
440                     "smarty_resource_{$type}_timestamp",
441                     "smarty_resource_{$type}_secure",
442                     "smarty_resource_{$type}_trusted"
443                 ));
444
445                 // give it another try, now that the resource is registered properly
446                 return self::load($smarty, $type);
447             }
448         }
449
450         // try streams
451         $_known_stream = stream_get_wrappers();
452         if (in_array($type, $_known_stream)) {
453             // is known stream
454             if (is_object($smarty->security_policy)) {
455                 $smarty->security_policy->isTrustedStream($type);
456             }
457             if (!isset(self::$resources['stream'])) {
458                 self::$resources['stream'] = new Smarty_Internal_Resource_Stream();
459             }
460
461             return $smarty->_resource_handlers[$type] = self::$resources['stream'];
462         }
463
464         // TODO: try default_(template|config)_handler
465
466         // give up
467         throw new SmartyException("Unknown resource type '{$type}'");
468     }
469
470     /**
471      * extract resource_type and resource_name from template_resource and config_resource
472      * @note "C:/foo.tpl" was forced to file resource up till Smarty 3.1.3 (including).
473      *
474      * @param  string $resource_name    template_resource or config_resource to parse
475      * @param  string $default_resource the default resource_type defined in $smarty
476      * @param  string &$name            the parsed resource name
477      * @param  string &$type            the parsed resource type
478      *
479      * @return void
480      */
481     protected static function parseResourceName($resource_name, $default_resource, &$name, &$type)
482     {
483         $parts = explode(':', $resource_name, 2);
484         if (!isset($parts[1]) || !isset($parts[0][1])) {
485             // no resource given, use default
486             // or single character before the colon is not a resource type, but part of the filepath
487             $type = $default_resource;
488             $name = $resource_name;
489         } else {
490             $type = $parts[0];
491             $name = $parts[1];
492         }
493     }
494
495     /**
496      * modify resource_name according to resource handlers specifications
497      *
498      * @param  Smarty $smarty        Smarty instance
499      * @param  string $resource_name resource_name to make unique
500      *
501      * @return string unique resource name
502      */
503
504     /**
505      * modify template_resource according to resource handlers specifications
506      *
507      * @param  Smarty_Internal_template $template          Smarty instance
508      * @param  string                   $template_resource template_resource to extract resource handler and name of
509      *
510      * @return string unique resource name
511      */
512     public static function getUniqueTemplateName($template, $template_resource)
513     {
514         self::parseResourceName($template_resource, $template->smarty->default_resource_type, $name, $type);
515         // TODO: optimize for Smarty's internal resource types
516         $resource = Smarty_Resource::load($template->smarty, $type);
517         // go relative to a given template?
518         $_file_is_dotted = $name[0] == '.' && ($name[1] == '.' || $name[1] == '/' || $name[1] == "\\");
519         if ($template instanceof Smarty_Internal_Template && $_file_is_dotted && ($template->source->type == 'file' || $template->parent->source->type == 'extends')) {
520             $name = dirname($template->source->filepath) . DS . $name;
521         }
522         return $resource->buildUniqueResourceName($template->smarty, $name);
523     }
524
525     /**
526      * initialize Source Object for given resource
527      * Either [$_template] or [$smarty, $template_resource] must be specified
528      *
529      * @param  Smarty_Internal_Template $_template         template object
530      * @param  Smarty                   $smarty            smarty object
531      * @param  string                   $template_resource resource identifier
532      *
533      * @return Smarty_Template_Source   Source Object
534      */
535     public static function source(Smarty_Internal_Template $_template = null, Smarty $smarty = null, $template_resource = null)
536     {
537         if ($_template) {
538             $smarty = $_template->smarty;
539             $template_resource = $_template->template_resource;
540         }
541
542         // parse resource_name, load resource handler, identify unique resource name
543         self::parseResourceName($template_resource, $smarty->default_resource_type, $name, $type);
544         $resource = Smarty_Resource::load($smarty, $type);
545         // go relative to a given template?
546         $_file_is_dotted = isset($name[0]) && $name[0] == '.' && ($name[1] == '.' || $name[1] == '/' || $name[1] == "\\");
547         if ($_file_is_dotted && isset($_template) && $_template->parent instanceof Smarty_Internal_Template && ($_template->parent->source->type == 'file' || $_template->parent->source->type == 'extends')) {
548             $name2 = dirname($_template->parent->source->filepath) . DS . $name;
549         } else {
550             $name2 = $name;
551         }
552         $unique_resource_name = $resource->buildUniqueResourceName($smarty, $name2);
553
554         // check runtime cache
555         $_cache_key = 'template|' . $unique_resource_name;
556         if ($smarty->compile_id) {
557             $_cache_key .= '|' . $smarty->compile_id;
558         }
559         if (isset(self::$sources[$_cache_key])) {
560             return self::$sources[$_cache_key];
561         }
562
563         // create source
564         $source = new Smarty_Template_Source($resource, $smarty, $template_resource, $type, $name, $unique_resource_name);
565         $resource->populate($source, $_template);
566
567         // runtime cache
568         self::$sources[$_cache_key] = $source;
569
570         return $source;
571     }
572
573     /**
574      * initialize Config Source Object for given resource
575      *
576      * @param  Smarty_Internal_Config $_config config object
577      *
578      * @throws SmartyException
579      * @return Smarty_Config_Source   Source Object
580      */
581     public static function config(Smarty_Internal_Config $_config)
582     {
583         static $_incompatible_resources = array('eval' => true, 'string' => true, 'extends' => true, 'php' => true);
584         $config_resource = $_config->config_resource;
585         $smarty = $_config->smarty;
586
587         // parse resource_name
588         self::parseResourceName($config_resource, $smarty->default_config_type, $name, $type);
589
590         // make sure configs are not loaded via anything smarty can't handle
591         if (isset($_incompatible_resources[$type])) {
592             throw new SmartyException ("Unable to use resource '{$type}' for config");
593         }
594
595         // load resource handler, identify unique resource name
596         $resource = Smarty_Resource::load($smarty, $type);
597         $unique_resource_name = $resource->buildUniqueResourceName($smarty, $name, true);
598
599         // check runtime cache
600         $_cache_key = 'config|' . $unique_resource_name;
601         if (isset(self::$sources[$_cache_key])) {
602             return self::$sources[$_cache_key];
603         }
604
605         // create source
606         $source = new Smarty_Config_Source($resource, $smarty, $config_resource, $type, $name, $unique_resource_name);
607         $resource->populate($source, null);
608
609         // runtime cache
610         self::$sources[$_cache_key] = $source;
611
612         return $source;
613     }
614 }
615
616 /**
617  * Smarty Resource Data Object
618  * Meta Data Container for Template Files
619  *
620  * @package    Smarty
621  * @subpackage TemplateResources
622  * @author     Rodney Rehm
623  * @property integer $timestamp Source Timestamp
624  * @property boolean $exists    Source Existence
625  * @property boolean $template  Extended Template reference
626  * @property string  $content   Source Content
627  */
628 class Smarty_Template_Source
629 {
630     /**
631      * Name of the Class to compile this resource's contents with
632      *
633      * @var string
634      */
635     public $compiler_class = null;
636
637     /**
638      * Name of the Class to tokenize this resource's contents with
639      *
640      * @var string
641      */
642     public $template_lexer_class = null;
643
644     /**
645      * Name of the Class to parse this resource's contents with
646      *
647      * @var string
648      */
649     public $template_parser_class = null;
650
651     /**
652      * Unique Template ID
653      *
654      * @var string
655      */
656     public $uid = null;
657
658     /**
659      * Template Resource (Smarty_Internal_Template::$template_resource)
660      *
661      * @var string
662      */
663     public $resource = null;
664
665     /**
666      * Resource Type
667      *
668      * @var string
669      */
670     public $type = null;
671
672     /**
673      * Resource Name
674      *
675      * @var string
676      */
677     public $name = null;
678
679     /**
680      * Unique Resource Name
681      *
682      * @var string
683      */
684     public $unique_resource = null;
685
686     /**
687      * Source Filepath
688      *
689      * @var string
690      */
691     public $filepath = null;
692
693     /**
694      * Source is bypassing compiler
695      *
696      * @var boolean
697      */
698     public $uncompiled = null;
699
700     /**
701      * Source must be recompiled on every occasion
702      *
703      * @var boolean
704      */
705     public $recompiled = null;
706
707     /**
708      * The Components an extended template is made of
709      *
710      * @var array
711      */
712     public $components = null;
713
714     /**
715      * Resource Handler
716      *
717      * @var Smarty_Resource
718      */
719     public $handler = null;
720
721     /**
722      * Smarty instance
723      *
724      * @var Smarty
725      */
726     public $smarty = null;
727
728     /**
729      * create Source Object container
730      *
731      * @param Smarty_Resource $handler         Resource Handler this source object communicates with
732      * @param Smarty          $smarty          Smarty instance this source object belongs to
733      * @param string          $resource        full template_resource
734      * @param string          $type            type of resource
735      * @param string          $name            resource name
736      * @param string          $unique_resource unique resource name
737      */
738     public function __construct(Smarty_Resource $handler, Smarty $smarty, $resource, $type, $name, $unique_resource)
739     {
740         $this->handler = $handler; // Note: prone to circular references
741
742         $this->compiler_class = $handler->compiler_class;
743         $this->template_lexer_class = $handler->template_lexer_class;
744         $this->template_parser_class = $handler->template_parser_class;
745         $this->uncompiled = $this->handler instanceof Smarty_Resource_Uncompiled;
746         $this->recompiled = $this->handler instanceof Smarty_Resource_Recompiled;
747
748         $this->smarty = $smarty;
749         $this->resource = $resource;
750         $this->type = $type;
751         $this->name = $name;
752         $this->unique_resource = $unique_resource;
753     }
754
755     /**
756      * get a Compiled Object of this source
757      *
758      * @param  Smarty_Internal_Template|Smarty_Internal_Config $_template template object
759      *
760      * @return Smarty_Template_Compiled compiled object
761      */
762     public function getCompiled($_template)
763     {
764         // check runtime cache
765         $_cache_key = $this->unique_resource . '#' . $_template->compile_id;
766         if (isset(Smarty_Resource::$compileds[$_cache_key])) {
767             return Smarty_Resource::$compileds[$_cache_key];
768         }
769
770         $compiled = new Smarty_Template_Compiled($this);
771         $this->handler->populateCompiledFilepath($compiled, $_template);
772         $compiled->timestamp = @filemtime($compiled->filepath);
773         $compiled->exists = !!$compiled->timestamp;
774
775         // runtime cache
776         Smarty_Resource::$compileds[$_cache_key] = $compiled;
777
778         return $compiled;
779     }
780
781     /**
782      * render the uncompiled source
783      *
784      * @param Smarty_Internal_Template $_template template object
785      */
786     public function renderUncompiled(Smarty_Internal_Template $_template)
787     {
788         return $this->handler->renderUncompiled($this, $_template);
789     }
790
791     /**
792      * <<magic>> Generic Setter.
793      *
794      * @param  string $property_name valid: timestamp, exists, content, template
795      * @param  mixed  $value         new value (is not checked)
796      *
797      * @throws SmartyException if $property_name is not valid
798      */
799     public function __set($property_name, $value)
800     {
801         switch ($property_name) {
802             // regular attributes
803             case 'timestamp':
804             case 'exists':
805             case 'content':
806                 // required for extends: only
807             case 'template':
808                 $this->$property_name = $value;
809                 break;
810
811             default:
812                 throw new SmartyException("invalid source property '$property_name'.");
813         }
814     }
815
816     /**
817      * <<magic>> Generic getter.
818      *
819      * @param  string $property_name valid: timestamp, exists, content
820      *
821      * @return mixed
822      * @throws SmartyException if $property_name is not valid
823      */
824     public function __get($property_name)
825     {
826         switch ($property_name) {
827             case 'timestamp':
828             case 'exists':
829                 $this->handler->populateTimestamp($this);
830
831                 return $this->$property_name;
832
833             case 'content':
834                 return $this->content = $this->handler->getContent($this);
835
836             default:
837                 throw new SmartyException("source property '$property_name' does not exist.");
838         }
839     }
840 }
841
842 /**
843  * Smarty Resource Data Object
844  * Meta Data Container for Template Files
845  *
846  * @package    Smarty
847  * @subpackage TemplateResources
848  * @author     Rodney Rehm
849  * @property string $content compiled content
850  */
851 class Smarty_Template_Compiled
852 {
853     /**
854      * Compiled Filepath
855      *
856      * @var string
857      */
858     public $filepath = null;
859
860     /**
861      * Compiled Timestamp
862      *
863      * @var integer
864      */
865     public $timestamp = null;
866
867     /**
868      * Compiled Existence
869      *
870      * @var boolean
871      */
872     public $exists = false;
873
874     /**
875      * Compiled Content Loaded
876      *
877      * @var boolean
878      */
879     public $loaded = false;
880
881     /**
882      * Template was compiled
883      *
884      * @var boolean
885      */
886     public $isCompiled = false;
887
888     /**
889      * Source Object
890      *
891      * @var Smarty_Template_Source
892      */
893     public $source = null;
894
895     /**
896      * Metadata properties
897      * populated by Smarty_Internal_Template::decodeProperties()
898      *
899      * @var array
900      */
901     public $_properties = null;
902
903     /**
904      * create Compiled Object container
905      *
906      * @param Smarty_Template_Source $source source object this compiled object belongs to
907      */
908     public function __construct(Smarty_Template_Source $source)
909     {
910         $this->source = $source;
911     }
912 }