punbb/include/functions.php
changeset 0 f9ffdbd96607
child 2 a8a21e1c7afa
equal deleted inserted replaced
-1:000000000000 0:f9ffdbd96607
       
     1 <?php
       
     2 /***********************************************************************
       
     3 
       
     4   Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
       
     5 
       
     6   This file is part of PunBB.
       
     7 
       
     8   PunBB is free software; you can redistribute it and/or modify it
       
     9   under the terms of the GNU General Public License as published
       
    10   by the Free Software Foundation; either version 2 of the License,
       
    11   or (at your option) any later version.
       
    12 
       
    13   PunBB is distributed in the hope that it will be useful, but
       
    14   WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    16   GNU General Public License for more details.
       
    17 
       
    18   You should have received a copy of the GNU General Public License
       
    19   along with this program; if not, write to the Free Software
       
    20   Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       
    21   MA  02111-1307  USA
       
    22 
       
    23 ************************************************************************/
       
    24 
       
    25 //
       
    26 // Cookie stuff!
       
    27 //
       
    28 function check_cookie(&$pun_user)
       
    29 {
       
    30 	global $db, $db_type, $pun_config, $cookie_name, $cookie_seed;
       
    31 
       
    32 	$now = time();
       
    33 	$expire = $now + 31536000;	// The cookie expires after a year
       
    34 
       
    35 	// We assume it's a guest
       
    36 	$cookie = array('user_id' => 1, 'password_hash' => 'Guest');
       
    37 
       
    38 	// If a cookie is set, we get the user_id and password hash from it
       
    39 	if (isset($_COOKIE[$cookie_name]))
       
    40 		list($cookie['user_id'], $cookie['password_hash']) = @unserialize($_COOKIE[$cookie_name]);
       
    41 
       
    42 	if ($cookie['user_id'] > 1)
       
    43 	{
       
    44 		// Check if there's a user with the user ID and password hash from the cookie
       
    45 		$result = $db->query('SELECT u.*, g.*, o.logged, o.idle FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE u.id='.intval($cookie['user_id'])) or error('Unable to fetch user information', __FILE__, __LINE__, $db->error());
       
    46 		$pun_user = $db->fetch_assoc($result);
       
    47 
       
    48 		// If user authorisation failed
       
    49 		if (!isset($pun_user['id']) || md5($cookie_seed.$pun_user['password']) !== $cookie['password_hash'])
       
    50 		{
       
    51 			pun_setcookie(0, random_pass(8), $expire);
       
    52 			set_default_user();
       
    53 
       
    54 			return;
       
    55 		}
       
    56 
       
    57 		// Set a default language if the user selected language no longer exists
       
    58 		if (!@file_exists(PUN_ROOT.'lang/'.$pun_user['language']))
       
    59 			$pun_user['language'] = $pun_config['o_default_lang'];
       
    60 
       
    61 		// Set a default style if the user selected style no longer exists
       
    62 		if (!@file_exists(PUN_ROOT.'style/'.$pun_user['style'].'.css'))
       
    63 			$pun_user['style'] = $pun_config['o_default_style'];
       
    64 
       
    65 		if (!$pun_user['disp_topics'])
       
    66 			$pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
       
    67 		if (!$pun_user['disp_posts'])
       
    68 			$pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
       
    69 
       
    70 		if ($pun_user['save_pass'] == '0')
       
    71 			$expire = 0;
       
    72 
       
    73 		// Define this if you want this visit to affect the online list and the users last visit data
       
    74 		if (!defined('PUN_QUIET_VISIT'))
       
    75 		{
       
    76 			// Update the online list
       
    77 			if (!$pun_user['logged'])
       
    78 			{
       
    79 				$pun_user['logged'] = $now;
       
    80 
       
    81 				// With MySQL/MySQLi, REPLACE INTO avoids a user having two rows in the online table
       
    82 				switch ($db_type)
       
    83 				{
       
    84 					case 'mysql':
       
    85 					case 'mysqli':
       
    86 						$db->query('REPLACE INTO '.$db->prefix.'online (user_id, ident, logged) VALUES('.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
       
    87 						break;
       
    88 
       
    89 					default:
       
    90 						$db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) VALUES('.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
       
    91 						break;
       
    92 				}
       
    93 			}
       
    94 			else
       
    95 			{
       
    96 				// Special case: We've timed out, but no other user has browsed the forums since we timed out
       
    97 				if ($pun_user['logged'] < ($now-$pun_config['o_timeout_visit']))
       
    98 				{
       
    99 					$db->query('UPDATE '.$db->prefix.'users SET last_visit='.$pun_user['logged'].' WHERE id='.$pun_user['id']) or error('Unable to update user visit data', __FILE__, __LINE__, $db->error());
       
   100 					$pun_user['last_visit'] = $pun_user['logged'];
       
   101 				}
       
   102 
       
   103 				$idle_sql = ($pun_user['idle'] == '1') ? ', idle=0' : '';
       
   104 				$db->query('UPDATE '.$db->prefix.'online SET logged='.$now.$idle_sql.' WHERE user_id='.$pun_user['id']) or error('Unable to update online list', __FILE__, __LINE__, $db->error());
       
   105 			}
       
   106 		}
       
   107 
       
   108 		$pun_user['is_guest'] = false;
       
   109 	}
       
   110 	else
       
   111 		set_default_user();
       
   112 }
       
   113 
       
   114 
       
   115 //
       
   116 // Fill $pun_user with default values (for guests)
       
   117 //
       
   118 function set_default_user()
       
   119 {
       
   120 	global $db, $db_type, $pun_user, $pun_config;
       
   121 
       
   122 	$remote_addr = get_remote_address();
       
   123 
       
   124 	// Fetch guest user
       
   125 	$result = $db->query('SELECT u.*, g.*, o.logged FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$db->prefix.'online AS o ON o.ident=\''.$remote_addr.'\' WHERE u.id=1') or error('Unable to fetch guest information', __FILE__, __LINE__, $db->error());
       
   126 	if (!$db->num_rows($result))
       
   127 		exit('Unable to fetch guest information. The table \''.$db->prefix.'users\' must contain an entry with id = 1 that represents anonymous users.');
       
   128 
       
   129 	$pun_user = $db->fetch_assoc($result);
       
   130 
       
   131 	// Update online list
       
   132 	if (!$pun_user['logged'])
       
   133 	{
       
   134 		$pun_user['logged'] = time();
       
   135 
       
   136 		// With MySQL/MySQLi, REPLACE INTO avoids a user having two rows in the online table
       
   137 		switch ($db_type)
       
   138 		{
       
   139 			case 'mysql':
       
   140 			case 'mysqli':
       
   141 				$db->query('REPLACE INTO '.$db->prefix.'online (user_id, ident, logged) VALUES(1, \''.$db->escape($remote_addr).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
       
   142 				break;
       
   143 
       
   144 			default:
       
   145 				$db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) VALUES(1, \''.$db->escape($remote_addr).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
       
   146 				break;
       
   147 		}
       
   148 	}
       
   149 	else
       
   150 		$db->query('UPDATE '.$db->prefix.'online SET logged='.time().' WHERE ident=\''.$db->escape($remote_addr).'\'') or error('Unable to update online list', __FILE__, __LINE__, $db->error());
       
   151 
       
   152 	$pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
       
   153 	$pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
       
   154 	$pun_user['timezone'] = $pun_config['o_server_timezone'];
       
   155 	$pun_user['language'] = $pun_config['o_default_lang'];
       
   156 	$pun_user['style'] = $pun_config['o_default_style'];
       
   157 	$pun_user['is_guest'] = true;
       
   158 }
       
   159 
       
   160 
       
   161 //
       
   162 // Set a cookie, PunBB style!
       
   163 //
       
   164 function pun_setcookie($user_id, $password_hash, $expire)
       
   165 {
       
   166 	global $cookie_name, $cookie_path, $cookie_domain, $cookie_secure, $cookie_seed;
       
   167 
       
   168 	// Enable sending of a P3P header by removing // from the following line (try this if login is failing in IE6)
       
   169 //	@header('P3P: CP="CUR ADM"');
       
   170 
       
   171 	if (version_compare(PHP_VERSION, '5.2.0', '>='))
       
   172 		setcookie($cookie_name, serialize(array($user_id, md5($cookie_seed.$password_hash))), $expire, $cookie_path, $cookie_domain, $cookie_secure, true);
       
   173 	else
       
   174 		setcookie($cookie_name, serialize(array($user_id, md5($cookie_seed.$password_hash))), $expire, $cookie_path.'; HttpOnly', $cookie_domain, $cookie_secure);
       
   175 }
       
   176 
       
   177 
       
   178 //
       
   179 // Check whether the connecting user is banned (and delete any expired bans while we're at it)
       
   180 //
       
   181 function check_bans()
       
   182 {
       
   183 	global $db, $pun_config, $lang_common, $pun_user, $pun_bans;
       
   184 
       
   185 	// Admins aren't affected
       
   186 	if ($pun_user['g_id'] == PUN_ADMIN || !$pun_bans)
       
   187 		return;
       
   188 
       
   189 	// Add a dot at the end of the IP address to prevent banned address 192.168.0.5 from matching e.g. 192.168.0.50
       
   190 	$user_ip = get_remote_address().'.';
       
   191 	$bans_altered = false;
       
   192 
       
   193 	foreach ($pun_bans as $cur_ban)
       
   194 	{
       
   195 		// Has this ban expired?
       
   196 		if ($cur_ban['expire'] != '' && $cur_ban['expire'] <= time())
       
   197 		{
       
   198 			$db->query('DELETE FROM '.$db->prefix.'bans WHERE id='.$cur_ban['id']) or error('Unable to delete expired ban', __FILE__, __LINE__, $db->error());
       
   199 			$bans_altered = true;
       
   200 			continue;
       
   201 		}
       
   202 
       
   203 		if ($cur_ban['username'] != '' && !strcasecmp($pun_user['username'], $cur_ban['username']))
       
   204 		{
       
   205 			$db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape($pun_user['username']).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $db->error());
       
   206 			message($lang_common['Ban message'].' '.(($cur_ban['expire'] != '') ? $lang_common['Ban message 2'].' '.strtolower(format_time($cur_ban['expire'], true)).'. ' : '').(($cur_ban['message'] != '') ? $lang_common['Ban message 3'].'<br /><br /><strong>'.pun_htmlspecialchars($cur_ban['message']).'</strong><br /><br />' : '<br /><br />').$lang_common['Ban message 4'].' <a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>.', true);
       
   207 		}
       
   208 
       
   209 		if ($cur_ban['ip'] != '')
       
   210 		{
       
   211 			$cur_ban_ips = explode(' ', $cur_ban['ip']);
       
   212 
       
   213 			for ($i = 0; $i < count($cur_ban_ips); ++$i)
       
   214 			{
       
   215 				$cur_ban_ips[$i] = $cur_ban_ips[$i].'.';
       
   216 
       
   217 				if (substr($user_ip, 0, strlen($cur_ban_ips[$i])) == $cur_ban_ips[$i])
       
   218 				{
       
   219 					$db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape($pun_user['username']).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $db->error());
       
   220 					message($lang_common['Ban message'].' '.(($cur_ban['expire'] != '') ? $lang_common['Ban message 2'].' '.strtolower(format_time($cur_ban['expire'], true)).'. ' : '').(($cur_ban['message'] != '') ? $lang_common['Ban message 3'].'<br /><br /><strong>'.pun_htmlspecialchars($cur_ban['message']).'</strong><br /><br />' : '<br /><br />').$lang_common['Ban message 4'].' <a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>.', true);
       
   221 				}
       
   222 			}
       
   223 		}
       
   224 	}
       
   225 
       
   226 	// If we removed any expired bans during our run-through, we need to regenerate the bans cache
       
   227 	if ($bans_altered)
       
   228 	{
       
   229 		require_once PUN_ROOT.'include/cache.php';
       
   230 		generate_bans_cache();
       
   231 	}
       
   232 }
       
   233 
       
   234 
       
   235 //
       
   236 // Update "Users online"
       
   237 //
       
   238 function update_users_online()
       
   239 {
       
   240 	global $db, $pun_config, $pun_user;
       
   241 
       
   242 	$now = time();
       
   243 
       
   244 	// Fetch all online list entries that are older than "o_timeout_online"
       
   245 	$result = $db->query('SELECT * FROM '.$db->prefix.'online WHERE logged<'.($now-$pun_config['o_timeout_online'])) or error('Unable to fetch old entries from online list', __FILE__, __LINE__, $db->error());
       
   246 	while ($cur_user = $db->fetch_assoc($result))
       
   247 	{
       
   248 		// If the entry is a guest, delete it
       
   249 		if ($cur_user['user_id'] == '1')
       
   250 			$db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape($cur_user['ident']).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $db->error());
       
   251 		else
       
   252 		{
       
   253 			// If the entry is older than "o_timeout_visit", update last_visit for the user in question, then delete him/her from the online list
       
   254 			if ($cur_user['logged'] < ($now-$pun_config['o_timeout_visit']))
       
   255 			{
       
   256 				$db->query('UPDATE '.$db->prefix.'users SET last_visit='.$cur_user['logged'].' WHERE id='.$cur_user['user_id']) or error('Unable to update user visit data', __FILE__, __LINE__, $db->error());
       
   257 				$db->query('DELETE FROM '.$db->prefix.'online WHERE user_id='.$cur_user['user_id']) or error('Unable to delete from online list', __FILE__, __LINE__, $db->error());
       
   258 			}
       
   259 			else if ($cur_user['idle'] == '0')
       
   260 				$db->query('UPDATE '.$db->prefix.'online SET idle=1 WHERE user_id='.$cur_user['user_id']) or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
       
   261 		}
       
   262 	}
       
   263 }
       
   264 
       
   265 
       
   266 //
       
   267 // Generate the "navigator" that appears at the top of every page
       
   268 //
       
   269 function generate_navlinks()
       
   270 {
       
   271 	global $pun_config, $lang_common, $pun_user;
       
   272 
       
   273 	// Index and Userlist should always be displayed
       
   274 	$links[] = '<li id="navindex"><a href="index.php">'.$lang_common['Index'].'</a>';
       
   275 	$links[] = '<li id="navuserlist"><a href="userlist.php">'.$lang_common['User list'].'</a>';
       
   276 
       
   277 	if ($pun_config['o_rules'] == '1')
       
   278 		$links[] = '<li id="navrules"><a href="misc.php?action=rules">'.$lang_common['Rules'].'</a>';
       
   279 
       
   280 	if ($pun_user['is_guest'])
       
   281 	{
       
   282 		if ($pun_user['g_search'] == '1')
       
   283 			$links[] = '<li id="navsearch"><a href="search.php">'.$lang_common['Search'].'</a>';
       
   284 
       
   285 		$links[] = '<li id="navregister"><a href="register.php">'.$lang_common['Register'].'</a>';
       
   286 		$links[] = '<li id="navlogin"><a href="login.php">'.$lang_common['Login'].'</a>';
       
   287 
       
   288 		$info = $lang_common['Not logged in'];
       
   289 	}
       
   290 	else
       
   291 	{
       
   292 		if ($pun_user['g_id'] > PUN_MOD)
       
   293 		{
       
   294 			if ($pun_user['g_search'] == '1')
       
   295 				$links[] = '<li id="navsearch"><a href="search.php">'.$lang_common['Search'].'</a>';
       
   296 
       
   297 			$links[] = '<li id="navprofile"><a href="profile.php?id='.$pun_user['id'].'">'.$lang_common['Profile'].'</a>';
       
   298 			$links[] = '<li id="navlogout"><a href="login.php?action=out&amp;id='.$pun_user['id'].'">'.$lang_common['Logout'].'</a>';
       
   299 		}
       
   300 		else
       
   301 		{
       
   302 			$links[] = '<li id="navsearch"><a href="search.php">'.$lang_common['Search'].'</a>';
       
   303 			$links[] = '<li id="navprofile"><a href="profile.php?id='.$pun_user['id'].'">'.$lang_common['Profile'].'</a>';
       
   304 			$links[] = '<li id="navadmin"><a href="admin_index.php">'.$lang_common['Admin'].'</a>';
       
   305 			$links[] = '<li id="navlogout"><a href="login.php?action=out&amp;id='.$pun_user['id'].'">'.$lang_common['Logout'].'</a>';
       
   306 		}
       
   307 	}
       
   308 
       
   309 	// Are there any additional navlinks we should insert into the array before imploding it?
       
   310 	if ($pun_config['o_additional_navlinks'] != '')
       
   311 	{
       
   312 		if (preg_match_all('#([0-9]+)\s*=\s*(.*?)\n#s', $pun_config['o_additional_navlinks']."\n", $extra_links))
       
   313 		{
       
   314 			// Insert any additional links into the $links array (at the correct index)
       
   315 			for ($i = 0; $i < count($extra_links[1]); ++$i)
       
   316 				array_splice($links, $extra_links[1][$i], 0, array('<li id="navextra'.($i + 1).'">'.$extra_links[2][$i]));
       
   317 		}
       
   318 	}
       
   319 
       
   320 	return '<ul>'."\n\t\t\t\t".implode($lang_common['Link separator'].'</li>'."\n\t\t\t\t", $links).'</li>'."\n\t\t\t".'</ul>';
       
   321 }
       
   322 
       
   323 
       
   324 //
       
   325 // Display the profile navigation menu
       
   326 //
       
   327 function generate_profile_menu($page = '')
       
   328 {
       
   329 	global $lang_profile, $pun_config, $pun_user, $id;
       
   330 
       
   331 ?>
       
   332 <div id="profile" class="block2col">
       
   333 	<div class="blockmenu">
       
   334 		<h2><span><?php echo $lang_profile['Profile menu'] ?></span></h2>
       
   335 		<div class="box">
       
   336 			<div class="inbox">
       
   337 				<ul>
       
   338 					<li<?php if ($page == 'essentials') echo ' class="isactive"'; ?>><a href="profile.php?section=essentials&amp;id=<?php echo $id ?>"><?php echo $lang_profile['Section essentials'] ?></a></li>
       
   339 					<li<?php if ($page == 'personal') echo ' class="isactive"'; ?>><a href="profile.php?section=personal&amp;id=<?php echo $id ?>"><?php echo $lang_profile['Section personal'] ?></a></li>
       
   340 					<li<?php if ($page == 'messaging') echo ' class="isactive"'; ?>><a href="profile.php?section=messaging&amp;id=<?php echo $id ?>"><?php echo $lang_profile['Section messaging'] ?></a></li>
       
   341 					<li<?php if ($page == 'personality') echo ' class="isactive"'; ?>><a href="profile.php?section=personality&amp;id=<?php echo $id ?>"><?php echo $lang_profile['Section personality'] ?></a></li>
       
   342 					<li<?php if ($page == 'display') echo ' class="isactive"'; ?>><a href="profile.php?section=display&amp;id=<?php echo $id ?>"><?php echo $lang_profile['Section display'] ?></a></li>
       
   343 					<li<?php if ($page == 'privacy') echo ' class="isactive"'; ?>><a href="profile.php?section=privacy&amp;id=<?php echo $id ?>"><?php echo $lang_profile['Section privacy'] ?></a></li>
       
   344 <?php if ($pun_user['g_id'] == PUN_ADMIN || ($pun_user['g_id'] == PUN_MOD && $pun_config['p_mod_ban_users'] == '1')): ?>					<li<?php if ($page == 'admin') echo ' class="isactive"'; ?>><a href="profile.php?section=admin&amp;id=<?php echo $id ?>"><?php echo $lang_profile['Section admin'] ?></a></li>
       
   345 <?php endif; ?>				</ul>
       
   346 			</div>
       
   347 		</div>
       
   348 	</div>
       
   349 <?php
       
   350 
       
   351 }
       
   352 
       
   353 
       
   354 //
       
   355 // Update posts, topics, last_post, last_post_id and last_poster for a forum (redirect topics are not included)
       
   356 //
       
   357 function update_forum($forum_id)
       
   358 {
       
   359 	global $db;
       
   360 
       
   361 	$result = $db->query('SELECT COUNT(id), SUM(num_replies) FROM '.$db->prefix.'topics WHERE moved_to IS NULL AND forum_id='.$forum_id) or error('Unable to fetch forum topic count', __FILE__, __LINE__, $db->error());
       
   362 	list($num_topics, $num_posts) = $db->fetch_row($result);
       
   363 
       
   364 	$num_posts = $num_posts + $num_topics;		// $num_posts is only the sum of all replies (we have to add the topic posts)
       
   365 
       
   366 	$result = $db->query('SELECT last_post, last_post_id, last_poster FROM '.$db->prefix.'topics WHERE forum_id='.$forum_id.' AND moved_to IS NULL ORDER BY last_post DESC LIMIT 1') or error('Unable to fetch last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error());
       
   367 	if ($db->num_rows($result))		// There are topics in the forum
       
   368 	{
       
   369 		list($last_post, $last_post_id, $last_poster) = $db->fetch_row($result);
       
   370 
       
   371 		$db->query('UPDATE '.$db->prefix.'forums SET num_topics='.$num_topics.', num_posts='.$num_posts.', last_post='.$last_post.', last_post_id='.$last_post_id.', last_poster=\''.$db->escape($last_poster).'\' WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error());
       
   372 	}
       
   373 	else	// There are no topics
       
   374 		$db->query('UPDATE '.$db->prefix.'forums SET num_topics=0, num_posts=0, last_post=NULL, last_post_id=NULL, last_poster=NULL WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error());
       
   375 }
       
   376 
       
   377 
       
   378 //
       
   379 // Delete a topic and all of it's posts
       
   380 //
       
   381 function delete_topic($topic_id)
       
   382 {
       
   383 	global $db;
       
   384 
       
   385 	// Delete the topic and any redirect topics
       
   386 	$db->query('DELETE FROM '.$db->prefix.'topics WHERE id='.$topic_id.' OR moved_to='.$topic_id) or error('Unable to delete topic', __FILE__, __LINE__, $db->error());
       
   387 
       
   388 	// Create a list of the post ID's in this topic
       
   389 	$post_ids = '';
       
   390 	$result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
       
   391 	while ($row = $db->fetch_row($result))
       
   392 		$post_ids .= ($post_ids != '') ? ','.$row[0] : $row[0];
       
   393 
       
   394 	// Make sure we have a list of post ID's
       
   395 	if ($post_ids != '')
       
   396 	{
       
   397 		strip_search_index($post_ids);
       
   398 
       
   399 		// Delete posts in topic
       
   400 		$db->query('DELETE FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error('Unable to delete posts', __FILE__, __LINE__, $db->error());
       
   401 	}
       
   402 
       
   403 	// Delete any subscriptions for this topic
       
   404 	$db->query('DELETE FROM '.$db->prefix.'subscriptions WHERE topic_id='.$topic_id) or error('Unable to delete subscriptions', __FILE__, __LINE__, $db->error());
       
   405 }
       
   406 
       
   407 
       
   408 //
       
   409 // Delete a single post
       
   410 //
       
   411 function delete_post($post_id, $topic_id)
       
   412 {
       
   413 	global $db;
       
   414 
       
   415 	$result = $db->query('SELECT id, poster, posted FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id.' ORDER BY id DESC LIMIT 2') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
       
   416 	list($last_id, ,) = $db->fetch_row($result);
       
   417 	list($second_last_id, $second_poster, $second_posted) = $db->fetch_row($result);
       
   418 
       
   419 	// Delete the post
       
   420 	$db->query('DELETE FROM '.$db->prefix.'posts WHERE id='.$post_id) or error('Unable to delete post', __FILE__, __LINE__, $db->error());
       
   421 
       
   422 	strip_search_index($post_id);
       
   423 
       
   424 	// Count number of replies in the topic
       
   425 	$result = $db->query('SELECT COUNT(id) FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error('Unable to fetch post count for topic', __FILE__, __LINE__, $db->error());
       
   426 	$num_replies = $db->result($result, 0) - 1;
       
   427 
       
   428 	// If the message we deleted is the most recent in the topic (at the end of the topic)
       
   429 	if ($last_id == $post_id)
       
   430 	{
       
   431 		// If there is a $second_last_id there is more than 1 reply to the topic
       
   432 		if (!empty($second_last_id))
       
   433 			$db->query('UPDATE '.$db->prefix.'topics SET last_post='.$second_posted.', last_post_id='.$second_last_id.', last_poster=\''.$db->escape($second_poster).'\', num_replies='.$num_replies.' WHERE id='.$topic_id) or error('Unable to update topic', __FILE__, __LINE__, $db->error());
       
   434 		else
       
   435 			// We deleted the only reply, so now last_post/last_post_id/last_poster is posted/id/poster from the topic itself
       
   436 			$db->query('UPDATE '.$db->prefix.'topics SET last_post=posted, last_post_id=id, last_poster=poster, num_replies='.$num_replies.' WHERE id='.$topic_id) or error('Unable to update topic', __FILE__, __LINE__, $db->error());
       
   437 	}
       
   438 	else
       
   439 		// Otherwise we just decrement the reply counter
       
   440 		$db->query('UPDATE '.$db->prefix.'topics SET num_replies='.$num_replies.' WHERE id='.$topic_id) or error('Unable to update topic', __FILE__, __LINE__, $db->error());
       
   441 }
       
   442 
       
   443 
       
   444 //
       
   445 // Replace censored words in $text
       
   446 //
       
   447 function censor_words($text)
       
   448 {
       
   449 	global $db;
       
   450 	static $search_for, $replace_with;
       
   451 
       
   452 	// If not already built in a previous call, build an array of censor words and their replacement text
       
   453 	if (!isset($search_for))
       
   454 	{
       
   455 		$result = $db->query('SELECT search_for, replace_with FROM '.$db->prefix.'censoring') or error('Unable to fetch censor word list', __FILE__, __LINE__, $db->error());
       
   456 		$num_words = $db->num_rows($result);
       
   457 
       
   458 		$search_for = array();
       
   459 		for ($i = 0; $i < $num_words; ++$i)
       
   460 		{
       
   461 			list($search_for[$i], $replace_with[$i]) = $db->fetch_row($result);
       
   462 			$search_for[$i] = '/\b('.str_replace('\*', '\w*?', preg_quote($search_for[$i], '/')).')\b/i';
       
   463 		}
       
   464 	}
       
   465 
       
   466 	if (!empty($search_for))
       
   467 		$text = substr(preg_replace($search_for, $replace_with, ' '.$text.' '), 1, -1);
       
   468 
       
   469 	return $text;
       
   470 }
       
   471 
       
   472 
       
   473 //
       
   474 // Determines the correct title for $user
       
   475 // $user must contain the elements 'username', 'title', 'posts', 'g_id' and 'g_user_title'
       
   476 //
       
   477 function get_title($user)
       
   478 {
       
   479 	global $db, $pun_config, $pun_bans, $lang_common;
       
   480 	static $ban_list, $pun_ranks;
       
   481 
       
   482 	// If not already built in a previous call, build an array of lowercase banned usernames
       
   483 	if (empty($ban_list))
       
   484 	{
       
   485 		$ban_list = array();
       
   486 
       
   487 		foreach ($pun_bans as $cur_ban)
       
   488 			$ban_list[] = strtolower($cur_ban['username']);
       
   489 	}
       
   490 
       
   491 	// If not already loaded in a previous call, load the cached ranks
       
   492 	if ($pun_config['o_ranks'] == '1' && empty($pun_ranks))
       
   493 	{
       
   494 		@include PUN_ROOT.'cache/cache_ranks.php';
       
   495 		if (!defined('PUN_RANKS_LOADED'))
       
   496 		{
       
   497 			require_once PUN_ROOT.'include/cache.php';
       
   498 			generate_ranks_cache();
       
   499 			require PUN_ROOT.'cache/cache_ranks.php';
       
   500 		}
       
   501 	}
       
   502 
       
   503 	// If the user has a custom title
       
   504 	if ($user['title'] != '')
       
   505 		$user_title = pun_htmlspecialchars($user['title']);
       
   506 	// If the user is banned
       
   507 	else if (in_array(strtolower($user['username']), $ban_list))
       
   508 		$user_title = $lang_common['Banned'];
       
   509 	// If the user group has a default user title
       
   510 	else if ($user['g_user_title'] != '')
       
   511 		$user_title = pun_htmlspecialchars($user['g_user_title']);
       
   512 	// If the user is a guest
       
   513 	else if ($user['g_id'] == PUN_GUEST)
       
   514 		$user_title = $lang_common['Guest'];
       
   515 	else
       
   516 	{
       
   517 		// Are there any ranks?
       
   518 		if ($pun_config['o_ranks'] == '1' && !empty($pun_ranks))
       
   519 		{
       
   520 			@reset($pun_ranks);
       
   521 			while (list(, $cur_rank) = @each($pun_ranks))
       
   522 			{
       
   523 				if (intval($user['num_posts']) >= $cur_rank['min_posts'])
       
   524 					$user_title = pun_htmlspecialchars($cur_rank['rank']);
       
   525 			}
       
   526 		}
       
   527 
       
   528 		// If the user didn't "reach" any rank (or if ranks are disabled), we assign the default
       
   529 		if (!isset($user_title))
       
   530 			$user_title = $lang_common['Member'];
       
   531 	}
       
   532 
       
   533 	return $user_title;
       
   534 }
       
   535 
       
   536 
       
   537 //
       
   538 // Generate a string with numbered links (for multipage scripts)
       
   539 //
       
   540 function paginate($num_pages, $cur_page, $link_to)
       
   541 {
       
   542 	$pages = array();
       
   543 	$link_to_all = false;
       
   544 
       
   545 	// If $cur_page == -1, we link to all pages (used in viewforum.php)
       
   546 	if ($cur_page == -1)
       
   547 	{
       
   548 		$cur_page = 1;
       
   549 		$link_to_all = true;
       
   550 	}
       
   551 
       
   552 	if ($num_pages <= 1)
       
   553 		$pages = array('<strong>1</strong>');
       
   554 	else
       
   555 	{
       
   556 		if ($cur_page > 3)
       
   557 		{
       
   558 			$pages[] = '<a href="'.$link_to.'&amp;p=1">1</a>';
       
   559 
       
   560 			if ($cur_page != 4)
       
   561 				$pages[] = '&hellip;';
       
   562 		}
       
   563 
       
   564 		// Don't ask me how the following works. It just does, OK? :-)
       
   565 		for ($current = $cur_page - 2, $stop = $cur_page + 3; $current < $stop; ++$current)
       
   566 		{
       
   567 			if ($current < 1 || $current > $num_pages)
       
   568 				continue;
       
   569 			else if ($current != $cur_page || $link_to_all)
       
   570 				$pages[] = '<a href="'.$link_to.'&amp;p='.$current.'">'.$current.'</a>';
       
   571 			else
       
   572 				$pages[] = '<strong>'.$current.'</strong>';
       
   573 		}
       
   574 
       
   575 		if ($cur_page <= ($num_pages-3))
       
   576 		{
       
   577 			if ($cur_page != ($num_pages-3))
       
   578 				$pages[] = '&hellip;';
       
   579 
       
   580 			$pages[] = '<a href="'.$link_to.'&amp;p='.$num_pages.'">'.$num_pages.'</a>';
       
   581 		}
       
   582 	}
       
   583 
       
   584 	return implode('&nbsp;', $pages);
       
   585 }
       
   586 
       
   587 
       
   588 //
       
   589 // Display a message
       
   590 //
       
   591 function message($message, $no_back_link = false)
       
   592 {
       
   593 	global $db, $lang_common, $pun_config, $pun_start, $tpl_main;
       
   594 
       
   595 	if (!defined('PUN_HEADER'))
       
   596 	{
       
   597 		global $pun_user;
       
   598 
       
   599 		$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_common['Info'];
       
   600 		require PUN_ROOT.'header.php';
       
   601 	}
       
   602 
       
   603 ?>
       
   604 
       
   605 <div id="msg" class="block">
       
   606 	<h2><span><?php echo $lang_common['Info'] ?></span></h2>
       
   607 	<div class="box">
       
   608 		<div class="inbox">
       
   609 		<p><?php echo $message ?></p>
       
   610 <?php if (!$no_back_link): ?>		<p><a href="javascript: history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
       
   611 <?php endif; ?>		</div>
       
   612 	</div>
       
   613 </div>
       
   614 <?php
       
   615 
       
   616 	require PUN_ROOT.'footer.php';
       
   617 }
       
   618 
       
   619 
       
   620 //
       
   621 // Format a time string according to $time_format and timezones
       
   622 //
       
   623 function format_time($timestamp, $date_only = false)
       
   624 {
       
   625 	global $pun_config, $lang_common, $pun_user;
       
   626 
       
   627 	if ($timestamp == '')
       
   628 		return $lang_common['Never'];
       
   629 
       
   630 	$diff = ($pun_user['timezone'] - $pun_config['o_server_timezone']) * 3600;
       
   631 	$timestamp += $diff;
       
   632 	$now = time();
       
   633 
       
   634 	$date = date($pun_config['o_date_format'], $timestamp);
       
   635 	$today = date($pun_config['o_date_format'], $now+$diff);
       
   636 	$yesterday = date($pun_config['o_date_format'], $now+$diff-86400);
       
   637 
       
   638 	if ($date == $today)
       
   639 		$date = $lang_common['Today'];
       
   640 	else if ($date == $yesterday)
       
   641 		$date = $lang_common['Yesterday'];
       
   642 
       
   643 	if (!$date_only)
       
   644 		return $date.' '.date($pun_config['o_time_format'], $timestamp);
       
   645 	else
       
   646 		return $date;
       
   647 }
       
   648 
       
   649 
       
   650 //
       
   651 // If we are running pre PHP 4.3.0, we add our own implementation of file_get_contents
       
   652 //
       
   653 if (!function_exists('file_get_contents'))
       
   654 {
       
   655 	function file_get_contents($filename, $use_include_path = 0)
       
   656 	{
       
   657 		$data = '';
       
   658 
       
   659 		if ($fh = fopen($filename, 'rb', $use_include_path))
       
   660 		{
       
   661 			$data = fread($fh, filesize($filename));
       
   662 			fclose($fh);
       
   663 		}
       
   664 
       
   665 		return $data;
       
   666 	}
       
   667 }
       
   668 
       
   669 
       
   670 //
       
   671 // Make sure that HTTP_REFERER matches $pun_config['o_base_url']/$script
       
   672 //
       
   673 function confirm_referrer($script)
       
   674 {
       
   675 	global $pun_config, $lang_common;
       
   676 
       
   677 	if (!preg_match('#^'.preg_quote(str_replace('www.', '', $pun_config['o_base_url']).'/'.$script, '#').'#i', str_replace('www.', '', (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''))))
       
   678 		message($lang_common['Bad referrer']);
       
   679 }
       
   680 
       
   681 
       
   682 //
       
   683 // Generate a random password of length $len
       
   684 //
       
   685 function random_pass($len)
       
   686 {
       
   687 	$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
       
   688 
       
   689 	$password = '';
       
   690 	for ($i = 0; $i < $len; ++$i)
       
   691 		$password .= substr($chars, (mt_rand() % strlen($chars)), 1);
       
   692 
       
   693 	return $password;
       
   694 }
       
   695 
       
   696 
       
   697 //
       
   698 // Compute a hash of $str
       
   699 // Uses sha1() if available. If not, SHA1 through mhash() if available. If not, fall back on md5().
       
   700 //
       
   701 function pun_hash($str)
       
   702 {
       
   703 	if (function_exists('sha1'))	// Only in PHP 4.3.0+
       
   704 		return sha1($str);
       
   705 	else if (function_exists('mhash'))	// Only if Mhash library is loaded
       
   706 		return bin2hex(mhash(MHASH_SHA1, $str));
       
   707 	else
       
   708 		return md5($str);
       
   709 }
       
   710 
       
   711 
       
   712 //
       
   713 // Try to determine the correct remote IP-address
       
   714 //
       
   715 function get_remote_address()
       
   716 {
       
   717 	return $_SERVER['REMOTE_ADDR'];
       
   718 }
       
   719 
       
   720 
       
   721 //
       
   722 // Equivalent to htmlspecialchars(), but allows &#[0-9]+ (for unicode)
       
   723 //
       
   724 function pun_htmlspecialchars($str)
       
   725 {
       
   726 	$str = preg_replace('/&(?!#[0-9]+;)/s', '&amp;', $str);
       
   727 	$str = str_replace(array('<', '>', '"'), array('&lt;', '&gt;', '&quot;'), $str);
       
   728 
       
   729 	return $str;
       
   730 }
       
   731 
       
   732 
       
   733 //
       
   734 // Equivalent to strlen(), but counts &#[0-9]+ as one character (for unicode)
       
   735 //
       
   736 function pun_strlen($str)
       
   737 {
       
   738 	return strlen(preg_replace('/&#([0-9]+);/', '!', $str));
       
   739 }
       
   740 
       
   741 
       
   742 //
       
   743 // Convert \r\n and \r to \n
       
   744 //
       
   745 function pun_linebreaks($str)
       
   746 {
       
   747 	return str_replace("\r", "\n", str_replace("\r\n", "\n", $str));
       
   748 }
       
   749 
       
   750 
       
   751 //
       
   752 // A more aggressive version of trim()
       
   753 //
       
   754 function pun_trim($str)
       
   755 {
       
   756 	global $lang_common;
       
   757 
       
   758 	if (strpos($lang_common['lang_encoding'], '8859') !== false)
       
   759 	{
       
   760 		$fishy_chars = array(chr(0x81), chr(0x8D), chr(0x8F), chr(0x90), chr(0x9D), chr(0xA0));
       
   761 		return trim(str_replace($fishy_chars, ' ', $str));
       
   762 	}
       
   763 	else
       
   764 		return trim($str);
       
   765 }
       
   766 
       
   767 
       
   768 //
       
   769 // Display a message when board is in maintenance mode
       
   770 //
       
   771 function maintenance_message()
       
   772 {
       
   773 	global $db, $pun_config, $lang_common, $pun_user;
       
   774 
       
   775 	// Deal with newlines, tabs and multiple spaces
       
   776 	$pattern = array("\t", '  ', '  ');
       
   777 	$replace = array('&nbsp; &nbsp; ', '&nbsp; ', ' &nbsp;');
       
   778 	$message = str_replace($pattern, $replace, $pun_config['o_maintenance_message']);
       
   779 
       
   780 
       
   781 	// Load the maintenance template
       
   782 	$tpl_maint = trim(file_get_contents(PUN_ROOT.'include/template/maintenance.tpl'));
       
   783 
       
   784 
       
   785 	// START SUBST - <pun_include "*">
       
   786 	while (preg_match('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_maint, $cur_include))
       
   787 	{
       
   788 		if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2]))
       
   789 			error('Unable to process user include '.htmlspecialchars($cur_include[0]).' from template maintenance.tpl. There is no such file in folder /include/user/');
       
   790 
       
   791 		ob_start();
       
   792 		include PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2];
       
   793 		$tpl_temp = ob_get_contents();
       
   794 		$tpl_maint = str_replace($cur_include[0], $tpl_temp, $tpl_maint);
       
   795 	    ob_end_clean();
       
   796 	}
       
   797 	// END SUBST - <pun_include "*">
       
   798 
       
   799 
       
   800 	// START SUBST - <pun_content_direction>
       
   801 	$tpl_maint = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_maint);
       
   802 	// END SUBST - <pun_content_direction>
       
   803 
       
   804 
       
   805 	// START SUBST - <pun_char_encoding>
       
   806 	$tpl_maint = str_replace('<pun_char_encoding>', $lang_common['lang_encoding'], $tpl_maint);
       
   807 	// END SUBST - <pun_char_encoding>
       
   808 
       
   809 
       
   810 	// START SUBST - <pun_head>
       
   811 	ob_start();
       
   812 
       
   813 ?>
       
   814 <title><?php echo pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_common['Maintenance'] ?></title>
       
   815 <link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" />
       
   816 <?php
       
   817 
       
   818 	$tpl_temp = trim(ob_get_contents());
       
   819 	$tpl_maint = str_replace('<pun_head>', $tpl_temp, $tpl_maint);
       
   820 	ob_end_clean();
       
   821 	// END SUBST - <pun_head>
       
   822 
       
   823 
       
   824 	// START SUBST - <pun_maint_heading>
       
   825 	$tpl_maint = str_replace('<pun_maint_heading>', $lang_common['Maintenance'], $tpl_maint);
       
   826 	// END SUBST - <pun_maint_heading>
       
   827 
       
   828 
       
   829 	// START SUBST - <pun_maint_message>
       
   830 	$tpl_maint = str_replace('<pun_maint_message>', $message, $tpl_maint);
       
   831 	// END SUBST - <pun_maint_message>
       
   832 
       
   833 
       
   834 	// End the transaction
       
   835 	$db->end_transaction();
       
   836 
       
   837 
       
   838 	// Close the db connection (and free up any result data)
       
   839 	$db->close();
       
   840 
       
   841 	exit($tpl_maint);
       
   842 }
       
   843 
       
   844 
       
   845 //
       
   846 // Display $message and redirect user to $destination_url
       
   847 //
       
   848 function redirect($destination_url, $message)
       
   849 {
       
   850 	global $db, $pun_config, $lang_common, $pun_user;
       
   851 
       
   852 	if ($destination_url == '')
       
   853 		$destination_url = 'index.php';
       
   854 
       
   855 	// If the delay is 0 seconds, we might as well skip the redirect all together
       
   856 	if ($pun_config['o_redirect_delay'] == '0')
       
   857 		header('Location: '.str_replace('&amp;', '&', $destination_url));
       
   858 
       
   859 
       
   860 	// Load the redirect template
       
   861 	$tpl_redir = trim(file_get_contents(PUN_ROOT.'include/template/redirect.tpl'));
       
   862 
       
   863 
       
   864 	// START SUBST - <pun_include "*">
       
   865 	while (preg_match('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_redir, $cur_include))
       
   866 	{
       
   867 		if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2]))
       
   868 			error('Unable to process user include '.htmlspecialchars($cur_include[0]).' from template redirect.tpl. There is no such file in folder /include/user/');
       
   869 
       
   870 		ob_start();
       
   871 		include PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2];
       
   872 		$tpl_temp = ob_get_contents();
       
   873 		$tpl_redir = str_replace($cur_include[0], $tpl_temp, $tpl_redir);
       
   874 	    ob_end_clean();
       
   875 	}
       
   876 	// END SUBST - <pun_include "*">
       
   877 
       
   878 
       
   879 	// START SUBST - <pun_content_direction>
       
   880 	$tpl_redir = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_redir);
       
   881 	// END SUBST - <pun_content_direction>
       
   882 
       
   883 
       
   884 	// START SUBST - <pun_char_encoding>
       
   885 	$tpl_redir = str_replace('<pun_char_encoding>', $lang_common['lang_encoding'], $tpl_redir);
       
   886 	// END SUBST - <pun_char_encoding>
       
   887 
       
   888 
       
   889 	// START SUBST - <pun_head>
       
   890 	ob_start();
       
   891 
       
   892 ?>
       
   893 <meta http-equiv="refresh" content="<?php echo $pun_config['o_redirect_delay'] ?>;URL=<?php echo str_replace(array('<', '>', '"'), array('&lt;', '&gt;', '&quot;'), $destination_url) ?>" />
       
   894 <title><?php echo pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_common['Redirecting'] ?></title>
       
   895 <link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" />
       
   896 <?php
       
   897 
       
   898 	$tpl_temp = trim(ob_get_contents());
       
   899 	$tpl_redir = str_replace('<pun_head>', $tpl_temp, $tpl_redir);
       
   900 	ob_end_clean();
       
   901 	// END SUBST - <pun_head>
       
   902 
       
   903 
       
   904 	// START SUBST - <pun_redir_heading>
       
   905 	$tpl_redir = str_replace('<pun_redir_heading>', $lang_common['Redirecting'], $tpl_redir);
       
   906 	// END SUBST - <pun_redir_heading>
       
   907 
       
   908 
       
   909 	// START SUBST - <pun_redir_text>
       
   910 	$tpl_temp = $message.'<br /><br />'.'<a href="'.$destination_url.'">'.$lang_common['Click redirect'].'</a>';
       
   911 	$tpl_redir = str_replace('<pun_redir_text>', $tpl_temp, $tpl_redir);
       
   912 	// END SUBST - <pun_redir_text>
       
   913 
       
   914 
       
   915 	// START SUBST - <pun_footer>
       
   916 	ob_start();
       
   917 
       
   918 	// End the transaction
       
   919 	$db->end_transaction();
       
   920 
       
   921 	// Display executed queries (if enabled)
       
   922 	if (defined('PUN_SHOW_QUERIES'))
       
   923 		display_saved_queries();
       
   924 
       
   925 	$tpl_temp = trim(ob_get_contents());
       
   926 	$tpl_redir = str_replace('<pun_footer>', $tpl_temp, $tpl_redir);
       
   927 	ob_end_clean();
       
   928 	// END SUBST - <pun_footer>
       
   929 
       
   930 
       
   931 	// Close the db connection (and free up any result data)
       
   932 	$db->close();
       
   933 
       
   934 	exit($tpl_redir);
       
   935 }
       
   936 
       
   937 
       
   938 //
       
   939 // Display a simple error message
       
   940 //
       
   941 function error($message, $file, $line, $db_error = false)
       
   942 {
       
   943 	global $pun_config;
       
   944 
       
   945 	// Set a default title if the script failed before $pun_config could be populated
       
   946 	if (empty($pun_config))
       
   947 		$pun_config['o_board_title'] = 'PunBB';
       
   948 
       
   949 	// Empty output buffer and stop buffering
       
   950 	@ob_end_clean();
       
   951 
       
   952 	// "Restart" output buffering if we are using ob_gzhandler (since the gzip header is already sent)
       
   953 	if (!empty($pun_config['o_gzip']) && extension_loaded('zlib') && (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false || strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') !== false))
       
   954 		ob_start('ob_gzhandler');
       
   955 
       
   956 ?>
       
   957 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
       
   958 <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
       
   959 <head>
       
   960 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
       
   961 <title><?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?> / Error</title>
       
   962 <style type="text/css">
       
   963 <!--
       
   964 BODY {MARGIN: 10% 20% auto 20%; font: 10px Verdana, Arial, Helvetica, sans-serif}
       
   965 #errorbox {BORDER: 1px solid #B84623}
       
   966 H2 {MARGIN: 0; COLOR: #FFFFFF; BACKGROUND-COLOR: #B84623; FONT-SIZE: 1.1em; PADDING: 5px 4px}
       
   967 #errorbox DIV {PADDING: 6px 5px; BACKGROUND-COLOR: #F1F1F1}
       
   968 -->
       
   969 </style>
       
   970 </head>
       
   971 <body>
       
   972 
       
   973 <div id="errorbox">
       
   974 	<h2>An error was encountered</h2>
       
   975 	<div>
       
   976 <?php
       
   977 
       
   978 	if (defined('PUN_DEBUG'))
       
   979 	{
       
   980 		echo "\t\t".'<strong>File:</strong> '.$file.'<br />'."\n\t\t".'<strong>Line:</strong> '.$line.'<br /><br />'."\n\t\t".'<strong>PunBB reported</strong>: '.$message."\n";
       
   981 
       
   982 		if ($db_error)
       
   983 		{
       
   984 			echo "\t\t".'<br /><br /><strong>Database reported:</strong> '.pun_htmlspecialchars($db_error['error_msg']).(($db_error['error_no']) ? ' (Errno: '.$db_error['error_no'].')' : '')."\n";
       
   985 
       
   986 			if ($db_error['error_sql'] != '')
       
   987 				echo "\t\t".'<br /><br /><strong>Failed query:</strong> '.pun_htmlspecialchars($db_error['error_sql'])."\n";
       
   988 		}
       
   989 	}
       
   990 	else
       
   991 		echo "\t\t".'Error: <strong>'.$message.'.</strong>'."\n";
       
   992 
       
   993 ?>
       
   994 	</div>
       
   995 </div>
       
   996 
       
   997 </body>
       
   998 </html>
       
   999 <?php
       
  1000 
       
  1001 	// If a database connection was established (before this error) we close it
       
  1002 	if ($db_error)
       
  1003 		$GLOBALS['db']->close();
       
  1004 
       
  1005 	exit;
       
  1006 }
       
  1007 
       
  1008 // DEBUG FUNCTIONS BELOW
       
  1009 
       
  1010 //
       
  1011 // Display executed queries (if enabled)
       
  1012 //
       
  1013 function display_saved_queries()
       
  1014 {
       
  1015 	global $db, $lang_common;
       
  1016 
       
  1017 	// Get the queries so that we can print them out
       
  1018 	$saved_queries = $db->get_saved_queries();
       
  1019 
       
  1020 ?>
       
  1021 
       
  1022 <div id="debug" class="blocktable">
       
  1023 	<h2><span><?php echo $lang_common['Debug table'] ?></span></h2>
       
  1024 	<div class="box">
       
  1025 		<div class="inbox">
       
  1026 			<table cellspacing="0">
       
  1027 			<thead>
       
  1028 				<tr>
       
  1029 					<th class="tcl" scope="col">Time (s)</th>
       
  1030 					<th class="tcr" scope="col">Query</th>
       
  1031 				</tr>
       
  1032 			</thead>
       
  1033 			<tbody>
       
  1034 <?php
       
  1035 
       
  1036 	$query_time_total = 0.0;
       
  1037 	while (list(, $cur_query) = @each($saved_queries))
       
  1038 	{
       
  1039 		$query_time_total += $cur_query[1];
       
  1040 
       
  1041 ?>
       
  1042 				<tr>
       
  1043 					<td class="tcl"><?php echo ($cur_query[1] != 0) ? $cur_query[1] : '&nbsp;' ?></td>
       
  1044 					<td class="tcr"><?php echo pun_htmlspecialchars($cur_query[0]) ?></td>
       
  1045 				</tr>
       
  1046 <?php
       
  1047 
       
  1048 	}
       
  1049 
       
  1050 ?>
       
  1051 				<tr>
       
  1052 					<td class="tcl" colspan="2">Total query time: <?php echo $query_time_total ?> s</td>
       
  1053 				</tr>
       
  1054 			</tbody>
       
  1055 			</table>
       
  1056 		</div>
       
  1057 	</div>
       
  1058 </div>
       
  1059 <?php
       
  1060 
       
  1061 }
       
  1062 
       
  1063 
       
  1064 //
       
  1065 // Unset any variables instantiated as a result of register_globals being enabled
       
  1066 //
       
  1067 function unregister_globals()
       
  1068 {
       
  1069 	$register_globals = @ini_get('register_globals');
       
  1070 	if ($register_globals === "" || $register_globals === "0" || strtolower($register_globals === "off"))
       
  1071 		return;
       
  1072 
       
  1073 	// Prevent script.php?GLOBALS[foo]=bar
       
  1074 	if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS']))
       
  1075 		exit('I\'ll have a steak sandwich and... a steak sandwich.');
       
  1076 	
       
  1077 	// Variables that shouldn't be unset
       
  1078 	$no_unset = array('GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES');
       
  1079 
       
  1080 	// Remove elements in $GLOBALS that are present in any of the superglobals
       
  1081 	$input = array_merge($_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_FILES, isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());
       
  1082 	foreach ($input as $k => $v)
       
  1083 	{
       
  1084 		if (!in_array($k, $no_unset) && isset($GLOBALS[$k]))
       
  1085 		{
       
  1086 			unset($GLOBALS[$k]);
       
  1087 			unset($GLOBALS[$k]);	// Double unset to circumvent the zend_hash_del_key_or_index hole in PHP <4.4.3 and <5.1.4
       
  1088 		}
       
  1089 	}
       
  1090 }
       
  1091 
       
  1092 
       
  1093 //
       
  1094 // Dump contents of variable(s)
       
  1095 //
       
  1096 function dump()
       
  1097 {
       
  1098 	echo '<pre>';
       
  1099 
       
  1100 	$num_args = func_num_args();
       
  1101 
       
  1102 	for ($i = 0; $i < $num_args; ++$i)
       
  1103 	{
       
  1104 		print_r(func_get_arg($i));
       
  1105 		echo "\n\n";
       
  1106 	}
       
  1107 
       
  1108 	echo '</pre>';
       
  1109 	exit;
       
  1110 }