3 /***************************************************************************
\r
6 * copyright : (C) 2001 The phpBB Group
\r
7 * email : support@phpbb.com
\r
9 * phpBB version : 2.0.x
\r
10 * eXtreme Styles mod : 2.3.1
\r
11 * Support : http://www.phpbbstyles.com
\r
13 * file revision : 77
\r
14 * project revision : 78
\r
15 * last modified : 05 Dec 2005 13:54:54
\r
17 ***************************************************************************/
\r
19 /***************************************************************************
\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
26 ***************************************************************************/
\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
34 * eXtreme Styles mod by CyberAlien.
\r
36 * IF, ELSEIF, ENDIF tags are backported from phpBB 2.2
\r
38 * Documentation for this mod can be found here:
\r
39 * http://www.phpbbstyles.com
\r
41 * Support for eXtreme Styles mod is provided at http://www.phpbbstyles.com
\r
43 * Thanks to DMaJ007 for idea on how to include some extra tags.
\r
47 define('XS_SEPARATOR', '.');
\r
48 define('XS_DIR_CACHE', 'cache');
\r
49 define('XS_USE_ISSET', '1');
\r
51 // cache filenames prefix
\r
52 define('XS_TPL_PREFIX', 'tpl_');
\r
53 define('XS_TPL_PREFIX2', 'tpl2_');
\r
55 // templates directory
\r
56 define('XS_TPL_START', 'templates/');
\r
57 define('XS_TPL_ANY', '/templates/');
\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
75 var $classname = "Template";
\r
77 // variable that holds all the data we'll be substituting into
\r
78 // the compiled templates.
\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
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
93 // Root template directory.
\r
96 // Cache directory (compatible with default cache mod)
\r
99 // Search/replace for unknown files
\r
100 var $cache_search = array();
\r
101 var $cache_replace = array();
\r
103 // Template root directory (generated by set_rootdir)
\r
105 var $tpldir_len = 0;
\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
111 // this will hash handle names to the compiled code for that handle.
\r
112 var $compiled_code = array();
\r
114 // This will hold the uncompiled code for that handle.
\r
115 var $uncompiled_code = array();
\r
118 var $use_cache = 1;
\r
119 var $cache_writable = 1;
\r
121 // Auto-compile setting
\r
122 var $auto_compile = 1;
\r
124 // Current template name
\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
131 // counter for include
\r
132 var $include_count = 0;
\r
134 // php extension. will be replaced by $phpEx in Template() function unless you disable it there
\r
137 // True if check switches
\r
138 var $xs_check_switches = 1;
\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
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
150 // subtemplates mod detection
\r
151 var $subtemplates = false;
\r
153 // style configuration
\r
154 var $style_config = array();
\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
159 // array(start_tag, end_tag)
\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
171 * Constructor. Installs XS mod on first run or updates it and sets the root dir.
\r
173 function Template($root = '.')
\r
175 // setting pointer "vars"
\r
176 $this->vars = &$this->_tpldata['.'][0];
\r
177 // load configuration
\r
178 $this->load_config($root, true);
\r
182 * Load mod configuration
\r
184 function load_config($root, $edit_db)
\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
194 // list of outdated variables
\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
202 // list of default values
\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
220 // checking if all variables exist
\r
221 foreach($default as $var => $value)
\r
223 if(!isset($board_config[$var]))
\r
225 $board_config[$var] = $value;
\r
229 // checking if there are any outdated variables that should be deleted
\r
230 for($i=0; $i<count($outdated); $i++)
\r
232 if(isset($board_config[$outdated[$i]]))
\r
234 $del[] = $outdated[$i];
\r
237 if(!isset($board_config['xs_version']))
\r
239 $board_config['xs_version'] = $this->xs_version;
\r
240 $add[] = 'xs_version';
\r
242 elseif($board_config['xs_version'] != $this->xs_version)
\r
244 $board_config['xs_version'] = $this->xs_version;
\r
245 $up[] = 'xs_version';
\r
248 if(!empty($board_config['xs_auto_recompile']))
\r
250 if(!$board_config['xs_auto_compile'])
\r
252 $board_config['xs_auto_compile'] = 1;
\r
253 if(!in_array('xs_auto_compile', $up) && !in_array('xs_auto_compile', $add))
\r
255 $up[] = 'xs_auto_compile';
\r
260 if($edit_db && ((count($add) > 0) || (count($up) > 0) || (count($del) > 0)))
\r
262 $board_config['xs_template_time'] = time();
\r
263 if(!in_array('xs_template_time', $up))
\r
265 $up[] = 'xs_template_time';
\r
270 // adding new config values
\r
271 for($i=0; $i<count($add); $i++)
\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
276 // removing old configuration variables that aren't used
\r
277 for($i=0; $i<count($del); $i++)
\r
279 $sql = "DELETE FROM " . CONFIG_TABLE . " WHERE config_name='" . $del[$i] . "'";
\r
280 $db->sql_query($sql);
\r
282 // updating variables that should be overwritten
\r
283 for($i=0; $i<count($up); $i++)
\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
288 // recache config table for cat_hierarchy 2.1.0
\r
290 if(isset($config->data) && $config->data === $board_config && isset($config->data['mod_cat_hierarchy']))
\r
292 $config->read(true);
\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
307 $this->load_replacements($this->tpldir . $this->tpl . '/xs.cfg');
\r
309 if($old_root !== $this->root)
\r
311 $this->clear_files();
\r
316 * Sets the template root directory for this Template object.
\r
318 function set_rootdir($dir)
\r
320 global $board_config, $phpbb_root_path;
\r
321 if (!@is_dir($dir))
\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
339 $this->subtemplates = true;
\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
350 $this->_tpldata = array('.' => array(0 => array()));
\r
351 $this->vars = &$this->_tpldata['.'][0];
\r
352 $this->xs_started = 0;
\r
356 * Clears list of compiled files.
\r
358 function clear_files()
\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
368 * Loads replacements from .cfg file
\r
370 function load_replacements($file)
\r
372 if(@file_exists($file))
\r
374 $replace = array();
\r
376 $this->replace = array_merge($this->replace, $replace);
\r
381 * Extracts template name from path
\r
383 function template_name($dir)
\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
391 if(substr($dir, 0, strlen($tpl_null)) !== $tpl_null)
\r
395 $str = substr($dir, strlen($tpl_null), strlen($dir));
\r
399 $str = substr($dir, $pos + strlen($tpl), strlen($dir));
\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
408 if(strpos($str, $tpl) !== false)
\r
410 $dir = $this->template_name($str);
\r
412 // check for another subdirectory
\r
413 $pos = strpos($dir, '/');
\r
416 $dir = substr($dir, 0, $pos);
\r
421 function subtemplates_make_filename($filename)
\r
423 global $HTTP_GET_VARS, $HTTP_POST_VARS, $db, $board_config, $images, $theme;
\r
424 global $sub_template_key_image, $sub_templates;
\r
427 // initiate the sub-template image pack that will be use
\r
428 $sub_template_key_image = POST_CAT_URL . '0';
\r
430 // Check if sub_templates are defined for this theme
\r
431 if ( $board_config['version'] > '.0.5' )
\r
433 $sub_templates_cfg = @phpbb_realpath($this->root . '/sub_templates.cfg');
\r
437 $sub_templates_cfg = $this->root . '/sub_templates.cfg';
\r
439 @include($sub_templates_cfg);
\r
440 if ( isset($sub_templates) )
\r
448 if ( !defined('IN_PRIVMSG') && ( isset($HTTP_GET_VARS[POST_POST_URL]) || isset($HTTP_POST_VARS[POST_POST_URL]) ) )
\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
453 if ( isset($HTTP_GET_VARS[POST_TOPIC_URL]) || isset($HTTP_POST_VARS[POST_TOPIC_URL]) )
\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
458 if ( isset($HTTP_GET_VARS[POST_FORUM_URL]) || isset($HTTP_POST_VARS[POST_FORUM_URL]) )
\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
463 if ( isset($HTTP_GET_VARS[POST_CAT_URL]) || isset($HTTP_POST_VARS[POST_CAT_URL]) )
\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
468 if ( isset($HTTP_GET_VARS['selected_id']) || isset($HTTP_POST_VARS['selected_id']) )
\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
478 case POST_FORUM_URL:
\r
481 case POST_TOPIC_URL:
\r
484 case POST_POST_URL:
\r
485 if ( !defined('IN_PRIVMSG') )
\r
496 if ( ($forum_id <= 0) && ($cat_id <= 0) )
\r
500 $sql = "SELECT * FROM " . POSTS_TABLE . " WHERE post_id=$post_id";
\r
501 if ( !($result = $db->sql_query($sql)) )
\r
503 message_die(GENERAL_ERROR, 'Wasn\'t able to access posts', '', __LINE__, __FILE__, $sql);
\r
505 if ( $row = $db->sql_fetchrow($result) )
\r
507 $forum_id = $row['forum_id'];
\r
513 $sql = "SELECT * FROM " . TOPICS_TABLE . " WHERE topic_id=$topic_id";
\r
514 if ( !($result = $db->sql_query($sql)) )
\r
516 message_die(GENERAL_ERROR, 'Wasn\'t able to access topics', '', __LINE__, __FILE__, $sql);
\r
518 if ( $row = $db->sql_fetchrow($result) )
\r
520 $forum_id = $row['forum_id'];
\r
525 // is the categories hierarchy v 2 installed ?
\r
526 $cat_hierarchy = function_exists('get_auth_keys');
\r
528 // get the ids (forums and cats)
\r
530 if (!$cat_hierarchy)
\r
534 // add the forum_id
\r
535 $fids[] = POST_FORUM_URL . $forum_id;
\r
538 $sql = "SELECT * FROM " . FORUMS_TABLE . " WHERE forum_id=$forum_id";
\r
539 if ( !($result = $db->sql_query($sql)) )
\r
541 message_die(GENERAL_ERROR, 'Wasn\'t able to access forums', '', __LINE__, __FILE__, $sql);
\r
543 if ( $row = $db->sql_fetchrow($result) )
\r
545 $cat_id = $row['cat_id'];
\r
552 $fids[] = POST_CAT_URL . $cat_id;
\r
555 // add the root level
\r
560 // categories hierarchy v 2 compliancy
\r
564 $cur = POST_FORUM_URL . $forum_id;
\r
566 else if ($cat_id > 0)
\r
568 $cur = POST_CAT_URL . $cat_id;
\r
573 while ( ($cur != 'Root') && !empty($cur) )
\r
575 // get parent level
\r
576 $cur = (isset($tree['main'][ $tree['keys'][$cur] ])) ? $tree['main'][ $tree['keys'][$cur] ] : 'Root';
\r
578 // add the parent level
\r
579 if ( !empty($cur) )
\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
596 $real_root = @phpbb_realpath($this->root);
\r
598 if (substr($filename, 0, 1) != '/')
\r
601 $num_fids = count($fids);
\r
602 for ($i = 0; !$found && ($i < $num_fids); $i++)
\r
606 // convert root into c0 category
\r
607 if ( ($key == 'Root') || empty($key) )
\r
609 $key = POST_CAT_URL . '0';
\r
612 if ( isset($sub_templates[$key]) )
\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
618 // set the filename
\r
619 if ( empty($sub_tpl_file) && file_exists($root_template_path . '/' . $filename) )
\r
622 $sub_tpl_file = $sub_templates[$key]['dir'] . '/' . $filename;
\r
628 // set the css file name
\r
630 $num_fids = count($fids);
\r
631 for ($i = 0; !$found && ($i < $num_fids); $i++)
\r
635 // convert root into c0 category
\r
636 if ( ($key == 'Root') || empty($key) )
\r
638 $key = POST_CAT_URL . '0';
\r
641 if ( isset($sub_templates[$key]) )
\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
649 $sub_css_file = $sub_templates[$key]['dir'] . '/' . $sub_templates[$key]['head_stylesheet'];
\r
655 // set the img file name
\r
657 $num_fids = count($fids);
\r
658 for ($i = 0; !$found && ($i < $num_fids); $i++)
\r
662 // convert root into c0 category
\r
663 if ( ($key == 'Root') || empty($key) )
\r
665 $key = POST_CAT_URL . '0';
\r
668 if ( isset($sub_templates[$key]) )
\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
675 $sub_img_path = $sub_templates[$key]['dir'];
\r
676 $sub_img_file = $sub_templates[$key]['imagefile'];
\r
678 // send back the lowest level of the images file
\r
680 $sub_template_key_image = $key;
\r
687 // set the tpl file
\r
688 if ( !empty($sub_tpl_file) )
\r
690 $filename = $sub_tpl_file;
\r
693 // set the css file
\r
694 if ( !empty($sub_css_file) )
\r
696 $theme['head_stylesheet'] = $sub_css_file;
\r
699 // get the root level images
\r
700 $key = POST_CAT_URL . '0';
\r
701 if ( isset($sub_templates[$key]) )
\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
708 $sav_images = $images;
\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
714 if ( !is_array($value) )
\r
716 $images[$key] = str_replace('{LANG}', 'lang_' . $img_lang, $value);
\r
718 $sav_images[$key] = $images[$key];
\r
720 $images = $sav_images;
\r
721 $sav_images = array();
\r
725 // get the current images
\r
726 if ( !empty($sub_template_key_image) && ($sub_template_key_image != POST_CAT_URL . '0') )
\r
728 $key = $sub_template_key_image;
\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
735 $sav_images = $images;
\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
741 if ( !is_array($value) )
\r
743 $images[$key] = str_replace('{LANG}', 'lang_' . $img_lang, $value);
\r
745 $sav_images[$key] = $images[$key];
\r
747 $images = $sav_images;
\r
748 $sav_images = array();
\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
760 function make_filename($filename, $xs_include = false)
\r
762 if($this->subtemplates)
\r
764 $filename = $this->subtemplates_make_filename($filename);
\r
766 // Check replacements list
\r
767 if(!$xs_include && isset($this->replace[$filename]))
\r
769 $filename = $this->replace[$filename];
\r
771 // Check if it's an absolute or relative path.
\r
772 if ((substr($filename, 0, 1) !== '/') && (substr($filename, 1, 1) !== ':'))
\r
774 return $this->root . '/' . $filename;
\r
778 return str_replace('\\', '/', $filename);
\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
787 function make_filename_cache($file)
\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
792 return $this->cachedir . XS_TPL_PREFIX2 . $str;
\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
801 * Sets the template filenames for handles. $filename_array
\r
802 * should be a hash of handle => filename pairs.
\r
804 function set_filenames($filename_array)
\r
806 if (!is_array($filename_array))
\r
811 foreach($filename_array as $handle => $filename)
\r
813 $this->set_filename($handle, $filename);
\r
821 * Assigns template filename for handle.
\r
823 function set_filename($handle, $filename, $xs_include = false, $quiet = false)
\r
825 global $board_config;
\r
826 $can_cache = $this->use_cache;
\r
827 if(strpos($filename, '..') !== false)
\r
829 $can_cache = false;
\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
837 xs_admin_override();
\r
839 // checking if we have valid filename
\r
840 if(!$this->files[$handle])
\r
842 if($xs_include || $quiet)
\r
848 die("Template->make_filename(): Error - invalid template $filename");
\r
851 // creating cache filename
\r
854 $this->files_cache2[$handle] = $this->make_filename_cache($this->files[$handle]);
\r
855 if(@file_exists($this->files_cache2[$handle]))
\r
857 $this->files_cache[$handle] = $this->files_cache2[$handle];
\r
860 // checking if tpl and/or php file exists
\r
861 if(empty($this->files_cache[$handle]) && !@file_exists($this->files[$handle]))
\r
863 // trying to load alternative filename (usually subSilver)
\r
864 if(!empty($this->tpldef) && !empty($this->tpl) && ($this->tpldef !== $this->tpl))
\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
886 if($board_config['xs_warn_includes'])
\r
888 die('Template->make_filename(): Error - included template file not found: ' . $filename);
\r
894 die('Template->make_filename(): Error - template file not found: ' . $filename);
\r
897 // checking if we should recompile cache
\r
898 if(!empty($this->files_cache[$handle]) && !empty($board_config['xs_auto_recompile']))
\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
903 // file was changed. don't use cache file (will be recompled if configuration allowes it)
\r
904 $this->files_cache[$handle] = '';
\r
911 * includes file or executes code
\r
913 function execute($filename, $code, $handle)
\r
915 global $lang, $theme, $board_config;
\r
916 $template = $theme['template_name'];
\r
918 $theme_info = &$$template;
\r
919 if($board_config['xs_add_comments'] && $handle)
\r
921 echo '<!-- template ', $this->files[$handle], ' start -->';
\r
925 include($filename);
\r
931 if($board_config['xs_add_comments'] && $handle)
\r
933 echo '<!-- template ', $this->files[$handle], ' end -->';
\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
943 function pparse($handle)
\r
945 global $board_config;
\r
946 // parsing header if there is one
\r
947 if($this->preparse || $this->postparse)
\r
949 $preparse = $this->preparse;
\r
950 $postparse = $this->postparse;
\r
951 $this->preparse = '';
\r
952 $this->postparse = '';
\r
955 $this->pparse($preparse);
\r
960 $handle = $postparse;
\r
961 $this->pparse($str);
\r
964 // checking if handle exists
\r
965 if (empty($this->files[$handle]) && empty($this->files_cache[$handle]))
\r
967 die("Template->loadfile(): No files found for handle $handle");
\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
974 // php file exists - running it instead of tpl
\r
975 $this->execute($this->files_cache[$handle], '', $handle);
\r
978 if (!$this->loadfile($handle))
\r
980 die("Template->pparse(): Couldn't load template file for handle $handle");
\r
982 // actually compile the template now.
\r
983 if (empty($this->compiled_code[$handle]))
\r
985 // Actually compile the code now.
\r
986 if(!empty($this->files_cache2[$handle]) && empty($this->files_cache[$handle]) && !$force_recompile)
\r
988 $this->compiled_code[$handle] = $this->compile2($this->uncompiled_code[$handle], $handle, $this->files_cache2[$handle]);
\r
992 $this->compiled_code[$handle] = $this->compile2($this->uncompiled_code[$handle], '', '');
\r
995 // Run the compiled code.
\r
996 if (empty($this->files_cache[$handle]) || $force_recompile)
\r
998 $this->execute('', $this->compiled_code[$handle], $handle);
\r
1002 $this->execute($this->files_cache[$handle], '', $handle);
\r
1010 function precompile($template, $filename)
\r
1012 global $precompile_num, $board_config;
\r
1013 if(empty($precompile_num))
\r
1015 $precompile_num = 0;
\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
1030 $res = $this->set_filename($handle, $filename, true, true);
\r
1031 if(!$res || !$this->files_cache2[$handle])
\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
1039 $this->files_cache[$handle] = '';
\r
1041 $res = $this->loadfile($handle);
\r
1042 if(!$res || empty($this->uncompiled_code[$handle]))
\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
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
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
1065 * Note that all desired assignments to the variables in $handle should be done
\r
1066 * BEFORE calling this function.
\r
1068 function assign_var_from_handle($varname, $handle)
\r
1071 $res = $this->pparse($handle);
\r
1072 $this->vars[$varname] = ob_get_contents();
\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
1082 function assign_block_vars($blockname, $vararray)
\r
1084 if (strstr($blockname, '.'))
\r
1087 $blocks = explode('.', $blockname);
\r
1088 $blockcount = sizeof($blocks) - 1;
\r
1090 $str = &$this->_tpldata;
\r
1091 for($i = 0; $i < $blockcount; $i++)
\r
1093 $str = &$str[$blocks[$i].'.'];
\r
1094 $str = &$str[sizeof($str)-1];
\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
1103 // Top-level block.
\r
1104 // Add a new iteration to this block with the variable assignments
\r
1106 $this->_tpldata[$blockname.'.'][] = $vararray;
\r
1113 * Root-level variable assignment. Adds to current assignments, overriding
\r
1114 * any existing variable assignment with the same name.
\r
1116 function assign_vars($vararray)
\r
1118 foreach($vararray as $key => $val)
\r
1120 $this->vars[$key] = $val;
\r
1126 * Root-level variable assignment. Adds to current assignments, overriding
\r
1127 * any existing variable assignment with the same name.
\r
1129 function assign_var($varname, $varval)
\r
1131 $this->vars[$varname] = $varval;
\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
1140 function loadfile($handle)
\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
1149 // If the file for this handle is already loaded and compiled, do nothing.
\r
1150 if (!empty($this->uncompiled_code[$handle]))
\r
1155 // If we don't have a file assigned to this handle, die.
\r
1156 if (empty($this->files[$handle]))
\r
1158 die("Template->loadfile(): No file specified for handle $handle");
\r
1161 $filename = $this->files[$handle];
\r
1163 $str = implode('', @file($filename));
\r
1166 die("Template->loadfile(): File $filename for handle $handle is empty");
\r
1169 $this->uncompiled_code[$handle] = $str;
\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
1183 function generate_block_varref($namespace, $varname, $use_isset = true)
\r
1185 // Strip the trailing period.
\r
1186 $namespace = substr($namespace, 0, strlen($namespace) - 1);
\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
1192 // Append the variable reference.
\r
1193 $varref .= '[\'' . $varname . '\']';
\r
1197 $varref = '<'.'?php echo isset(' . $varref . ') ? ' . $varref . ' : \'\'; ?'.'>';
\r
1201 $varref = '<'.'?php echo ' . $varref . '; ?'.'>';
\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
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
1217 function generate_block_data_ref($blockname, $include_last_iterator, $defop = false)
\r
1219 // Get an array of the blocks involved.
\r
1220 $blocks = explode('.', $blockname);
\r
1221 $blockcount = sizeof($blocks) - 1;
\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
1228 $varref .= "['" . $blocks[$i] . ".'][\$" . $blocks[$i] . '_i]';
\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
1235 $varref .= '[$' . $blocks[$blockcount] . '_i]';
\r
1239 if($include_last_iterator)
\r
1241 return '$'. $blocks[$blockcount]. '_item';
\r
1245 return '$'. $blocks[$blockcount-1]. '_item[\''. $blocks[$blockcount]. '.\']';
\r
1249 function compile_code($filename, $code, $use_isset = false)
\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
1259 // load code from file
\r
1260 if(!$code && !empty($filename))
\r
1262 $code = @implode('', @file($filename));
\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
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
1275 $code_lines[$i] .= ' -->';
\r
1278 $block_nesting_level = 0;
\r
1279 $block_names = array();
\r
1280 $block_names[0] = ".";
\r
1281 $block_items = array();
\r
1284 // prepare array for compiled code
\r
1285 $compiled = array();
\r
1286 $count_bugs = count($this->bugs);
\r
1288 // array of switches
\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
1296 $line = $code_lines[$i];
\r
1297 $pos = strpos($line, '<?');
\r
1298 if($pos === false)
\r
1300 $new_code[] = $line;
\r
1303 if(substr($line, $pos, 5) === '<?php')
\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
1311 // invalid php tag
\r
1312 $new_code[] = substr($line, 0, $pos) . '<?php echo \'<?\'; ?>';
\r
1313 $code_lines[$i] = substr($line, $pos + 2);
\r
1316 $code_lines = $new_code;
\r
1319 $line_count = count($code_lines);
\r
1320 for($i=0; $i<$line_count; $i++)
\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
1329 // no keywords in this line
\r
1330 $compiled[] = $this->_compile_text($line, $use_isset);
\r
1333 // find end of html comment
\r
1334 $pos2 = strpos($line, ' -->', $pos1);
\r
1335 if($pos2 !== false)
\r
1337 // find end of keyword in comment
\r
1338 $pos3 = strpos($line, ' ', $pos1 + 5);
\r
1339 if($pos3 !== false && $pos3 <= $pos2)
\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
1345 $keyword_type = XS_TAG_BEGIN;
\r
1347 elseif($keyword === 'END')
\r
1349 $keyword_type = XS_TAG_END;
\r
1351 elseif($keyword === 'INCLUDE')
\r
1353 $keyword_type = XS_TAG_INCLUDE;
\r
1355 elseif($keyword === 'IF')
\r
1357 $keyword_type = XS_TAG_IF;
\r
1359 elseif($keyword === 'ELSE')
\r
1361 $keyword_type = XS_TAG_ELSE;
\r
1363 elseif($keyword === 'ELSEIF')
\r
1365 $keyword_type = XS_TAG_ELSEIF;
\r
1367 elseif($keyword === 'ENDIF')
\r
1369 $keyword_type = XS_TAG_ENDIF;
\r
1371 elseif($keyword === 'DEFINE')
\r
1373 $keyword_type = XS_TAG_DEFINE;
\r
1375 elseif($keyword === 'UNDEFINE')
\r
1377 $keyword_type = XS_TAG_UNDEFINE;
\r
1379 elseif($keyword === 'BEGINELSE')
\r
1381 $keyword_type = XS_TAG_BEGINELSE;
\r
1385 if(!$keyword_type)
\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
1393 // remove code before keyword
\r
1396 $compiled[] = $this->_compile_text(substr($line, 0, $pos1), $use_isset);
\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
1408 if($keyword_type == XS_TAG_BEGIN)
\r
1410 $params = explode(' ', $params_str);
\r
1411 $num_params = count($params);
\r
1412 // get variable name
\r
1413 if($num_params == 1)
\r
1415 $var = $params[0];
\r
1417 elseif($num_params == 2)
\r
1419 if($params[0] === '')
\r
1421 $var = $params[1];
\r
1423 elseif($params[1] === '')
\r
1425 $var = $params[0];
\r
1430 $compiled[] = $keyword_str;
\r
1437 $compiled[] = $keyword_str;
\r
1440 // check variable for matching end
\r
1441 if($this->xs_check_switches)
\r
1444 $str = '<!-- END ' . $var . ' -->';
\r
1445 for ($j = $i+1; ($j < $line_count) && !$found; $j++)
\r
1447 $pos = strpos($code_lines[$j], $str);
\r
1448 if($pos !== false)
\r
1451 $found_var = $var;
\r
1454 if(!$found && ($this->xs_check_switches == 1))
\r
1456 // checking list of known buggy switches
\r
1458 for($j=0; $j<$count_bugs; $j++)
\r
1460 if($this->bugs[$j][0] === $var)
\r
1467 $str1 = '<!-- END ' . $this->bugs[$item][1] . ' -->';
\r
1468 for ($j = $i+1; ($j < $line_count) && !$found; $j++)
\r
1470 $pos = strpos($code_lines[$j], $str1);
\r
1471 if($pos !== false)
\r
1473 $found_var = $this->bugs[$item][1];
\r
1475 $code_lines[$j] = str_replace($str, $str1, $code_lines[$j]);
\r
1482 $compiled[] = $keyword_str;
\r
1485 // adding to list of switches
\r
1486 if(isset($sw[$found_var]))
\r
1488 $sw[$found_var] ++;
\r
1492 $sw[$found_var] = 1;
\r
1496 $block_nesting_level++;
\r
1497 $block_names[$block_nesting_level] = $var;
\r
1498 if(isset($block_items[$var]))
\r
1500 $block_items[$var] ++;
\r
1504 $block_items[$var] = 1;
\r
1506 if ($block_nesting_level < 2)
\r
1508 // Block is not nested.
\r
1509 $line = '<'."?php\n\n";
\r
1512 $line .= '$'. $var. '_count = ( isset($this->_tpldata[\''. $var. '.\']) ) ? sizeof($this->_tpldata[\''. $var. '.\']) : 0;';
\r
1516 $line .= '$'. $var. '_count = sizeof($this->_tpldata[\''. $var. '.\']);';
\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
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
1539 $line .= '$'. $var. '_count = ( isset('. $varref. ') ) ? sizeof('. $varref. ') : 0;';
\r
1543 $line .= '$'. $var. '_count = sizeof('. $varref. ');';
\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
1552 $compiled[] = $line;
\r
1558 if($keyword_type == XS_TAG_END)
\r
1560 $params = explode(' ', $params_str);
\r
1561 $num_params = count($params);
\r
1562 if($num_params == 1)
\r
1564 $var = $params[0];
\r
1566 elseif($num_params == 2 && $params[0] === '')
\r
1568 $var = $params[1];
\r
1570 elseif($num_params == 2 && $params[1] === '')
\r
1572 $var = $params[0];
\r
1576 $compiled[] = $keyword_str;
\r
1579 if($this->xs_check_switches)
\r
1581 // checking if this switch was opened
\r
1582 if(!isset($sw[$var]) || ($sw[$var] < 1))
\r
1584 // there is no opening switch
\r
1585 $compiled[] = $keyword_str;
\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
1597 $block_items[$var] --;
\r
1601 $block_items[$var] = -1;
\r
1603 unset($block_names[$block_nesting_level]);
\r
1604 $block_nesting_level--;
\r
1605 $compiled[] = $line;
\r
1609 * <!-- BEGINELSE -->
\r
1611 if($keyword_type == XS_TAG_BEGINELSE)
\r
1613 if($block_nesting_level)
\r
1615 $var = $block_names[$block_nesting_level];
\r
1616 $compiled[] = '<' . '?php } if(!$' . $var . '_count) { ?' . '>';
\r
1620 $compiled[] = $keyword_str;
\r
1625 * <!-- INCLUDE -->
\r
1627 if($keyword_type == XS_TAG_INCLUDE)
\r
1629 $params = explode(' ', $params_str);
\r
1630 $num_params = count($params);
\r
1631 if($num_params != 1)
\r
1633 $compiled[] = $keyword_str;
\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
1648 if($keyword_type == XS_TAG_IF || $keyword_type == XS_TAG_ELSEIF)
\r
1652 $keyword_type = XS_TAG_IF;
\r
1654 $str = $this->compile_tag_if($params_str, $keyword_type == XS_TAG_IF ? false : true);
\r
1657 $compiled[] = '<?php ' . $str . ' ?>';
\r
1658 if($keyword_type == XS_TAG_IF)
\r
1665 $compiled[] = $keyword_str;
\r
1672 if($keyword_type == XS_TAG_ELSE && $count_if > 0)
\r
1674 $compiled[] = '<?php } else { ?>';
\r
1680 if($keyword_type == XS_TAG_ENDIF && $count_if > 0)
\r
1682 $compiled[] = '<?php } ?>';
\r
1689 if($keyword_type == XS_TAG_DEFINE)
\r
1691 $str = $this->compile_tag_define($params_str);
\r
1694 $compiled[] = '<?php ' . $str . ' ?>';
\r
1698 $compiled[] = $keyword_str;
\r
1702 * <!-- UNDEFINE -->
\r
1704 if($keyword_type == XS_TAG_UNDEFINE)
\r
1706 $str = $this->compile_tag_undefine($params_str);
\r
1709 $compiled[] = '<?php ' . $str . ' ?>';
\r
1713 $compiled[] = $keyword_str;
\r
1718 // bring it back into a single string.
\r
1719 $code_header = '';
\r
1720 $code_footer = '';
\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
1727 return $code_header . implode('', $compiled) . $code_footer;
\r
1731 * Compile code between tags
\r
1733 function _compile_text($code, $use_isset)
\r
1735 if(strlen($code) < 3)
\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
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
1754 if(count($search) > 0)
\r
1756 $code = str_replace($search, $replace, $code);
\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
1765 // Compile IF tags - much of this is from Smarty with
\r
1766 // some adaptions for our block level methods
\r
1768 function compile_tag_if($tag_args, $elseif)
\r
1770 /* Tokenize args for 'if' tag. */
\r
1771 preg_match_all('/(?:
\r
1772 "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
\r
1773 \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' |
\r
1775 [^\s(),]+)/x', $tag_args, $match);
\r
1777 $tokens = $match[0];
\r
1778 $is_arg_stack = array();
\r
1780 for ($i = 0; $i < count($tokens); $i++)
\r
1782 $token = &$tokens[$i];
\r
1858 array_push($is_arg_stack, $i);
\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
1865 $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
\r
1867 array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
\r
1869 $i = $is_arg_start;
\r
1872 if (preg_match('#^(([a-z0-9\-_]+?\.)+?)?(\$)?([A-Z]+[A-Z0-9\-_]+)$#s', $token, $varrefs))
\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
1880 $code = (($elseif) ? '} elseif (' : 'if (') . (implode(' ', $tokens) . ') { ');
\r
1885 // This is from Smarty
\r
1886 function _parse_is_expr($is_arg, $tokens)
\r
1889 $negate_expr = false;
\r
1891 if (($first_token = array_shift($tokens)) == 'not')
\r
1893 $negate_expr = true;
\r
1894 $expr_type = array_shift($tokens);
\r
1898 $expr_type = $first_token;
\r
1901 switch ($expr_type)
\r
1904 if (@$tokens[$expr_end] == 'by')
\r
1907 $expr_arg = $tokens[$expr_end++];
\r
1908 $expr = "!(($is_arg / $expr_arg) % $expr_arg)";
\r
1912 $expr = "!($is_arg % 2)";
\r
1917 if (@$tokens[$expr_end] == 'by')
\r
1920 $expr_arg = $tokens[$expr_end++];
\r
1921 $expr = "(($is_arg / $expr_arg) % $expr_arg)";
\r
1925 $expr = "($is_arg % 2)";
\r
1930 if (@$tokens[$expr_end] == 'by')
\r
1933 $expr_arg = $tokens[$expr_end++];
\r
1934 $expr = "!($is_arg % $expr_arg)";
\r
1944 $expr = "!($expr)";
\r
1947 array_splice($tokens, 0, $expr_end, $expr);
\r
1953 function compile_tag_define($tag_args)
\r
1955 preg_match('#^(([a-z0-9\-_]+?\.)+?)?\$([A-Z][A-Z0-9_\-]*?) = (\'?)(.*?)(\'?)$#', $tag_args, $match);
\r
1957 if (empty($match[3]) || empty($match[5]))
\r
1962 // Are we a string?
\r
1963 if ($match[4] && $match[6])
\r
1965 $match[5] = "'" . addslashes(str_replace(array('\\\'', '\\\\'), array('\'', '\\'), $match[5])) . "'";
\r
1969 preg_match('#(true|false|\.)#i', $match[5], $type);
\r
1971 switch (strtolower($type[1]))
\r
1975 $match[5] = strtoupper($match[5]);
\r
1978 $match[5] = doubleval($match[5]);
\r
1981 $match[5] = intval($match[5]);
\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
1989 function compile_tag_undefine($tag_args)
\r
1991 preg_match('#^(([a-z0-9\-_]+?\.)+?)?\$([A-Z][A-Z0-9_\-]*?)$#', $tag_args, $match);
\r
1992 if (empty($match[3]))
\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
2000 * Compiles code and writes to cache if needed
\r
2002 function compile2($code, $handle, $cache_file)
\r
2004 $code = $this->compile_code('', $code, XS_USE_ISSET);
\r
2005 if($cache_file && !empty($this->use_cache) && !empty($this->auto_compile))
\r
2007 $res = $this->write_cache($cache_file, $code);
\r
2008 if($handle && $res)
\r
2010 $this->files_cache[$handle] = $cache_file;
\r
2013 $code = '?'.'>'.$code.'<'."?php\n";
\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
2025 function compile($code, $do_not_echo = false, $retvar = '')
\r
2027 $code = ' ?'.'>' . $this->compile_code('', $code, true) . '<'."?php \n";
\r
2030 $code = "ob_start();\n". $code. "\n\${$retvar} = ob_get_contents();\nob_end_clean();\n";
\r
2036 * Write cache to disk
\r
2038 function write_cache($filename, $code)
\r
2040 // check if cache is writable
\r
2041 if(!$this->cache_writable)
\r
2045 // check if filename is valid
\r
2046 if(substr($filename, 0, strlen($this->cachedir)) !== $this->cachedir)
\r
2050 // try to open file
\r
2051 $file = @fopen($filename, 'w');
\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
2059 if(!@is_dir($path))
\r
2061 if(!@mkdir($path))
\r
2063 $this->cache_writable = 0;
\r
2068 @chmod($path, 0777);
\r
2071 $count = count($dirs);
\r
2073 for($i=0; $i<$count-1; $i++)
\r
2079 $path .= $dirs[$i];
\r
2080 if(!@is_dir($path))
\r
2082 if(!@mkdir($path))
\r
2084 $this->cache_writable = 0;
\r
2089 @chmod($path, 0777);
\r
2093 // try to open file again after directories were created
\r
2094 $file = @fopen($filename, 'w');
\r
2098 $this->cache_writable = 0;
\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
2104 @chmod($filename, 0777);
\r
2108 function xs_startup()
\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
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
2134 $tpl = substr($tpl, 2, strlen($tpl));
\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
2143 * Checks for empty variable and shows language variable if possible.
\r
2145 function lang($var)
\r
2148 if(substr($var, 0, 2) === 'L_')
\r
2150 $var = substr($var, 2);
\r
2151 // check variable as it is
\r
2152 if(isset($lang[$var]))
\r
2154 return $lang[$var];
\r
2156 // check variable in lower case
\r
2157 if(isset($lang[strtolower($var)]))
\r
2159 return $lang[strtolower($var)];
\r
2161 // check variable with first letter in upper case
\r
2162 $str = ucfirst(strtolower($var));
\r
2163 if(isset($lang[$str]))
\r
2165 return $lang[$str];
\r
2167 return ''; //str_replace('_', ' ', $var);
\r
2174 // Functions added for USERGROUP MOD (optimized)
\r
2177 function append_var_from_handle_to_block($blockname, $varname, $handle)
\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
2185 function append_block_vars($blockname, $vararray)
\r
2187 if(strstr($blockname, '.'))
\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
2195 $str = &$str[$blocks[$i].'.'];
\r
2196 $str = &$str[sizeof($str)-1];
\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
2205 // adding only if there is at least one item
\r
2206 $str[$count] = array_merge($str[$count], $vararray);
\r
2211 // Top-level block.
\r
2212 // Add a new iteration to this block with the variable assignments
\r
2214 $str = &$this->_tpldata[$blockname.'.'];
\r
2215 $count = sizeof($str) - 1;
\r
2218 // adding only if there is at least one item
\r
2219 $str[$count] = array_merge($str[$count], $vararray);
\r
2226 * Flush a root level block, so it becomes empty.
\r
2228 function flush_block_vars($blockname)
\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
2238 * Add style configuration
\r
2240 function _add_config($tpl, $add_vars = true)
\r
2242 global $phpbb_root_path;
\r
2243 if(@file_exists($phpbb_root_path . 'templates/' . $tpl . '/xs_config.cfg'))
\r
2245 $style_config = array();
\r
2246 include($phpbb_root_path . 'templates/' . $tpl . '/xs_config.cfg');
\r
2247 if(count($style_config))
\r
2249 global $board_config, $db;
\r
2250 for($i=0; $i<count($style_config); $i++)
\r
2252 $this->style_config[$style_config[$i]['var']] = $style_config[$i]['default'];
\r
2255 $this->vars['TPL_CFG_' . strtoupper($style_config[$i]['var'])] = $style_config[$i]['default'];
\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
2265 if(isset($config->data) && $config->data === $board_config && isset($config->data['mod_cat_hierarchy']))
\r
2267 $config->read(true);
\r
2275 function add_config($tpl)
\r
2277 $config_name = 'xs_style_' . $tpl;
\r
2278 global $board_config;
\r
2280 if(empty($board_config[$config_name]))
\r
2282 $old = $this->style_config;
\r
2283 $result = $this->_add_config($tpl, false);
\r
2284 $this->style_config = $old;
\r
2290 * Refresh config data
\r
2292 function _refresh_config($tpl, $add_vars = false)
\r
2294 global $phpbb_root_path;
\r
2295 if(@file_exists($phpbb_root_path . 'templates/' . $tpl . '/xs_config.cfg'))
\r
2297 $style_config = array();
\r
2298 include($phpbb_root_path . 'templates/' . $tpl . '/xs_config.cfg');
\r
2299 if(count($style_config))
\r
2301 global $board_config, $db;
\r
2302 for($i=0; $i<count($style_config); $i++)
\r
2304 if(!isset($this->style_config[$style_config[$i]['var']]))
\r
2306 $this->style_config[$style_config[$i]['var']] = $style_config[$i]['default'];
\r
2309 $this->vars['TPL_CFG_' . strtoupper($style_config[$i]['var'])] = $style_config[$i]['default'];
\r
2313 $str = $this->_serialize($this->style_config);
\r
2314 $config_name = 'xs_style_' . $tpl;
\r
2315 if(isset($board_config[$config_name]))
\r
2317 $sql = "UPDATE " . CONFIG_TABLE . " SET config_value='" . str_replace('\\\'', '\'\'', addslashes($str)) . "' WHERE config_name='" . str_replace('\\\'', '\'\'', addslashes($config_name)) . "'";
\r
2321 $sql = "INSERT INTO " . CONFIG_TABLE . " (config_name, config_value) VALUES ('" . str_replace('\\\'', '\'\'', addslashes($config_name)) . "', '" . str_replace('\\\'', '\'\'', addslashes($str)) . "')";
\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
2327 if(isset($config->data) && $config->data === $board_config && isset($config->data['mod_cat_hierarchy']))
\r
2329 $config->read(true);
\r
2337 function refresh_config($tpl = '')
\r
2341 $tpl = $this->tpl;
\r
2343 if($tpl == $this->tpl)
\r
2345 $result = $this->_refresh_config($tpl, true);
\r
2349 $old = $this->style_config;
\r
2350 $result = $this->_refresh_config($tpl, false);
\r
2351 $this->style_config = $old;
\r
2357 * Get style configuration
\r
2359 function _get_config($tpl, $add_config)
\r
2361 $this->style_config = array();
\r
2364 $tpl = $this->tpl;
\r
2366 $config_name = 'xs_style_' . $tpl;
\r
2367 global $board_config;
\r
2368 if(empty($board_config[$config_name]))
\r
2372 $this->_add_config($tpl, $tpl === $this->tpl ? true : false);
\r
2374 return $this->style_config;
\r
2376 $this->style_config = $this->_unserialize($board_config[$config_name]);
\r
2377 if($tpl === $this->tpl)
\r
2379 foreach($this->style_config as $var => $value)
\r
2381 $this->vars['TPL_CFG_' . strtoupper($var)] = $value;
\r
2384 return $this->style_config;
\r
2387 function get_config($tpl = '', $add_config = true)
\r
2391 if(empty($this->tpl))
\r
2395 $this->_get_config($this->tpl, $add_config);
\r
2396 return $this->style_config;
\r
2400 $old_config = $this->style_config;
\r
2401 $result = $this->_get_config($tpl, $add_config);
\r
2402 $this->style_config = $old_config;
\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
2411 function _serialize($array)
\r
2413 if(!is_array($array))
\r
2418 foreach($array as $var => $value)
\r
2424 $str .= $var . '=' . str_replace('|', '', $value);
\r
2428 function _unserialize($str)
\r
2431 $list = explode('|', $str);
\r
2432 for($i=0; $i<count($list); $i++)
\r
2434 $row = explode('=', $list[$i], 2);
\r
2435 if(count($row) == 2)
\r
2437 $array[$row[0]] = $row[1];
\r
2445 function xs_switch($tpl, $name)
\r
2447 return (isset($tpl->_tpldata[$name.'.']) && count($tpl->_tpldata[$name.'.']) > 0);
\r