PageRenderTime 58ms CodeModel.GetById 2ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 0ms

/other/punbb-modified-forum/include/functions.php

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