3 /***************************************************************************
6 * copyright : (C) 2001 The phpBB Group
7 * email : support@phpbb.com
9 * phpBB version : 2.0.x
10 * eXtreme Styles mod : 2.0.1
11 * Support : http://www.phpbbstyles.com
14 * project revision : 51
15 * last modified : 25 Aug 2004 11:51:47
17 ***************************************************************************/
19 /***************************************************************************
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26 ***************************************************************************/
30 * Template class. By Nathan Codding of the phpBB group.
31 * The interface was originally inspired by PHPLib templates,
32 * and the template file formats are quite similar.
34 * eXtreme Styles mod by CyberAlien.
36 * IF, ELSEIF, ENDIF tags are backported from phpBB 2.2
38 * Documentation for this mod can be found here:
39 * http://www.phpbbstyles.com
41 * Support for eXtreme Styles mod is provided at http://www.phpbbstyles.com
43 * Thanks to DMaJ007 for idea on how to include some extra tags.
47 define('XS_SEPARATOR', '.');
48 define('XS_DIR_CACHE', 'cache');
49 define('XS_USE_ISSET', '1');
51 // cache filenames prefix
52 define('XS_TPL_PREFIX', 'tpl_');
53 define('XS_TPL_PREFIX2', 'tpl2_');
55 // templates directory
56 define('XS_TPL_START', 'templates/');
57 define('XS_TPL_ANY', '/templates/');
59 // internal xs mod definitions. do not edit.
60 define('XS_TAG_NONE', 0);
61 define('XS_TAG_PHP', 1);
62 define('XS_TAG_BEGIN', 2);
63 define('XS_TAG_END', 3);
64 define('XS_TAG_INCLUDE', 4);
65 define('XS_TAG_IF', 5);
66 define('XS_TAG_ELSE', 6);
67 define('XS_TAG_ELSEIF', 7);
68 define('XS_TAG_ENDIF', 8);
69 define('XS_TAG_DEFINE', 9);
70 define('XS_TAG_UNDEFINE', 10);
74 var $classname = "Template";
76 // variable that holds all the data we'll be substituting into
77 // the compiled templates.
79 // This will end up being a multi-dimensional array like this:
80 // $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value
81 // if it's a root-level variable, it'll be like this:
82 // $this->vars[varname] == value or $this->_tpldata['.'][0][varname] == value
83 // array "vars" is added for easier access to data
84 var $_tpldata = array('.' => array(0 => array()));
87 // Hash of filenames for each template handle.
89 var $files_cache = array(); // array of cache files that exists
90 var $files_cache2 = array(); // array of cache files (exists or not exists)
92 // Root template directory.
95 // Cache directory (compatible with default cache mod)
98 // Search/replace for unknown files
99 var $cache_search = array();
100 var $cache_replace = array();
102 // Template root directory (generated by set_rootdir)
106 // Default template directory.
107 // If file for default template isn't found file from this template is used.
108 var $tpldef = 'subSilver';
110 // this will hash handle names to the compiled code for that handle.
111 var $compiled_code = array();
113 // This will hold the uncompiled code for that handle.
114 var $uncompiled_code = array();
118 var $cache_writable = 1;
120 // Auto-compile setting
121 var $auto_compile = 1;
123 // Current template name
126 // List of replacements. tpl files in this list will be replaced with other tpl files
127 // according to configuration in xs.cfg
128 var $replace = array();
130 // counter for include
131 var $include_count = 0;
133 // php extension. will be replaced by $phpEx in Template() function unless you disable it there
136 // True if check switches
137 var $xs_check_switches = 1;
139 // eXtreme Styles variables
141 var $xs_version = 5; // number version. internal. do not change.
142 var $xs_versiontxt = '2.0.1'; // text version
144 // These handles will be parsed if pparse() is executed.
145 // Can be used to automatically include header/footer if there is any content.
149 // subtemplates mod detection
150 var $subtemplates = false;
152 // list of switches that are known typos in some mods.
153 // when error checking is enabled these errors will be auto-fixed.
155 // array(start_tag, end_tag)
158 array('fetchpost_row', 'fetch_post_row'),
159 // mycalendar 2.2.7 typos:
160 array('date_cell', 'date_cells'),
161 array('date_row', 'date_rows'),
163 array('site_today', 'site_week'),
167 * Constructor. Installs XS mod on first run or updates it and sets the root dir.
169 function Template($root = '.')
171 // setting pointer "vars"
172 $this->vars = &$this->_tpldata['.'][0];
173 // load configuration
174 $this->load_config($root, true);
178 * Load mod configuration
180 function load_config($root, $edit_db)
182 global $board_config, $phpbb_root_path, $phpEx;
183 // getting mod version from config and comparing with real data
184 $ver = isset($board_config['xs_version']) ? $board_config['xs_version'] : 0;
185 // check configuration
186 // set config values if there aren't any
190 // list of outdated variables
192 'xs_versoin', // was a typo in one of previous versions
193 'xs_separator', // no longer used
194 'xs_cache_dir_absolute', // no longer used
195 'xs_cache_dir', // no longer used
196 'xs_use_isset', // no longer used
198 // list of default values
200 'xs_auto_compile' => 1,
201 'xs_auto_recompile' => 1,
204 'xs_def_template' => 'subSilver',
205 'xs_check_switches' => 1,
206 'xs_warn_includes' => 1,
207 'xs_add_comments' => 0,
209 'xs_ftp_login' => '',
211 'xs_downloads_count' => '0',
212 'xs_downloads_default' => '0',
214 'xs_template_time' => '0',
216 // checking if all variables exist
217 foreach($default as $var => $value)
219 if(!isset($board_config[$var]))
221 $board_config[$var] = $value;
225 // checking if there are any outdated variables that should be deleted
226 for($i=0; $i<count($outdated); $i++)
228 if(isset($board_config[$outdated[$i]]))
230 $del[] = $outdated[$i];
233 if(!isset($board_config['xs_version']))
235 $board_config['xs_version'] = $this->xs_version;
236 $add[] = 'xs_version';
238 elseif($board_config['xs_version'] != $this->xs_version)
240 $board_config['xs_version'] = $this->xs_version;
241 $up[] = 'xs_version';
244 if(!empty($board_config['xs_auto_recompile']))
246 if(!$board_config['xs_auto_compile'])
248 $board_config['xs_auto_compile'] = 1;
249 if(!in_array('xs_auto_compile', $up) && !in_array('xs_auto_compile', $add))
251 $up[] = 'xs_auto_compile';
256 if($edit_db && ((count($add) > 0) || (count($up) > 0) || (count($del) > 0)))
258 $board_config['xs_template_time'] = time();
259 if(!in_array('xs_template_time', $up))
261 $up[] = 'xs_template_time';
264 if(isset($db) && (@get_class($db) === 'sql_db'))
266 // adding new config values
267 for($i=0; $i<count($add); $i++)
269 $sql = "INSERT INTO " . CONFIG_TABLE . " (config_name, config_value) VALUES ('" . $add[$i] . "', '" . str_replace("'", "''", $board_config[$add[$i]]) . "')";
270 $db->sql_query($sql);
272 // removing old configuration variables that aren't used
273 for($i=0; $i<count($del); $i++)
275 $sql = "DELETE FROM " . CONFIG_TABLE . " WHERE config_name='" . $del[$i] . "'";
276 $db->sql_query($sql);
278 // updating variables that should be overwritten
279 for($i=0; $i<count($up); $i++)
281 $sql = "UPDATE " . CONFIG_TABLE . " SET config_value='" . str_replace("'", "''", $board_config[$up[$i]]) . "' WHERE config_name='" . $up[$i] . "'";
282 $db->sql_query($sql);
286 $this->php = $board_config['xs_php'];
287 $this->tpldef = $board_config['xs_def_template'];
288 $this->use_cache = $board_config['xs_use_cache'];
289 $this->auto_compile = $board_config['xs_auto_compile'];
290 $this->xs_check_switches = $board_config['xs_check_switches'];
291 $this->cache_search = array('.', '\\', '/', '_tpl');
292 $this->cache_replace = array('_', XS_SEPARATOR, XS_SEPARATOR, '.'.$this->php);
293 $old_root = $this->root;
294 $this->set_rootdir($root);
295 if(!empty($this->tpl))
297 $this->load_replacements($this->tpldir . $this->tpl . '/xs.cfg');
299 if($old_root !== $this->root)
301 $this->clear_files();
306 * Sets the template root directory for this Template object.
308 function set_rootdir($dir)
310 global $board_config, $phpbb_root_path;
315 $dir = str_replace('\\', '/', $dir);
316 // creating absolute path for cache
317 $this->cachedir = $phpbb_root_path . XS_DIR_CACHE . '/';
318 // creating absolute path for current template and root dir
319 $this->tpldir = $phpbb_root_path . 'templates/';
320 $this->tpldir_len = strlen($this->tpldir);
322 $this->tpl = $this->template_name($dir);
323 // check subtemplates mod
324 $sub_templates_cfg = $this->root . '/sub_templates.cfg';
325 if(defined('LANG_EXTEND_DONE') && @file_exists($sub_templates_cfg))
327 $this->subtemplates = true;
333 * Destroys this template object. Should be called when you're done with it, in order
334 * to clear out the template data so you can load/parse a new template set.
338 $this->_tpldata = array('.' => array(0 => array()));
339 $this->vars = &$this->_tpldata['.'][0];
340 $this->xs_started = 0;
344 * Clears list of compiled files.
346 function clear_files()
348 $this->files = array();
349 $this->files_cache = array();
350 $this->files_cache2 = array();
351 $this->compiled_code = array();
352 $this->uncompiled_code = array();
356 * Loads replacements from .cfg file
358 function load_replacements($file)
360 if(@file_exists($file))
364 $this->replace = array_merge($this->replace, $replace);
369 * Extracts template name from path
371 function template_name($dir)
373 $tpl = XS_TPL_ANY; // can start at any position
374 $tpl_null = XS_TPL_START; // can start only at zero position
375 // searching for 'templates/' and removing everything before it
376 $pos = strpos($dir, $tpl);
379 if(substr($dir, 0, strlen($tpl_null)) !== $tpl_null)
383 $str = substr($dir, strlen($tpl_null), strlen($dir));
387 $str = substr($dir, $pos + strlen($tpl), strlen($dir));
389 // searching for one more 'templates/'
390 // that can happen if full path is like /home/some_dude/templates/phpbb/templates/subSilver/
391 $dir = $this->template_name($str);
396 if(strpos($str, $tpl) !== false)
398 $dir = $this->template_name($str);
400 // check for another subdirectory
401 $pos = strpos($dir, '/');
404 $dir = substr($dir, 0, $pos);
409 function subtemplates_make_filename($filename)
411 global $HTTP_GET_VARS, $HTTP_POST_VARS, $db, $board_config, $images, $theme;
412 global $sub_template_key_image, $sub_templates;
415 // initiate the sub-template image pack that will be use
416 $sub_template_key_image = POST_CAT_URL . '0';
418 // Check if sub_templates are defined for this theme
419 if ( $board_config['version'] > '.0.5' )
421 $sub_templates_cfg = @phpbb_realpath($this->root . '/sub_templates.cfg');
425 $sub_templates_cfg = $this->root . '/sub_templates.cfg';
427 @include($sub_templates_cfg);
428 if ( isset($sub_templates) )
436 if ( !defined('IN_PRIVMSG') && ( isset($HTTP_GET_VARS[POST_POST_URL]) || isset($HTTP_POST_VARS[POST_POST_URL]) ) )
438 $post_id = isset($HTTP_GET_VARS[POST_POST_URL]) ? intval($HTTP_GET_VARS[POST_POST_URL]) : intval($HTTP_POST_VARS[POST_POST_URL]);
441 if ( isset($HTTP_GET_VARS[POST_TOPIC_URL]) || isset($HTTP_POST_VARS[POST_TOPIC_URL]) )
443 $topic_id = intval($HTTP_GET_VARS[POST_TOPIC_URL]) ? intval($HTTP_GET_VARS[POST_TOPIC_URL]) : intval($HTTP_POST_VARS[POST_TOPIC_URL]);
446 if ( isset($HTTP_GET_VARS[POST_FORUM_URL]) || isset($HTTP_POST_VARS[POST_FORUM_URL]) )
448 $forum_id = isset($HTTP_GET_VARS[POST_FORUM_URL]) ? intval($HTTP_GET_VARS[POST_FORUM_URL]) : intval($HTTP_POST_VARS[POST_FORUM_URL]);
451 if ( isset($HTTP_GET_VARS[POST_CAT_URL]) || isset($HTTP_POST_VARS[POST_CAT_URL]) )
453 $cat_id = isset($HTTP_GET_VARS[POST_CAT_URL]) ? intval($HTTP_GET_VARS[POST_CAT_URL]) : intval($HTTP_POST_VARS[POST_CAT_URL]);
456 if ( isset($HTTP_GET_VARS['selected_id']) || isset($HTTP_POST_VARS['selected_id']) )
458 $selected_id = isset($HTTP_GET_VARS['selected_id']) ? $HTTP_GET_VARS['selected_id'] : $HTTP_POST_VARS['selected_id'];
459 $type = substr($selected_id, 0, 1);
460 $id = intval(substr($selected_id, 1));
461 if (!empty($id)) switch ($type)
473 if ( !defined('IN_PRIVMSG') )
484 if ( ($forum_id <= 0) && ($cat_id <= 0) )
488 $sql = "SELECT * FROM " . POSTS_TABLE . " WHERE post_id=$post_id";
489 if ( !($result = $db->sql_query($sql)) )
491 message_die(GENERAL_ERROR, 'Wasn\'t able to access posts', '', __LINE__, __FILE__, $sql);
493 if ( $row = $db->sql_fetchrow($result) )
495 $forum_id = $row['forum_id'];
501 $sql = "SELECT * FROM " . TOPICS_TABLE . " WHERE topic_id=$topic_id";
502 if ( !($result = $db->sql_query($sql)) )
504 message_die(GENERAL_ERROR, 'Wasn\'t able to access topics', '', __LINE__, __FILE__, $sql);
506 if ( $row = $db->sql_fetchrow($result) )
508 $forum_id = $row['forum_id'];
513 // is the categories hierarchy v 2 installed ?
514 $cat_hierarchy = function_exists(get_auth_keys);
516 // get the ids (forums and cats)
523 $fids[] = POST_FORUM_URL . $forum_id;
526 $sql = "SELECT * FROM " . FORUMS_TABLE . " WHERE forum_id=$forum_id";
527 if ( !($result = $db->sql_query($sql)) )
529 message_die(GENERAL_ERROR, 'Wasn\'t able to access forums', '', __LINE__, __FILE__, $sql);
531 if ( $row = $db->sql_fetchrow($result) )
533 $cat_id = $row['cat_id'];
540 $fids[] = POST_CAT_URL . $cat_id;
543 // add the root level
548 // categories hierarchy v 2 compliancy
552 $cur = POST_FORUM_URL . $forum_id;
554 else if ($cat_id > 0)
556 $cur = POST_CAT_URL . $cat_id;
561 while ( ($cur != 'Root') && !empty($cur) )
564 $cur = (isset($tree['main'][ $tree['keys'][$cur] ])) ? $tree['main'][ $tree['keys'][$cur] ] : 'Root';
566 // add the parent level
574 // search if this file is part of a sub-template
579 $template_path = 'templates/';
580 $template_name = substr( $this->root, strpos($this->root, $template_path) + strlen($template_path) );
581 $real_root = $this->root;
582 if ( $board_config['version'] > '.0.5' )
584 $real_root = @phpbb_realpath($this->root);
586 if (substr($filename, 0, 1) != '/')
589 $num_fids = count($fids);
590 for ($i = 0; !$found && ($i < $num_fids); $i++)
594 // convert root into c0 category
595 if ( ($key == 'Root') || empty($key) )
597 $key = POST_CAT_URL . '0';
600 if ( isset($sub_templates[$key]) )
602 // get the sub-template path
603 $current_template_path = $template_path . $template_name . '/' . $sub_templates[$key]['dir'];
604 $root_template_path = $real_root . '/' . $sub_templates[$key]['dir'];
607 if ( empty($sub_tpl_file) && file_exists($root_template_path . '/' . $filename) )
610 $sub_tpl_file = $sub_templates[$key]['dir'] . '/' . $filename;
616 // set the css file name
618 $num_fids = count($fids);
619 for ($i = 0; !$found && ($i < $num_fids); $i++)
623 // convert root into c0 category
624 if ( ($key == 'Root') || empty($key) )
626 $key = POST_CAT_URL . '0';
629 if ( isset($sub_templates[$key]) )
631 // get the sub-template path
632 $current_template_path = $template_path . $template_name . '/' . $sub_templates[$key]['dir'];
633 $root_template_path = $real_root . '/' . $sub_templates[$key]['dir'];
634 if ( empty($sub_css_file) && isset($sub_templates[$key]['head_stylesheet']) && file_exists($root_template_path . '/' . $sub_templates[$key]['head_stylesheet']) )
637 $sub_css_file = $sub_templates[$key]['dir'] . '/' . $sub_templates[$key]['head_stylesheet'];
643 // set the img file name
645 $num_fids = count($fids);
646 for ($i = 0; !$found && ($i < $num_fids); $i++)
650 // convert root into c0 category
651 if ( ($key == 'Root') || empty($key) )
653 $key = POST_CAT_URL . '0';
656 if ( isset($sub_templates[$key]) )
658 // get the sub-template path
659 $current_template_path = $template_path . $template_name . '/' . $sub_templates[$key]['dir'];
660 $root_template_path = $real_root . '/' . $sub_templates[$key]['dir'];
661 if ( isset($sub_templates[$key]['imagefile']) && file_exists($root_template_path . '/' . $sub_templates[$key]['imagefile']) )
663 $sub_img_path = $sub_templates[$key]['dir'];
664 $sub_img_file = $sub_templates[$key]['imagefile'];
666 // send back the lowest level of the images file
668 $sub_template_key_image = $key;
676 if ( !empty($sub_tpl_file) )
678 $filename = $sub_tpl_file;
682 if ( !empty($sub_css_file) )
684 $theme['head_stylesheet'] = $sub_css_file;
687 // get the root level images
688 $key = POST_CAT_URL . '0';
689 if ( isset($sub_templates[$key]) )
691 // get the sub-template path
692 $current_template_path = $template_path . $template_name . '/' . $sub_templates[$key]['dir'];
693 $root_template_path = $real_root . '/' . $sub_templates[$key]['dir'];
694 if ( isset($sub_templates[$key]['imagefile']) && file_exists($root_template_path . '/' . $sub_templates[$key]['imagefile']) )
696 $sav_images = $images;
698 @include($root_template_path . '/' . $sub_templates[$key]['imagefile']);
699 $img_lang = ( file_exists($root_template_path . '/images/lang_' . $board_config['default_lang']) ) ? $board_config['default_lang'] : 'english';
700 foreach($images as $key => $value)
702 if ( !is_array($value) )
704 $images[$key] = str_replace('{LANG}', 'lang_' . $img_lang, $value);
706 $sav_images[$key] = $images[$key];
708 $images = $sav_images;
709 $sav_images = array();
713 // get the current images
714 if ( !empty($sub_template_key_image) && ($sub_template_key_image != POST_CAT_URL . '0') )
716 $key = $sub_template_key_image;
718 // get the sub-template path
719 $current_template_path = $template_path . $template_name . '/' . $sub_templates[$key]['dir'];
720 $root_template_path = $real_root . '/' . $sub_templates[$key]['dir'];
721 if ( isset($sub_templates[$key]['imagefile']) && file_exists($root_template_path . '/' . $sub_templates[$key]['imagefile']) )
723 $sav_images = $images;
725 @include($root_template_path . '/' . $sub_templates[$key]['imagefile']);
726 $img_lang = ( file_exists($root_template_path . '/images/lang_' . $board_config['default_lang']) ) ? $board_config['default_lang'] : 'english';
727 foreach($images as $key => $value)
729 if ( !is_array($value) )
731 $images[$key] = str_replace('{LANG}', 'lang_' . $img_lang, $value);
733 $sav_images[$key] = $images[$key];
735 $images = $sav_images;
736 $sav_images = array();
744 * Generates a full path+filename for the given filename, which can either
745 * be an absolute name, or a name relative to the rootdir for this Template
748 function make_filename($filename, $xs_include = false)
750 if($this->subtemplates)
752 $filename = $this->subtemplates_make_filename($filename);
754 // Check replacements list
755 if(!$xs_include && isset($this->replace[$filename]))
757 $filename = $this->replace[$filename];
759 // Check if it's an absolute or relative path.
760 if ((substr($filename, 0, 1) !== '/') && (substr($filename, 1, 1) !== ':'))
762 return $this->root . '/' . $filename;
766 return str_replace('\\', '/', $filename);
771 * Converts template filename to cache filename.
772 * Returns empty string if non-cachable (for tpl files outside of root dir).
773 * $file should be absolute filename
775 function make_filename_cache($file)
777 $str = str_replace($this->cache_search, $this->cache_replace, $file);
778 if(substr($file, 0, $this->tpldir_len) !== $this->tpldir || empty($this->tpl))
780 return $this->cachedir . XS_TPL_PREFIX2 . $str;
782 // removing not needed part
783 $file = substr($file, $this->tpldir_len, strlen($file));
785 return $this->cachedir . XS_TPL_PREFIX . str_replace($this->cache_search, $this->cache_replace, $file);
789 * Sets the template filenames for handles. $filename_array
790 * should be a hash of handle => filename pairs.
792 function set_filenames($filename_array)
794 if (!is_array($filename_array))
799 foreach($filename_array as $handle => $filename)
801 $this->set_filename($handle, $filename);
809 * Assigns template filename for handle.
811 function set_filename($handle, $filename, $xs_include = false, $quiet = false)
813 global $board_config;
814 $can_cache = $this->use_cache;
815 if(strpos($filename, '..') !== false)
819 $this->files[$handle] = $this->make_filename($filename, $xs_include);
820 $this->files_cache[$handle] = '';
821 $this->files_cache2[$handle] = '';
822 // check if we are in admin control panel and override extreme styles mod controls if needed
823 if(defined('XS_ADMIN_OVERRIDE') && XS_ADMIN_OVERRIDE === true && @function_exists('xs_admin_override'))
827 // checking if we have valid filename
828 if(!$this->files[$handle])
830 if($xs_include || $quiet)
836 die("Template->make_filename(): Error - invalid template $filename");
839 // creating cache filename
842 $this->files_cache2[$handle] = $this->make_filename_cache($this->files[$handle]);
843 if(@file_exists($this->files_cache2[$handle]))
845 $this->files_cache[$handle] = $this->files_cache2[$handle];
848 // checking if tpl and/or php file exists
849 if(empty($this->files_cache[$handle]) && !@file_exists($this->files[$handle]))
851 // trying to load alternative filename (usually subSilver)
852 if(!empty($this->tpldef) && !empty($this->tpl) && ($this->tpldef !== $this->tpl))
854 $this->files[$handle] = '';
855 // save old configuration
857 $tpl_name = $this->tpl;
858 // set temporary configuration
859 $this->root = $this->tpldir . $this->tpldef;
860 $this->tpl = $this->tpldef;
861 // recursively run set_filename
862 $res = $this->set_filename($handle, $filename, $xs_include, $quiet);
863 // restore old configuration
865 $this->tpl = $tpl_name;
874 if($board_config['xs_warn_includes'])
876 die('Template->make_filename(): Error - included template file not found: ' . $filename);
882 die('Template->make_filename(): Error - template file not found: ' . $filename);
885 // checking if we should recompile cache
886 if(!empty($this->files_cache[$handle]) && !empty($board_config['xs_auto_recompile']))
888 $cache_time = @filemtime($this->files_cache[$handle]);
889 if(@filemtime($this->files[$handle]) > $cache_time || $board_config['xs_template_time'] > $cache_time)
891 // file was changed. don't use cache file (will be recompled if configuration allowes it)
892 $this->files_cache[$handle] = '';
899 * includes file or executes code
901 function execute($filename, $code, $handle)
903 global $lang, $theme, $board_config;
904 $template = $theme['template_name'];
906 $theme_info = &$$template;
907 if($board_config['xs_add_comments'] && $handle)
909 echo '<!-- template ', $this->files[$handle], ' start -->';
919 if($board_config['xs_add_comments'] && $handle)
921 echo '<!-- template ', $this->files[$handle], ' end -->';
927 * Load the file for the handle, compile the file,
928 * and run the compiled code. This will print out
929 * the results of executing the template.
931 function pparse($handle)
933 global $board_config;
934 // parsing header if there is one
935 if($this->preparse || $this->postparse)
937 $preparse = $this->preparse;
938 $postparse = $this->postparse;
939 $this->preparse = $this->postparse = '';
942 $this->pparse($preparse);
947 $handle = $postparse;
951 // checking if handle exists
952 if (empty($this->files[$handle]) && empty($this->files_cache[$handle]))
954 die("Template->loadfile(): No files found for handle $handle");
957 $force_recompile = empty($this->uncompiled_code[$handle]) ? false : true;
958 // checking if php file exists.
959 if (!empty($this->files_cache[$handle]) && !$force_recompile)
961 // php file exists - running it instead of tpl
962 $this->execute($this->files_cache[$handle], '', $handle);
965 if (!$this->loadfile($handle))
967 die("Template->pparse(): Couldn't load template file for handle $handle");
969 // actually compile the template now.
970 if (empty($this->compiled_code[$handle]))
972 // Actually compile the code now.
973 if(!empty($this->files_cache2[$handle]) && empty($this->files_cache[$handle]) && !$force_recompile)
975 $this->compiled_code[$handle] = $this->compile2($this->uncompiled_code[$handle], $handle, $this->files_cache2[$handle]);
979 $this->compiled_code[$handle] = $this->compile2($this->uncompiled_code[$handle], '', '');
982 // Run the compiled code.
983 if (empty($this->files_cache[$handle]) || $force_recompile)
985 $this->execute('', $this->compiled_code[$handle], $handle);
989 $this->execute($this->files_cache[$handle], '', $handle);
997 function precompile($template, $filename)
999 global $precompile_num, $board_config;
1000 if(empty($precompile_num))
1002 $precompile_num = 0;
1005 $handle = 'precompile_' . $precompile_num;
1006 // save old configuration
1007 $root = $this->root;
1008 $tpl_name = $this->tpl;
1009 $old_config = $this->use_cache;
1010 $old_autosave = $this->auto_compile;
1011 // set temporary configuration
1012 $this->root = $this->tpldir . $template;
1013 $this->tpl = $template;
1014 $this->use_cache = 1;
1015 $this->auto_compile = 1;
1017 $res = $this->set_filename($handle, $filename, true, true);
1018 if(!$res || !$this->files_cache2[$handle])
1020 $this->root = $root;
1021 $this->tpl = $tpl_name;
1022 $this->use_cache = $old_config;
1023 $this->auto_compile = $old_autosave;
1026 $this->files_cache[$handle] = '';
1028 $res = $this->loadfile($handle);
1029 if(!$res || empty($this->uncompiled_code[$handle]))
1031 $this->root = $root;
1032 $this->tpl = $tpl_name;
1033 $this->use_cache = $old_config;
1034 $this->auto_compile = $old_autosave;
1038 $this->compile2($this->uncompiled_code[$handle], $handle, $this->files_cache2[$handle]);
1039 // restore confirugation
1040 $this->root = $root;
1041 $this->tpl = $tpl_name;
1042 $this->use_cache = $old_config;
1043 $this->auto_compile = $old_autosave;
1048 * Inserts the uncompiled code for $handle as the
1049 * value of $varname in the root-level. This can be used
1050 * to effectively include a template in the middle of another
1052 * Note that all desired assignments to the variables in $handle should be done
1053 * BEFORE calling this function.
1055 function assign_var_from_handle($varname, $handle)
1058 $res = $this->pparse($handle);
1059 $this->vars[$varname] = ob_get_contents();
1065 * Block-level variable assignment. Adds a new block iteration with the given
1066 * variable assignments. Note that this should only be called once per block
1069 function assign_block_vars($blockname, $vararray)
1071 if (strstr($blockname, '.'))
1074 $blocks = explode('.', $blockname);
1075 $blockcount = sizeof($blocks) - 1;
1077 $str = &$this->_tpldata;
1078 for($i = 0; $i < $blockcount; $i++)
1080 $str = &$str[$blocks[$i].'.'];
1081 $str = &$str[sizeof($str)-1];
1083 // Now we add the block that we're actually assigning to.
1084 // We're adding a new iteration to this block with the given
1085 // variable assignments.
1086 $str[$blocks[$blockcount].'.'][] = $vararray;
1091 // Add a new iteration to this block with the variable assignments
1093 $this->_tpldata[$blockname.'.'][] = $vararray;
1100 * Root-level variable assignment. Adds to current assignments, overriding
1101 * any existing variable assignment with the same name.
1103 function assign_vars($vararray)
1105 foreach($vararray as $key => $val)
1107 $this->vars[$key] = $val;
1113 * Root-level variable assignment. Adds to current assignments, overriding
1114 * any existing variable assignment with the same name.
1116 function assign_var($varname, $varval)
1118 $this->vars[$varname] = $varval;
1124 * If not already done, load the file for the given handle and populate
1125 * the uncompiled_code[] hash with its code. Do not compile.
1127 function loadfile($handle)
1129 global $board_config;
1130 // If cached file exists do nothing - it will be included via include()
1131 if(!empty($this->files_cache[$handle]))
1136 // If the file for this handle is already loaded and compiled, do nothing.
1137 if (!empty($this->uncompiled_code[$handle]))
1142 // If we don't have a file assigned to this handle, die.
1143 if (empty($this->files[$handle]))
1145 die("Template->loadfile(): No file specified for handle $handle");
1148 $filename = $this->files[$handle];
1150 $str = implode('', @file($filename));
1153 die("Template->loadfile(): File $filename for handle $handle is empty");
1156 $this->uncompiled_code[$handle] = $str;
1164 * Generates a reference to the given variable inside the given (possibly nested)
1165 * block namespace. This is a string of the form:
1166 * ' . $this->_tpldata['parent.'][$_parent_i]['$child1.'][$_child1_i]['$child2.'][$_child2_i]...['varname'] . '
1167 * It's ready to be inserted into an "echo" line in one of the templates.
1168 * NOTE: expects a trailing "." on the namespace.
1170 function generate_block_varref($namespace, $varname, $use_isset = true)
1172 // Strip the trailing period.
1173 $namespace = substr($namespace, 0, strlen($namespace) - 1);
1175 // Get a reference to the data block for this namespace.
1176 $varref = $this->generate_block_data_ref($namespace, true);
1177 // Prepend the necessary code to stick this in an echo line.
1179 // Append the variable reference.
1180 $varref .= '[\'' . $varname . '\']';
1184 $varref = '<'.'?php echo isset(' . $varref . ') ? ' . $varref . ' : \'\'; ?'.'>';
1188 $varref = '<'.'?php echo ' . $varref . '; ?'.'>';
1197 * Generates a reference to the array of data values for the given
1198 * (possibly nested) block namespace. This is a string of the form:
1199 * $this->_tpldata['parent.'][$_parent_i]['$child1.'][$_child1_i]['$child2.'][$_child2_i]...['$childN.']
1201 * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
1202 * NOTE: does not expect a trailing "." on the blockname.
1204 function generate_block_data_ref($blockname, $include_last_iterator, $defop = false)
1206 // Get an array of the blocks involved.
1207 $blocks = explode('.', $blockname);
1208 $blockcount = sizeof($blocks) - 1;
1211 $varref = '$this->_tpldata[\'DEFINE\']';
1212 // Build up the string with everything but the last child.
1213 for ($i = 0; $i < $blockcount; $i++)
1215 $varref .= "['" . $blocks[$i] . ".'][\$" . $blocks[$i] . '_i]';
1217 // Add the block reference for the last child.
1218 $varref .= "['" . $blocks[$blockcount] . ".']";
1219 // Add the iterator for the last child if requried.
1220 if ($include_last_iterator)
1222 $varref .= '[$' . $blocks[$blockcount] . '_i]';
1226 if($include_last_iterator)
1228 return '$'. $blocks[$blockcount]. '_item';
1232 return '$'. $blocks[$blockcount-1]. '_item[\''. $blocks[$blockcount]. '.\']';
1236 function compile_code($filename, $code, $use_isset = false)
1238 // $filename - file to load code from. used if $code is empty
1240 // $use_isset - if false then compiled code looks more beautiful and easier
1241 // to understand and it adds error_reporting() to supress php warnings.
1242 // if true then isset() is used to check variables instead of supressing
1243 // php warnings. note: for extreme styles mod 2.x it works only for
1244 // block variables and for usual variables its always true.
1246 // load code from file
1247 if(!$code && !empty($filename))
1249 $code = @implode('', @file($filename));
1252 // Replace phpBB 2.2 <!-- (END)PHP --> tags
1253 $search = array('<!-- PHP -->', '<!-- ENDPHP -->');
1254 $replace = array('<'.'?php ', ' ?'.'>');
1255 $code = str_replace($search, $replace, $code);
1257 // Break it up into lines and put " -->" back.
1258 $code_lines = explode(' -->', $code);
1259 $count = count($code_lines);
1260 for ($i = 0; $i < ($count - 1); $i++)
1262 $code_lines[$i] .= ' -->';
1265 $block_nesting_level = 0;
1266 $block_names = array();
1267 $block_names[0] = ".";
1268 $block_items = array();
1271 // prepare array for compiled code
1272 $compiled = array();
1273 $count_bugs = count($this->bugs);
1275 // array of switches
1278 // replace all short php tags
1279 $new_code = array();
1280 $line_count = count($code_lines);
1281 for($i=0; $i<$line_count; $i++)
1283 $line = $code_lines[$i];
1284 $pos = strpos($line, '<?');
1287 $new_code[] = $line;
1290 if(substr($line, $pos, 5) === '<?php')
1292 // valid php tag. skip it
1293 $new_code[] = substr($line, 0, $pos + 5);
1294 $code_lines[$i] = substr($line, $pos + 5);
1299 $new_code[] = substr($line, 0, $pos) . '<?php echo \'<?\'; ?>';
1300 $code_lines[$i] = substr($line, $pos + 2);
1303 $code_lines = $new_code;
1306 $line_count = count($code_lines);
1307 for($i=0; $i<$line_count; $i++)
1309 $line = $code_lines[$i];
1310 // reset keyword type
1311 $keyword_type = XS_TAG_NONE;
1312 // check if we have valid keyword in current line
1313 $pos1 = strpos($line, '<!-- ');
1316 // no keywords in this line
1317 $compiled[] = $this->_compile_text($line, $use_isset);
1320 // find end of html comment
1321 $pos2 = strpos($line, ' -->', $pos1);
1324 // find end of keyword in comment
1325 $pos3 = strpos($line, ' ', $pos1 + 5);
1326 if($pos3 !== false && $pos3 <= $pos2)
1328 $keyword = substr($line, $pos1 + 5, $pos3 - $pos1 - 5);
1329 // check keyword against list of supported keywords. case-sensitive
1330 if($keyword === 'BEGIN')
1332 $keyword_type = XS_TAG_BEGIN;
1334 elseif($keyword === 'END')
1336 $keyword_type = XS_TAG_END;
1338 elseif($keyword === 'INCLUDE')
1340 $keyword_type = XS_TAG_INCLUDE;
1342 elseif($keyword === 'IF')
1344 $keyword_type = XS_TAG_IF;
1346 elseif($keyword === 'ELSE')
1348 $keyword_type = XS_TAG_ELSE;
1350 elseif($keyword === 'ELSEIF')
1352 $keyword_type = XS_TAG_ELSEIF;
1354 elseif($keyword === 'ENDIF')
1356 $keyword_type = XS_TAG_ENDIF;
1358 elseif($keyword === 'DEFINE')
1360 $keyword_type = XS_TAG_DEFINE;
1362 elseif($keyword === 'UNDEFINE')
1364 $keyword_type = XS_TAG_UNDEFINE;
1370 // not valid keyword. process the rest of line
1371 $compiled[] = $this->_compile_text(substr($line, 0, $pos1 + 4), $use_isset);
1372 $code_lines[$i] = substr($line, $pos1 + 4);
1376 // remove code before keyword
1379 $compiled[] = $this->_compile_text(substr($line, 0, $pos1), $use_isset);
1382 $keyword_str = substr($line, $pos1, $pos2 - $pos1 + 4);
1383 $params_str = $pos2 == $pos3 ? '' : substr($line, $pos3 + 1, $pos2 - $pos3 - 1);
1384 $code_lines[$i] = substr($line, $pos2 + 4);
1391 if($keyword_type == XS_TAG_BEGIN)
1393 $params = explode(' ', $params_str);
1394 $num_params = count($params);
1395 // get variable name
1396 if($num_params == 1)
1400 elseif($num_params == 2)
1402 if($params[0] === '')
1406 elseif($params[1] === '')
1413 $compiled[] = $keyword_str;
1420 $compiled[] = $keyword_str;
1423 // check variable for matching end
1424 if($this->xs_check_switches)
1427 $str = '<!-- END ' . $var . ' -->';
1428 for ($j = $i+1; ($j < $line_count) && !$found; $j++)
1430 $pos = strpos($code_lines[$j], $str);
1437 if(!$found && ($this->xs_check_switches == 1))
1439 // checking list of known buggy switches
1441 for($j=0; $j<$count_bugs; $j++)
1443 if($this->bugs[$j][0] === $var)
1450 $str1 = '<!-- END ' . $this->bugs[$item][1] . ' -->';
1451 for ($j = $i+1; ($j < $line_count) && !$found; $j++)
1453 $pos = strpos($code_lines[$j], $str1);
1456 $found_var = $this->bugs[$item][1];
1458 $code_lines[$j] = str_replace($str, $str1, $code_lines[$j]);
1465 $compiled[] = $keyword_str;
1468 // adding to list of switches
1469 if(isset($sw[$found_var]))
1475 $sw[$found_var] = 1;
1479 $block_nesting_level++;
1480 $block_names[$block_nesting_level] = $var;
1481 if(isset($block_items[$var]))
1483 $block_items[$var] ++;
1487 $block_items[$var] = 1;
1489 if ($block_nesting_level < 2)
1491 // Block is not nested.
1492 $line = '<'."?php\n\n";
1495 $line .= '$'. $var. '_count = ( isset($this->_tpldata[\''. $var. '.\']) ) ? sizeof($this->_tpldata[\''. $var. '.\']) : 0;';
1499 $line .= '$'. $var. '_count = sizeof($this->_tpldata[\''. $var. '.\']);';
1501 $line .= "\n" . 'for ($'. $var. '_i = 0; $'. $var. '_i < $'. $var. '_count; $'. $var. '_i++)';
1502 $line .= "\n". '{'. "\n";
1503 $line .= ' $'. $var. '_item = &$this->_tpldata[\''. $var. '.\'][$'. $var. '_i];'."\n";
1504 $line .= " \${$var}_item['S_ROW_COUNT'] = \${$var}_i;\n";
1505 $line .= " \${$var}_item['S_NUM_ROWS'] = \${$var}_count;\n";
1510 // This block is nested.
1511 // Generate a namespace string for this block.
1512 $namespace = implode('.', $block_names);
1513 // strip leading period from root level..
1514 $namespace = substr($namespace, 2);
1515 // Get a reference to the data array for this block that depends on the
1516 // current indices of all parent blocks.
1517 $varref = $this->generate_block_data_ref($namespace, false);
1518 // Create the for loop code to iterate over this block.
1519 $line = '<'."?php\n\n";
1522 $line .= '$'. $var. '_count = ( isset('. $varref. ') ) ? sizeof('. $varref. ') : 0;';
1526 $line .= '$'. $var. '_count = sizeof('. $varref. ');';
1528 $line .= "\n". 'for ($'. $var. '_i = 0; $'. $var. '_i < $'. $var. '_count; $'. $var. '_i++)';
1529 $line .= "\n". '{'. "\n";
1530 $line .= ' $'. $var. '_item = &'. $varref. '[$'. $var. '_i];'."\n";
1531 $line .= " \${$var}_item['S_ROW_COUNT'] = \${$var}_i;\n";
1532 $line .= " \${$var}_item['S_NUM_ROWS'] = \${$var}_count;\n";
1535 $compiled[] = $line;
1541 if($keyword_type == XS_TAG_END)
1543 $params = explode(' ', $params_str);
1544 $num_params = count($params);
1545 if($num_params == 1)
1549 elseif($num_params == 2 && $params[0] === '')
1553 elseif($num_params == 2 && $params[1] === '')
1559 $compiled[] = $keyword_str;
1562 if($this->xs_check_switches)
1564 // checking if this switch was opened
1565 if(!isset($sw[$var]) || ($sw[$var] < 1))
1567 // there is no opening switch
1568 $compiled[] = $keyword_str;
1573 // We have the end of a block.
1574 $line = '<'."?php\n\n";
1575 $line .= '} // END ' . $var . "\n\n";
1576 $line .= 'if(isset($' . $var . '_item)) { unset($' . $var . '_item); } ';
1577 $line .= "\n\n?".">";
1578 if(isset($block_items[$var]))
1580 $block_items[$var] --;
1584 $block_items[$var] = -1;
1586 unset($block_names[$block_nesting_level]);
1587 $block_nesting_level--;
1588 $compiled[] = $line;
1594 if($keyword_type == XS_TAG_INCLUDE)
1596 $params = explode(' ', $params_str);
1597 $num_params = count($params);
1598 if($num_params != 1)
1600 $compiled[] = $keyword_str;
1603 $line = '<'.'?php ';
1604 $line .= ' $this->set_filename(\'xs_include' . $this->include_count . '\', \'' . $params_str .'\', true); ';
1605 $line .= ' $this->pparse(\'xs_include' . $this->include_count . '\'); ';
1607 $this->include_count ++;
1608 $compiled[] = $line;
1614 if($keyword_type == XS_TAG_IF || $keyword_type == XS_TAG_ELSEIF)
1618 $keyword_type = XS_TAG_IF;
1620 $str = $this->compile_tag_if($params_str, $keyword_type == XS_TAG_IF ? false : true);
1623 $compiled[] = '<?php ' . $str . ' ?>';
1624 if($keyword_type == XS_TAG_IF)
1631 $compiled[] = $keyword_str;
1638 if($keyword_type == XS_TAG_ELSE && $count_if > 0)
1640 $compiled[] = '<?php } else { ?>';
1646 if($keyword_type == XS_TAG_ENDIF && $count_if > 0)
1648 $compiled[] = '<?php } ?>';
1655 if($keyword_type == XS_TAG_DEFINE)
1657 $str = $this->compile_tag_define($params_str);
1660 $compiled[] = '<?php ' . $str . ' ?>';
1664 $compiled[] = $keyword_str;
1670 if($keyword_type == XS_TAG_UNDEFINE)
1672 $str = $this->compile_tag_undefine($params_str);
1675 $compiled[] = '<?php ' . $str . ' ?>';
1679 $compiled[] = $keyword_str;
1684 // bring it back into a single string.
1689 $code_header = "<". "?php\n\$old_level = @error_reporting(E_ERROR | E_WARNING | E_PARSE); \n?".">";
1690 $code_footer = '<'."?php @error_reporting(\$old_level); ?".'>';
1693 return $code_header . implode('', $compiled) . $code_footer;
1697 * Compile code between tags
1699 function _compile_text($code, $use_isset)
1701 if(strlen($code) < 3)
1705 // change template varrefs into PHP varrefs
1706 // This one will handle varrefs WITH namespaces
1708 preg_match_all('#\{(([a-z0-9\-_]+?\.)+?)([a-z0-9\-_]+?)\}#is', $code, $varrefs);
1709 $varcount = sizeof($varrefs[1]);
1712 for ($i = 0; $i < $varcount; $i++)
1714 $namespace = $varrefs[1][$i];
1715 $varname = $varrefs[3][$i];
1716 $new = $this->generate_block_varref($namespace, $varname, $use_isset);
1717 $search[] = $varrefs[0][$i];
1720 if(count($search) > 0)
1722 $code = str_replace($search, $replace, $code);
1724 // This will handle the remaining root-level varrefs
1725 $code = preg_replace('#\{([a-z0-9\-_]*?)\}#is', '<'.'?php echo isset($this->vars[\'\1\']) ? $this->vars[\'\1\'] : $this->lang(\'\1\'); ?'.'>', $code);
1726 $code = preg_replace('#\{\$([a-z0-9\-_]*?)\}#is', '<'.'?php echo isset($this->_tpldata[\'DEFINE\'][\'.\'][\'\\1\']) ? $this->_tpldata[\'DEFINE\'][\'.\'][\'\\1\'] : \'\'; ?'.'>', $code);
1731 // Compile IF tags - much of this is from Smarty with
1732 // some adaptions for our block level methods
1734 function compile_tag_if($tag_args, $elseif)
1736 /* Tokenize args for 'if' tag. */
1737 preg_match_all('/(?:
1738 "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
1739 \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' |
1741 [^\s(),]+)/x', $tag_args, $match);
1743 $tokens = $match[0];
1744 $is_arg_stack = array();
1746 for ($i = 0; $i < count($tokens); $i++)
1748 $token = &$tokens[$i];
1824 array_push($is_arg_stack, $i);
1828 $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1;
1829 $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
1831 $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
1833 array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
1838 if (preg_match('#^(([a-z0-9\-_]+?\.)+?)?(\$)?([A-Z]+[A-Z0-9\-_]+)$#s', $token, $varrefs))
1840 $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] . '\']');
1846 $code = (($elseif) ? '} elseif (' : 'if (') . (implode(' ', $tokens) . ') { ');
1851 // This is from Smarty
1852 function _parse_is_expr($is_arg, $tokens)
1855 $negate_expr = false;
1857 if (($first_token = array_shift($tokens)) == 'not')
1859 $negate_expr = true;
1860 $expr_type = array_shift($tokens);
1864 $expr_type = $first_token;
1870 if (@$tokens[$expr_end] == 'by')
1873 $expr_arg = $tokens[$expr_end++];
1874 $expr = "!(($is_arg / $expr_arg) % $expr_arg)";
1878 $expr = "!($is_arg % 2)";
1883 if (@$tokens[$expr_end] == 'by')
1886 $expr_arg = $tokens[$expr_end++];
1887 $expr = "(($is_arg / $expr_arg) % $expr_arg)";
1891 $expr = "($is_arg % 2)";
1896 if (@$tokens[$expr_end] == 'by')
1899 $expr_arg = $tokens[$expr_end++];
1900 $expr = "!($is_arg % $expr_arg)";
1913 array_splice($tokens, 0, $expr_end, $expr);
1919 function compile_tag_define($tag_args)
1921 preg_match('#^(([a-z0-9\-_]+?\.)+?)?\$([A-Z][A-Z0-9_\-]*?) = (\'?)(.*?)(\'?)$#', $tag_args, $match);
1923 if (empty($match[3]) || empty($match[5]))
1929 if ($match[4] && $match[6])
1931 $match[5] = "'" . addslashes(str_replace(array('\\\'', '\\\\'), array('\'', '\\'), $match[5])) . "'";
1935 preg_match('#(true|false|\.)#i', $match[5], $type);
1937 switch (strtolower($type[1]))
1941 $match[5] = strtoupper($match[5]);
1944 $match[5] = doubleval($match[5]);
1947 $match[5] = intval($match[5]);
1952 return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[3] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[3] . '\']') . ' = ' . $match[5] . ';';
1955 function compile_tag_undefine($tag_args)
1957 preg_match('#^(([a-z0-9\-_]+?\.)+?)?\$([A-Z][A-Z0-9_\-]*?)$#', $tag_args, $match);
1958 if (empty($match[3]))
1962 return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[3] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[3] . '\']') . ');';
1966 * Compiles code and writes to cache if needed
1968 function compile2($code, $handle, $cache_file)
1970 $code = $this->compile_code('', $code, XS_USE_ISSET);
1971 if($cache_file && !empty($this->use_cache) && !empty($this->auto_compile))
1973 $res = $this->write_cache($cache_file, $code);
1976 $this->files_cache[$handle] = $cache_file;
1979 $code = '?'.'>'.$code.'<'."?php\n";
1984 * Compiles the given string of code, and returns
1985 * the result in a string.
1986 * If "do_not_echo" is true, the returned code will not be directly
1987 * executable, but can be used as part of a variable assignment
1988 * for use in assign_code_from_handle().
1989 * This function isn't used and kept only for compatibility with original template.php
1991 function compile($code, $do_not_echo = false, $retvar = '')
1993 $code = ' ?'.'>' . $this->compile_code('', $code, true) . '<'."?php \n";
1996 $code = "ob_start();\n". $code. "\n\${$retvar} = ob_get_contents();\nob_end_clean();\n";
2002 * Write cache to disk
2004 function write_cache($filename, $code)
2006 // check if cache is writable
2007 if(!$this->cache_writable)
2011 // check if filename is valid
2012 if(substr($filename, 0, strlen($this->cachedir)) !== $this->cachedir)
2017 $file = @fopen($filename, 'w');
2020 // try to create directories
2021 $dir = substr($filename, strlen($this->cachedir), strlen($filename));
2022 $dirs = explode('/', $dir);
2023 $path = $this->cachedir;
2029 $this->cache_writable = 0;
2034 @chmod($path, 0777);
2037 $count = count($dirs);
2039 for($i=0; $i<$count-1; $i++)
2050 $this->cache_writable = 0;
2055 @chmod($path, 0777);
2059 // try to open file again after directories were created
2060 $file = @fopen($filename, 'w');
2064 $this->cache_writable = 0;
2067 fputs($file, "<?php\n\n// eXtreme Styles mod cache. Generated on " . date('r') . " (time=" . time() . ")\n\n?>");
2068 fputs($file, $code);
2070 @chmod($filename, 0777);
2074 function xs_startup()
2076 global $phpEx, $board_config, $phpbb_root_path;
2077 if(empty($this->xs_started))
2078 { // adding predefined variables
2079 $this->xs_started = 1;
2080 // file extension with session ID (eg: "php?sid=123&" or "php?")
2081 // can be used to make custom URLs without modding phpbb
2082 // contains "&" or "?" at the end so you can easily append paramenters
2083 $php = append_sid($phpEx);
2084 if(strpos($php, '?'))
2092 $this->vars['PHP'] = $php;
2093 // adding language variable (eg: "english" or "german")
2094 // can be used to make truly multi-lingual templates
2095 $this->vars['LANG'] = $board_config['default_lang'];
2096 // adding current template
2097 $tpl = $this->root . '/'; // $phpbb_root_path . 'templates/' . $this->tpl . '/';
2098 if(substr($tpl, 0, 2) === './')
2100 $tpl = substr($tpl, 2, strlen($tpl));
2102 $this->vars['TEMPLATE'] = $tpl;
2103 $this->vars['TEMPLATE_NAME'] = $this->tpl;
2104 $this->_tpldata['switch_xs_enabled.'] = array(array('version' => $this->xs_versiontxt));
2109 * Checks for empty variable and shows language variable if possible.
2114 if(substr($var, 0, 2) === 'L_')
2116 $var = substr($var, 2);
2117 // check variable as it is
2118 if(isset($lang[$var]))
2122 // check variable in lower case
2123 if(isset($lang[strtolower($var)]))
2125 return $lang[strtolower($var)];
2127 // check variable with first letter in upper case
2128 $str = ucfirst(strtolower($var));
2129 if(isset($lang[$str]))
2133 return ''; //str_replace('_', ' ', $var);
2140 // Functions added for USERGROUP MOD (optimized)
2143 function append_var_from_handle_to_block($blockname, $varname, $handle)
2145 $this->assign_var_from_handle('_tmp', $handle);
2146 // assign the value of the generated variable to the given varname.
2147 $this->append_block_vars($blockname, array($varname => $this->vars['_tmp']));
2151 function append_block_vars($blockname, $vararray)
2153 if(strstr($blockname, '.'))
2156 $blocks = explode('.', $blockname);
2157 $blockcount = sizeof($blocks) - 1;
2158 $str = &$this->_tpldata;
2159 for($i = 0; $i < $blockcount; $i++)
2161 $str = &$str[$blocks[$i].'.'];
2162 $str = &$str[sizeof($str)-1];
2164 // Now we add the block that we're actually assigning to.
2165 // We're adding a new iteration to this block with the given
2166 // variable assignments.
2167 $str = &$str[$blocks[$blockcount].'.'];
2168 $count = sizeof($str) - 1;
2171 // adding only if there is at least one item
2172 $str[$count] = array_merge($str[$count], $vararray);
2178 // Add a new iteration to this block with the variable assignments
2180 $str = &$this->_tpldata[$blockname.'.'];
2181 $count = sizeof($str) - 1;
2184 // adding only if there is at least one item
2185 $str[$count] = array_merge($str[$count], $vararray);
2192 * Flush a root level block, so it becomes empty.
2194 function flush_block_vars($blockname)
2197 // flush a existing block we were given.
2198 $current_iteration = sizeof($this->_tpldata[$blockname . '.']) - 1;
2199 unset($this->_tpldata[$blockname . '.']);
2204 function xs_switch($tpl, $name)
2206 return (isset($tpl->_tpldata[$name.'.']) && count($tpl->_tpldata[$name.'.']) > 0);