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