]> git.vanrenterghem.biz Git - www.vanrenterghem.biz.git/blob - phpBB2/includes/template.php
Baseline
[www.vanrenterghem.biz.git] / phpBB2 / includes / template.php
1 <?php\r
2 \r
3 /***************************************************************************\r
4  *                               template.php\r
5  *                            ------------------\r
6  *   copyright            : (C) 2001 The phpBB Group\r
7  *   email                : support@phpbb.com\r
8  *\r
9  *   phpBB version        : 2.0.x\r
10  *   eXtreme Styles mod   : 2.3.1\r
11  *   Support              : http://www.phpbbstyles.com\r
12  *\r
13  *   file revision        : 77\r
14  *   project revision     : 78\r
15  *   last modified        : 05 Dec 2005  13:54:54\r
16  *\r
17  ***************************************************************************/\r
18 \r
19 /***************************************************************************\r
20  *\r
21  *   This program is free software; you can redistribute it and/or modify\r
22  *   it under the terms of the GNU General Public License as published by\r
23  *   the Free Software Foundation; either version 2 of the License, or\r
24  *   (at your option) any later version.\r
25  *\r
26  ***************************************************************************/\r
27 \r
28 /**\r
29  *\r
30  * Template class. By Nathan Codding of the phpBB group.\r
31  * The interface was originally inspired by PHPLib templates,\r
32  * and the template file formats are quite similar.\r
33  *\r
34  * eXtreme Styles mod by CyberAlien.\r
35  *\r
36  * IF, ELSEIF, ENDIF tags are backported from phpBB 2.2\r
37  *\r
38  * Documentation for this mod can be found here:\r
39  * http://www.phpbbstyles.com\r
40  *\r
41  * Support for eXtreme Styles mod is provided at http://www.phpbbstyles.com\r
42  *\r
43  * Thanks to DMaJ007 for idea on how to include some extra tags.\r
44  *\r
45  */\r
46 \r
47 define('XS_SEPARATOR', '.');\r
48 define('XS_DIR_CACHE', 'cache');\r
49 define('XS_USE_ISSET', '1');\r
50 \r
51 // cache filenames prefix\r
52 define('XS_TPL_PREFIX', 'tpl_');\r
53 define('XS_TPL_PREFIX2', 'tpl2_');\r
54 \r
55 // templates directory\r
56 define('XS_TPL_START', 'templates/');\r
57 define('XS_TPL_ANY', '/templates/');\r
58 \r
59 // internal xs mod definitions. do not edit.\r
60 define('XS_TAG_NONE', 0);\r
61 define('XS_TAG_PHP', 1);\r
62 define('XS_TAG_BEGIN', 2);\r
63 define('XS_TAG_END', 3);\r
64 define('XS_TAG_INCLUDE', 4);\r
65 define('XS_TAG_IF', 5);\r
66 define('XS_TAG_ELSE', 6);\r
67 define('XS_TAG_ELSEIF', 7);\r
68 define('XS_TAG_ENDIF', 8);\r
69 define('XS_TAG_DEFINE', 9);\r
70 define('XS_TAG_UNDEFINE', 10);\r
71 define('XS_TAG_BEGINELSE', 11);\r
72 \r
73 \r
74 class Template {\r
75         var $classname = "Template";\r
76 \r
77         // variable that holds all the data we'll be substituting into\r
78         // the compiled templates.\r
79         // ...\r
80         // This will end up being a multi-dimensional array like this:\r
81         // $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value\r
82         // if it's a root-level variable, it'll be like this:\r
83         // $this->vars[varname] == value  or  $this->_tpldata['.'][0][varname] == value\r
84         // array "vars" is added for easier access to data\r
85         var $_tpldata = array('.' => array(0 => array()));\r
86         var $vars;\r
87 \r
88         // Hash of filenames for each template handle.\r
89         var $files = array();\r
90         var $files_cache = array(); // array of cache files that exists\r
91         var $files_cache2 = array(); // array of cache files (exists or not exists)\r
92 \r
93         // Root template directory.\r
94         var $root = '';\r
95 \r
96         // Cache directory (compatible with default cache mod)\r
97         var $cachedir = '';\r
98 \r
99         // Search/replace for unknown files\r
100         var $cache_search = array();\r
101         var $cache_replace = array();\r
102 \r
103         // Template root directory (generated by set_rootdir)\r
104         var $tpldir = '';\r
105         var $tpldir_len = 0;\r
106 \r
107         // Default template directory.\r
108         // If file for default template isn't found file from this template is used.\r
109         var $tpldef = 'subSilver';\r
110 \r
111         // this will hash handle names to the compiled code for that handle.\r
112         var $compiled_code = array();\r
113 \r
114         // This will hold the uncompiled code for that handle.\r
115         var $uncompiled_code = array();\r
116 \r
117         // Cache settings\r
118         var $use_cache = 1;\r
119         var $cache_writable = 1;\r
120 \r
121         // Auto-compile setting\r
122         var $auto_compile = 1;\r
123 \r
124         // Current template name\r
125         var $tpl = '';\r
126 \r
127         // List of replacements. tpl files in this list will be replaced with other tpl files\r
128         // according to configuration in xs.cfg\r
129         var $replace = array();\r
130 \r
131         // counter for include\r
132         var $include_count = 0;\r
133 \r
134         // php extension. will be replaced by $phpEx in Template() function unless you disable it there\r
135         var $php = 'php';\r
136 \r
137         // True if check switches\r
138         var $xs_check_switches = 1;\r
139 \r
140         // eXtreme Styles variables\r
141         var $xs_started = 0;\r
142         var $xs_version = 8; // number version. internal. do not change.\r
143         var $xs_versiontxt = '2.3.1'; // text version\r
144 \r
145         // These handles will be parsed if pparse() is executed.\r
146         // Can be used to automatically include header/footer if there is any content.\r
147         var $preparse = '';\r
148         var $postparse = '';\r
149 \r
150         // subtemplates mod detection\r
151         var $subtemplates = false;\r
152 \r
153         // style configuration\r
154         var $style_config = array();\r
155 \r
156         // list of switches that are known typos in some mods.\r
157         // when error checking is enabled these errors will be auto-fixed.\r
158         // format:\r
159         //  array(start_tag, end_tag)\r
160         var $bugs = array(\r
161                 // ezportal typo:\r
162                 array('fetchpost_row', 'fetch_post_row'),\r
163                 // mycalendar 2.2.7 typos:\r
164                 array('date_cell', 'date_cells'),\r
165                 array('date_row', 'date_rows'),\r
166                 // history mod typo:\r
167                 array('site_today', 'site_week'),\r
168                 );\r
169 \r
170         /**\r
171          * Constructor. Installs XS mod on first run or updates it and sets the root dir.\r
172          */\r
173         function Template($root = '.')\r
174         {\r
175                 // setting pointer "vars"\r
176                 $this->vars = &$this->_tpldata['.'][0];\r
177                 // load configuration\r
178                 $this->load_config($root, true);\r
179         }\r
180 \r
181         /**\r
182          * Load mod configuration\r
183          */\r
184         function load_config($root, $edit_db)\r
185         {\r
186                 global $board_config, $phpbb_root_path, $phpEx;\r
187                 // getting mod version from config and comparing with real data\r
188                 $ver = isset($board_config['xs_version']) ? $board_config['xs_version'] : 0;\r
189                 // check configuration\r
190                 // set config values if there aren't any\r
191                 $add = array();\r
192                 $del = array();\r
193                 $up = array();\r
194                 // list of outdated variables\r
195                 $outdated = array(\r
196                         'xs_versoin',   // was a typo in one of previous versions\r
197                         'xs_separator', // no longer used\r
198                         'xs_cache_dir_absolute',        // no longer used\r
199                         'xs_cache_dir', // no longer used\r
200                         'xs_use_isset', // no longer used\r
201                         );\r
202                 // list of default values\r
203                 $default = array(\r
204                         'xs_auto_compile'                       => 1,\r
205                         'xs_auto_recompile'                     => 1,\r
206                         'xs_use_cache'                          => 1,\r
207                         'xs_php'                                        => $phpEx,\r
208                         'xs_def_template'                       => 'subSilver',\r
209                         'xs_check_switches'                     => 1,\r
210                         'xs_warn_includes'                      => 1,\r
211                         'xs_add_comments'                       => 0,\r
212                         'xs_ftp_host'                           => '',\r
213                         'xs_ftp_login'                          => '',\r
214                         'xs_ftp_path'                           => '',\r
215                         'xs_downloads_count'            => '0',\r
216                         'xs_downloads_default'          => '0',\r
217                         'xs_shownav'                            => '1',\r
218                         'xs_template_time'                      => '0',\r
219                         );\r
220                 // checking if all variables exist\r
221                 foreach($default as $var => $value)\r
222                 {\r
223                         if(!isset($board_config[$var]))\r
224                         {\r
225                                 $board_config[$var] = $value;\r
226                                 $add[] = $var;\r
227                         }\r
228                 }\r
229                 // checking if there are any outdated variables that should be deleted\r
230                 for($i=0; $i<count($outdated); $i++)\r
231                 {\r
232                         if(isset($board_config[$outdated[$i]]))\r
233                         {\r
234                                 $del[] = $outdated[$i];\r
235                         }\r
236                 }\r
237                 if(!isset($board_config['xs_version']))\r
238                 {\r
239                         $board_config['xs_version'] = $this->xs_version;\r
240                         $add[] = 'xs_version';\r
241                 }\r
242                 elseif($board_config['xs_version'] != $this->xs_version)\r
243                 {\r
244                         $board_config['xs_version'] = $this->xs_version;\r
245                         $up[] = 'xs_version';\r
246                 }\r
247                 // check config\r
248                 if(!empty($board_config['xs_auto_recompile']))\r
249                 {\r
250                         if(!$board_config['xs_auto_compile'])\r
251                         {\r
252                                 $board_config['xs_auto_compile'] = 1;\r
253                                 if(!in_array('xs_auto_compile', $up) && !in_array('xs_auto_compile', $add))\r
254                                 {\r
255                                         $up[] = 'xs_auto_compile';\r
256                                 }\r
257                         }\r
258                 }\r
259                 // install/upgrade\r
260                 if($edit_db && ((count($add) > 0) || (count($up) > 0) || (count($del) > 0)))\r
261                 {\r
262                         $board_config['xs_template_time'] = time();\r
263                         if(!in_array('xs_template_time', $up))\r
264                         {\r
265                                 $up[] = 'xs_template_time';\r
266                         }\r
267                         global $db;\r
268                         if(!empty($db))\r
269                         {\r
270                                 // adding new config values\r
271                                 for($i=0; $i<count($add); $i++)\r
272                                 {\r
273                                         $sql = "INSERT INTO " . CONFIG_TABLE . " (config_name, config_value) VALUES ('" . $add[$i] . "', '" . str_replace('\\\'', '\'\'', addslashes($board_config[$add[$i]])) . "')";\r
274                                         $db->sql_query($sql);\r
275                                 }\r
276                                 // removing old configuration variables that aren't used\r
277                                 for($i=0; $i<count($del); $i++)\r
278                                 {\r
279                                         $sql = "DELETE FROM " . CONFIG_TABLE . " WHERE config_name='" . $del[$i] . "'";\r
280                                         $db->sql_query($sql);\r
281                                 }\r
282                                 // updating variables that should be overwritten\r
283                                 for($i=0; $i<count($up); $i++)\r
284                                 {\r
285                                         $sql = "UPDATE " . CONFIG_TABLE . " SET config_value='" . str_replace('\\\'', '\'\'', addslashes($board_config[$up[$i]])) . "' WHERE config_name='" . $up[$i] . "'";\r
286                                         $db->sql_query($sql);\r
287                                 }\r
288                                 // recache config table for cat_hierarchy 2.1.0\r
289                                 global $config;\r
290                                 if(isset($config->data) && $config->data === $board_config && isset($config->data['mod_cat_hierarchy']))\r
291                                 {\r
292                                         $config->read(true);\r
293                                 }\r
294                         }\r
295                 }\r
296                 $this->php = $board_config['xs_php'];\r
297                 $this->tpldef = $board_config['xs_def_template'];\r
298                 $this->use_cache = $board_config['xs_use_cache'];\r
299                 $this->auto_compile = $board_config['xs_auto_compile'];\r
300                 $this->xs_check_switches = $board_config['xs_check_switches'];\r
301                 $this->cache_search = array('.', '\\', '/', '_tpl');\r
302                 $this->cache_replace = array('_', XS_SEPARATOR, XS_SEPARATOR, '.'.$this->php);\r
303                 $old_root = $this->root;\r
304                 $this->set_rootdir($root);\r
305                 if(!empty($this->tpl))\r
306                 {\r
307                         $this->load_replacements($this->tpldir . $this->tpl . '/xs.cfg');\r
308                 }\r
309                 if($old_root !== $this->root)\r
310                 {\r
311                         $this->clear_files();\r
312                 }\r
313         }\r
314 \r
315         /**\r
316          * Sets the template root directory for this Template object.\r
317          */\r
318         function set_rootdir($dir)\r
319         {\r
320                 global $board_config, $phpbb_root_path;\r
321                 if (!@is_dir($dir))\r
322                 {\r
323                         return false;\r
324                 }\r
325                 $dir = str_replace('\\', '/', $dir);\r
326                 // creating absolute path for cache\r
327                 $this->cachedir = $phpbb_root_path . XS_DIR_CACHE . '/';\r
328                 // creating absolute path for current template and root dir\r
329                 $this->tpldir = $phpbb_root_path . 'templates/';\r
330                 $this->tpldir_len = strlen($this->tpldir);\r
331                 $this->root = $dir;\r
332                 $this->tpl = $this->template_name($dir);\r
333                 // check configuration\r
334                 $this->get_config();\r
335                 // check subtemplates mod\r
336                 $sub_templates_cfg = $this->root . '/sub_templates.cfg';\r
337                 if(defined('LANG_EXTEND_DONE') && @file_exists($sub_templates_cfg))\r
338                 {\r
339                         $this->subtemplates = true;\r
340                 }\r
341                 return true;\r
342         }\r
343 \r
344         /**\r
345          * Destroys this template object. Should be called when you're done with it, in order\r
346          * to clear out the template data so you can load/parse a new template set.\r
347          */\r
348         function destroy()\r
349         {\r
350                 $this->_tpldata = array('.' => array(0 => array()));\r
351                 $this->vars = &$this->_tpldata['.'][0];\r
352                 $this->xs_started = 0;\r
353         }\r
354 \r
355         /**\r
356          * Clears list of compiled files.\r
357          */\r
358         function clear_files()\r
359         {\r
360                 $this->files = array();\r
361                 $this->files_cache = array();\r
362                 $this->files_cache2 = array();\r
363                 $this->compiled_code = array();\r
364                 $this->uncompiled_code = array();\r
365         }\r
366 \r
367         /**\r
368          * Loads replacements from .cfg file\r
369          */\r
370         function load_replacements($file)\r
371         {\r
372                 if(@file_exists($file))\r
373                 {\r
374                         $replace = array();\r
375                         @include($file);\r
376                         $this->replace = array_merge($this->replace, $replace);\r
377                 }\r
378         }\r
379 \r
380         /**\r
381          * Extracts template name from path\r
382          */\r
383         function template_name($dir)\r
384         {\r
385                 $tpl = XS_TPL_ANY; // can start at any position\r
386                 $tpl_null = XS_TPL_START; // can start only at zero position\r
387                 // searching for 'templates/' and removing everything before it\r
388                 $pos = strpos($dir, $tpl);\r
389                 if($pos === false)\r
390                 {\r
391                         if(substr($dir, 0, strlen($tpl_null)) !== $tpl_null)\r
392                         {\r
393                                 return '';\r
394                         }\r
395                         $str = substr($dir, strlen($tpl_null), strlen($dir));\r
396                 }\r
397                 else\r
398                 {\r
399                         $str = substr($dir, $pos + strlen($tpl), strlen($dir));\r
400                 }\r
401                 // searching for one more 'templates/'\r
402                 // that can happen if full path is like /home/some_dude/templates/phpbb/templates/subSilver/\r
403                 $dir = $this->template_name($str);\r
404                 if(!$dir)\r
405                 {\r
406                         $dir = $str;\r
407                 }\r
408                 if(strpos($str, $tpl) !== false)\r
409                 {\r
410                         $dir = $this->template_name($str);\r
411                 }\r
412                 // check for another subdirectory\r
413                 $pos = strpos($dir, '/');\r
414                 if($pos)\r
415                 {\r
416                         $dir = substr($dir, 0, $pos);\r
417                 }\r
418                 return $dir;\r
419         }\r
420 \r
421         function subtemplates_make_filename($filename)\r
422         {\r
423                 global $HTTP_GET_VARS, $HTTP_POST_VARS, $db, $board_config, $images, $theme;\r
424                 global $sub_template_key_image, $sub_templates;\r
425                 global $tree;\r
426 \r
427                 // initiate the sub-template image pack that will be use\r
428                 $sub_template_key_image = POST_CAT_URL . '0';\r
429 \r
430                 // Check if sub_templates are defined for this theme\r
431                 if ( $board_config['version'] > '.0.5' )\r
432                 {\r
433                         $sub_templates_cfg = @phpbb_realpath($this->root . '/sub_templates.cfg');\r
434                 }\r
435                 else\r
436                 {\r
437                         $sub_templates_cfg = $this->root . '/sub_templates.cfg';\r
438                 }\r
439                 @include($sub_templates_cfg);\r
440                 if ( isset($sub_templates) )\r
441                 {\r
442                         // search an id\r
443                         $cat_id = 0;\r
444                         $forum_id = 0;\r
445                         $topic_id = 0;\r
446                         $post_id = 0;\r
447 \r
448                         if ( !defined('IN_PRIVMSG') && ( isset($HTTP_GET_VARS[POST_POST_URL]) || isset($HTTP_POST_VARS[POST_POST_URL]) ) )\r
449                         {\r
450                                 $post_id = isset($HTTP_GET_VARS[POST_POST_URL]) ? intval($HTTP_GET_VARS[POST_POST_URL]) : intval($HTTP_POST_VARS[POST_POST_URL]);\r
451                         }\r
452 \r
453                         if ( isset($HTTP_GET_VARS[POST_TOPIC_URL]) || isset($HTTP_POST_VARS[POST_TOPIC_URL]) )\r
454                         {\r
455                                 $topic_id = intval($HTTP_GET_VARS[POST_TOPIC_URL]) ? intval($HTTP_GET_VARS[POST_TOPIC_URL]) : intval($HTTP_POST_VARS[POST_TOPIC_URL]);\r
456                         }\r
457 \r
458                         if ( isset($HTTP_GET_VARS[POST_FORUM_URL]) || isset($HTTP_POST_VARS[POST_FORUM_URL]) )\r
459                         {\r
460                                 $forum_id = isset($HTTP_GET_VARS[POST_FORUM_URL]) ? intval($HTTP_GET_VARS[POST_FORUM_URL]) : intval($HTTP_POST_VARS[POST_FORUM_URL]);\r
461                         }\r
462 \r
463                         if ( isset($HTTP_GET_VARS[POST_CAT_URL]) || isset($HTTP_POST_VARS[POST_CAT_URL]) )\r
464                         {\r
465                                 $cat_id = isset($HTTP_GET_VARS[POST_CAT_URL]) ? intval($HTTP_GET_VARS[POST_CAT_URL]) : intval($HTTP_POST_VARS[POST_CAT_URL]);\r
466                         }\r
467 \r
468                         if ( isset($HTTP_GET_VARS['selected_id']) || isset($HTTP_POST_VARS['selected_id']) )\r
469                         {\r
470                                 $selected_id = isset($HTTP_GET_VARS['selected_id']) ? $HTTP_GET_VARS['selected_id'] : $HTTP_POST_VARS['selected_id'];\r
471                                 $type = substr($selected_id, 0, 1);\r
472                                 $id = intval(substr($selected_id, 1));\r
473                                 if (!empty($id)) switch ($type)\r
474                                 {\r
475                                         case POST_CAT_URL:\r
476                                                 $cat_id = $id;\r
477                                                 break;\r
478                                         case POST_FORUM_URL:\r
479                                                 $forum_id = $id;\r
480                                                 break;\r
481                                         case POST_TOPIC_URL:\r
482                                                 $topic_id = $id;\r
483                                                 break;\r
484                                         case POST_POST_URL:\r
485                                                 if ( !defined('IN_PRIVMSG') )\r
486                                                 {\r
487                                                         $post_id = $id;\r
488                                                         break;\r
489                                                 }\r
490                                         default:\r
491                                                 break;\r
492                                 }\r
493                         }\r
494 \r
495                         // find the forum\r
496                         if ( ($forum_id <= 0) && ($cat_id <= 0) )\r
497                         {\r
498                                 if ($post_id > 0)\r
499                                 {\r
500                                         $sql = "SELECT * FROM " . POSTS_TABLE . " WHERE post_id=$post_id";                      \r
501                                         if ( !($result = $db->sql_query($sql)) )\r
502                                         {\r
503                                                 message_die(GENERAL_ERROR, 'Wasn\'t able to access posts', '', __LINE__, __FILE__, $sql);\r
504                                         }\r
505                                         if ( $row = $db->sql_fetchrow($result) )\r
506                                         {\r
507                                                 $forum_id = $row['forum_id'];\r
508                                         }\r
509                                 }\r
510 \r
511                                 if ($topic_id > 0)\r
512                                 {\r
513                                         $sql = "SELECT * FROM " . TOPICS_TABLE . " WHERE topic_id=$topic_id";                   \r
514                                         if ( !($result = $db->sql_query($sql)) )\r
515                                         {\r
516                                                 message_die(GENERAL_ERROR, 'Wasn\'t able to access topics', '', __LINE__, __FILE__, $sql);\r
517                                         }\r
518                                         if ( $row = $db->sql_fetchrow($result) )\r
519                                         {\r
520                                                 $forum_id = $row['forum_id'];\r
521                                         }\r
522                                 }\r
523                         }\r
524 \r
525                         // is the categories hierarchy v 2 installed ?\r
526                         $cat_hierarchy = function_exists('get_auth_keys');\r
527 \r
528                         // get the ids (forums and cats)\r
529                         $fids = array();\r
530                         if (!$cat_hierarchy)\r
531                         {\r
532                                 if ($forum_id > 0)\r
533                                 {\r
534                                         // add the forum_id\r
535                                         $fids[] = POST_FORUM_URL . $forum_id;\r
536 \r
537                                         // get the cat_id\r
538                                         $sql = "SELECT * FROM " . FORUMS_TABLE . " WHERE forum_id=$forum_id";\r
539                                         if ( !($result = $db->sql_query($sql)) )\r
540                                         {\r
541                                                 message_die(GENERAL_ERROR, 'Wasn\'t able to access forums', '', __LINE__, __FILE__, $sql);\r
542                                         }\r
543                                         if ( $row = $db->sql_fetchrow($result) )\r
544                                         {\r
545                                                 $cat_id = $row['cat_id'];\r
546                                         }\r
547                                 }\r
548 \r
549                                 // add the cat_id\r
550                                 if ($cat_id > 0)\r
551                                 {\r
552                                         $fids[] = POST_CAT_URL . $cat_id;\r
553                                 }\r
554 \r
555                                 // add the root level\r
556                                 $fids[] = 'Root';\r
557                         }\r
558                         else\r
559                         {\r
560                                 // categories hierarchy v 2 compliancy\r
561                                 $cur = 'Root';\r
562                                 if ($forum_id > 0)\r
563                                 {\r
564                                         $cur = POST_FORUM_URL . $forum_id;\r
565                                 }\r
566                                 else if ($cat_id > 0)\r
567                                 {\r
568                                         $cur = POST_CAT_URL . $cat_id;\r
569                                 }\r
570 \r
571                                 // add start\r
572                                 $fids[] = $cur;\r
573                                 while ( ($cur != 'Root') && !empty($cur) )\r
574                                 {\r
575                                         // get parent level\r
576                                         $cur = (isset($tree['main'][ $tree['keys'][$cur] ])) ? $tree['main'][ $tree['keys'][$cur] ] : 'Root';\r
577 \r
578                                         // add the parent level\r
579                                         if ( !empty($cur) )\r
580                                         {\r
581                                                 $fids[] = $cur;\r
582                                         }\r
583                                 }\r
584                         }\r
585 \r
586                         // search if this file is part of a sub-template\r
587                         $sub_tpl_file = '';\r
588                         $sub_css_file = '';\r
589                         $sub_img_file = '';\r
590                         $sub_img_path = '';\r
591                         $template_path = 'templates/';\r
592                         $template_name = substr( $this->root, strpos($this->root, $template_path) + strlen($template_path) );\r
593                         $real_root = $this->root;\r
594                         if ( $board_config['version'] > '.0.5' )\r
595                         {\r
596                                 $real_root = @phpbb_realpath($this->root);\r
597                         }\r
598                         if (substr($filename, 0, 1) != '/')\r
599                         {\r
600                                 $found = false;\r
601                                 $num_fids = count($fids);\r
602                                 for ($i = 0; !$found && ($i < $num_fids); $i++)\r
603                                 {\r
604                                         $key = $fids[$i];\r
605 \r
606                                         // convert root into c0 category\r
607                                         if ( ($key == 'Root') || empty($key) )\r
608                                         {\r
609                                                 $key = POST_CAT_URL . '0';\r
610                                         }\r
611 \r
612                                         if ( isset($sub_templates[$key]) )\r
613                                         {\r
614                                                 // get the sub-template path\r
615                                                 $current_template_path = $template_path . $template_name . '/' . $sub_templates[$key]['dir'];\r
616                                                 $root_template_path = $real_root . '/' . $sub_templates[$key]['dir'];\r
617 \r
618                                                 // set the filename\r
619                                                 if ( empty($sub_tpl_file) && file_exists($root_template_path . '/' . $filename) )\r
620                                                 {\r
621                                                         $found = true;\r
622                                                         $sub_tpl_file = $sub_templates[$key]['dir'] . '/' . $filename;\r
623                                                         break;\r
624                                                 }\r
625                                         }\r
626                                 }\r
627 \r
628                                 // set the css file name\r
629                                 $found = false;\r
630                                 $num_fids = count($fids);\r
631                                 for ($i = 0; !$found && ($i < $num_fids); $i++)\r
632                                 {\r
633                                         $key = $fids[$i];\r
634 \r
635                                         // convert root into c0 category\r
636                                         if ( ($key == 'Root') || empty($key) )\r
637                                         {\r
638                                                 $key = POST_CAT_URL . '0';\r
639                                         }\r
640 \r
641                                         if ( isset($sub_templates[$key]) )\r
642                                         {\r
643                                                 // get the sub-template path\r
644                                                 $current_template_path = $template_path . $template_name . '/' . $sub_templates[$key]['dir'];\r
645                                                 $root_template_path = $real_root . '/' . $sub_templates[$key]['dir'];\r
646                                                 if ( empty($sub_css_file) && isset($sub_templates[$key]['head_stylesheet']) && file_exists($root_template_path . '/' . $sub_templates[$key]['head_stylesheet']) )\r
647                                                 {\r
648                                                         $found = true;\r
649                                                         $sub_css_file = $sub_templates[$key]['dir'] . '/' . $sub_templates[$key]['head_stylesheet'];\r
650                                                         break;\r
651                                                 }\r
652                                         }\r
653                                 }\r
654 \r
655                                 // set the img file name\r
656                                 $found = false;\r
657                                 $num_fids = count($fids);\r
658                                 for ($i = 0; !$found && ($i < $num_fids); $i++)\r
659                                 {\r
660                                         $key = $fids[$i];\r
661 \r
662                                         // convert root into c0 category\r
663                                         if ( ($key == 'Root') || empty($key) )\r
664                                         {\r
665                                                 $key = POST_CAT_URL . '0';\r
666                                         }\r
667 \r
668                                         if ( isset($sub_templates[$key]) )\r
669                                         {\r
670                                                 // get the sub-template path\r
671                                                 $current_template_path = $template_path . $template_name . '/' . $sub_templates[$key]['dir'];\r
672                                                 $root_template_path = $real_root . '/' . $sub_templates[$key]['dir'];\r
673                                                 if ( isset($sub_templates[$key]['imagefile']) && file_exists($root_template_path . '/' . $sub_templates[$key]['imagefile']) )\r
674                                                 {\r
675                                                         $sub_img_path = $sub_templates[$key]['dir'];\r
676                                                         $sub_img_file = $sub_templates[$key]['imagefile'];\r
677 \r
678                                                         // send back the lowest level of the images file\r
679                                                         $found = true;\r
680                                                         $sub_template_key_image = $key;\r
681                                                         break;\r
682                                                 }\r
683                                         }\r
684                                 }\r
685                         }\r
686 \r
687                         // set the tpl file\r
688                         if ( !empty($sub_tpl_file) )\r
689                         {\r
690                                 $filename = $sub_tpl_file;\r
691                         }\r
692 \r
693                         // set the css file\r
694                         if ( !empty($sub_css_file) )\r
695                         {\r
696                                 $theme['head_stylesheet'] = $sub_css_file;\r
697                         }\r
698 \r
699                         // get the root level images\r
700                         $key = POST_CAT_URL . '0';\r
701                         if ( isset($sub_templates[$key]) )\r
702                         {\r
703                                 // get the sub-template path\r
704                                 $current_template_path = $template_path . $template_name . '/' . $sub_templates[$key]['dir'];\r
705                                 $root_template_path = $real_root . '/' . $sub_templates[$key]['dir'];\r
706                                 if ( isset($sub_templates[$key]['imagefile']) && file_exists($root_template_path . '/' . $sub_templates[$key]['imagefile']) )\r
707                                 {\r
708                                         $sav_images = $images;\r
709                                         $images = array();\r
710                                         @include($root_template_path . '/' . $sub_templates[$key]['imagefile']);\r
711                                         $img_lang = ( file_exists($root_template_path . '/images/lang_' . $board_config['default_lang']) ) ? $board_config['default_lang'] : 'english';\r
712                                         foreach($images as $key => $value)\r
713                                         {\r
714                                                 if ( !is_array($value) )\r
715                                                 {\r
716                                                         $images[$key] = str_replace('{LANG}', 'lang_' . $img_lang, $value);\r
717                                                 }\r
718                                                 $sav_images[$key] = $images[$key];\r
719                                         }\r
720                                         $images = $sav_images;\r
721                                         $sav_images = array();\r
722                                 }\r
723                         }\r
724 \r
725                         // get the current images\r
726                         if ( !empty($sub_template_key_image) && ($sub_template_key_image != POST_CAT_URL . '0') )\r
727                         {\r
728                                 $key = $sub_template_key_image;\r
729 \r
730                                 // get the sub-template path\r
731                                 $current_template_path = $template_path . $template_name . '/' . $sub_templates[$key]['dir'];\r
732                                 $root_template_path = $real_root . '/' . $sub_templates[$key]['dir'];\r
733                                 if ( isset($sub_templates[$key]['imagefile']) && file_exists($root_template_path . '/' . $sub_templates[$key]['imagefile']) )\r
734                                 {\r
735                                         $sav_images = $images;\r
736                                         $images = array();\r
737                                         @include($root_template_path . '/' . $sub_templates[$key]['imagefile']);\r
738                                         $img_lang = ( file_exists($root_template_path . '/images/lang_' . $board_config['default_lang']) ) ? $board_config['default_lang'] : 'english';\r
739                                         foreach($images as $key => $value)\r
740                                         {\r
741                                                 if ( !is_array($value) )\r
742                                                 {\r
743                                                         $images[$key] = str_replace('{LANG}', 'lang_' . $img_lang, $value);\r
744                                                 }\r
745                                                 $sav_images[$key] = $images[$key];\r
746                                         }\r
747                                         $images = $sav_images;\r
748                                         $sav_images = array();\r
749                                 }\r
750                         }\r
751                 }\r
752                 return $filename;\r
753         }\r
754 \r
755         /**\r
756          * Generates a full path+filename for the given filename, which can either\r
757          * be an absolute name, or a name relative to the rootdir for this Template\r
758          * object.\r
759          */\r
760         function make_filename($filename, $xs_include = false)\r
761         {\r
762                 if($this->subtemplates)\r
763                 {\r
764                         $filename = $this->subtemplates_make_filename($filename);\r
765                 }\r
766                 // Check replacements list\r
767                 if(!$xs_include && isset($this->replace[$filename]))\r
768                 {\r
769                         $filename = $this->replace[$filename];\r
770                 }\r
771                 // Check if it's an absolute or relative path.\r
772                 if ((substr($filename, 0, 1) !== '/') && (substr($filename, 1, 1) !== ':'))\r
773                 {\r
774                 return $this->root . '/' . $filename;\r
775                 }\r
776                 else\r
777                 {\r
778                         return str_replace('\\', '/', $filename);\r
779                 }\r
780         }\r
781 \r
782         /**\r
783          * Converts template filename to cache filename.\r
784          * Returns empty string if non-cachable (for tpl files outside of root dir).\r
785          * $file should be absolute filename\r
786          */\r
787         function make_filename_cache($file)\r
788         {\r
789                 $str = str_replace($this->cache_search, $this->cache_replace, $file);\r
790                 if(substr($file, 0, $this->tpldir_len) !== $this->tpldir || empty($this->tpl))\r
791                 {\r
792                         return $this->cachedir . XS_TPL_PREFIX2 . $str;\r
793                 }\r
794                 // removing not needed part\r
795                 $file = substr($file, $this->tpldir_len, strlen($file));\r
796                 // creating filename\r
797                 return $this->cachedir . XS_TPL_PREFIX . str_replace($this->cache_search, $this->cache_replace, $file);\r
798         }\r
799 \r
800         /**\r
801          * Sets the template filenames for handles. $filename_array\r
802          * should be a hash of handle => filename pairs.\r
803          */\r
804         function set_filenames($filename_array)\r
805         {\r
806                 if (!is_array($filename_array))\r
807                 {\r
808                         return false;\r
809                 }\r
810 \r
811                 foreach($filename_array as $handle => $filename)\r
812                 {\r
813                         $this->set_filename($handle, $filename);\r
814                 }\r
815 \r
816                 return true;\r
817         }\r
818 \r
819 \r
820         /**\r
821          * Assigns template filename for handle.\r
822          */\r
823         function set_filename($handle, $filename, $xs_include = false, $quiet = false)\r
824         {\r
825                 global $board_config;\r
826                 $can_cache = $this->use_cache;\r
827                 if(strpos($filename, '..') !== false)\r
828                 {\r
829                         $can_cache = false;\r
830                 }\r
831                 $this->files[$handle] = $this->make_filename($filename, $xs_include);\r
832                 $this->files_cache[$handle] = '';\r
833                 $this->files_cache2[$handle] = '';\r
834                 // check if we are in admin control panel and override extreme styles mod controls if needed\r
835                 if(defined('XS_ADMIN_OVERRIDE') && XS_ADMIN_OVERRIDE === true && @function_exists('xs_admin_override'))\r
836                 {\r
837                         xs_admin_override();\r
838                 }\r
839                 // checking if we have valid filename\r
840                 if(!$this->files[$handle])\r
841                 {\r
842                         if($xs_include || $quiet)\r
843                         {\r
844                                 return false;\r
845                         }\r
846                         else\r
847                         {\r
848                                 die("Template->make_filename(): Error - invalid template $filename");\r
849                         }\r
850                 }\r
851                 // creating cache filename\r
852                 if($can_cache)\r
853                 {\r
854                         $this->files_cache2[$handle] = $this->make_filename_cache($this->files[$handle]);\r
855                         if(@file_exists($this->files_cache2[$handle]))\r
856                         {\r
857                                 $this->files_cache[$handle] = $this->files_cache2[$handle];\r
858                         }\r
859                 }\r
860                 // checking if tpl and/or php file exists\r
861                 if(empty($this->files_cache[$handle]) && !@file_exists($this->files[$handle]))\r
862                 {\r
863                         // trying to load alternative filename (usually subSilver)\r
864                         if(!empty($this->tpldef) && !empty($this->tpl) && ($this->tpldef !== $this->tpl))\r
865                         {\r
866                                 $this->files[$handle] = '';\r
867                                 // save old configuration\r
868                                 $root = $this->root;\r
869                                 $tpl_name = $this->tpl;\r
870                                 // set temporary configuration\r
871                                 $this->root = $this->tpldir . $this->tpldef;\r
872                                 $this->tpl = $this->tpldef;\r
873                                 // recursively run set_filename\r
874                                 $res = $this->set_filename($handle, $filename, $xs_include, $quiet);\r
875                                 // restore old configuration\r
876                                 $this->root = $root;\r
877                                 $this->tpl = $tpl_name;\r
878                                 return $res;\r
879                         }\r
880                         if($quiet)\r
881                         {\r
882                                 return false;\r
883                         }\r
884                         if($xs_include)\r
885                         {\r
886                                 if($board_config['xs_warn_includes'])\r
887                                 {\r
888                                         die('Template->make_filename(): Error - included template file not found: ' . $filename);\r
889                                 }\r
890                                 return false;\r
891                         }\r
892                         else\r
893                         {\r
894                                 die('Template->make_filename(): Error - template file not found: ' . $filename);\r
895                         }\r
896                 }\r
897                 // checking if we should recompile cache\r
898                 if(!empty($this->files_cache[$handle]) && !empty($board_config['xs_auto_recompile']))\r
899                 {\r
900                         $cache_time = @filemtime($this->files_cache[$handle]);\r
901                         if(@filemtime($this->files[$handle]) > $cache_time || $board_config['xs_template_time'] > $cache_time)\r
902                         {       \r
903                                 // file was changed. don't use cache file (will be recompled if configuration allowes it)\r
904                                 $this->files_cache[$handle] = '';\r
905                         }\r
906                 }\r
907                 return true;\r
908         }\r
909 \r
910         /**\r
911          * includes file or executes code\r
912          */\r
913         function execute($filename, $code, $handle)\r
914         {\r
915                 global $lang, $theme, $board_config;\r
916                 $template = $theme['template_name'];\r
917                 global $$template;\r
918                 $theme_info = &$$template;\r
919                 if($board_config['xs_add_comments'] && $handle)\r
920                 {\r
921                         echo '<!-- template ', $this->files[$handle], ' start -->';\r
922                 }\r
923                 if($filename)\r
924                 {\r
925                         include($filename);\r
926                 }\r
927                 else\r
928                 {\r
929                         eval($code);\r
930                 }\r
931                 if($board_config['xs_add_comments'] && $handle)\r
932                 {\r
933                         echo '<!-- template ', $this->files[$handle], ' end -->';\r
934                 }\r
935                 return true;\r
936         }\r
937 \r
938         /**\r
939          * Load the file for the handle, compile the file,\r
940          * and run the compiled code. This will print out\r
941          * the results of executing the template.\r
942          */\r
943         function pparse($handle)\r
944         {\r
945                 global $board_config;\r
946                 // parsing header if there is one\r
947                 if($this->preparse || $this->postparse)\r
948                 {\r
949                         $preparse = $this->preparse;\r
950                         $postparse = $this->postparse;\r
951                         $this->preparse = '';\r
952                         $this->postparse = '';\r
953                         if($preparse)\r
954                         {\r
955                                 $this->pparse($preparse);\r
956                         }\r
957                         if($postparse)\r
958                         {\r
959                                 $str = $handle;\r
960                                 $handle = $postparse;\r
961                                 $this->pparse($str);\r
962                         }\r
963                 }\r
964                 // checking if handle exists\r
965                 if (empty($this->files[$handle]) && empty($this->files_cache[$handle]))\r
966                 {\r
967                         die("Template->loadfile(): No files found for handle $handle");\r
968                 }\r
969                 $this->xs_startup();\r
970                 $force_recompile = empty($this->uncompiled_code[$handle]) ? false : true;\r
971                 // checking if php file exists.\r
972                 if (!empty($this->files_cache[$handle]) && !$force_recompile)\r
973                 {\r
974                         // php file exists - running it instead of tpl\r
975                         $this->execute($this->files_cache[$handle], '', $handle);\r
976                         return true;\r
977                 }\r
978                 if (!$this->loadfile($handle))\r
979                 {\r
980                         die("Template->pparse(): Couldn't load template file for handle $handle");\r
981                 }\r
982                 // actually compile the template now.\r
983                 if (empty($this->compiled_code[$handle]))\r
984                 {\r
985                         // Actually compile the code now.\r
986                         if(!empty($this->files_cache2[$handle]) && empty($this->files_cache[$handle]) && !$force_recompile)\r
987                         {\r
988                                 $this->compiled_code[$handle] = $this->compile2($this->uncompiled_code[$handle], $handle, $this->files_cache2[$handle]);\r
989                         }\r
990                         else\r
991                         {\r
992                                 $this->compiled_code[$handle] = $this->compile2($this->uncompiled_code[$handle], '', '');\r
993                         }\r
994                 }\r
995                 // Run the compiled code.\r
996                 if (empty($this->files_cache[$handle]) || $force_recompile)\r
997                 {\r
998                         $this->execute('', $this->compiled_code[$handle], $handle);\r
999                 }\r
1000                 else\r
1001                 {\r
1002                         $this->execute($this->files_cache[$handle], '', $handle);\r
1003                 }\r
1004                 return true;\r
1005         }\r
1006 \r
1007         /**\r
1008          * Precompile file\r
1009          */\r
1010         function precompile($template, $filename)\r
1011         {\r
1012                 global $precompile_num, $board_config;\r
1013                 if(empty($precompile_num))\r
1014                 {\r
1015                         $precompile_num = 0;\r
1016                 }\r
1017                 $precompile_num ++;\r
1018                 $handle = 'precompile_' . $precompile_num;\r
1019                 // save old configuration\r
1020                 $root = $this->root;\r
1021                 $tpl_name = $this->tpl;\r
1022                 $old_config = $this->use_cache;\r
1023                 $old_autosave = $this->auto_compile;\r
1024                 // set temporary configuration\r
1025                 $this->root = $this->tpldir . $template;\r
1026                 $this->tpl = $template;\r
1027                 $this->use_cache = 1;\r
1028                 $this->auto_compile = 1;\r
1029                 // set filename\r
1030                 $res = $this->set_filename($handle, $filename, true, true);\r
1031                 if(!$res || !$this->files_cache2[$handle])\r
1032                 {\r
1033                         $this->root = $root;\r
1034                         $this->tpl = $tpl_name;\r
1035                         $this->use_cache = $old_config;\r
1036                         $this->auto_compile = $old_autosave;\r
1037                         return false;\r
1038                 }\r
1039                 $this->files_cache[$handle] = '';\r
1040                 // load template\r
1041                 $res = $this->loadfile($handle);\r
1042                 if(!$res || empty($this->uncompiled_code[$handle]))\r
1043                 {\r
1044                         $this->root = $root;\r
1045                         $this->tpl = $tpl_name;\r
1046                         $this->use_cache = $old_config;\r
1047                         $this->auto_compile = $old_autosave;\r
1048                         return false;\r
1049                 }\r
1050                 // compile the code\r
1051                 $this->compile2($this->uncompiled_code[$handle], $handle, $this->files_cache2[$handle]);\r
1052                 // restore confirugation\r
1053                 $this->root = $root;\r
1054                 $this->tpl = $tpl_name;\r
1055                 $this->use_cache = $old_config;\r
1056                 $this->auto_compile = $old_autosave;\r
1057                 return true;\r
1058         }\r
1059 \r
1060         /**\r
1061          * Inserts the uncompiled code for $handle as the\r
1062          * value of $varname in the root-level. This can be used\r
1063          * to effectively include a template in the middle of another\r
1064          * template.\r
1065          * Note that all desired assignments to the variables in $handle should be done\r
1066          * BEFORE calling this function.\r
1067          */\r
1068         function assign_var_from_handle($varname, $handle)\r
1069         {\r
1070                 ob_start();\r
1071                 $res = $this->pparse($handle);\r
1072                 $this->vars[$varname] = ob_get_contents();\r
1073                 ob_end_clean();\r
1074                 return $res;\r
1075         }\r
1076 \r
1077         /**\r
1078          * Block-level variable assignment. Adds a new block iteration with the given\r
1079          * variable assignments. Note that this should only be called once per block\r
1080          * iteration.\r
1081          */\r
1082         function assign_block_vars($blockname, $vararray)\r
1083         {\r
1084                 if (strstr($blockname, '.'))\r
1085                 {\r
1086                         // Nested block.\r
1087                         $blocks = explode('.', $blockname);\r
1088                         $blockcount = sizeof($blocks) - 1;\r
1089 \r
1090                         $str = &$this->_tpldata; \r
1091                         for($i = 0; $i < $blockcount; $i++) \r
1092                         { \r
1093                                 $str = &$str[$blocks[$i].'.']; \r
1094                                 $str = &$str[sizeof($str)-1]; \r
1095                         } \r
1096                         // Now we add the block that we're actually assigning to. \r
1097                         // We're adding a new iteration to this block with the given \r
1098                         //      variable assignments. \r
1099                         $str[$blocks[$blockcount].'.'][] = $vararray;\r
1100                 }\r
1101                 else\r
1102                 {\r
1103                         // Top-level block.\r
1104                         // Add a new iteration to this block with the variable assignments\r
1105                         // we were given.\r
1106                         $this->_tpldata[$blockname.'.'][] = $vararray;\r
1107                 }\r
1108 \r
1109                 return true;\r
1110         }\r
1111 \r
1112         /**\r
1113          * Root-level variable assignment. Adds to current assignments, overriding\r
1114          * any existing variable assignment with the same name.\r
1115          */\r
1116         function assign_vars($vararray)\r
1117         {\r
1118                 foreach($vararray as $key => $val)\r
1119                 {\r
1120                         $this->vars[$key] = $val;\r
1121                 }\r
1122                 return true;\r
1123         }\r
1124 \r
1125         /**\r
1126          * Root-level variable assignment. Adds to current assignments, overriding\r
1127          * any existing variable assignment with the same name.\r
1128          */\r
1129         function assign_var($varname, $varval)\r
1130         {\r
1131                 $this->vars[$varname] = $varval;\r
1132 \r
1133                 return true;\r
1134         }\r
1135 \r
1136         /**\r
1137          * If not already done, load the file for the given handle and populate\r
1138          * the uncompiled_code[] hash with its code. Do not compile.\r
1139          */\r
1140         function loadfile($handle)\r
1141         {\r
1142                 global $board_config;\r
1143                 // If cached file exists do nothing - it will be included via include()\r
1144                 if(!empty($this->files_cache[$handle]))\r
1145                 {\r
1146                         return true;\r
1147                 }\r
1148 \r
1149                 // If the file for this handle is already loaded and compiled, do nothing.\r
1150                 if (!empty($this->uncompiled_code[$handle]))\r
1151                 {\r
1152                         return true;\r
1153                 }\r
1154 \r
1155                 // If we don't have a file assigned to this handle, die.\r
1156                 if (empty($this->files[$handle]))\r
1157                 {\r
1158                         die("Template->loadfile(): No file specified for handle $handle");\r
1159                 }\r
1160 \r
1161                 $filename = $this->files[$handle];\r
1162 \r
1163                 $str = implode('', @file($filename));\r
1164                 if (empty($str))\r
1165                 {\r
1166                         die("Template->loadfile(): File $filename for handle $handle is empty");\r
1167                 }\r
1168 \r
1169                 $this->uncompiled_code[$handle] = $str;\r
1170 \r
1171                 return true;\r
1172         }\r
1173 \r
1174 \r
1175 \r
1176         /**\r
1177          * Generates a reference to the given variable inside the given (possibly nested)\r
1178          * block namespace. This is a string of the form:\r
1179          * ' . $this->_tpldata['parent.'][$_parent_i]['$child1.'][$_child1_i]['$child2.'][$_child2_i]...['varname'] . '\r
1180          * It's ready to be inserted into an "echo" line in one of the templates.\r
1181          * NOTE: expects a trailing "." on the namespace.\r
1182          */\r
1183         function generate_block_varref($namespace, $varname, $use_isset = true)\r
1184         {\r
1185                 // Strip the trailing period.\r
1186                 $namespace = substr($namespace, 0, strlen($namespace) - 1);\r
1187 \r
1188                 // Get a reference to the data block for this namespace.\r
1189                 $varref = $this->generate_block_data_ref($namespace, true);\r
1190                 // Prepend the necessary code to stick this in an echo line.\r
1191 \r
1192                 // Append the variable reference.\r
1193                 $varref .= '[\'' . $varname . '\']';\r
1194 \r
1195                 if($use_isset)\r
1196                 {\r
1197                         $varref = '<'.'?php echo isset(' . $varref . ') ? ' . $varref . ' : \'\'; ?'.'>';\r
1198                 }\r
1199                 else\r
1200                 {\r
1201                         $varref = '<'.'?php echo ' . $varref . '; ?'.'>';\r
1202                 }\r
1203 \r
1204                 return $varref;\r
1205 \r
1206         }\r
1207 \r
1208 \r
1209         /**\r
1210          * Generates a reference to the array of data values for the given\r
1211          * (possibly nested) block namespace. This is a string of the form:\r
1212          * $this->_tpldata['parent.'][$_parent_i]['$child1.'][$_child1_i]['$child2.'][$_child2_i]...['$childN.']\r
1213          *\r
1214          * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.\r
1215          * NOTE: does not expect a trailing "." on the blockname.\r
1216          */\r
1217         function generate_block_data_ref($blockname, $include_last_iterator, $defop = false)\r
1218         {\r
1219                 // Get an array of the blocks involved.\r
1220                 $blocks = explode('.', $blockname);\r
1221                 $blockcount = sizeof($blocks) - 1;\r
1222                 if($defop)\r
1223                 {\r
1224                         $varref = '$this->_tpldata[\'DEFINE\']';\r
1225                         // Build up the string with everything but the last child.\r
1226                         for ($i = 0; $i < $blockcount; $i++)\r
1227                         {\r
1228                                 $varref .= "['" . $blocks[$i] . ".'][\$" . $blocks[$i] . '_i]';\r
1229                         }\r
1230                         // Add the block reference for the last child.\r
1231                         $varref .= "['" . $blocks[$blockcount] . ".']";\r
1232                         // Add the iterator for the last child if requried.\r
1233                         if ($include_last_iterator)\r
1234                         {\r
1235                                 $varref .= '[$' . $blocks[$blockcount] . '_i]';\r
1236                         }\r
1237                         return $varref;\r
1238                 }\r
1239                 if($include_last_iterator)\r
1240                 {\r
1241                         return '$'. $blocks[$blockcount]. '_item';\r
1242                 }\r
1243                 else\r
1244                 {\r
1245                         return '$'. $blocks[$blockcount-1]. '_item[\''. $blocks[$blockcount]. '.\']';\r
1246                 }\r
1247         }\r
1248 \r
1249         function compile_code($filename, $code, $use_isset = false)\r
1250         {\r
1251                 //      $filename - file to load code from. used if $code is empty\r
1252                 //      $code - tpl code\r
1253                 //      $use_isset - if false then compiled code looks more beautiful and easier\r
1254                 //      to understand and it adds error_reporting() to supress php warnings.\r
1255                 //      if true then isset() is used to check variables instead of supressing\r
1256                 //          php warnings. note: for extreme styles mod 2.x it works only for\r
1257                 //              block variables and for usual variables its always true.\r
1258 \r
1259                 // load code from file\r
1260                 if(!$code && !empty($filename))\r
1261                 {\r
1262                         $code = @implode('', @file($filename));\r
1263                 }\r
1264 \r
1265                 // Replace phpBB 2.2 <!-- (END)PHP --> tags\r
1266                 $search = array('<!-- PHP -->', '<!-- ENDPHP -->');\r
1267                 $replace = array('<'.'?php ', ' ?'.'>');\r
1268                 $code = str_replace($search, $replace, $code);\r
1269 \r
1270                 // Break it up into lines and put " -->" back.\r
1271                 $code_lines = explode(' -->', $code);\r
1272                 $count = count($code_lines);\r
1273                 for ($i = 0; $i < ($count - 1); $i++)\r
1274                 {\r
1275                         $code_lines[$i] .= ' -->';\r
1276                 }\r
1277 \r
1278                 $block_nesting_level = 0;\r
1279                 $block_names = array();\r
1280                 $block_names[0] = ".";\r
1281                 $block_items = array();\r
1282                 $count_if = 0;\r
1283 \r
1284                 // prepare array for compiled code\r
1285                 $compiled = array();\r
1286                 $count_bugs = count($this->bugs);\r
1287 \r
1288                 // array of switches\r
1289                 $sw = array();\r
1290 \r
1291                 // replace all short php tags\r
1292                 $new_code = array();\r
1293                 $line_count = count($code_lines);\r
1294                 for($i=0; $i<$line_count; $i++)\r
1295                 {\r
1296                         $line = $code_lines[$i];\r
1297                         $pos = strpos($line, '<?');\r
1298                         if($pos === false)\r
1299                         {\r
1300                                 $new_code[] = $line;\r
1301                                 continue;\r
1302                         }\r
1303                         if(substr($line, $pos, 5) === '<?php')\r
1304                         {\r
1305                                 // valid php tag. skip it\r
1306                                 $new_code[] = substr($line, 0, $pos + 5);\r
1307                                 $code_lines[$i] = substr($line, $pos + 5);\r
1308                                 $i --;\r
1309                                 continue;\r
1310                         }\r
1311                         // invalid php tag\r
1312                         $new_code[] = substr($line, 0, $pos) . '<?php echo \'<?\'; ?>';\r
1313                         $code_lines[$i] = substr($line, $pos + 2);\r
1314                         $i --;\r
1315                 }\r
1316                 $code_lines = $new_code;\r
1317 \r
1318                 // main loop\r
1319                 $line_count = count($code_lines);\r
1320                 for($i=0; $i<$line_count; $i++)\r
1321                 {\r
1322                         $line = $code_lines[$i];\r
1323                         // reset keyword type\r
1324                         $keyword_type = XS_TAG_NONE;\r
1325                         // check if we have valid keyword in current line\r
1326                         $pos1 = strpos($line, '<!-- ');\r
1327                         if($pos1 === false)\r
1328                         {\r
1329                                 // no keywords in this line\r
1330                                 $compiled[] = $this->_compile_text($line, $use_isset);\r
1331                                 continue;\r
1332                         }\r
1333                         // find end of html comment\r
1334                         $pos2 = strpos($line, ' -->', $pos1);\r
1335                         if($pos2 !== false)\r
1336                         {\r
1337                                 // find end of keyword in comment\r
1338                                 $pos3 = strpos($line, ' ', $pos1 + 5);\r
1339                                 if($pos3 !== false && $pos3 <= $pos2)\r
1340                                 {\r
1341                                         $keyword = substr($line, $pos1 + 5, $pos3 - $pos1 - 5);\r
1342                                         // check keyword against list of supported keywords. case-sensitive\r
1343                                         if($keyword === 'BEGIN')\r
1344                                         {\r
1345                                                 $keyword_type = XS_TAG_BEGIN;\r
1346                                         }\r
1347                                         elseif($keyword === 'END')\r
1348                                         {\r
1349                                                 $keyword_type = XS_TAG_END;\r
1350                                         }\r
1351                                         elseif($keyword === 'INCLUDE')\r
1352                                         {\r
1353                                                 $keyword_type = XS_TAG_INCLUDE;\r
1354                                         }\r
1355                                         elseif($keyword === 'IF')\r
1356                                         {\r
1357                                                 $keyword_type = XS_TAG_IF;\r
1358                                         }\r
1359                                         elseif($keyword === 'ELSE')\r
1360                                         {\r
1361                                                 $keyword_type = XS_TAG_ELSE;\r
1362                                         }\r
1363                                         elseif($keyword === 'ELSEIF')\r
1364                                         {\r
1365                                                 $keyword_type = XS_TAG_ELSEIF;\r
1366                                         }\r
1367                                         elseif($keyword === 'ENDIF')\r
1368                                         {\r
1369                                                 $keyword_type = XS_TAG_ENDIF;\r
1370                                         }\r
1371                                         elseif($keyword === 'DEFINE')\r
1372                                         {\r
1373                                                 $keyword_type = XS_TAG_DEFINE;\r
1374                                         }\r
1375                                         elseif($keyword === 'UNDEFINE')\r
1376                                         {\r
1377                                                 $keyword_type = XS_TAG_UNDEFINE;\r
1378                                         }\r
1379                                         elseif($keyword === 'BEGINELSE')\r
1380                                         {\r
1381                                                 $keyword_type = XS_TAG_BEGINELSE;\r
1382                                         }\r
1383                                 }\r
1384                         }\r
1385                         if(!$keyword_type)\r
1386                         {\r
1387                                 // not valid keyword. process the rest of line\r
1388                                 $compiled[] = $this->_compile_text(substr($line, 0, $pos1 + 4), $use_isset);\r
1389                                 $code_lines[$i] = substr($line, $pos1 + 4);\r
1390                                 $i --;\r
1391                                 continue;\r
1392                         }\r
1393                         // remove code before keyword\r
1394                         if($pos1 > 0)\r
1395                         {\r
1396                                 $compiled[] = $this->_compile_text(substr($line, 0, $pos1), $use_isset);\r
1397                         }\r
1398                         // remove keyword\r
1399                         $keyword_str = substr($line, $pos1, $pos2 - $pos1 + 4);\r
1400                         $params_str = $pos2 == $pos3 ? '' : substr($line, $pos3 + 1, $pos2 - $pos3 - 1);\r
1401                         $code_lines[$i] = substr($line, $pos2 + 4);\r
1402                         $i--;\r
1403                         // Check keywords\r
1404 \r
1405                         /*\r
1406                         * <!-- BEGIN -->\r
1407                         */\r
1408                         if($keyword_type == XS_TAG_BEGIN)\r
1409                         {\r
1410                                 $params = explode(' ', $params_str);\r
1411                                 $num_params = count($params);\r
1412                                 // get variable name\r
1413                                 if($num_params == 1)\r
1414                                 {\r
1415                                         $var = $params[0];\r
1416                                 }\r
1417                                 elseif($num_params == 2)\r
1418                                 {\r
1419                                         if($params[0] === '')\r
1420                                         {\r
1421                                                 $var = $params[1];\r
1422                                         }\r
1423                                         elseif($params[1] === '')\r
1424                                         {\r
1425                                                 $var = $params[0];\r
1426                                         }\r
1427                                         else\r
1428                                         {\r
1429                                                 // invalid tag\r
1430                                                 $compiled[] = $keyword_str;\r
1431                                                 continue;\r
1432                                         }\r
1433                                 }\r
1434                                 else\r
1435                                 {\r
1436                                         // invalid tag\r
1437                                         $compiled[] = $keyword_str;\r
1438                                         continue;\r
1439                                 }\r
1440                                 // check variable for matching end\r
1441                                 if($this->xs_check_switches)\r
1442                                 {\r
1443                                         $found = 0;\r
1444                                         $str = '<!-- END ' . $var . ' -->';\r
1445                                         for ($j = $i+1; ($j < $line_count) && !$found; $j++)\r
1446                                         {\r
1447                                                 $pos = strpos($code_lines[$j], $str);\r
1448                                                 if($pos !== false)\r
1449                                                 {\r
1450                                                         $found = 1;\r
1451                                                         $found_var = $var;\r
1452                                                 }\r
1453                                         }\r
1454                                         if(!$found && ($this->xs_check_switches == 1))\r
1455                                         {\r
1456                                                 // checking list of known buggy switches\r
1457                                                 $item = -1;\r
1458                                                 for($j=0; $j<$count_bugs; $j++)\r
1459                                                 {\r
1460                                                         if($this->bugs[$j][0] === $var)\r
1461                                                         {\r
1462                                                                 $item = $j;\r
1463                                                         }\r
1464                                                 }\r
1465                                                 if($item >= 0)\r
1466                                                 {\r
1467                                                         $str1 = '<!-- END ' . $this->bugs[$item][1] . ' -->';\r
1468                                                         for ($j = $i+1; ($j < $line_count) && !$found; $j++)\r
1469                                                         {\r
1470                                                                 $pos = strpos($code_lines[$j], $str1);\r
1471                                                                 if($pos !== false)\r
1472                                                                 {\r
1473                                                                         $found_var = $this->bugs[$item][1];\r
1474                                                                         $found = 1;\r
1475                                                                         $code_lines[$j] = str_replace($str, $str1, $code_lines[$j]);\r
1476                                                                 }\r
1477                                                         }\r
1478                                                 }\r
1479                                         }\r
1480                                         if(!$found)\r
1481                                         {\r
1482                                                 $compiled[] = $keyword_str;\r
1483                                                 continue;\r
1484                                         }\r
1485                                         // adding to list of switches\r
1486                                         if(isset($sw[$found_var]))\r
1487                                         {\r
1488                                                 $sw[$found_var] ++;\r
1489                                         }\r
1490                                         else\r
1491                                         {\r
1492                                                 $sw[$found_var] = 1;\r
1493                                         }\r
1494                                 }\r
1495                                 // adding code\r
1496                                 $block_nesting_level++;\r
1497                                 $block_names[$block_nesting_level] = $var;\r
1498                                 if(isset($block_items[$var]))\r
1499                                 {\r
1500                                         $block_items[$var] ++;\r
1501                                 }\r
1502                                 else\r
1503                                 {\r
1504                                         $block_items[$var] = 1;\r
1505                                 }\r
1506                                 if ($block_nesting_level < 2)\r
1507                                 {\r
1508                                         // Block is not nested.\r
1509                                         $line = '<'."?php\n\n";\r
1510                                         if($use_isset)\r
1511                                         {\r
1512                                                 $line .= '$'. $var. '_count = ( isset($this->_tpldata[\''. $var. '.\']) ) ?  sizeof($this->_tpldata[\''. $var. '.\']) : 0;';\r
1513                                         }\r
1514                                         else\r
1515                                         {\r
1516                                                 $line .= '$'. $var. '_count = sizeof($this->_tpldata[\''. $var. '.\']);';\r
1517                                         }\r
1518                                         $line .= "\n" . 'for ($'. $var. '_i = 0; $'. $var. '_i < $'. $var. '_count; $'. $var. '_i++)';\r
1519                                         $line .= "\n". '{'. "\n";\r
1520                                         $line .= ' $'. $var. '_item = &$this->_tpldata[\''. $var. '.\'][$'. $var. '_i];'."\n";\r
1521                                         $line .= " \${$var}_item['S_ROW_COUNT'] = \${$var}_i;\n";\r
1522                                         $line .= " \${$var}_item['S_NUM_ROWS'] = \${$var}_count;\n";\r
1523                                         $line .= "\n?".">";\r
1524                                 }\r
1525                                 else\r
1526                                 {\r
1527                                         // This block is nested.\r
1528                                         // Generate a namespace string for this block.\r
1529                                         $namespace = implode('.', $block_names);\r
1530                                         // strip leading period from root level..\r
1531                                         $namespace = substr($namespace, 2);\r
1532                                         // Get a reference to the data array for this block that depends on the\r
1533                                         // current indices of all parent blocks.\r
1534                                         $varref = $this->generate_block_data_ref($namespace, false);\r
1535                                         // Create the for loop code to iterate over this block.\r
1536                                         $line = '<'."?php\n\n";\r
1537                                         if($use_isset)\r
1538                                         {\r
1539                                                 $line .= '$'. $var. '_count = ( isset('. $varref. ') ) ? sizeof('. $varref. ') : 0;';\r
1540                                         }\r
1541                                         else\r
1542                                         {\r
1543                                                 $line .= '$'. $var. '_count = sizeof('. $varref. ');';\r
1544                                         }\r
1545                                         $line .= "\n". 'for ($'. $var. '_i = 0; $'. $var. '_i < $'. $var. '_count; $'. $var. '_i++)';\r
1546                                         $line .= "\n". '{'. "\n";\r
1547                                         $line .= ' $'. $var. '_item = &'. $varref. '[$'. $var. '_i];'."\n";\r
1548                                         $line .= " \${$var}_item['S_ROW_COUNT'] = \${$var}_i;\n";\r
1549                                         $line .= " \${$var}_item['S_NUM_ROWS'] = \${$var}_count;\n";\r
1550                                         $line .= "\n?".">";\r
1551                                 }\r
1552                                 $compiled[] = $line;\r
1553                                 continue;\r
1554                         }\r
1555                         /*\r
1556                         * <!-- END -->\r
1557                         */\r
1558                         if($keyword_type == XS_TAG_END)\r
1559                         {\r
1560                                 $params = explode(' ', $params_str);\r
1561                                 $num_params = count($params);\r
1562                                 if($num_params == 1)\r
1563                                 {\r
1564                                         $var = $params[0];\r
1565                                 }\r
1566                                 elseif($num_params == 2 && $params[0] === '')\r
1567                                 {\r
1568                                         $var = $params[1];\r
1569                                 }\r
1570                                 elseif($num_params == 2 && $params[1] === '')\r
1571                                 {\r
1572                                         $var = $params[0];\r
1573                                 }\r
1574                                 else\r
1575                                 {\r
1576                                         $compiled[] = $keyword_str;\r
1577                                         continue;\r
1578                                 }\r
1579                                 if($this->xs_check_switches)\r
1580                                 {       \r
1581                                         // checking if this switch was opened\r
1582                                         if(!isset($sw[$var]) || ($sw[$var] < 1))\r
1583                                         {       \r
1584                                                 // there is no opening switch\r
1585                                                 $compiled[] = $keyword_str;\r
1586                                                 continue;\r
1587                                         }\r
1588                                         $sw[$var] --;\r
1589                                 }\r
1590                                 // We have the end of a block.\r
1591                                 $line = '<'."?php\n\n";\r
1592                                 $line .= '} // END ' . $var . "\n\n";\r
1593                                 $line .= 'if(isset($' . $var . '_item)) { unset($' . $var . '_item); } ';\r
1594                                 $line .= "\n\n?".">";\r
1595                                 if(isset($block_items[$var]))\r
1596                                 {\r
1597                                         $block_items[$var] --;\r
1598                                 }\r
1599                                 else\r
1600                                 {\r
1601                                         $block_items[$var] = -1;\r
1602                                 }\r
1603                                 unset($block_names[$block_nesting_level]);\r
1604                                 $block_nesting_level--;\r
1605                                 $compiled[] = $line;\r
1606                                 continue;\r
1607                         }\r
1608                         /*\r
1609                         * <!-- BEGINELSE -->\r
1610                         */\r
1611                         if($keyword_type == XS_TAG_BEGINELSE)\r
1612                         {\r
1613                                 if($block_nesting_level)\r
1614                                 {\r
1615                                         $var = $block_names[$block_nesting_level];\r
1616                                         $compiled[] = '<' . '?php } if(!$' . $var . '_count) { ?' . '>';\r
1617                                 }\r
1618                                 else\r
1619                                 {\r
1620                                         $compiled[] = $keyword_str;\r
1621                                         continue;\r
1622                                 }\r
1623                         }\r
1624                         /*\r
1625                         * <!-- INCLUDE -->\r
1626                         */\r
1627                         if($keyword_type == XS_TAG_INCLUDE)\r
1628                         {\r
1629                                 $params = explode(' ', $params_str);\r
1630                                 $num_params = count($params);\r
1631                                 if($num_params != 1)\r
1632                                 {\r
1633                                         $compiled[] = $keyword_str;\r
1634                                         continue;\r
1635                                 }\r
1636                                 $line = '<'.'?php ';\r
1637                                 $filehash = md5($params_str . $this->include_count . time());\r
1638                                 $line .= ' $this->set_filename(\'xs_include_' . $filehash . '\', \'' . $params_str .'\', true); ';\r
1639                                 $line .= ' $this->pparse(\'xs_include_' . $filehash . '\'); ';\r
1640                                 $line .= ' ?'.'>';\r
1641                                 $this->include_count ++;\r
1642                                 $compiled[] = $line;\r
1643                                 continue;\r
1644                         }\r
1645                         /*\r
1646                         * <!-- IF -->\r
1647                         */\r
1648                         if($keyword_type == XS_TAG_IF || $keyword_type == XS_TAG_ELSEIF)\r
1649                         {\r
1650                                 if(!$count_if)\r
1651                                 {\r
1652                                         $keyword_type = XS_TAG_IF;\r
1653                                 }\r
1654                                 $str = $this->compile_tag_if($params_str, $keyword_type == XS_TAG_IF ? false : true);\r
1655                                 if($str)\r
1656                                 {\r
1657                                         $compiled[] = '<?php ' . $str . ' ?>';\r
1658                                         if($keyword_type == XS_TAG_IF)\r
1659                                         {\r
1660                                                 $count_if ++;\r
1661                                         }\r
1662                                 }\r
1663                                 else\r
1664                                 {\r
1665                                         $compiled[] = $keyword_str;\r
1666                                 }\r
1667                                 continue;\r
1668                         }\r
1669                         /*\r
1670                         * <!-- ELSE -->\r
1671                         */\r
1672                         if($keyword_type == XS_TAG_ELSE && $count_if > 0)\r
1673                         {\r
1674                                 $compiled[] = '<?php } else { ?>';\r
1675                                 continue;\r
1676                         }\r
1677                         /*\r
1678                         * <!-- ENDIF -->\r
1679                         */\r
1680                         if($keyword_type == XS_TAG_ENDIF && $count_if > 0)\r
1681                         {\r
1682                                 $compiled[] = '<?php } ?>';\r
1683                                 $count_if --;\r
1684                                 continue;\r
1685                         }\r
1686                         /*\r
1687                         * <!-- DEFINE -->\r
1688                         */\r
1689                         if($keyword_type == XS_TAG_DEFINE)\r
1690                         {\r
1691                                 $str = $this->compile_tag_define($params_str);\r
1692                                 if($str)\r
1693                                 {\r
1694                                         $compiled[] = '<?php ' . $str . ' ?>';\r
1695                                 }\r
1696                                 else\r
1697                                 {\r
1698                                         $compiled[] = $keyword_str;\r
1699                                 }\r
1700                         }\r
1701                         /*\r
1702                         * <!-- UNDEFINE -->\r
1703                         */\r
1704                         if($keyword_type == XS_TAG_UNDEFINE)\r
1705                         {\r
1706                                 $str = $this->compile_tag_undefine($params_str);\r
1707                                 if($str)\r
1708                                 {\r
1709                                         $compiled[] = '<?php ' . $str . ' ?>';\r
1710                                 }\r
1711                                 else\r
1712                                 {\r
1713                                         $compiled[] = $keyword_str;\r
1714                                 }\r
1715                         }\r
1716                 }\r
1717                 \r
1718                 // bring it back into a single string.\r
1719                 $code_header = '';\r
1720                 $code_footer = '';\r
1721                 if(!$use_isset)\r
1722                 {\r
1723                         $code_header =  "<". "?php\n\$old_level = @error_reporting(E_ERROR | E_WARNING | E_PARSE); \n?".">";\r
1724                         $code_footer = '<'."?php @error_reporting(\$old_level); ?".'>';\r
1725                 }\r
1726 \r
1727                 return $code_header . implode('', $compiled) . $code_footer;\r
1728         }\r
1729 \r
1730         /*\r
1731         * Compile code between tags\r
1732         */\r
1733         function _compile_text($code, $use_isset)\r
1734         {\r
1735                 if(strlen($code) < 3)\r
1736                 {\r
1737                         return $code;\r
1738                 }\r
1739                 // change template varrefs into PHP varrefs\r
1740                 // This one will handle varrefs WITH namespaces\r
1741                 $varrefs = array();\r
1742                 preg_match_all('#\{(([a-z0-9\-_]+?\.)+?)([a-z0-9\-_]+?)\}#is', $code, $varrefs);\r
1743                 $varcount = sizeof($varrefs[1]);\r
1744                 $search = array();\r
1745                 $replace = array();\r
1746                 for ($i = 0; $i < $varcount; $i++)\r
1747                 {\r
1748                         $namespace = $varrefs[1][$i];\r
1749                         $varname = $varrefs[3][$i];\r
1750                         $new = $this->generate_block_varref($namespace, $varname, $use_isset);\r
1751                         $search[] = $varrefs[0][$i];\r
1752                         $replace[] = $new;\r
1753                 }\r
1754                 if(count($search) > 0)\r
1755                 {\r
1756                         $code = str_replace($search, $replace, $code);\r
1757                 }\r
1758                 // This will handle the remaining root-level varrefs\r
1759                 $code = preg_replace('#\{([a-z0-9\-_]*?)\}#is', '<'.'?php echo isset($this->vars[\'\1\']) ? $this->vars[\'\1\'] : $this->lang(\'\1\'); ?'.'>', $code);\r
1760                 $code = preg_replace('#\{\$([a-z0-9\-_]*?)\}#is', '<'.'?php echo isset($this->_tpldata[\'DEFINE\'][\'.\'][\'\\1\']) ? $this->_tpldata[\'DEFINE\'][\'.\'][\'\\1\'] : \'\'; ?'.'>', $code);\r
1761                 return $code;\r
1762         }\r
1763 \r
1764         //\r
1765         // Compile IF tags - much of this is from Smarty with\r
1766         // some adaptions for our block level methods\r
1767         //\r
1768         function compile_tag_if($tag_args, $elseif)\r
1769         {\r
1770         /* Tokenize args for 'if' tag. */\r
1771         preg_match_all('/(?:\r
1772                          "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"         |\r
1773                          \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'     |\r
1774                          [(),]                                  |\r
1775                          [^\s(),]+)/x', $tag_args, $match);\r
1776 \r
1777         $tokens = $match[0];\r
1778         $is_arg_stack = array();\r
1779 \r
1780         for ($i = 0; $i < count($tokens); $i++)\r
1781                 {\r
1782                         $token = &$tokens[$i];\r
1783 \r
1784                         switch ($token)\r
1785                         {\r
1786                 case '!':\r
1787                 case '%':\r
1788                 case '!==':\r
1789                 case '==':\r
1790                 case '===':\r
1791                 case '>':\r
1792                 case '<':\r
1793                 case '!=':\r
1794                 case '<>':\r
1795                 case '<<':\r
1796                 case '>>':\r
1797                 case '<=':\r
1798                 case '>=':\r
1799                 case '&&':\r
1800                 case '||':\r
1801                                 case '|':\r
1802                                 case '^':\r
1803                                 case '&':\r
1804                                 case '~':\r
1805                                 case ')':\r
1806                                 case ',':\r
1807                                 case '+':\r
1808                                 case '-':\r
1809                                 case '*':\r
1810                                 case '/':\r
1811                                 case '@':\r
1812                                         break;  \r
1813 \r
1814                                 case 'eq':\r
1815                                         $token = '==';\r
1816                                         break;\r
1817 \r
1818                                 case 'ne':\r
1819                                 case 'neq':\r
1820                                         $token = '!=';\r
1821                                         break;\r
1822 \r
1823                                 case 'lt':\r
1824                                         $token = '<';\r
1825                                         break;\r
1826 \r
1827                                 case 'le':\r
1828                                 case 'lte':\r
1829                                         $token = '<=';\r
1830                                         break;\r
1831 \r
1832                                 case 'gt':\r
1833                                         $token = '>';\r
1834                                         break;\r
1835 \r
1836                                 case 'ge':\r
1837                                 case 'gte':\r
1838                                         $token = '>=';\r
1839                                         break;\r
1840 \r
1841                                 case 'and':\r
1842                                         $token = '&&';\r
1843                                         break;\r
1844 \r
1845                                 case 'or':\r
1846                                         $token = '||';\r
1847                                         break;\r
1848 \r
1849                                 case 'not':\r
1850                                         $token = '!';\r
1851                                         break;\r
1852 \r
1853                                 case 'mod':\r
1854                                         $token = '%';\r
1855                                         break;\r
1856 \r
1857                                 case '(':\r
1858                                         array_push($is_arg_stack, $i);\r
1859                                         break;\r
1860 \r
1861                                 case 'is':\r
1862                                         $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1;\r
1863                                         $is_arg = implode('     ', array_slice($tokens, $is_arg_start, $i -     $is_arg_start));\r
1864 \r
1865                                         $new_tokens     = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));\r
1866 \r
1867                                         array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);\r
1868 \r
1869                                         $i = $is_arg_start;\r
1870 \r
1871                                 default:\r
1872                                         if (preg_match('#^(([a-z0-9\-_]+?\.)+?)?(\$)?([A-Z]+[A-Z0-9\-_]+)$#s', $token, $varrefs))\r
1873                                         {\r
1874                                                 $token = (!empty($varrefs[1])) ? $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[3]) . '[\'' . $varrefs[4] . '\']' : (($varrefs[3]) ? '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[4] . '\']' : '$this->vars[\'' . $varrefs[4] . '\']');\r
1875                                         }\r
1876                                         break;\r
1877             }\r
1878         }\r
1879 \r
1880                 $code = (($elseif) ? '} elseif (' : 'if (') . (implode(' ', $tokens) . ') { ');\r
1881         \r
1882                 return $code;\r
1883         }\r
1884 \r
1885         // This is from Smarty\r
1886         function _parse_is_expr($is_arg, $tokens)\r
1887         {\r
1888                 $expr_end =     0;\r
1889                 $negate_expr = false;\r
1890 \r
1891                 if (($first_token = array_shift($tokens)) == 'not')\r
1892                 {\r
1893                         $negate_expr = true;\r
1894                         $expr_type = array_shift($tokens);\r
1895                 }\r
1896                 else\r
1897                 {\r
1898                         $expr_type = $first_token;\r
1899                 }\r
1900 \r
1901                 switch ($expr_type)\r
1902                 {\r
1903                         case 'even':\r
1904                                 if (@$tokens[$expr_end] == 'by')\r
1905                                 {\r
1906                                         $expr_end++;\r
1907                                         $expr_arg =     $tokens[$expr_end++];\r
1908                                         $expr = "!(($is_arg     / $expr_arg) % $expr_arg)";\r
1909                                 }\r
1910                                 else\r
1911                                 {\r
1912                                         $expr = "!($is_arg % 2)";\r
1913                                 }\r
1914                                 break;\r
1915 \r
1916                         case 'odd':\r
1917                                 if (@$tokens[$expr_end] == 'by')\r
1918                                 {\r
1919                                         $expr_end++;\r
1920                                         $expr_arg =     $tokens[$expr_end++];\r
1921                                         $expr = "(($is_arg / $expr_arg) % $expr_arg)";\r
1922                                 }\r
1923                                 else\r
1924                                 {\r
1925                                         $expr = "($is_arg %     2)";\r
1926                                 }\r
1927                                 break;\r
1928 \r
1929                         case 'div':\r
1930                                 if (@$tokens[$expr_end] == 'by')\r
1931                                 {\r
1932                                         $expr_end++;\r
1933                                         $expr_arg =     $tokens[$expr_end++];\r
1934                                         $expr = "!($is_arg % $expr_arg)";\r
1935                                 }\r
1936                                 break;\r
1937 \r
1938                         default:\r
1939                                 break;\r
1940                 }\r
1941 \r
1942                 if ($negate_expr)\r
1943                 {\r
1944                         $expr = "!($expr)";\r
1945                 }\r
1946 \r
1947                 array_splice($tokens, 0, $expr_end,     $expr);\r
1948 \r
1949                 return $tokens;\r
1950         }\r
1951 \r
1952 \r
1953         function compile_tag_define($tag_args)\r
1954         {\r
1955                 preg_match('#^(([a-z0-9\-_]+?\.)+?)?\$([A-Z][A-Z0-9_\-]*?) = (\'?)(.*?)(\'?)$#', $tag_args, $match);\r
1956 \r
1957                 if (empty($match[3]) || empty($match[5]))\r
1958                 {\r
1959                         return '';\r
1960                 }\r
1961 \r
1962                 // Are we a string?\r
1963                 if ($match[4] && $match[6])\r
1964                 {\r
1965                         $match[5] = "'" . addslashes(str_replace(array('\\\'', '\\\\'), array('\'', '\\'), $match[5])) . "'";\r
1966                 }\r
1967                 else\r
1968                 {\r
1969                         preg_match('#(true|false|\.)#i', $match[5], $type);\r
1970 \r
1971                         switch (strtolower($type[1]))\r
1972                         {\r
1973                                 case 'true':\r
1974                                 case 'false':\r
1975                                         $match[5] = strtoupper($match[5]);\r
1976                                         break;\r
1977                                 case '.';\r
1978                                         $match[5] = doubleval($match[5]);\r
1979                                         break;\r
1980                                 default:\r
1981                                         $match[5] = intval($match[5]);\r
1982                                         break;\r
1983                         }\r
1984                 }\r
1985 \r
1986                 return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[3] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[3] . '\']') . ' = ' . $match[5] . ';';\r
1987         }\r
1988 \r
1989         function compile_tag_undefine($tag_args)\r
1990         {\r
1991                 preg_match('#^(([a-z0-9\-_]+?\.)+?)?\$([A-Z][A-Z0-9_\-]*?)$#', $tag_args, $match);\r
1992                 if (empty($match[3]))\r
1993                 {\r
1994                         return '';\r
1995                 }\r
1996                 return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[3] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[3] . '\']') . ');';\r
1997         }\r
1998 \r
1999         /**\r
2000          * Compiles code and writes to cache if needed\r
2001          */\r
2002         function compile2($code, $handle, $cache_file)\r
2003         {\r
2004                 $code = $this->compile_code('', $code, XS_USE_ISSET);\r
2005                 if($cache_file && !empty($this->use_cache) && !empty($this->auto_compile))\r
2006                 {\r
2007                         $res = $this->write_cache($cache_file, $code);\r
2008                         if($handle && $res)\r
2009                         {\r
2010                                 $this->files_cache[$handle] = $cache_file;\r
2011                         }\r
2012                 }\r
2013                 $code = '?'.'>'.$code.'<'."?php\n";\r
2014                 return $code;\r
2015         }\r
2016 \r
2017         /**\r
2018          * Compiles the given string of code, and returns\r
2019          * the result in a string.\r
2020          * If "do_not_echo" is true, the returned code will not be directly\r
2021          * executable, but can be used as part of a variable assignment\r
2022          * for use in assign_code_from_handle().\r
2023          * This function isn't used and kept only for compatibility with original template.php\r
2024          */\r
2025         function compile($code, $do_not_echo = false, $retvar = '')\r
2026         {\r
2027                 $code = ' ?'.'>' . $this->compile_code('', $code, true) . '<'."?php \n";\r
2028                 if($do_not_echo)\r
2029                 {\r
2030                         $code = "ob_start();\n". $code. "\n\${$retvar} = ob_get_contents();\nob_end_clean();\n";\r
2031                 }\r
2032                 return $code;\r
2033         }\r
2034 \r
2035         /**\r
2036          * Write cache to disk\r
2037          */\r
2038         function write_cache($filename, $code)\r
2039         {\r
2040                 // check if cache is writable\r
2041                 if(!$this->cache_writable)\r
2042                 {\r
2043                         return false;\r
2044                 }\r
2045                 // check if filename is valid\r
2046                 if(substr($filename, 0, strlen($this->cachedir)) !== $this->cachedir)\r
2047                 {\r
2048                         return false;\r
2049                 }\r
2050                 // try to open file\r
2051                 $file = @fopen($filename, 'w');\r
2052                 if(!$file)\r
2053                 {\r
2054                         // try to create directories\r
2055                         $dir = substr($filename, strlen($this->cachedir), strlen($filename));\r
2056                         $dirs = explode('/', $dir);\r
2057                         $path = $this->cachedir; \r
2058                         @umask(0);\r
2059                         if(!@is_dir($path))\r
2060                         {\r
2061                                 if(!@mkdir($path))\r
2062                                 {\r
2063                                         $this->cache_writable = 0;\r
2064                                         return false;\r
2065                                 }\r
2066                                 else\r
2067                                 {\r
2068                                         @chmod($path, 0777);\r
2069                                 }\r
2070                         }\r
2071                         $count = count($dirs);\r
2072                         if($count > 0)\r
2073                         for($i=0; $i<$count-1; $i++)\r
2074                         {\r
2075                                 if($i>0)\r
2076                                 {\r
2077                                         $path .= '/';\r
2078                                 }\r
2079                                 $path .= $dirs[$i];\r
2080                                 if(!@is_dir($path))\r
2081                                 {\r
2082                                         if(!@mkdir($path))\r
2083                                         {\r
2084                                                 $this->cache_writable = 0;\r
2085                                                 return false;\r
2086                                         }\r
2087                                         else\r
2088                                         {\r
2089                                                 @chmod($path, 0777);\r
2090                                         }\r
2091                                 }\r
2092                         }\r
2093                         // try to open file again after directories were created\r
2094                         $file = @fopen($filename, 'w');\r
2095                 }\r
2096                 if(!$file)\r
2097                 {\r
2098                         $this->cache_writable = 0;\r
2099                         return false;\r
2100                 }\r
2101                 fputs($file, "<?php\n\n// eXtreme Styles mod cache. Generated on " . date('r') . " (time=" . time() . ")\n\n?>");\r
2102                 fputs($file, $code);\r
2103                 fclose($file);\r
2104                 @chmod($filename, 0777);\r
2105                 return true;\r
2106         }\r
2107 \r
2108         function xs_startup()\r
2109         {\r
2110                 global $phpEx, $board_config, $phpbb_root_path;\r
2111                 if(empty($this->xs_started))\r
2112                 {       // adding predefined variables\r
2113                         $this->xs_started = 1;\r
2114                         // file extension with session ID (eg: "php?sid=123&" or "php?")\r
2115                         // can be used to make custom URLs without modding phpbb\r
2116                         // contains "&" or "?" at the end so you can easily append paramenters\r
2117                         $php = append_sid($phpEx);\r
2118                         if(strpos($php, '?'))\r
2119                         {\r
2120                                 $php .= '&';\r
2121                         }\r
2122                         else\r
2123                         {\r
2124                                 $php .= '?';\r
2125                         }\r
2126                         $this->vars['PHP'] = isset($this->vars['PHP']) ? $this->vars['PHP'] : $php;\r
2127                         // adding language variable (eg: "english" or "german")\r
2128                         // can be used to make truly multi-lingual templates\r
2129                         $this->vars['LANG'] = isset($this->vars['LANG']) ? $this->vars['LANG'] : $board_config['default_lang'];\r
2130                         // adding current template\r
2131                         $tpl = $this->root . '/'; // $phpbb_root_path . 'templates/' . $this->tpl . '/';\r
2132                         if(substr($tpl, 0, 2) === './')\r
2133                         {\r
2134                                 $tpl = substr($tpl, 2, strlen($tpl));\r
2135                         }\r
2136                         $this->vars['TEMPLATE'] = isset($this->vars['TEMPLATE']) ? $this->vars['TEMPLATE'] : $tpl;\r
2137                         $this->vars['TEMPLATE_NAME'] = isset($this->vars['TEMPLATE_NAME']) ? $this->vars['TEMPLATE_NAME'] : $this->tpl;\r
2138                         $this->_tpldata['switch_xs_enabled.'] = array(array('version' => $this->xs_versiontxt));\r
2139                 }\r
2140         }\r
2141 \r
2142         /**\r
2143          * Checks for empty variable and shows language variable if possible.\r
2144          */\r
2145         function lang($var)\r
2146         {\r
2147                 global $lang;\r
2148                 if(substr($var, 0, 2) === 'L_')\r
2149                 {\r
2150                         $var = substr($var, 2);\r
2151                         // check variable as it is\r
2152                         if(isset($lang[$var]))\r
2153                         {\r
2154                                 return $lang[$var];\r
2155                         }\r
2156                         // check variable in lower case\r
2157                         if(isset($lang[strtolower($var)]))\r
2158                         {\r
2159                                 return $lang[strtolower($var)];\r
2160                         }\r
2161                         // check variable with first letter in upper case\r
2162                         $str = ucfirst(strtolower($var));\r
2163                         if(isset($lang[$str]))\r
2164                         {\r
2165                                 return $lang[$str];\r
2166                         }\r
2167                         return ''; //str_replace('_', ' ', $var);\r
2168                 }\r
2169                 return '';\r
2170         }\r
2171 \r
2172         //\r
2173         //\r
2174         // Functions added for USERGROUP MOD (optimized)\r
2175         //\r
2176         //\r
2177         function append_var_from_handle_to_block($blockname, $varname, $handle)\r
2178         {\r
2179                 $this->assign_var_from_handle('_tmp', $handle);\r
2180                 // assign the value of the generated variable to the given varname.\r
2181                 $this->append_block_vars($blockname, array($varname => $this->vars['_tmp']));\r
2182                 return true;\r
2183         }\r
2184 \r
2185         function append_block_vars($blockname, $vararray)\r
2186         {\r
2187                 if(strstr($blockname, '.'))\r
2188                 {\r
2189                         // Nested block.\r
2190                         $blocks = explode('.', $blockname);\r
2191                         $blockcount = sizeof($blocks) - 1;\r
2192                         $str = &$this->_tpldata;\r
2193                         for($i = 0; $i < $blockcount; $i++)\r
2194                         {\r
2195                                 $str = &$str[$blocks[$i].'.'];\r
2196                                 $str = &$str[sizeof($str)-1];\r
2197                         }\r
2198                         // Now we add the block that we're actually assigning to.\r
2199                         // We're adding a new iteration to this block with the given\r
2200                         //   variable assignments.\r
2201                         $str = &$str[$blocks[$blockcount].'.'];\r
2202                         $count = sizeof($str) - 1;\r
2203                         if($count >= 0)\r
2204                         {\r
2205                                 // adding only if there is at least one item\r
2206                                 $str[$count] = array_merge($str[$count], $vararray);\r
2207                         }\r
2208                 }\r
2209                 else\r
2210                 {\r
2211                         // Top-level block.\r
2212                         // Add a new iteration to this block with the variable assignments\r
2213                         // we were given.\r
2214                         $str = &$this->_tpldata[$blockname.'.'];\r
2215                         $count = sizeof($str) - 1;\r
2216                         if($count >= 0)\r
2217                         {\r
2218                                 // adding only if there is at least one item\r
2219                                 $str[$count] = array_merge($str[$count], $vararray);\r
2220                         }\r
2221                 }\r
2222                 return true;\r
2223         }\r
2224 \r
2225         /*\r
2226         * Flush a root level block, so it becomes empty.\r
2227         */\r
2228         function flush_block_vars($blockname)\r
2229         {\r
2230                 // Top-level block.\r
2231                 // flush a existing block we were given.\r
2232                 $current_iteration = sizeof($this->_tpldata[$blockname . '.']) - 1;\r
2233                 unset($this->_tpldata[$blockname . '.']);\r
2234                 return true;\r
2235         }\r
2236 \r
2237         /*\r
2238         * Add style configuration\r
2239         */\r
2240         function _add_config($tpl, $add_vars = true)\r
2241         {\r
2242                 global $phpbb_root_path;\r
2243                 if(@file_exists($phpbb_root_path . 'templates/' . $tpl . '/xs_config.cfg'))\r
2244                 {\r
2245                         $style_config = array();\r
2246                         include($phpbb_root_path . 'templates/' . $tpl . '/xs_config.cfg');\r
2247                         if(count($style_config))\r
2248                         {\r
2249                                 global $board_config, $db;\r
2250                                 for($i=0; $i<count($style_config); $i++)\r
2251                                 {\r
2252                                         $this->style_config[$style_config[$i]['var']] = $style_config[$i]['default'];\r
2253                                         if($add_vars)\r
2254                                         {\r
2255                                                 $this->vars['TPL_CFG_' . strtoupper($style_config[$i]['var'])] = $style_config[$i]['default'];\r
2256                                         }\r
2257                                 }\r
2258                                 $str = $this->_serialize($this->style_config);\r
2259                                 $config_name = 'xs_style_' . $tpl;\r
2260                                 $board_config[$config_name] = $str;\r
2261                                 $sql = "INSERT INTO " . CONFIG_TABLE . " (config_name, config_value) VALUES ('" . str_replace('\\\'', '\'\'', addslashes($config_name)) . "', '" . str_replace('\\\'', '\'\'', addslashes($str)) . "')";\r
2262                                 $db->sql_query($sql);\r
2263                                 // recache config table for cat_hierarchy 2.1.0\r
2264                                 global $config;\r
2265                                 if(isset($config->data) && $config->data === $board_config && isset($config->data['mod_cat_hierarchy']))\r
2266                                 {\r
2267                                         $config->read(true);\r
2268                                 }\r
2269                                 return true;\r
2270                         }\r
2271                 }\r
2272                 return false;\r
2273         }\r
2274 \r
2275         function add_config($tpl)\r
2276         {\r
2277                 $config_name = 'xs_style_' . $tpl;\r
2278                 global $board_config;\r
2279                 $result = false;\r
2280                 if(empty($board_config[$config_name]))\r
2281                 {\r
2282                         $old = $this->style_config;\r
2283                         $result = $this->_add_config($tpl, false);\r
2284                         $this->style_config = $old;\r
2285                 }\r
2286                 return $result;\r
2287         }\r
2288 \r
2289         /*\r
2290         * Refresh config data\r
2291         */\r
2292         function _refresh_config($tpl, $add_vars = false)\r
2293         {\r
2294                 global $phpbb_root_path;\r
2295                 if(@file_exists($phpbb_root_path . 'templates/' . $tpl . '/xs_config.cfg'))\r
2296                 {\r
2297                         $style_config = array();\r
2298                         include($phpbb_root_path . 'templates/' . $tpl . '/xs_config.cfg');\r
2299                         if(count($style_config))\r
2300                         {\r
2301                                 global $board_config, $db;\r
2302                                 for($i=0; $i<count($style_config); $i++)\r
2303                                 {\r
2304                                         if(!isset($this->style_config[$style_config[$i]['var']]))\r
2305                                         {\r
2306                                                 $this->style_config[$style_config[$i]['var']] = $style_config[$i]['default'];\r
2307                                                 if($add_vars)\r
2308                                                 {\r
2309                                                         $this->vars['TPL_CFG_' . strtoupper($style_config[$i]['var'])] = $style_config[$i]['default'];\r
2310                                                 }\r
2311                                         }\r
2312                                 }\r
2313                                 $str = $this->_serialize($this->style_config);\r
2314                                 $config_name = 'xs_style_' . $tpl;\r
2315                                 if(isset($board_config[$config_name]))\r
2316                                 {\r
2317                                         $sql = "UPDATE " . CONFIG_TABLE . " SET config_value='" . str_replace('\\\'', '\'\'', addslashes($str)) . "' WHERE config_name='" . str_replace('\\\'', '\'\'', addslashes($config_name)) . "'";\r
2318                                 }\r
2319                                 else\r
2320                                 {\r
2321                                         $sql = "INSERT INTO " . CONFIG_TABLE . " (config_name, config_value) VALUES ('" . str_replace('\\\'', '\'\'', addslashes($config_name)) . "', '" . str_replace('\\\'', '\'\'', addslashes($str)) . "')";\r
2322                                 }\r
2323                                 $db->sql_query($sql);\r
2324                                 $board_config[$config_name] = $str;\r
2325                                 // recache config table for cat_hierarchy 2.1.0\r
2326                                 global $config;\r
2327                                 if(isset($config->data) && $config->data === $board_config && isset($config->data['mod_cat_hierarchy']))\r
2328                                 {\r
2329                                         $config->read(true);\r
2330                                 }\r
2331                                 return true;\r
2332                         }\r
2333                 }\r
2334                 return false;\r
2335         }\r
2336 \r
2337         function refresh_config($tpl = '')\r
2338         {\r
2339                 if($tpl === '')\r
2340                 {\r
2341                         $tpl = $this->tpl;\r
2342                 }\r
2343                 if($tpl == $this->tpl)\r
2344                 {\r
2345                         $result = $this->_refresh_config($tpl, true);\r
2346                 }\r
2347                 else\r
2348                 {\r
2349                         $old = $this->style_config;\r
2350                         $result = $this->_refresh_config($tpl, false);\r
2351                         $this->style_config = $old;\r
2352                 }\r
2353                 return $result;\r
2354         }\r
2355 \r
2356         /*\r
2357         * Get style configuration\r
2358         */\r
2359         function _get_config($tpl, $add_config)\r
2360         {\r
2361                 $this->style_config = array();\r
2362                 if(empty($tpl))\r
2363                 {\r
2364                         $tpl = $this->tpl;\r
2365                 }\r
2366                 $config_name = 'xs_style_' . $tpl;\r
2367                 global $board_config;\r
2368                 if(empty($board_config[$config_name]))\r
2369                 {\r
2370                         if($add_config)\r
2371                         {\r
2372                                 $this->_add_config($tpl, $tpl === $this->tpl ? true : false);\r
2373                         }\r
2374                         return $this->style_config;\r
2375                 }\r
2376                 $this->style_config = $this->_unserialize($board_config[$config_name]);\r
2377                 if($tpl === $this->tpl)\r
2378                 {\r
2379                         foreach($this->style_config as $var => $value)\r
2380                         {\r
2381                                 $this->vars['TPL_CFG_' . strtoupper($var)] = $value;\r
2382                         }\r
2383                 }\r
2384                 return $this->style_config;\r
2385         }\r
2386 \r
2387         function get_config($tpl = '', $add_config = true)\r
2388         {\r
2389                 if(empty($tpl))\r
2390                 {\r
2391                         if(empty($this->tpl))\r
2392                         {\r
2393                                 return array();\r
2394                         }\r
2395                         $this->_get_config($this->tpl, $add_config);\r
2396                         return $this->style_config;\r
2397                 }\r
2398                 else\r
2399                 {\r
2400                         $old_config = $this->style_config;\r
2401                         $result = $this->_get_config($tpl, $add_config);\r
2402                         $this->style_config = $old_config;\r
2403                         return $result;\r
2404                 }\r
2405         }\r
2406 \r
2407         /*\r
2408         * Split/merge config data.\r
2409         * Using this function instead of (un)serialize because it generates smaller string so it can be stored in phpbb_config\r
2410         */\r
2411         function _serialize($array)\r
2412         {\r
2413                 if(!is_array($array))\r
2414                 {\r
2415                         return '';\r
2416                 }\r
2417                 $str = '';\r
2418                 foreach($array as $var => $value)\r
2419                 {\r
2420                         if($str)\r
2421                         {\r
2422                                 $str .= '|';\r
2423                         }\r
2424                         $str .= $var . '=' . str_replace('|', '', $value);\r
2425                 }\r
2426                 return $str;\r
2427         }\r
2428         function _unserialize($str)\r
2429         {\r
2430                 $array = array();\r
2431                 $list = explode('|', $str);\r
2432                 for($i=0; $i<count($list); $i++)\r
2433                 {\r
2434                         $row = explode('=', $list[$i], 2);\r
2435                         if(count($row) == 2)\r
2436                         {\r
2437                                 $array[$row[0]] = $row[1];\r
2438                         }\r
2439                 }\r
2440                 return $array;\r
2441         }\r
2442 \r
2443 }\r
2444 \r
2445 function xs_switch($tpl, $name)\r
2446 {\r
2447         return (isset($tpl->_tpldata[$name.'.']) && count($tpl->_tpldata[$name.'.']) > 0);\r
2448 }\r
2449 \r
2450 ?>