1: <?php
  2:   3:   4:   5:   6:   7:   8: 
  9: 
 10:  11:  12:  13:  14:  15:  16: 
 17: abstract class Smarty_Resource
 18: {
 19:      20:  21:  22:  23: 
 24:     public static $sources = array();
 25:      26:  27:  28:  29: 
 30:     public static $compileds = array();
 31:      32:  33:  34:  35: 
 36:     public static $resources = array();
 37:      38:  39:  40:  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:  53:  54:  55: 
 56:     public $compiler_class = 'Smarty_Internal_SmartyTemplateCompiler';
 57: 
 58:      59:  60:  61:  62: 
 63:     public $template_lexer_class = 'Smarty_Internal_Templatelexer';
 64: 
 65:      66:  67:  68:  69: 
 70:     public $template_parser_class = 'Smarty_Internal_Templateparser';
 71: 
 72:      73:  74:  75:  76:  77:  78:  79:  80: 
 81:     abstract public function getContent(Smarty_Template_Source $source);
 82: 
 83:      84:  85:  86:  87:  88: 
 89:     abstract public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null);
 90: 
 91:      92:  93:  94:  95: 
 96:     public function populateTimestamp(Smarty_Template_Source $source)
 97:     {
 98:         
 99:     }
100: 
101:     102: 103: 104: 105: 106: 107: 108: 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: 121: 122: 123: 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:         
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:         
141:         if ($_template->caching) {
142:             $_cache = '.cache';
143:         } else {
144:             $_cache = '';
145:         }
146:         $_compile_dir = $_template->smarty->getCompileDir();
147:         
148:         $_basename = $this->getBasename($compiled->source);
149:         if ($_basename === null) {
150:             $_basename = basename(preg_replace('![^\w\/]+!', '_', $compiled->source->name));
151:         }
152:         
153:         if ($_basename) {
154:             $_basename = '.' . $_basename;
155:         }
156: 
157:         $compiled->filepath = $_compile_dir . $_filepath . '.' . $compiled->source->type . $_basename . $_cache . '.php';
158:     }
159: 
160:     161: 162: 163: 164: 165: 166: 167: 
168:     protected function normalizePath($_path, $ds = true)
169:     {
170:         if ($ds) {
171:             
172:             $_path = str_replace('\\', '/', $_path);
173:         }
174: 
175:         $offset = 0;
176: 
177:         
178:         $_path = preg_replace('#/\./(\./)*#', '/', $_path);
179:         
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:                 
192:                 $_pos = $_parent;
193:             }
194: 
195:             $_path = substr_replace($_path, '', $_pos, $_parent + 3 - $_pos);
196:         }
197: 
198:         if ($ds && DS != '/') {
199:             
200:             $_path = str_replace('/', '\\', $_path);
201:         }
202: 
203:         return $_path;
204:     }
205: 
206:     207: 208: 209: 210: 211: 212: 213: 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:         
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:                 
236:                 
237:                 $file = getcwd() . DS . $file;
238:             }
239:         }
240: 
241:         
242:         if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) {
243:             
244:             $_path = DS . trim($file, '/');
245:             $_was_relative = true;
246:         } else {
247:             
248:             $_path = str_replace('\\', '/', $file);
249:         }
250:         $_path = $this->normalizePath($_path, false);
251:         if (DS != '/') {
252:             
253:             $_path = str_replace('/', '\\', $_path);
254:         }
255:         
256:         if (isset($_was_relative)) {
257:             $_path = substr($_path, 1);
258:         }
259: 
260:         
261:         $file = rtrim($_path, '/\\');
262: 
263:         
264:         if (isset($_file_exact_match)) {
265:             return $this->fileExists($source, $file) ? $file : false;
266:         }
267: 
268:         
269:         if (preg_match('#^\[(?P<key>[^\]]+)\](?P<file>.+)$#', $file, $match)) {
270:             $_directory = null;
271:             
272:             if (isset($_directories[$match['key']])) {
273:                 $_directory = $_directories[$match['key']];
274:             } elseif (is_numeric($match['key'])) {
275:                 
276:                 $match['key'] = (int) $match['key'];
277:                 if (isset($_directories[$match['key']])) {
278:                     $_directory = $_directories[$match['key']];
279:                 } else {
280:                     
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:         
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:                     
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:         
322:         if ($this->fileExists($source, $file)) {
323:             return $file;
324:         }
325: 
326:         
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:         
352:         return false;
353:     }
354: 
355:     356: 357: 358: 359: 360: 361: 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: 372: 373: 374: 375: 376: 
377:     protected function getBasename(Smarty_Template_Source $source)
378:     {
379:         return null;
380:     }
381: 
382:     383: 384: 385: 386: 387: 388: 389: 390: 
391:     public static function load(Smarty $smarty, $type)
392:     {
393:         
394:         if (isset($smarty->_resource_handlers[$type])) {
395:             return $smarty->_resource_handlers[$type];
396:         }
397: 
398:         
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:                 
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:         
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:         
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:                 
446:                 return self::load($smarty, $type);
447:             }
448:         }
449: 
450:         
451:         $_known_stream = stream_get_wrappers();
452:         if (in_array($type, $_known_stream)) {
453:             
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:         
465: 
466:         
467:         throw new SmartyException("Unknown resource type '{$type}'");
468:     }
469: 
470:     471: 472: 473: 474: 475: 476: 477: 478: 479: 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:             
486:             
487:             $type = $default_resource;
488:             $name = $resource_name;
489:         } else {
490:             $type = $parts[0];
491:             $name = $parts[1];
492:         }
493:     }
494: 
495:     496: 497: 498: 499: 500: 501: 502: 
503: 
504:     505: 506: 507: 508: 509: 510: 511: 
512:     public static function getUniqueTemplateName($template, $template_resource)
513:     {
514:         self::parseResourceName($template_resource, $template->smarty->default_resource_type, $name, $type);
515:         
516:         $resource = Smarty_Resource::load($template->smarty, $type);
517:         
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: 527: 528: 529: 530: 531: 532: 533: 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:         
543:         self::parseResourceName($template_resource, $smarty->default_resource_type, $name, $type);
544:         $resource = Smarty_Resource::load($smarty, $type);
545:         
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:         
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:         
564:         $source = new Smarty_Template_Source($resource, $smarty, $template_resource, $type, $name, $unique_resource_name);
565:         $resource->populate($source, $_template);
566: 
567:         
568:         self::$sources[$_cache_key] = $source;
569: 
570:         return $source;
571:     }
572: 
573:     574: 575: 576: 577: 578: 579: 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:         
588:         self::parseResourceName($config_resource, $smarty->default_config_type, $name, $type);
589: 
590:         
591:         if (isset($_incompatible_resources[$type])) {
592:             throw new SmartyException ("Unable to use resource '{$type}' for config");
593:         }
594: 
595:         
596:         $resource = Smarty_Resource::load($smarty, $type);
597:         $unique_resource_name = $resource->buildUniqueResourceName($smarty, $name, true);
598: 
599:         
600:         $_cache_key = 'config|' . $unique_resource_name;
601:         if (isset(self::$sources[$_cache_key])) {
602:             return self::$sources[$_cache_key];
603:         }
604: 
605:         
606:         $source = new Smarty_Config_Source($resource, $smarty, $config_resource, $type, $name, $unique_resource_name);
607:         $resource->populate($source, null);
608: 
609:         
610:         self::$sources[$_cache_key] = $source;
611: 
612:         return $source;
613:     }
614: }
615: 
616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 
628: class Smarty_Template_Source
629: {
630:     631: 632: 633: 634: 
635:     public $compiler_class = null;
636: 
637:     638: 639: 640: 641: 
642:     public $template_lexer_class = null;
643: 
644:     645: 646: 647: 648: 
649:     public $template_parser_class = null;
650: 
651:     652: 653: 654: 655: 
656:     public $uid = null;
657: 
658:     659: 660: 661: 662: 
663:     public $resource = null;
664: 
665:     666: 667: 668: 669: 
670:     public $type = null;
671: 
672:     673: 674: 675: 676: 
677:     public $name = null;
678: 
679:     680: 681: 682: 683: 
684:     public $unique_resource = null;
685: 
686:     687: 688: 689: 690: 
691:     public $filepath = null;
692: 
693:     694: 695: 696: 697: 
698:     public $uncompiled = null;
699: 
700:     701: 702: 703: 704: 
705:     public $recompiled = null;
706: 
707:     708: 709: 710: 711: 
712:     public $components = null;
713: 
714:     715: 716: 717: 718: 
719:     public $handler = null;
720: 
721:     722: 723: 724: 725: 
726:     public $smarty = null;
727: 
728:     729: 730: 731: 732: 733: 734: 735: 736: 737: 
738:     public function __construct(Smarty_Resource $handler, Smarty $smarty, $resource, $type, $name, $unique_resource)
739:     {
740:         $this->handler = $handler; 
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: 757: 758: 759: 760: 761: 
762:     public function getCompiled($_template)
763:     {
764:         
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:         
776:         Smarty_Resource::$compileds[$_cache_key] = $compiled;
777: 
778:         return $compiled;
779:     }
780: 
781:     782: 783: 784: 785: 
786:     public function renderUncompiled(Smarty_Internal_Template $_template)
787:     {
788:         return $this->handler->renderUncompiled($this, $_template);
789:     }
790: 
791:     792: 793: 794: 795: 796: 797: 798: 
799:     public function __set($property_name, $value)
800:     {
801:         switch ($property_name) {
802:             
803:             case 'timestamp':
804:             case 'exists':
805:             case 'content':
806:                 
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: 818: 819: 820: 821: 822: 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: 844: 845: 846: 847: 848: 849: 850: 
851: class Smarty_Template_Compiled
852: {
853:     854: 855: 856: 857: 
858:     public $filepath = null;
859: 
860:     861: 862: 863: 864: 
865:     public $timestamp = null;
866: 
867:     868: 869: 870: 871: 
872:     public $exists = false;
873: 
874:     875: 876: 877: 878: 
879:     public $loaded = false;
880: 
881:     882: 883: 884: 885: 
886:     public $isCompiled = false;
887: 
888:     889: 890: 891: 892: 
893:     public $source = null;
894: 
895:     896: 897: 898: 899: 900: 
901:     public $_properties = null;
902: 
903:     904: 905: 906: 907: 
908:     public function __construct(Smarty_Template_Source $source)
909:     {
910:         $this->source = $source;
911:     }
912: }
913: