1<?php 2/** 3 * Project: Smarty: the PHP compiling template engine 4 * File: Smarty.class.php 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * For questions, help, comments, discussion, etc., please join the 20 * Smarty mailing list. Send a blank e-mail to 21 * smarty-discussion-subscribe@googlegroups.com 22 * 23 * @link http://www.smarty.net/ 24 * @copyright 2015 New Digital Group, Inc. 25 * @copyright 2015 Uwe Tews 26 * @author Monte Ohrt <monte at ohrt dot com> 27 * @author Uwe Tews 28 * @author Rodney Rehm 29 * @package Smarty 30 * @version 3.1.29 31 */ 32 33/** 34 * define shorthand directory separator constant 35 */ 36if (!defined('DS')) { 37 define('DS', DIRECTORY_SEPARATOR); 38} 39 40/** 41 * set SMARTY_DIR to absolute path to Smarty library files. 42 * Sets SMARTY_DIR only if user application has not already defined it. 43 */ 44if (!defined('SMARTY_DIR')) { 45 define('SMARTY_DIR', dirname(__FILE__) . DS); 46} 47 48/** 49 * set SMARTY_SYSPLUGINS_DIR to absolute path to Smarty internal plugins. 50 * Sets SMARTY_SYSPLUGINS_DIR only if user application has not already defined it. 51 */ 52if (!defined('SMARTY_SYSPLUGINS_DIR')) { 53 define('SMARTY_SYSPLUGINS_DIR', SMARTY_DIR . 'sysplugins' . DS); 54} 55if (!defined('SMARTY_PLUGINS_DIR')) { 56 define('SMARTY_PLUGINS_DIR', SMARTY_DIR . 'plugins' . DS); 57} 58if (!defined('SMARTY_MBSTRING')) { 59 define('SMARTY_MBSTRING', function_exists('mb_get_info')); 60} 61if (!defined('SMARTY_RESOURCE_CHAR_SET')) { 62 // UTF-8 can only be done properly when mbstring is available! 63 /** 64 * @deprecated in favor of Smarty::$_CHARSET 65 */ 66 define('SMARTY_RESOURCE_CHAR_SET', SMARTY_MBSTRING ? 'UTF-8' : 'ISO-8859-1'); 67} 68if (!defined('SMARTY_RESOURCE_DATE_FORMAT')) { 69 /** 70 * @deprecated in favor of Smarty::$_DATE_FORMAT 71 */ 72 define('SMARTY_RESOURCE_DATE_FORMAT', '%b %e, %Y'); 73} 74 75/** 76 * Try loading the Smarty_Internal_Data class 77 * If we fail we must load Smarty's autoloader. 78 * Otherwise we may have a global autoloader like Composer 79 */ 80if (!class_exists('Smarty_Autoloader', false)) { 81 if (!class_exists('Smarty_Internal_Data', true)) { 82 require_once dirname(__FILE__) . '/Autoloader.php'; 83 Smarty_Autoloader::registerBC(); 84 } 85} 86 87/** 88 * Load always needed external class files 89 */ 90if (!class_exists('Smarty_Internal_Data', false)) { 91 require_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_data.php'; 92} 93require_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_extension_handler.php'; 94require_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_templatebase.php'; 95require_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_template.php'; 96require_once SMARTY_SYSPLUGINS_DIR . 'smarty_resource.php'; 97require_once SMARTY_SYSPLUGINS_DIR . 'smarty_variable.php'; 98require_once SMARTY_SYSPLUGINS_DIR . 'smarty_template_source.php'; 99require_once SMARTY_SYSPLUGINS_DIR . 'smarty_template_resource_base.php'; 100 101/** 102 * This is the main Smarty class 103 * 104 * @package Smarty 105 * 106 * @method int clearAllCache(int $exp_time = null, string $type = null) 107 * @method int clearCache(string $template_name, string $cache_id = null, string $compile_id = null, int $exp_time = null, string $type = null) 108 * @method int compileAllTemplates(Smarty $smarty, string $extension = '.tpl', bool $force_compile = false, int $time_limit = 0, int $max_errors = null) 109 * @method int compileAllConfig(Smarty $smarty, string $extension = '.conf', bool $force_compile = false, int $time_limit = 0, int $max_errors = null) 110 * 111 */ 112class Smarty extends Smarty_Internal_TemplateBase 113{ 114 /**#@+ 115 * constant definitions 116 */ 117 118 /** 119 * smarty version 120 */ 121 const SMARTY_VERSION = '3.1.29'; 122 123 /** 124 * define variable scopes 125 */ 126 const SCOPE_LOCAL = 0; 127 128 const SCOPE_PARENT = 2; 129 130 const SCOPE_TPL_ROOT = 4; 131 132 const SCOPE_ROOT = 8; 133 134 const SCOPE_SMARTY = 16; 135 136 const SCOPE_GLOBAL = 32; 137 138 const SCOPE_BUBBLE_UP = 64; 139 140 /** 141 * define caching modes 142 */ 143 const CACHING_OFF = 0; 144 145 const CACHING_LIFETIME_CURRENT = 1; 146 147 const CACHING_LIFETIME_SAVED = 2; 148 149 /** 150 * define constant for clearing cache files be saved expiration dates 151 */ 152 const CLEAR_EXPIRED = - 1; 153 154 /** 155 * define compile check modes 156 */ 157 const COMPILECHECK_OFF = 0; 158 159 const COMPILECHECK_ON = 1; 160 161 const COMPILECHECK_CACHEMISS = 2; 162 163 /** 164 * define debug modes 165 */ 166 const DEBUG_OFF = 0; 167 168 const DEBUG_ON = 1; 169 170 const DEBUG_INDIVIDUAL = 2; 171 172 /** 173 * modes for handling of "<?php ... ?>" tags in templates. 174 */ 175 const PHP_PASSTHRU = 0; //-> print tags as plain text 176 177 const PHP_QUOTE = 1; //-> escape tags as entities 178 179 const PHP_REMOVE = 2; //-> escape tags as entities 180 181 const PHP_ALLOW = 3; //-> escape tags as entities 182 183 /** 184 * filter types 185 */ 186 const FILTER_POST = 'post'; 187 188 const FILTER_PRE = 'pre'; 189 190 const FILTER_OUTPUT = 'output'; 191 192 const FILTER_VARIABLE = 'variable'; 193 194 /** 195 * plugin types 196 */ 197 const PLUGIN_FUNCTION = 'function'; 198 199 const PLUGIN_BLOCK = 'block'; 200 201 const PLUGIN_COMPILER = 'compiler'; 202 203 const PLUGIN_MODIFIER = 'modifier'; 204 205 const PLUGIN_MODIFIERCOMPILER = 'modifiercompiler'; 206 207 /** 208 * Resource caching modes 209 */ 210 const RESOURCE_CACHE_OFF = 0; 211 212 const RESOURCE_CACHE_AUTOMATIC = 1; // cache template objects by rules 213 214 const RESOURCE_CACHE_TEMPLATE = 2; // cache all template objects 215 216 const RESOURCE_CACHE_ON = 4; // cache source and compiled resources 217 218 /**#@-*/ 219 220 /** 221 * assigned global tpl vars 222 */ 223 public static $global_tpl_vars = array(); 224 225 /** 226 * error handler returned by set_error_handler() in Smarty::muteExpectedErrors() 227 */ 228 public static $_previous_error_handler = null; 229 230 /** 231 * contains directories outside of SMARTY_DIR that are to be muted by muteExpectedErrors() 232 */ 233 public static $_muted_directories = array(); 234 235 /** 236 * Flag denoting if Multibyte String functions are available 237 */ 238 public static $_MBSTRING = SMARTY_MBSTRING; 239 240 /** 241 * The character set to adhere to (e.g. "UTF-8") 242 */ 243 public static $_CHARSET = SMARTY_RESOURCE_CHAR_SET; 244 245 /** 246 * The date format to be used internally 247 * (accepts date() and strftime()) 248 */ 249 public static $_DATE_FORMAT = SMARTY_RESOURCE_DATE_FORMAT; 250 251 /** 252 * Flag denoting if PCRE should run in UTF-8 mode 253 */ 254 public static $_UTF8_MODIFIER = 'u'; 255 256 /** 257 * Flag denoting if operating system is windows 258 */ 259 public static $_IS_WINDOWS = false; 260 261 /**#@+ 262 * variables 263 */ 264 265 /** 266 * auto literal on delimiters with whitespace 267 * 268 * @var boolean 269 */ 270 public $auto_literal = true; 271 272 /** 273 * display error on not assigned variables 274 * 275 * @var boolean 276 */ 277 public $error_unassigned = false; 278 279 /** 280 * look up relative file path in include_path 281 * 282 * @var boolean 283 */ 284 public $use_include_path = false; 285 286 /** 287 * template directory 288 * 289 * @var array 290 */ 291 private $template_dir = array('./templates/'); 292 293 /** 294 * joined template directory string used in cache keys 295 * 296 * @var string 297 */ 298 public $_joined_template_dir = null; 299 300 /** 301 * joined config directory string used in cache keys 302 * 303 * @var string 304 */ 305 public $_joined_config_dir = null; 306 307 /** 308 * default template handler 309 * 310 * @var callable 311 */ 312 public $default_template_handler_func = null; 313 314 /** 315 * default config handler 316 * 317 * @var callable 318 */ 319 public $default_config_handler_func = null; 320 321 /** 322 * default plugin handler 323 * 324 * @var callable 325 */ 326 public $default_plugin_handler_func = null; 327 328 /** 329 * compile directory 330 * 331 * @var string 332 */ 333 private $compile_dir = './templates_c/'; 334 335 /** 336 * plugins directory 337 * 338 * @var array 339 */ 340 private $plugins_dir = null; 341 342 /** 343 * cache directory 344 * 345 * @var string 346 */ 347 private $cache_dir = './cache/'; 348 349 /** 350 * config directory 351 * 352 * @var array 353 */ 354 private $config_dir = array('./configs/'); 355 356 /** 357 * force template compiling? 358 * 359 * @var boolean 360 */ 361 public $force_compile = false; 362 363 /** 364 * check template for modifications? 365 * 366 * @var boolean 367 */ 368 public $compile_check = true; 369 370 /** 371 * use sub dirs for compiled/cached files? 372 * 373 * @var boolean 374 */ 375 public $use_sub_dirs = false; 376 377 /** 378 * allow ambiguous resources (that are made unique by the resource handler) 379 * 380 * @var boolean 381 */ 382 public $allow_ambiguous_resources = false; 383 384 /** 385 * merge compiled includes 386 * 387 * @var boolean 388 */ 389 public $merge_compiled_includes = false; 390 391 /** 392 * force cache file creation 393 * 394 * @var boolean 395 */ 396 public $force_cache = false; 397 398 /** 399 * template left-delimiter 400 * 401 * @var string 402 */ 403 public $left_delimiter = "{"; 404 405 /** 406 * template right-delimiter 407 * 408 * @var string 409 */ 410 public $right_delimiter = "}"; 411 412 /**#@+ 413 * security 414 */ 415 /** 416 * class name 417 * This should be instance of Smarty_Security. 418 * 419 * @var string 420 * @see Smarty_Security 421 */ 422 public $security_class = 'Smarty_Security'; 423 424 /** 425 * implementation of security class 426 * 427 * @var Smarty_Security 428 */ 429 public $security_policy = null; 430 431 /** 432 * controls handling of PHP-blocks 433 * 434 * @var integer 435 */ 436 public $php_handling = self::PHP_PASSTHRU; 437 438 /** 439 * controls if the php template file resource is allowed 440 * 441 * @var bool 442 */ 443 public $allow_php_templates = false; 444 445 /**#@-*/ 446 /** 447 * debug mode 448 * Setting this to true enables the debug-console. 449 * 450 * @var boolean 451 */ 452 public $debugging = false; 453 454 /** 455 * This determines if debugging is enable-able from the browser. 456 * <ul> 457 * <li>NONE => no debugging control allowed</li> 458 * <li>URL => enable debugging when SMARTY_DEBUG is found in the URL.</li> 459 * </ul> 460 * 461 * @var string 462 */ 463 public $debugging_ctrl = 'NONE'; 464 465 /** 466 * Name of debugging URL-param. 467 * Only used when $debugging_ctrl is set to 'URL'. 468 * The name of the URL-parameter that activates debugging. 469 * 470 * @var string 471 */ 472 public $smarty_debug_id = 'SMARTY_DEBUG'; 473 474 /** 475 * Path of debug template. 476 * 477 * @var string 478 */ 479 public $debug_tpl = null; 480 481 /** 482 * When set, smarty uses this value as error_reporting-level. 483 * 484 * @var int 485 */ 486 public $error_reporting = null; 487 488 /**#@+ 489 * config var settings 490 */ 491 492 /** 493 * Controls whether variables with the same name overwrite each other. 494 * 495 * @var boolean 496 */ 497 public $config_overwrite = true; 498 499 /** 500 * Controls whether config values of on/true/yes and off/false/no get converted to boolean. 501 * 502 * @var boolean 503 */ 504 public $config_booleanize = true; 505 506 /** 507 * Controls whether hidden config sections/vars are read from the file. 508 * 509 * @var boolean 510 */ 511 public $config_read_hidden = false; 512 513 /**#@-*/ 514 515 /**#@+ 516 * resource locking 517 */ 518 519 /** 520 * locking concurrent compiles 521 * 522 * @var boolean 523 */ 524 public $compile_locking = true; 525 526 /** 527 * Controls whether cache resources should use locking mechanism 528 * 529 * @var boolean 530 */ 531 public $cache_locking = false; 532 533 /** 534 * seconds to wait for acquiring a lock before ignoring the write lock 535 * 536 * @var float 537 */ 538 public $locking_timeout = 10; 539 540 /**#@-*/ 541 542 /** 543 * resource type used if none given 544 * Must be an valid key of $registered_resources. 545 * 546 * @var string 547 */ 548 public $default_resource_type = 'file'; 549 550 /** 551 * caching type 552 * Must be an element of $cache_resource_types. 553 * 554 * @var string 555 */ 556 public $caching_type = 'file'; 557 558 /** 559 * config type 560 * 561 * @var string 562 */ 563 public $default_config_type = 'file'; 564 565 /** 566 * enable resource caching 567 * 568 * @var bool 569 */ 570 public $resource_cache_mode = 1; 571 572 /** 573 * check If-Modified-Since headers 574 * 575 * @var boolean 576 */ 577 public $cache_modified_check = false; 578 579 /** 580 * registered plugins 581 * 582 * @var array 583 */ 584 public $registered_plugins = array(); 585 586 /** 587 * registered objects 588 * 589 * @var array 590 */ 591 public $registered_objects = array(); 592 593 /** 594 * registered classes 595 * 596 * @var array 597 */ 598 public $registered_classes = array(); 599 600 /** 601 * registered filters 602 * 603 * @var array 604 */ 605 public $registered_filters = array(); 606 607 /** 608 * registered resources 609 * 610 * @var array 611 */ 612 public $registered_resources = array(); 613 614 /** 615 * registered cache resources 616 * 617 * @var array 618 */ 619 public $registered_cache_resources = array(); 620 621 /** 622 * autoload filter 623 * 624 * @var array 625 */ 626 public $autoload_filters = array(); 627 628 /** 629 * default modifier 630 * 631 * @var array 632 */ 633 public $default_modifiers = array(); 634 635 /** 636 * autoescape variable output 637 * 638 * @var boolean 639 */ 640 public $escape_html = false; 641 642 /** 643 * start time for execution time calculation 644 * 645 * @var int 646 */ 647 public $start_time = 0; 648 649 /** 650 * required by the compiler for BC 651 * 652 * @var string 653 */ 654 public $_current_file = null; 655 656 /** 657 * internal flag to enable parser debugging 658 * 659 * @var bool 660 */ 661 public $_parserdebug = false; 662 663 /** 664 * This object type (Smarty = 1, template = 2, data = 4) 665 * 666 * @var int 667 */ 668 public $_objType = 1; 669 670 /** 671 * Debug object 672 * 673 * @var Smarty_Internal_Debug 674 */ 675 public $_debug = null; 676 677 /** 678 * removed properties 679 * 680 * @var string[] 681 */ 682 private static $obsoleteProperties = array('resource_caching', 'template_resource_caching', 683 'direct_access_security', '_dir_perms', '_file_perms', 684 'plugin_search_order', 'inheritance_merge_compiled_includes'); 685 686 /** 687 * List of private properties which will call getter/setter ona direct access 688 * 689 * @var array 690 */ 691 private static $accessMap = array('template_dir' => 'TemplateDir', 'config_dir' => 'ConfigDir', 692 'plugins_dir' => 'PluginsDir', 'compile_dir' => 'CompileDir', 693 'cache_dir' => 'CacheDir',); 694 695 /**#@-*/ 696 697 /** 698 * Initialize new Smarty object 699 */ 700 public function __construct() 701 { 702 parent::__construct(); 703 if (is_callable('mb_internal_encoding')) { 704 mb_internal_encoding(Smarty::$_CHARSET); 705 } 706 $this->start_time = microtime(true); 707 708 if (isset($_SERVER['SCRIPT_NAME'])) { 709 Smarty::$global_tpl_vars['SCRIPT_NAME'] = new Smarty_Variable($_SERVER['SCRIPT_NAME']); 710 } 711 712 // Check if we're running on windows 713 Smarty::$_IS_WINDOWS = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; 714 715 // let PCRE (preg_*) treat strings as ISO-8859-1 if we're not dealing with UTF-8 716 if (Smarty::$_CHARSET !== 'UTF-8') { 717 Smarty::$_UTF8_MODIFIER = ''; 718 } 719 } 720 721 /** 722 * Check if a template resource exists 723 * 724 * @param string $resource_name template name 725 * 726 * @return boolean status 727 */ 728 public function templateExists($resource_name) 729 { 730 // create source object 731 $source = Smarty_Template_Source::load(null, $this, $resource_name); 732 return $source->exists; 733 } 734 735 /** 736 * Returns a single or all global variables 737 * 738 * @param string $varname variable name or null 739 * 740 * @return string variable value or or array of variables 741 */ 742 public function getGlobal($varname = null) 743 { 744 if (isset($varname)) { 745 if (isset(self::$global_tpl_vars[$varname])) { 746 return self::$global_tpl_vars[$varname]->value; 747 } else { 748 return ''; 749 } 750 } else { 751 $_result = array(); 752 foreach (self::$global_tpl_vars AS $key => $var) { 753 $_result[$key] = $var->value; 754 } 755 756 return $_result; 757 } 758 } 759 760 /** 761 * Loads security class and enables security 762 * 763 * @param string|Smarty_Security $security_class if a string is used, it must be class-name 764 * 765 * @return Smarty current Smarty instance for chaining 766 * @throws SmartyException when an invalid class name is provided 767 */ 768 public function enableSecurity($security_class = null) 769 { 770 Smarty_Security::enableSecurity($this, $security_class); 771 return $this; 772 } 773 774 /** 775 * Disable security 776 * 777 * @return Smarty current Smarty instance for chaining 778 */ 779 public function disableSecurity() 780 { 781 $this->security_policy = null; 782 783 return $this; 784 } 785 786 /** 787 * Set template directory 788 * 789 * @param string|array $template_dir directory(s) of template sources 790 * @param bool $isConfig true for config_dir 791 * 792 * @return \Smarty current Smarty instance for chaining 793 */ 794 public function setTemplateDir($template_dir, $isConfig = false) 795 { 796 $type = $isConfig ? 'config_dir' : 'template_dir'; 797 $joined = '_joined_' . $type; 798 $this->{$type} = (array) $template_dir; 799 $this->{$joined} = join(' # ', $this->{$type}); 800 $this->_cache[$type . '_new'] = true; 801 $this->_cache[$type] = false; 802 return $this; 803 } 804 805 /** 806 * Add template directory(s) 807 * 808 * @param string|array $template_dir directory(s) of template sources 809 * @param string $key of the array element to assign the template dir to 810 * @param bool $isConfig true for config_dir 811 * 812 * @return Smarty current Smarty instance for chaining 813 */ 814 public function addTemplateDir($template_dir, $key = null, $isConfig = false) 815 { 816 $type = $isConfig ? 'config_dir' : 'template_dir'; 817 $joined = '_joined_' . $type; 818 if (!isset($this->_cache[$type])) { 819 $this->{$type} = (array) $this->{$type}; 820 $this->{$joined} = join(' # ', $this->{$type}); 821 $this->_cache[$type . '_new'] = true; 822 $this->_cache[$type] = false; 823 } 824 $this->{$joined} .= ' # ' . join(' # ', (array) $template_dir); 825 $this->_addDir($type, $template_dir, $key); 826 return $this; 827 } 828 829 /** 830 * Get template directories 831 * 832 * @param mixed $index index of directory to get, null to get all 833 * @param bool $isConfig true for config_dir 834 * 835 * @return array list of template directories, or directory of $index 836 */ 837 public function getTemplateDir($index = null, $isConfig = false) 838 { 839 $type = $isConfig ? 'config_dir' : 'template_dir'; 840 if (!isset($this->_cache[$type])) { 841 $joined = '_joined_' . $type; 842 $this->{$type} = (array) $this->{$type}; 843 $this->{$joined} = join(' # ', $this->{$type}); 844 $this->_cache[$type] = false; 845 } 846 if ($this->_cache[$type] == false) { 847 foreach ($this->{$type} as $k => $v) { 848 $this->{$type}[$k] = $this->_realpath($v . DS, true); 849 } 850 $this->_cache[$type . '_new'] = true; 851 $this->_cache[$type] = true; 852 } 853 if ($index !== null) { 854 return isset($this->{$type}[$index]) ? $this->{$type}[$index] : null; 855 } 856 return $this->{$type}; 857 } 858 859 /** 860 * Set config directory 861 * 862 * @param $config_dir 863 * 864 * @return Smarty current Smarty instance for chaining 865 */ 866 public function setConfigDir($config_dir) 867 { 868 return $this->setTemplateDir($config_dir, true); 869 } 870 871 /** 872 * Add config directory(s) 873 * 874 * @param string|array $config_dir directory(s) of config sources 875 * @param mixed $key key of the array element to assign the config dir to 876 * 877 * @return Smarty current Smarty instance for chaining 878 */ 879 public function addConfigDir($config_dir, $key = null) 880 { 881 return $this->addTemplateDir($config_dir, $key, true); 882 } 883 884 /** 885 * Get config directory 886 * 887 * @param mixed $index index of directory to get, null to get all 888 * 889 * @return array configuration directory 890 */ 891 public function getConfigDir($index = null) 892 { 893 return $this->getTemplateDir($index, true); 894 } 895 896 /** 897 * Set plugins directory 898 * 899 * @param string|array $plugins_dir directory(s) of plugins 900 * 901 * @return Smarty current Smarty instance for chaining 902 */ 903 public function setPluginsDir($plugins_dir) 904 { 905 $this->plugins_dir = (array) $plugins_dir; 906 if (isset($this->_cache['plugins_dir'])) { 907 unset($this->_cache['plugins_dir']); 908 } 909 return $this; 910 } 911 912 /** 913 * Adds directory of plugin files 914 * 915 * @param $plugins_dir 916 * 917 * @return Smarty current Smarty instance for chaining 918 */ 919 public function addPluginsDir($plugins_dir) 920 { 921 if (!isset($this->plugins_dir)) { 922 $this->plugins_dir = array(SMARTY_PLUGINS_DIR); 923 } 924 $this->plugins_dir = array_merge((array) $this->plugins_dir, (array) $plugins_dir); 925 if (isset($this->_cache['plugins_dir'])) { 926 unset($this->_cache['plugins_dir']); 927 } 928 return $this; 929 } 930 931 /** 932 * Get plugin directories 933 * 934 * @return array list of plugin directories 935 */ 936 public function getPluginsDir() 937 { 938 if (!isset($this->_cache['plugins_dir'])) { 939 if (!isset($this->plugins_dir)) { 940 $this->plugins_dir = array(SMARTY_PLUGINS_DIR); 941 } else { 942 $plugins_dir = (array) $this->plugins_dir; 943 $this->plugins_dir = array(); 944 foreach ($plugins_dir as $v) { 945 $this->plugins_dir[] = $this->_realpath($v . DS, true); 946 } 947 $this->plugins_dir = array_unique($this->plugins_dir); 948 } 949 $this->_cache['plugin_files'] = array(); 950 $this->_cache['plugins_dir'] = true; 951 } 952 return $this->plugins_dir; 953 } 954 955 /** 956 * Set compile directory 957 * 958 * @param string $compile_dir directory to store compiled templates in 959 * 960 * @return Smarty current Smarty instance for chaining 961 */ 962 public function setCompileDir($compile_dir) 963 { 964 $this->compile_dir = $this->_realpath($compile_dir . DS, true); 965 if (!isset(Smarty::$_muted_directories[$this->compile_dir])) { 966 Smarty::$_muted_directories[$this->compile_dir] = null; 967 } 968 $this->_cache['compile_dir'] = true; 969 return $this; 970 } 971 972 /** 973 * Get compiled directory 974 * 975 * @return string path to compiled templates 976 */ 977 public function getCompileDir() 978 { 979 if (!isset($this->_cache['compile_dir'])) { 980 $this->compile_dir = $this->_realpath($this->compile_dir . DS, true); 981 if (!isset(Smarty::$_muted_directories[$this->compile_dir])) { 982 Smarty::$_muted_directories[$this->compile_dir] = null; 983 } 984 $this->_cache['compile_dir'] = true; 985 } 986 return $this->compile_dir; 987 } 988 989 /** 990 * Set cache directory 991 * 992 * @param string $cache_dir directory to store cached templates in 993 * 994 * @return Smarty current Smarty instance for chaining 995 */ 996 public function setCacheDir($cache_dir) 997 { 998 $this->cache_dir = $this->_realpath($cache_dir . DS, true); 999 if (!isset(Smarty::$_muted_directories[$this->cache_dir])) { 1000 Smarty::$_muted_directories[$this->cache_dir] = null; 1001 } 1002 $this->_cache['cache_dir'] = true; 1003 return $this; 1004 } 1005 1006 /** 1007 * Get cache directory 1008 * 1009 * @return string path of cache directory 1010 */ 1011 public function getCacheDir() 1012 { 1013 if (!isset($this->_cache['cache_dir'])) { 1014 $this->cache_dir = $this->_realpath($this->cache_dir . DS, true); 1015 if (!isset(Smarty::$_muted_directories[$this->cache_dir])) { 1016 Smarty::$_muted_directories[$this->cache_dir] = null; 1017 } 1018 $this->_cache['cache_dir'] = true; 1019 } 1020 return $this->cache_dir; 1021 } 1022 1023 /** 1024 * add directories to given property name 1025 * 1026 * @param string $dirName directory property name 1027 * @param string|array $dir directory string or array of strings 1028 * @param mixed $key optional key 1029 */ 1030 private function _addDir($dirName, $dir, $key = null) 1031 { 1032 $rp = $this->_cache[$dirName]; 1033 if (is_array($dir)) { 1034 foreach ($dir as $k => $v) { 1035 $path = $rp ? $this->_realpath($v . DS, true) : $v; 1036 if (is_int($k)) { 1037 // indexes are not merged but appended 1038 $this->{$dirName}[] = $path; 1039 } else { 1040 // string indexes are overridden 1041 $this->{$dirName}[$k] = $path; 1042 } 1043 } 1044 } else { 1045 $path = $rp ? $this->_realpath($dir . DS, true) : $dir; 1046 if ($key !== null) { 1047 // override directory at specified index 1048 $this->{$dirName}[$key] = $path; 1049 } else { 1050 // append new directory 1051 $this->{$dirName}[] = $path; 1052 } 1053 } 1054 } 1055 1056 /** 1057 * creates a template object 1058 * 1059 * @param string $template the resource handle of the template file 1060 * @param mixed $cache_id cache id to be used with this template 1061 * @param mixed $compile_id compile id to be used with this template 1062 * @param object $parent next higher level of Smarty variables 1063 * @param boolean $do_clone flag is Smarty object shall be cloned 1064 * 1065 * @return object template object 1066 */ 1067 public function createTemplate($template, $cache_id = null, $compile_id = null, $parent = null, $do_clone = true) 1068 { 1069 if ($cache_id !== null && (is_object($cache_id) || is_array($cache_id))) { 1070 $parent = $cache_id; 1071 $cache_id = null; 1072 } 1073 if ($parent !== null && is_array($parent)) { 1074 $data = $parent; 1075 $parent = null; 1076 } else { 1077 $data = null; 1078 } 1079 if ($this->caching && 1080 isset($this->_cache['isCached'][$_templateId = $this->_getTemplateId($template, $cache_id, $compile_id)]) 1081 ) { 1082 $tpl = $do_clone ? clone $this->_cache['isCached'][$_templateId] : $this->_cache['isCached'][$_templateId]; 1083 $tpl->parent = $parent; 1084 $tpl->tpl_vars = array(); 1085 $tpl->config_vars = array(); 1086 } else { 1087 /* @var Smarty_Internal_Template $tpl */ 1088 $tpl = new $this->template_class($template, $this, $parent, $cache_id, $compile_id, null, null); 1089 } 1090 if ($do_clone) { 1091 $tpl->smarty = clone $tpl->smarty; 1092 } elseif ($parent === null) { 1093 $tpl->parent = $this; 1094 } 1095 // fill data if present 1096 if (!empty($data) && is_array($data)) { 1097 // set up variable values 1098 foreach ($data as $_key => $_val) { 1099 $tpl->tpl_vars[$_key] = new Smarty_Variable($_val); 1100 } 1101 } 1102 if ($this->debugging || $this->debugging_ctrl == 'URL') { 1103 $tpl->smarty->_debug = new Smarty_Internal_Debug(); 1104 // check URL debugging control 1105 if (!$this->debugging && $this->debugging_ctrl == 'URL') { 1106 $tpl->smarty->_debug->debugUrl($tpl->smarty); 1107 } 1108 } 1109 return $tpl; 1110 } 1111 1112 /** 1113 * Takes unknown classes and loads plugin files for them 1114 * class name format: Smarty_PluginType_PluginName 1115 * plugin filename format: plugintype.pluginname.php 1116 * 1117 * @param string $plugin_name class plugin name to load 1118 * @param bool $check check if already loaded 1119 * 1120 * @throws SmartyException 1121 * @return string |boolean filepath of loaded file or false 1122 */ 1123 public function loadPlugin($plugin_name, $check = true) 1124 { 1125 return $this->ext->loadPlugin->loadPlugin($this, $plugin_name, $check); 1126 } 1127 1128 /** 1129 * Get unique template id 1130 * 1131 * @param string $template_name 1132 * @param null|mixed $cache_id 1133 * @param null|mixed $compile_id 1134 * @param null $caching 1135 * 1136 * @return string 1137 */ 1138 public function _getTemplateId($template_name, $cache_id = null, $compile_id = null, $caching = null) 1139 { 1140 $cache_id = $cache_id === null ? $this->cache_id : $cache_id; 1141 $compile_id = $compile_id === null ? $this->compile_id : $compile_id; 1142 $caching = (int) ($caching === null ? $this->caching : $caching); 1143 1144 if ($this->allow_ambiguous_resources) { 1145 $_templateId = 1146 Smarty_Resource::getUniqueTemplateName($this, $template_name) . "#{$cache_id}#{$compile_id}#{$caching}"; 1147 } else { 1148 $_templateId = $this->_joined_template_dir . "#{$template_name}#{$cache_id}#{$compile_id}#{$caching}"; 1149 } 1150 if (isset($_templateId[150])) { 1151 $_templateId = sha1($_templateId); 1152 } 1153 return $_templateId; 1154 } 1155 1156 /** 1157 * Normalize path 1158 * - remove /./ and /../ 1159 * - make it absolute if required 1160 * 1161 * @param string $path file path 1162 * @param bool $realpath leave $path relative 1163 * 1164 * @return string 1165 */ 1166 public function _realpath($path, $realpath = null) 1167 { 1168 static $pattern = null; 1169 static $nds = null; 1170 if ($pattern == null) { 1171 $nds = DS == '/' ? '\\' : '/'; 1172 $ds = '\\' . DS; 1173 $pattern = 1174 "#([{$ds}]+[^{$ds}]+[{$ds}]+[.]([{$ds}]+[.])*[.][{$ds}]+([.][{$ds}]+)*)|([{$ds}]+([.][{$ds}]+)+)|[{$ds}]{2,}#"; 1175 } 1176 // normalize DS 1177 if (strpos($path, $nds) !== false) { 1178 $path = str_replace($nds, DS, $path); 1179 } 1180 1181 if ($realpath === true && (($path[0] !== '/' && DS == '/') || ($path[1] !== ':' && DS != '/'))) { 1182 $path = getcwd() . DS . $path; 1183 } 1184 while ((strpos($path, '.' . DS) !== false) || (strpos($path, DS . DS) !== false)) { 1185 $path = preg_replace($pattern, DS, $path); 1186 } 1187 if ($realpath === false && ($path[0] == '/' || $path[1] == ':')) { 1188 $path = str_ireplace(getcwd(), '.', $path); 1189 } 1190 return $path; 1191 } 1192 1193 /** 1194 * @param boolean $compile_check 1195 */ 1196 public function setCompileCheck($compile_check) 1197 { 1198 $this->compile_check = $compile_check; 1199 } 1200 1201 /** 1202 * @param boolean $use_sub_dirs 1203 */ 1204 public function setUseSubDirs($use_sub_dirs) 1205 { 1206 $this->use_sub_dirs = $use_sub_dirs; 1207 } 1208 1209 /** 1210 * @param int $error_reporting 1211 */ 1212 public function setErrorReporting($error_reporting) 1213 { 1214 $this->error_reporting = $error_reporting; 1215 } 1216 1217 /** 1218 * @param boolean $escape_html 1219 */ 1220 public function setEscapeHtml($escape_html) 1221 { 1222 $this->escape_html = $escape_html; 1223 } 1224 1225 /** 1226 * @param boolean $auto_literal 1227 */ 1228 public function setAutoLiteral($auto_literal) 1229 { 1230 $this->auto_literal = $auto_literal; 1231 } 1232 1233 /** 1234 * @param boolean $force_compile 1235 */ 1236 public function setForceCompile($force_compile) 1237 { 1238 $this->force_compile = $force_compile; 1239 } 1240 1241 /** 1242 * @param boolean $merge_compiled_includes 1243 */ 1244 public function setMergeCompiledIncludes($merge_compiled_includes) 1245 { 1246 $this->merge_compiled_includes = $merge_compiled_includes; 1247 } 1248 1249 /** 1250 * @param string $left_delimiter 1251 */ 1252 public function setLeftDelimiter($left_delimiter) 1253 { 1254 $this->left_delimiter = $left_delimiter; 1255 } 1256 1257 /** 1258 * @param string $right_delimiter 1259 */ 1260 public function setRightDelimiter($right_delimiter) 1261 { 1262 $this->right_delimiter = $right_delimiter; 1263 } 1264 1265 /** 1266 * @param boolean $debugging 1267 */ 1268 public function setDebugging($debugging) 1269 { 1270 $this->debugging = $debugging; 1271 } 1272 1273 /** 1274 * @param boolean $config_overwrite 1275 */ 1276 public function setConfigOverwrite($config_overwrite) 1277 { 1278 $this->config_overwrite = $config_overwrite; 1279 } 1280 1281 /** 1282 * @param boolean $config_booleanize 1283 */ 1284 public function setConfigBooleanize($config_booleanize) 1285 { 1286 $this->config_booleanize = $config_booleanize; 1287 } 1288 1289 /** 1290 * @param boolean $config_read_hidden 1291 */ 1292 public function setConfigReadHidden($config_read_hidden) 1293 { 1294 $this->config_read_hidden = $config_read_hidden; 1295 } 1296 1297 /** 1298 * @param boolean $compile_locking 1299 */ 1300 public function setCompileLocking($compile_locking) 1301 { 1302 $this->compile_locking = $compile_locking; 1303 } 1304 1305 /** 1306 * @param string $default_resource_type 1307 */ 1308 public function setDefaultResourceType($default_resource_type) 1309 { 1310 $this->default_resource_type = $default_resource_type; 1311 } 1312 1313 /** 1314 * @param string $caching_type 1315 */ 1316 public function setCachingType($caching_type) 1317 { 1318 $this->caching_type = $caching_type; 1319 } 1320 1321 /** 1322 * Test install 1323 * 1324 * @param null $errors 1325 */ 1326 public function testInstall(&$errors = null) 1327 { 1328 Smarty_Internal_TestInstall::testInstall($this, $errors); 1329 } 1330 1331 /** 1332 * Class destructor 1333 */ 1334 public function __destruct() 1335 { 1336 $i = 0;// intentionally left blank 1337 } 1338 1339 /** 1340 * <<magic>> Generic getter. 1341 * Calls the appropriate getter function. 1342 * Issues an E_USER_NOTICE if no valid getter is found. 1343 * 1344 * @param string $name property name 1345 * 1346 * @return mixed 1347 */ 1348 public function __get($name) 1349 { 1350 1351 if (isset(self::$accessMap[$name])) { 1352 $method = 'get' . self::$accessMap[$name]; 1353 return $this->{$method}(); 1354 } elseif (in_array($name, self::$obsoleteProperties)) { 1355 return null; 1356 } else { 1357 trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE); 1358 } 1359 } 1360 1361 /** 1362 * <<magic>> Generic setter. 1363 * Calls the appropriate setter function. 1364 * Issues an E_USER_NOTICE if no valid setter is found. 1365 * 1366 * @param string $name property name 1367 * @param mixed $value parameter passed to setter 1368 */ 1369 public function __set($name, $value) 1370 { 1371 if (isset(self::$accessMap[$name])) { 1372 $method = 'set' . self::$accessMap[$name]; 1373 $this->{$method}($value); 1374 } elseif (in_array($name, self::$obsoleteProperties)) { 1375 return; 1376 } else { 1377 if (is_object($value) && method_exists($value, $name)) { 1378 $this->$name = $value; 1379 } else { 1380 trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE); 1381 } 1382 } 1383 } 1384 1385 /** 1386 * Error Handler to mute expected messages 1387 * 1388 * @link http://php.net/set_error_handler 1389 * 1390 * @param integer $errno Error level 1391 * @param $errstr 1392 * @param $errfile 1393 * @param $errline 1394 * @param $errcontext 1395 * 1396 * @return boolean 1397 */ 1398 public static function mutingErrorHandler($errno, $errstr, $errfile, $errline, $errcontext) 1399 { 1400 $_is_muted_directory = false; 1401 1402 // add the SMARTY_DIR to the list of muted directories 1403 if (!isset(Smarty::$_muted_directories[SMARTY_DIR])) { 1404 $smarty_dir = realpath(SMARTY_DIR); 1405 if ($smarty_dir !== false) { 1406 Smarty::$_muted_directories[SMARTY_DIR] = 1407 array('file' => $smarty_dir, 'length' => strlen($smarty_dir),); 1408 } 1409 } 1410 1411 // walk the muted directories and test against $errfile 1412 foreach (Smarty::$_muted_directories as $key => &$dir) { 1413 if (!$dir) { 1414 // resolve directory and length for speedy comparisons 1415 $file = realpath($key); 1416 if ($file === false) { 1417 // this directory does not exist, remove and skip it 1418 unset(Smarty::$_muted_directories[$key]); 1419 continue; 1420 } 1421 $dir = array('file' => $file, 'length' => strlen($file),); 1422 } 1423 if (!strncmp($errfile, $dir['file'], $dir['length'])) { 1424 $_is_muted_directory = true; 1425 break; 1426 } 1427 } 1428 1429 // pass to next error handler if this error did not occur inside SMARTY_DIR 1430 // or the error was within smarty but masked to be ignored 1431 if (!$_is_muted_directory || ($errno && $errno & error_reporting())) { 1432 if (Smarty::$_previous_error_handler) { 1433 return call_user_func(Smarty::$_previous_error_handler, $errno, $errstr, $errfile, $errline, 1434 $errcontext); 1435 } else { 1436 return false; 1437 } 1438 } 1439 } 1440 1441 /** 1442 * Enable error handler to mute expected messages 1443 * 1444 * @return void 1445 */ 1446 public static function muteExpectedErrors() 1447 { 1448 /* 1449 error muting is done because some people implemented custom error_handlers using 1450 http://php.net/set_error_handler and for some reason did not understand the following paragraph: 1451 1452 It is important to remember that the standard PHP error handler is completely bypassed for the 1453 error types specified by error_types unless the callback function returns FALSE. 1454 error_reporting() settings will have no effect and your error handler will be called regardless - 1455 however you are still able to read the current value of error_reporting and act appropriately. 1456 Of particular note is that this value will be 0 if the statement that caused the error was 1457 prepended by the @ error-control operator. 1458 1459 Smarty deliberately uses @filemtime() over file_exists() and filemtime() in some places. Reasons include 1460 - @filemtime() is almost twice as fast as using an additional file_exists() 1461 - between file_exists() and filemtime() a possible race condition is opened, 1462 which does not exist using the simple @filemtime() approach. 1463 */ 1464 $error_handler = array('Smarty', 'mutingErrorHandler'); 1465 $previous = set_error_handler($error_handler); 1466 1467 // avoid dead loops 1468 if ($previous !== $error_handler) { 1469 Smarty::$_previous_error_handler = $previous; 1470 } 1471 } 1472 1473 /** 1474 * Disable error handler muting expected messages 1475 * 1476 * @return void 1477 */ 1478 public static function unmuteExpectedErrors() 1479 { 1480 restore_error_handler(); 1481 } 1482} 1483