Linux multi-monitor fullscreen support
[ryzomcore.git] / web / private_php / ams / smarty / libs / Smarty.class.php
blob6291e4cd5ef0cc5a278461d66d663a6008eb732e
1 <?php
2 /**
3 * Project: Smarty: the PHP compiling template engine
4 * File: Smarty.class.php
5 * SVN: $Id: Smarty.class.php 4848 2014-06-08 18:12:09Z Uwe.Tews@googlemail.com $
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 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * For questions, help, comments, discussion, etc., please join the
18 * Smarty mailing list. Send a blank e-mail to
19 * smarty-discussion-subscribe@googlegroups.com
21 * @link http://www.smarty.net/
22 * @copyright 2008 New Digital Group, Inc.
23 * @author Monte Ohrt <monte at ohrt dot com>
24 * @author Uwe Tews
25 * @author Rodney Rehm
26 * @package Smarty
27 * @version 3.1.19
30 /**
31 * define shorthand directory separator constant
33 if (!defined('DS')) {
34 define('DS', DIRECTORY_SEPARATOR);
37 /**
38 * set SMARTY_DIR to absolute path to Smarty library files.
39 * Sets SMARTY_DIR only if user application has not already defined it.
41 if (!defined('SMARTY_DIR')) {
42 define('SMARTY_DIR', dirname(__FILE__) . DS);
45 /**
46 * set SMARTY_SYSPLUGINS_DIR to absolute path to Smarty internal plugins.
47 * Sets SMARTY_SYSPLUGINS_DIR only if user application has not already defined it.
49 if (!defined('SMARTY_SYSPLUGINS_DIR')) {
50 define('SMARTY_SYSPLUGINS_DIR', SMARTY_DIR . 'sysplugins' . DS);
52 if (!defined('SMARTY_PLUGINS_DIR')) {
53 define('SMARTY_PLUGINS_DIR', SMARTY_DIR . 'plugins' . DS);
55 if (!defined('SMARTY_MBSTRING')) {
56 define('SMARTY_MBSTRING', function_exists('mb_split'));
58 if (!defined('SMARTY_RESOURCE_CHAR_SET')) {
59 // UTF-8 can only be done properly when mbstring is available!
60 /**
61 * @deprecated in favor of Smarty::$_CHARSET
63 define('SMARTY_RESOURCE_CHAR_SET', SMARTY_MBSTRING ? 'UTF-8' : 'ISO-8859-1');
65 if (!defined('SMARTY_RESOURCE_DATE_FORMAT')) {
66 /**
67 * @deprecated in favor of Smarty::$_DATE_FORMAT
69 define('SMARTY_RESOURCE_DATE_FORMAT', '%b %e, %Y');
72 /**
73 * register the class autoloader
75 if (!defined('SMARTY_SPL_AUTOLOAD')) {
76 define('SMARTY_SPL_AUTOLOAD', 0);
79 if (SMARTY_SPL_AUTOLOAD && set_include_path(get_include_path() . PATH_SEPARATOR . SMARTY_SYSPLUGINS_DIR) !== false) {
80 $registeredAutoLoadFunctions = spl_autoload_functions();
81 if (!isset($registeredAutoLoadFunctions['spl_autoload'])) {
82 spl_autoload_register();
84 } else {
85 spl_autoload_register('smartyAutoload');
88 /**
89 * Load always needed external class files
91 include_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_data.php';
92 include_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_templatebase.php';
93 include_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_template.php';
94 include_once SMARTY_SYSPLUGINS_DIR . 'smarty_resource.php';
95 include_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_resource_file.php';
96 include_once SMARTY_SYSPLUGINS_DIR . 'smarty_cacheresource.php';
97 include_once SMARTY_SYSPLUGINS_DIR . 'smarty_internal_cacheresource_file.php';
99 /**
100 * This is the main Smarty class
102 * @package Smarty
104 class Smarty extends Smarty_Internal_TemplateBase
106 /**#@+
107 * constant definitions
111 * smarty version
113 const SMARTY_VERSION = 'Smarty-3.1.19';
116 * define variable scopes
118 const SCOPE_LOCAL = 0;
119 const SCOPE_PARENT = 1;
120 const SCOPE_ROOT = 2;
121 const SCOPE_GLOBAL = 3;
123 * define caching modes
125 const CACHING_OFF = 0;
126 const CACHING_LIFETIME_CURRENT = 1;
127 const CACHING_LIFETIME_SAVED = 2;
129 * define constant for clearing cache files be saved expiration datees
131 const CLEAR_EXPIRED = - 1;
134 * define compile check modes
136 const COMPILECHECK_OFF = 0;
137 const COMPILECHECK_ON = 1;
138 const COMPILECHECK_CACHEMISS = 2;
140 * modes for handling of "<?php ... ?>" tags in templates.
142 const PHP_PASSTHRU = 0; //-> print tags as plain text
143 const PHP_QUOTE = 1; //-> escape tags as entities
144 const PHP_REMOVE = 2; //-> escape tags as entities
145 const PHP_ALLOW = 3; //-> escape tags as entities
147 * filter types
149 const FILTER_POST = 'post';
150 const FILTER_PRE = 'pre';
151 const FILTER_OUTPUT = 'output';
152 const FILTER_VARIABLE = 'variable';
154 * plugin types
156 const PLUGIN_FUNCTION = 'function';
157 const PLUGIN_BLOCK = 'block';
158 const PLUGIN_COMPILER = 'compiler';
159 const PLUGIN_MODIFIER = 'modifier';
160 const PLUGIN_MODIFIERCOMPILER = 'modifiercompiler';
162 /**#@-*/
165 * assigned global tpl vars
167 public static $global_tpl_vars = array();
170 * error handler returned by set_error_hanlder() in Smarty::muteExpectedErrors()
172 public static $_previous_error_handler = null;
174 * contains directories outside of SMARTY_DIR that are to be muted by muteExpectedErrors()
176 public static $_muted_directories = array();
178 * Flag denoting if Multibyte String functions are available
180 public static $_MBSTRING = SMARTY_MBSTRING;
182 * The character set to adhere to (e.g. "UTF-8")
184 public static $_CHARSET = SMARTY_RESOURCE_CHAR_SET;
186 * The date format to be used internally
187 * (accepts date() and strftime())
189 public static $_DATE_FORMAT = SMARTY_RESOURCE_DATE_FORMAT;
191 * Flag denoting if PCRE should run in UTF-8 mode
193 public static $_UTF8_MODIFIER = 'u';
196 * Flag denoting if operating system is windows
198 public static $_IS_WINDOWS = false;
200 /**#@+
201 * variables
205 * auto literal on delimiters with whitspace
207 * @var boolean
209 public $auto_literal = true;
211 * display error on not assigned variables
213 * @var boolean
215 public $error_unassigned = false;
217 * look up relative filepaths in include_path
219 * @var boolean
221 public $use_include_path = false;
223 * template directory
225 * @var array
227 private $template_dir = array();
229 * joined template directory string used in cache keys
231 * @var string
233 public $joined_template_dir = null;
235 * joined config directory string used in cache keys
237 * @var string
239 public $joined_config_dir = null;
241 * default template handler
243 * @var callable
245 public $default_template_handler_func = null;
247 * default config handler
249 * @var callable
251 public $default_config_handler_func = null;
253 * default plugin handler
255 * @var callable
257 public $default_plugin_handler_func = null;
259 * compile directory
261 * @var string
263 private $compile_dir = null;
265 * plugins directory
267 * @var array
269 private $plugins_dir = array();
271 * cache directory
273 * @var string
275 private $cache_dir = null;
277 * config directory
279 * @var array
281 private $config_dir = array();
283 * force template compiling?
285 * @var boolean
287 public $force_compile = false;
289 * check template for modifications?
291 * @var boolean
293 public $compile_check = true;
295 * use sub dirs for compiled/cached files?
297 * @var boolean
299 public $use_sub_dirs = false;
301 * allow ambiguous resources (that are made unique by the resource handler)
303 * @var boolean
305 public $allow_ambiguous_resources = false;
307 * caching enabled
309 * @var boolean
311 public $caching = false;
313 * merge compiled includes
315 * @var boolean
317 public $merge_compiled_includes = false;
319 * template inheritance merge compiled includes
321 * @var boolean
323 public $inheritance_merge_compiled_includes = true;
325 * cache lifetime in seconds
327 * @var integer
329 public $cache_lifetime = 3600;
331 * force cache file creation
333 * @var boolean
335 public $force_cache = false;
337 * Set this if you want different sets of cache files for the same
338 * templates.
340 * @var string
342 public $cache_id = null;
344 * Set this if you want different sets of compiled files for the same
345 * templates.
347 * @var string
349 public $compile_id = null;
351 * template left-delimiter
353 * @var string
355 public $left_delimiter = "{";
357 * template right-delimiter
359 * @var string
361 public $right_delimiter = "}";
362 /**#@+
363 * security
366 * class name
367 * This should be instance of Smarty_Security.
369 * @var string
370 * @see Smarty_Security
372 public $security_class = 'Smarty_Security';
374 * implementation of security class
376 * @var Smarty_Security
378 public $security_policy = null;
380 * controls handling of PHP-blocks
382 * @var integer
384 public $php_handling = self::PHP_PASSTHRU;
386 * controls if the php template file resource is allowed
388 * @var bool
390 public $allow_php_templates = false;
392 * Should compiled-templates be prevented from being called directly?
393 * {@internal
394 * Currently used by Smarty_Internal_Template only.
395 * }}
397 * @var boolean
399 public $direct_access_security = true;
400 /**#@-*/
402 * debug mode
403 * Setting this to true enables the debug-console.
405 * @var boolean
407 public $debugging = false;
409 * This determines if debugging is enable-able from the browser.
410 * <ul>
411 * <li>NONE => no debugging control allowed</li>
412 * <li>URL => enable debugging when SMARTY_DEBUG is found in the URL.</li>
413 * </ul>
415 * @var string
417 public $debugging_ctrl = 'NONE';
419 * Name of debugging URL-param.
420 * Only used when $debugging_ctrl is set to 'URL'.
421 * The name of the URL-parameter that activates debugging.
423 * @var type
425 public $smarty_debug_id = 'SMARTY_DEBUG';
427 * Path of debug template.
429 * @var string
431 public $debug_tpl = null;
433 * When set, smarty uses this value as error_reporting-level.
435 * @var int
437 public $error_reporting = null;
439 * Internal flag for getTags()
441 * @var boolean
443 public $get_used_tags = false;
445 /**#@+
446 * config var settings
450 * Controls whether variables with the same name overwrite each other.
452 * @var boolean
454 public $config_overwrite = true;
456 * Controls whether config values of on/true/yes and off/false/no get converted to boolean.
458 * @var boolean
460 public $config_booleanize = true;
462 * Controls whether hidden config sections/vars are read from the file.
464 * @var boolean
466 public $config_read_hidden = false;
468 /**#@-*/
470 /**#@+
471 * resource locking
475 * locking concurrent compiles
477 * @var boolean
479 public $compile_locking = true;
481 * Controls whether cache resources should emply locking mechanism
483 * @var boolean
485 public $cache_locking = false;
487 * seconds to wait for acquiring a lock before ignoring the write lock
489 * @var float
491 public $locking_timeout = 10;
493 /**#@-*/
496 * global template functions
498 * @var array
500 public $template_functions = array();
502 * resource type used if none given
503 * Must be an valid key of $registered_resources.
505 * @var string
507 public $default_resource_type = 'file';
509 * caching type
510 * Must be an element of $cache_resource_types.
512 * @var string
514 public $caching_type = 'file';
516 * internal config properties
518 * @var array
520 public $properties = array();
522 * config type
524 * @var string
526 public $default_config_type = 'file';
528 * cached template objects
530 * @var array
532 public $template_objects = array();
534 * check If-Modified-Since headers
536 * @var boolean
538 public $cache_modified_check = false;
540 * registered plugins
542 * @var array
544 public $registered_plugins = array();
546 * plugin search order
548 * @var array
550 public $plugin_search_order = array('function', 'block', 'compiler', 'class');
552 * registered objects
554 * @var array
556 public $registered_objects = array();
558 * registered classes
560 * @var array
562 public $registered_classes = array();
564 * registered filters
566 * @var array
568 public $registered_filters = array();
570 * registered resources
572 * @var array
574 public $registered_resources = array();
576 * resource handler cache
578 * @var array
580 public $_resource_handlers = array();
582 * registered cache resources
584 * @var array
586 public $registered_cache_resources = array();
588 * cache resource handler cache
590 * @var array
592 public $_cacheresource_handlers = array();
594 * autoload filter
596 * @var array
598 public $autoload_filters = array();
600 * default modifier
602 * @var array
604 public $default_modifiers = array();
606 * autoescape variable output
608 * @var boolean
610 public $escape_html = false;
612 * global internal smarty vars
614 * @var array
616 public static $_smarty_vars = array();
618 * start time for execution time calculation
620 * @var int
622 public $start_time = 0;
624 * default file permissions
626 * @var int
628 public $_file_perms = 0644;
630 * default dir permissions
632 * @var int
634 public $_dir_perms = 0771;
636 * block tag hierarchy
638 * @var array
640 public $_tag_stack = array();
642 * self pointer to Smarty object
644 * @var Smarty
646 public $smarty;
648 * required by the compiler for BC
650 * @var string
652 public $_current_file = null;
654 * internal flag to enable parser debugging
656 * @var bool
658 public $_parserdebug = false;
660 * Saved parameter of merged templates during compilation
662 * @var array
664 public $merged_templates_func = array();
665 /**#@-*/
668 * Initialize new Smarty object
671 public function __construct()
673 // selfpointer needed by some other class methods
674 $this->smarty = $this;
675 if (is_callable('mb_internal_encoding')) {
676 mb_internal_encoding(Smarty::$_CHARSET);
678 $this->start_time = microtime(true);
679 // set default dirs
680 $this->setTemplateDir('.' . DS . 'templates' . DS)
681 ->setCompileDir('.' . DS . 'templates_c' . DS)
682 ->setPluginsDir(SMARTY_PLUGINS_DIR)
683 ->setCacheDir('.' . DS . 'cache' . DS)
684 ->setConfigDir('.' . DS . 'configs' . DS);
686 $this->debug_tpl = 'file:' . dirname(__FILE__) . '/debug.tpl';
687 if (isset($_SERVER['SCRIPT_NAME'])) {
688 $this->assignGlobal('SCRIPT_NAME', $_SERVER['SCRIPT_NAME']);
693 * Class destructor
695 public function __destruct()
697 // intentionally left blank
701 * <<magic>> set selfpointer on cloned object
703 public function __clone()
705 $this->smarty = $this;
709 * <<magic>> Generic getter.
710 * Calls the appropriate getter function.
711 * Issues an E_USER_NOTICE if no valid getter is found.
713 * @param string $name property name
715 * @return mixed
717 public function __get($name)
719 $allowed = array(
720 'template_dir' => 'getTemplateDir',
721 'config_dir' => 'getConfigDir',
722 'plugins_dir' => 'getPluginsDir',
723 'compile_dir' => 'getCompileDir',
724 'cache_dir' => 'getCacheDir',
727 if (isset($allowed[$name])) {
728 return $this->{$allowed[$name]}();
729 } else {
730 trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE);
735 * <<magic>> Generic setter.
736 * Calls the appropriate setter function.
737 * Issues an E_USER_NOTICE if no valid setter is found.
739 * @param string $name property name
740 * @param mixed $value parameter passed to setter
742 public function __set($name, $value)
744 $allowed = array(
745 'template_dir' => 'setTemplateDir',
746 'config_dir' => 'setConfigDir',
747 'plugins_dir' => 'setPluginsDir',
748 'compile_dir' => 'setCompileDir',
749 'cache_dir' => 'setCacheDir',
752 if (isset($allowed[$name])) {
753 $this->{$allowed[$name]}($value);
754 } else {
755 trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE);
760 * Check if a template resource exists
762 * @param string $resource_name template name
764 * @return boolean status
766 public function templateExists($resource_name)
768 // create template object
769 $save = $this->template_objects;
770 $tpl = new $this->template_class($resource_name, $this);
771 // check if it does exists
772 $result = $tpl->source->exists;
773 $this->template_objects = $save;
775 return $result;
779 * Returns a single or all global variables
781 * @param string $varname variable name or null
783 * @return string variable value or or array of variables
785 public function getGlobal($varname = null)
787 if (isset($varname)) {
788 if (isset(self::$global_tpl_vars[$varname])) {
789 return self::$global_tpl_vars[$varname]->value;
790 } else {
791 return '';
793 } else {
794 $_result = array();
795 foreach (self::$global_tpl_vars AS $key => $var) {
796 $_result[$key] = $var->value;
799 return $_result;
804 * Empty cache folder
806 * @param integer $exp_time expiration time
807 * @param string $type resource type
809 * @return integer number of cache files deleted
811 public function clearAllCache($exp_time = null, $type = null)
813 // load cache resource and call clearAll
814 $_cache_resource = Smarty_CacheResource::load($this, $type);
815 Smarty_CacheResource::invalidLoadedCache($this);
817 return $_cache_resource->clearAll($this, $exp_time);
821 * Empty cache for a specific template
823 * @param string $template_name template name
824 * @param string $cache_id cache id
825 * @param string $compile_id compile id
826 * @param integer $exp_time expiration time
827 * @param string $type resource type
829 * @return integer number of cache files deleted
831 public function clearCache($template_name, $cache_id = null, $compile_id = null, $exp_time = null, $type = null)
833 // load cache resource and call clear
834 $_cache_resource = Smarty_CacheResource::load($this, $type);
835 Smarty_CacheResource::invalidLoadedCache($this);
837 return $_cache_resource->clear($this, $template_name, $cache_id, $compile_id, $exp_time);
841 * Loads security class and enables security
843 * @param string|Smarty_Security $security_class if a string is used, it must be class-name
845 * @return Smarty current Smarty instance for chaining
846 * @throws SmartyException when an invalid class name is provided
848 public function enableSecurity($security_class = null)
850 if ($security_class instanceof Smarty_Security) {
851 $this->security_policy = $security_class;
853 return $this;
854 } elseif (is_object($security_class)) {
855 throw new SmartyException("Class '" . get_class($security_class) . "' must extend Smarty_Security.");
857 if ($security_class == null) {
858 $security_class = $this->security_class;
860 if (!class_exists($security_class)) {
861 throw new SmartyException("Security class '$security_class' is not defined");
862 } elseif ($security_class !== 'Smarty_Security' && !is_subclass_of($security_class, 'Smarty_Security')) {
863 throw new SmartyException("Class '$security_class' must extend Smarty_Security.");
864 } else {
865 $this->security_policy = new $security_class($this);
868 return $this;
872 * Disable security
874 * @return Smarty current Smarty instance for chaining
876 public function disableSecurity()
878 $this->security_policy = null;
880 return $this;
884 * Set template directory
886 * @param string|array $template_dir directory(s) of template sources
888 * @return Smarty current Smarty instance for chaining
890 public function setTemplateDir($template_dir)
892 $this->template_dir = array();
893 foreach ((array) $template_dir as $k => $v) {
894 $this->template_dir[$k] = preg_replace('#(\w+)(/|\\\\){1,}#', '$1$2', rtrim($v, '/\\')) . DS;
897 $this->joined_template_dir = join(DIRECTORY_SEPARATOR, $this->template_dir);
899 return $this;
903 * Add template directory(s)
905 * @param string|array $template_dir directory(s) of template sources
906 * @param string $key of the array element to assign the template dir to
908 * @return Smarty current Smarty instance for chaining
909 * @throws SmartyException when the given template directory is not valid
911 public function addTemplateDir($template_dir, $key = null)
913 // make sure we're dealing with an array
914 $this->template_dir = (array) $this->template_dir;
916 if (is_array($template_dir)) {
917 foreach ($template_dir as $k => $v) {
918 $v = preg_replace('#(\w+)(/|\\\\){1,}#', '$1$2', rtrim($v, '/\\')) . DS;
919 if (is_int($k)) {
920 // indexes are not merged but appended
921 $this->template_dir[] = $v;
922 } else {
923 // string indexes are overridden
924 $this->template_dir[$k] = $v;
927 } else {
928 $v = preg_replace('#(\w+)(/|\\\\){1,}#', '$1$2', rtrim($template_dir, '/\\')) . DS;
929 if ($key !== null) {
930 // override directory at specified index
931 $this->template_dir[$key] = $v;
932 } else {
933 // append new directory
934 $this->template_dir[] = $v;
937 $this->joined_template_dir = join(DIRECTORY_SEPARATOR, $this->template_dir);
939 return $this;
943 * Get template directories
945 * @param mixed $index index of directory to get, null to get all
947 * @return array|string list of template directories, or directory of $index
949 public function getTemplateDir($index = null)
951 if ($index !== null) {
952 return isset($this->template_dir[$index]) ? $this->template_dir[$index] : null;
955 return (array) $this->template_dir;
959 * Set config directory
961 * @param $config_dir
963 * @return Smarty current Smarty instance for chaining
965 public function setConfigDir($config_dir)
967 $this->config_dir = array();
968 foreach ((array) $config_dir as $k => $v) {
969 $this->config_dir[$k] = preg_replace('#(\w+)(/|\\\\){1,}#', '$1$2', rtrim($v, '/\\')) . DS;
972 $this->joined_config_dir = join(DIRECTORY_SEPARATOR, $this->config_dir);
974 return $this;
978 * Add config directory(s)
980 * @param string|array $config_dir directory(s) of config sources
981 * @param mixed $key key of the array element to assign the config dir to
983 * @return Smarty current Smarty instance for chaining
985 public function addConfigDir($config_dir, $key = null)
987 // make sure we're dealing with an array
988 $this->config_dir = (array) $this->config_dir;
990 if (is_array($config_dir)) {
991 foreach ($config_dir as $k => $v) {
992 $v = preg_replace('#(\w+)(/|\\\\){1,}#', '$1$2', rtrim($v, '/\\')) . DS;
993 if (is_int($k)) {
994 // indexes are not merged but appended
995 $this->config_dir[] = $v;
996 } else {
997 // string indexes are overridden
998 $this->config_dir[$k] = $v;
1001 } else {
1002 $v = preg_replace('#(\w+)(/|\\\\){1,}#', '$1$2', rtrim($config_dir, '/\\')) . DS;
1003 if ($key !== null) {
1004 // override directory at specified index
1005 $this->config_dir[$key] = rtrim($v, '/\\') . DS;
1006 } else {
1007 // append new directory
1008 $this->config_dir[] = rtrim($v, '/\\') . DS;
1012 $this->joined_config_dir = join(DIRECTORY_SEPARATOR, $this->config_dir);
1014 return $this;
1018 * Get config directory
1020 * @param mixed $index index of directory to get, null to get all
1022 * @return array|string configuration directory
1024 public function getConfigDir($index = null)
1026 if ($index !== null) {
1027 return isset($this->config_dir[$index]) ? $this->config_dir[$index] : null;
1030 return (array) $this->config_dir;
1034 * Set plugins directory
1036 * @param string|array $plugins_dir directory(s) of plugins
1038 * @return Smarty current Smarty instance for chaining
1040 public function setPluginsDir($plugins_dir)
1042 $this->plugins_dir = array();
1043 foreach ((array) $plugins_dir as $k => $v) {
1044 $this->plugins_dir[$k] = rtrim($v, '/\\') . DS;
1047 return $this;
1051 * Adds directory of plugin files
1053 * @param $plugins_dir
1055 * @return Smarty current Smarty instance for chaining
1057 public function addPluginsDir($plugins_dir)
1059 // make sure we're dealing with an array
1060 $this->plugins_dir = (array) $this->plugins_dir;
1062 if (is_array($plugins_dir)) {
1063 foreach ($plugins_dir as $k => $v) {
1064 if (is_int($k)) {
1065 // indexes are not merged but appended
1066 $this->plugins_dir[] = rtrim($v, '/\\') . DS;
1067 } else {
1068 // string indexes are overridden
1069 $this->plugins_dir[$k] = rtrim($v, '/\\') . DS;
1072 } else {
1073 // append new directory
1074 $this->plugins_dir[] = rtrim($plugins_dir, '/\\') . DS;
1077 $this->plugins_dir = array_unique($this->plugins_dir);
1079 return $this;
1083 * Get plugin directories
1085 * @return array list of plugin directories
1087 public function getPluginsDir()
1089 return (array) $this->plugins_dir;
1093 * Set compile directory
1095 * @param string $compile_dir directory to store compiled templates in
1097 * @return Smarty current Smarty instance for chaining
1099 public function setCompileDir($compile_dir)
1101 $this->compile_dir = rtrim($compile_dir, '/\\') . DS;
1102 if (!isset(Smarty::$_muted_directories[$this->compile_dir])) {
1103 Smarty::$_muted_directories[$this->compile_dir] = null;
1106 return $this;
1110 * Get compiled directory
1112 * @return string path to compiled templates
1114 public function getCompileDir()
1116 return $this->compile_dir;
1120 * Set cache directory
1122 * @param string $cache_dir directory to store cached templates in
1124 * @return Smarty current Smarty instance for chaining
1126 public function setCacheDir($cache_dir)
1128 $this->cache_dir = rtrim($cache_dir, '/\\') . DS;
1129 if (!isset(Smarty::$_muted_directories[$this->cache_dir])) {
1130 Smarty::$_muted_directories[$this->cache_dir] = null;
1133 return $this;
1137 * Get cache directory
1139 * @return string path of cache directory
1141 public function getCacheDir()
1143 return $this->cache_dir;
1147 * Set default modifiers
1149 * @param array|string $modifiers modifier or list of modifiers to set
1151 * @return Smarty current Smarty instance for chaining
1153 public function setDefaultModifiers($modifiers)
1155 $this->default_modifiers = (array) $modifiers;
1157 return $this;
1161 * Add default modifiers
1163 * @param array|string $modifiers modifier or list of modifiers to add
1165 * @return Smarty current Smarty instance for chaining
1167 public function addDefaultModifiers($modifiers)
1169 if (is_array($modifiers)) {
1170 $this->default_modifiers = array_merge($this->default_modifiers, $modifiers);
1171 } else {
1172 $this->default_modifiers[] = $modifiers;
1175 return $this;
1179 * Get default modifiers
1181 * @return array list of default modifiers
1183 public function getDefaultModifiers()
1185 return $this->default_modifiers;
1189 * Set autoload filters
1191 * @param array $filters filters to load automatically
1192 * @param string $type "pre", "output", … specify the filter type to set. Defaults to none treating $filters' keys as the appropriate types
1194 * @return Smarty current Smarty instance for chaining
1196 public function setAutoloadFilters($filters, $type = null)
1198 if ($type !== null) {
1199 $this->autoload_filters[$type] = (array) $filters;
1200 } else {
1201 $this->autoload_filters = (array) $filters;
1204 return $this;
1208 * Add autoload filters
1210 * @param array $filters filters to load automatically
1211 * @param string $type "pre", "output", … specify the filter type to set. Defaults to none treating $filters' keys as the appropriate types
1213 * @return Smarty current Smarty instance for chaining
1215 public function addAutoloadFilters($filters, $type = null)
1217 if ($type !== null) {
1218 if (!empty($this->autoload_filters[$type])) {
1219 $this->autoload_filters[$type] = array_merge($this->autoload_filters[$type], (array) $filters);
1220 } else {
1221 $this->autoload_filters[$type] = (array) $filters;
1223 } else {
1224 foreach ((array) $filters as $key => $value) {
1225 if (!empty($this->autoload_filters[$key])) {
1226 $this->autoload_filters[$key] = array_merge($this->autoload_filters[$key], (array) $value);
1227 } else {
1228 $this->autoload_filters[$key] = (array) $value;
1233 return $this;
1237 * Get autoload filters
1239 * @param string $type type of filter to get autoloads for. Defaults to all autoload filters
1241 * @return array array( 'type1' => array( 'filter1', 'filter2', … ) ) or array( 'filter1', 'filter2', …) if $type was specified
1243 public function getAutoloadFilters($type = null)
1245 if ($type !== null) {
1246 return isset($this->autoload_filters[$type]) ? $this->autoload_filters[$type] : array();
1249 return $this->autoload_filters;
1253 * return name of debugging template
1255 * @return string
1257 public function getDebugTemplate()
1259 return $this->debug_tpl;
1263 * set the debug template
1265 * @param string $tpl_name
1267 * @return Smarty current Smarty instance for chaining
1268 * @throws SmartyException if file is not readable
1270 public function setDebugTemplate($tpl_name)
1272 if (!is_readable($tpl_name)) {
1273 throw new SmartyException("Unknown file '{$tpl_name}'");
1275 $this->debug_tpl = $tpl_name;
1277 return $this;
1281 * creates a template object
1283 * @param string $template the resource handle of the template file
1284 * @param mixed $cache_id cache id to be used with this template
1285 * @param mixed $compile_id compile id to be used with this template
1286 * @param object $parent next higher level of Smarty variables
1287 * @param boolean $do_clone flag is Smarty object shall be cloned
1289 * @return object template object
1291 public function createTemplate($template, $cache_id = null, $compile_id = null, $parent = null, $do_clone = true)
1293 if ($cache_id !== null && (is_object($cache_id) || is_array($cache_id))) {
1294 $parent = $cache_id;
1295 $cache_id = null;
1297 if ($parent !== null && is_array($parent)) {
1298 $data = $parent;
1299 $parent = null;
1300 } else {
1301 $data = null;
1303 // default to cache_id and compile_id of Smarty object
1304 $cache_id = $cache_id === null ? $this->cache_id : $cache_id;
1305 $compile_id = $compile_id === null ? $this->compile_id : $compile_id;
1306 // already in template cache?
1307 if ($this->allow_ambiguous_resources) {
1308 $_templateId = Smarty_Resource::getUniqueTemplateName($this, $template) . $cache_id . $compile_id;
1309 } else {
1310 $_templateId = $this->joined_template_dir . '#' . $template . $cache_id . $compile_id;
1312 if (isset($_templateId[150])) {
1313 $_templateId = sha1($_templateId);
1315 if ($do_clone) {
1316 if (isset($this->template_objects[$_templateId])) {
1317 // return cached template object
1318 $tpl = clone $this->template_objects[$_templateId];
1319 $tpl->smarty = clone $tpl->smarty;
1320 $tpl->parent = $parent;
1321 $tpl->tpl_vars = array();
1322 $tpl->config_vars = array();
1323 } else {
1324 $tpl = new $this->template_class($template, clone $this, $parent, $cache_id, $compile_id);
1326 } else {
1327 if (isset($this->template_objects[$_templateId])) {
1328 // return cached template object
1329 $tpl = $this->template_objects[$_templateId];
1330 $tpl->parent = $parent;
1331 $tpl->tpl_vars = array();
1332 $tpl->config_vars = array();
1333 } else {
1334 $tpl = new $this->template_class($template, $this, $parent, $cache_id, $compile_id);
1337 // fill data if present
1338 if (!empty($data) && is_array($data)) {
1339 // set up variable values
1340 foreach ($data as $_key => $_val) {
1341 $tpl->tpl_vars[$_key] = new Smarty_variable($_val);
1345 return $tpl;
1349 * Takes unknown classes and loads plugin files for them
1350 * class name format: Smarty_PluginType_PluginName
1351 * plugin filename format: plugintype.pluginname.php
1353 * @param string $plugin_name class plugin name to load
1354 * @param bool $check check if already loaded
1356 * @throws SmartyException
1357 * @return string |boolean filepath of loaded file or false
1359 public function loadPlugin($plugin_name, $check = true)
1361 // if function or class exists, exit silently (already loaded)
1362 if ($check && (is_callable($plugin_name) || class_exists($plugin_name, false))) {
1363 return true;
1365 // Plugin name is expected to be: Smarty_[Type]_[Name]
1366 $_name_parts = explode('_', $plugin_name, 3);
1367 // class name must have three parts to be valid plugin
1368 // count($_name_parts) < 3 === !isset($_name_parts[2])
1369 if (!isset($_name_parts[2]) || strtolower($_name_parts[0]) !== 'smarty') {
1370 throw new SmartyException("plugin {$plugin_name} is not a valid name format");
1372 // if type is "internal", get plugin from sysplugins
1373 if (strtolower($_name_parts[1]) == 'internal') {
1374 $file = SMARTY_SYSPLUGINS_DIR . strtolower($plugin_name) . '.php';
1375 if (file_exists($file)) {
1376 require_once($file);
1378 return $file;
1379 } else {
1380 return false;
1383 // plugin filename is expected to be: [type].[name].php
1384 $_plugin_filename = "{$_name_parts[1]}.{$_name_parts[2]}.php";
1386 $_stream_resolve_include_path = function_exists('stream_resolve_include_path');
1388 // loop through plugin dirs and find the plugin
1389 foreach ($this->getPluginsDir() as $_plugin_dir) {
1390 $names = array(
1391 $_plugin_dir . $_plugin_filename,
1392 $_plugin_dir . strtolower($_plugin_filename),
1394 foreach ($names as $file) {
1395 if (file_exists($file)) {
1396 require_once($file);
1398 return $file;
1400 if ($this->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_plugin_dir)) {
1401 // try PHP include_path
1402 if ($_stream_resolve_include_path) {
1403 $file = stream_resolve_include_path($file);
1404 } else {
1405 $file = Smarty_Internal_Get_Include_Path::getIncludePath($file);
1408 if ($file !== false) {
1409 require_once($file);
1411 return $file;
1416 // no plugin loaded
1417 return false;
1421 * Compile all template files
1423 * @param string $extension file extension
1424 * @param bool $force_compile force all to recompile
1425 * @param int $time_limit
1426 * @param int $max_errors
1428 * @return integer number of template files recompiled
1430 public function compileAllTemplates($extension = '.tpl', $force_compile = false, $time_limit = 0, $max_errors = null)
1432 return Smarty_Internal_Utility::compileAllTemplates($extension, $force_compile, $time_limit, $max_errors, $this);
1436 * Compile all config files
1438 * @param string $extension file extension
1439 * @param bool $force_compile force all to recompile
1440 * @param int $time_limit
1441 * @param int $max_errors
1443 * @return integer number of template files recompiled
1445 public function compileAllConfig($extension = '.conf', $force_compile = false, $time_limit = 0, $max_errors = null)
1447 return Smarty_Internal_Utility::compileAllConfig($extension, $force_compile, $time_limit, $max_errors, $this);
1451 * Delete compiled template file
1453 * @param string $resource_name template name
1454 * @param string $compile_id compile id
1455 * @param integer $exp_time expiration time
1457 * @return integer number of template files deleted
1459 public function clearCompiledTemplate($resource_name = null, $compile_id = null, $exp_time = null)
1461 return Smarty_Internal_Utility::clearCompiledTemplate($resource_name, $compile_id, $exp_time, $this);
1465 * Return array of tag/attributes of all tags used by an template
1467 * @param Smarty_Internal_Template $template
1469 * @return array of tag/attributes
1471 public function getTags(Smarty_Internal_Template $template)
1473 return Smarty_Internal_Utility::getTags($template);
1477 * Run installation test
1479 * @param array $errors Array to write errors into, rather than outputting them
1481 * @return boolean true if setup is fine, false if something is wrong
1483 public function testInstall(&$errors = null)
1485 return Smarty_Internal_Utility::testInstall($this, $errors);
1489 * Error Handler to mute expected messages
1491 * @link http://php.net/set_error_handler
1493 * @param integer $errno Error level
1494 * @param $errstr
1495 * @param $errfile
1496 * @param $errline
1497 * @param $errcontext
1499 * @return boolean
1501 public static function mutingErrorHandler($errno, $errstr, $errfile, $errline, $errcontext)
1503 $_is_muted_directory = false;
1505 // add the SMARTY_DIR to the list of muted directories
1506 if (!isset(Smarty::$_muted_directories[SMARTY_DIR])) {
1507 $smarty_dir = realpath(SMARTY_DIR);
1508 if ($smarty_dir !== false) {
1509 Smarty::$_muted_directories[SMARTY_DIR] = array(
1510 'file' => $smarty_dir,
1511 'length' => strlen($smarty_dir),
1516 // walk the muted directories and test against $errfile
1517 foreach (Smarty::$_muted_directories as $key => &$dir) {
1518 if (!$dir) {
1519 // resolve directory and length for speedy comparisons
1520 $file = realpath($key);
1521 if ($file === false) {
1522 // this directory does not exist, remove and skip it
1523 unset(Smarty::$_muted_directories[$key]);
1524 continue;
1526 $dir = array(
1527 'file' => $file,
1528 'length' => strlen($file),
1531 if (!strncmp($errfile, $dir['file'], $dir['length'])) {
1532 $_is_muted_directory = true;
1533 break;
1537 // pass to next error handler if this error did not occur inside SMARTY_DIR
1538 // or the error was within smarty but masked to be ignored
1539 if (!$_is_muted_directory || ($errno && $errno & error_reporting())) {
1540 if (Smarty::$_previous_error_handler) {
1541 return call_user_func(Smarty::$_previous_error_handler, $errno, $errstr, $errfile, $errline, $errcontext);
1542 } else {
1543 return false;
1549 * Enable error handler to mute expected messages
1551 * @return void
1553 public static function muteExpectedErrors()
1556 error muting is done because some people implemented custom error_handlers using
1557 http://php.net/set_error_handler and for some reason did not understand the following paragraph:
1559 It is important to remember that the standard PHP error handler is completely bypassed for the
1560 error types specified by error_types unless the callback function returns FALSE.
1561 error_reporting() settings will have no effect and your error handler will be called regardless -
1562 however you are still able to read the current value of error_reporting and act appropriately.
1563 Of particular note is that this value will be 0 if the statement that caused the error was
1564 prepended by the @ error-control operator.
1566 Smarty deliberately uses @filemtime() over file_exists() and filemtime() in some places. Reasons include
1567 - @filemtime() is almost twice as fast as using an additional file_exists()
1568 - between file_exists() and filemtime() a possible race condition is opened,
1569 which does not exist using the simple @filemtime() approach.
1571 $error_handler = array('Smarty', 'mutingErrorHandler');
1572 $previous = set_error_handler($error_handler);
1574 // avoid dead loops
1575 if ($previous !== $error_handler) {
1576 Smarty::$_previous_error_handler = $previous;
1581 * Disable error handler muting expected messages
1583 * @return void
1585 public static function unmuteExpectedErrors()
1587 restore_error_handler();
1591 // Check if we're running on windows
1592 Smarty::$_IS_WINDOWS = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
1594 // let PCRE (preg_*) treat strings as ISO-8859-1 if we're not dealing with UTF-8
1595 if (Smarty::$_CHARSET !== 'UTF-8') {
1596 Smarty::$_UTF8_MODIFIER = '';
1600 * Smarty exception class
1602 * @package Smarty
1604 class SmartyException extends Exception
1606 public static $escape = false;
1608 public function __toString()
1610 return ' --> Smarty: ' . (self::$escape ? htmlentities($this->message) : $this->message) . ' <-- ';
1615 * Smarty compiler exception class
1617 * @package Smarty
1619 class SmartyCompilerException extends SmartyException
1621 public function __toString()
1623 return ' --> Smarty Compiler: ' . $this->message . ' <-- ';
1627 * The line number of the template error
1629 * @type int|null
1631 public $line = null;
1633 * The template source snippet relating to the error
1635 * @type string|null
1637 public $source = null;
1639 * The raw text of the error message
1641 * @type string|null
1643 public $desc = null;
1645 * The resource identifier or template name
1647 * @type string|null
1649 public $template = null;
1653 * Autoloader
1655 function smartyAutoload($class)
1657 $_class = strtolower($class);
1658 static $_classes = array(
1659 'smarty_config_source' => true,
1660 'smarty_config_compiled' => true,
1661 'smarty_security' => true,
1662 'smarty_cacheresource' => true,
1663 'smarty_cacheresource_custom' => true,
1664 'smarty_cacheresource_keyvaluestore' => true,
1665 'smarty_resource' => true,
1666 'smarty_resource_custom' => true,
1667 'smarty_resource_uncompiled' => true,
1668 'smarty_resource_recompiled' => true,
1671 if (!strncmp($_class, 'smarty_internal_', 16) || isset($_classes[$_class])) {
1672 include SMARTY_SYSPLUGINS_DIR . $_class . '.php';