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: