PluginProbe
Smart Forms – when you need more than just a contact form / trunk
Smart Forms – when you need more than just a contact form vtrunk
trunk 0.5 0.5.5 0.6 0.7 0.8 0.8.5 0.9.1
smart-forms / php_classes / smarty / Smarty.class.php

Smarty.class.php in Smart Forms – when you need more than just a contact form trunk, at php_classes/smarty/Smarty.class.php

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