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