Blame Identity/Models/Html/phpBB/3.0.4/includes/functions.php

d6e8d8
d6e8d8
/**
d6e8d8
*
d6e8d8
* @package phpBB3
d6e8d8
* @version $Id: functions.php 9153 2008-12-02 17:02:56Z acydburn $
d6e8d8
* @copyright (c) 2005 phpBB Group
d6e8d8
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
d6e8d8
*
d6e8d8
*/
d6e8d8
d6e8d8
/**
d6e8d8
* @ignore
d6e8d8
*/
d6e8d8
if (!defined('IN_PHPBB'))
d6e8d8
{
d6e8d8
	exit;
d6e8d8
}
d6e8d8
d6e8d8
// Common global functions
d6e8d8
d6e8d8
/**
d6e8d8
* set_var
d6e8d8
*
d6e8d8
* Set variable, used by {@link request_var the request_var function}
d6e8d8
*
d6e8d8
* @access private
d6e8d8
*/
d6e8d8
function set_var(&$result, $var, $type, $multibyte = false)
d6e8d8
{
d6e8d8
	settype($var, $type);
d6e8d8
	$result = $var;
d6e8d8
d6e8d8
	if ($type == 'string')
d6e8d8
	{
d6e8d8
		$result = trim(htmlspecialchars(str_replace(array("\r\n", "\r", "\0"), array("\n", "\n", ''), $result), ENT_COMPAT, 'UTF-8'));
d6e8d8
d6e8d8
		if (!empty($result))
d6e8d8
		{
d6e8d8
			// Make sure multibyte characters are wellformed
d6e8d8
			if ($multibyte)
d6e8d8
			{
d6e8d8
				if (!preg_match('/^./u', $result))
d6e8d8
				{
d6e8d8
					$result = '';
d6e8d8
				}
d6e8d8
			}
d6e8d8
			else
d6e8d8
			{
d6e8d8
				// no multibyte, allow only ASCII (0-127)
d6e8d8
				$result = preg_replace('/[\x80-\xFF]/', '?', $result);
d6e8d8
			}
d6e8d8
		}
d6e8d8
d6e8d8
		$result = (STRIP) ? stripslashes($result) : $result;
d6e8d8
	}
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* request_var
d6e8d8
*
d6e8d8
* Used to get passed variable
d6e8d8
*/
d6e8d8
function request_var($var_name, $default, $multibyte = false, $cookie = false)
d6e8d8
{
d6e8d8
	if (!$cookie && isset($_COOKIE[$var_name]))
d6e8d8
	{
d6e8d8
		if (!isset($_GET[$var_name]) && !isset($_POST[$var_name]))
d6e8d8
		{
d6e8d8
			return (is_array($default)) ? array() : $default;
d6e8d8
		}
d6e8d8
		$_REQUEST[$var_name] = isset($_POST[$var_name]) ? $_POST[$var_name] : $_GET[$var_name];
d6e8d8
	}
d6e8d8
d6e8d8
	if (!isset($_REQUEST[$var_name]) || (is_array($_REQUEST[$var_name]) && !is_array($default)) || (is_array($default) && !is_array($_REQUEST[$var_name])))
d6e8d8
	{
d6e8d8
		return (is_array($default)) ? array() : $default;
d6e8d8
	}
d6e8d8
d6e8d8
	$var = $_REQUEST[$var_name];
d6e8d8
	if (!is_array($default))
d6e8d8
	{
d6e8d8
		$type = gettype($default);
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		list($key_type, $type) = each($default);
d6e8d8
		$type = gettype($type);
d6e8d8
		$key_type = gettype($key_type);
d6e8d8
		if ($type == 'array')
d6e8d8
		{
d6e8d8
			reset($default);
d6e8d8
			$default = current($default);
d6e8d8
			list($sub_key_type, $sub_type) = each($default);
d6e8d8
			$sub_type = gettype($sub_type);
d6e8d8
			$sub_type = ($sub_type == 'array') ? 'NULL' : $sub_type;
d6e8d8
			$sub_key_type = gettype($sub_key_type);
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	if (is_array($var))
d6e8d8
	{
d6e8d8
		$_var = $var;
d6e8d8
		$var = array();
d6e8d8
d6e8d8
		foreach ($_var as $k => $v)
d6e8d8
		{
d6e8d8
			set_var($k, $k, $key_type);
d6e8d8
			if ($type == 'array' && is_array($v))
d6e8d8
			{
d6e8d8
				foreach ($v as $_k => $_v)
d6e8d8
				{
d6e8d8
					if (is_array($_v))
d6e8d8
					{
d6e8d8
						$_v = null;
d6e8d8
					}
d6e8d8
					set_var($_k, $_k, $sub_key_type);
d6e8d8
					set_var($var[$k][$_k], $_v, $sub_type, $multibyte);
d6e8d8
				}
d6e8d8
			}
d6e8d8
			else
d6e8d8
			{
d6e8d8
				if ($type == 'array' || is_array($v))
d6e8d8
				{
d6e8d8
					$v = null;
d6e8d8
				}
d6e8d8
				set_var($var[$k], $v, $type, $multibyte);
d6e8d8
			}
d6e8d8
		}
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		set_var($var, $var, $type, $multibyte);
d6e8d8
	}
d6e8d8
d6e8d8
	return $var;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Set config value. Creates missing config entry.
d6e8d8
*/
d6e8d8
function set_config($config_name, $config_value, $is_dynamic = false)
d6e8d8
{
d6e8d8
	global $db, $cache, $config;
d6e8d8
d6e8d8
	$sql = 'UPDATE ' . CONFIG_TABLE . "
d6e8d8
		SET config_value = '" . $db->sql_escape($config_value) . "'
d6e8d8
		WHERE config_name = '" . $db->sql_escape($config_name) . "'";
d6e8d8
	$db->sql_query($sql);
d6e8d8
d6e8d8
	if (!$db->sql_affectedrows() && !isset($config[$config_name]))
d6e8d8
	{
d6e8d8
		$sql = 'INSERT INTO ' . CONFIG_TABLE . ' ' . $db->sql_build_array('INSERT', array(
d6e8d8
			'config_name'	=> $config_name,
d6e8d8
			'config_value'	=> $config_value,
d6e8d8
			'is_dynamic'	=> ($is_dynamic) ? 1 : 0));
d6e8d8
		$db->sql_query($sql);
d6e8d8
	}
d6e8d8
d6e8d8
	$config[$config_name] = $config_value;
d6e8d8
d6e8d8
	if (!$is_dynamic)
d6e8d8
	{
d6e8d8
		$cache->destroy('config');
d6e8d8
	}
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Generates an alphanumeric random string of given length
d6e8d8
*/
d6e8d8
function gen_rand_string($num_chars = 8)
d6e8d8
{
d6e8d8
	$rand_str = unique_id();
d6e8d8
	$rand_str = str_replace('0', 'Z', strtoupper(base_convert($rand_str, 16, 35)));
d6e8d8
d6e8d8
	return substr($rand_str, 0, $num_chars);
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Return unique id
d6e8d8
* @param string $extra additional entropy
d6e8d8
*/
d6e8d8
function unique_id($extra = 'c')
d6e8d8
{
d6e8d8
	static $dss_seeded = false;
d6e8d8
	global $config;
d6e8d8
d6e8d8
	$val = $config['rand_seed'] . microtime();
d6e8d8
	$val = md5($val);
d6e8d8
	$config['rand_seed'] = md5($config['rand_seed'] . $val . $extra);
d6e8d8
d6e8d8
	if ($dss_seeded !== true && ($config['rand_seed_last_update'] < time() - rand(1,10)))
d6e8d8
	{
d6e8d8
		set_config('rand_seed', $config['rand_seed'], true);
d6e8d8
		set_config('rand_seed_last_update', time(), true);
d6e8d8
		$dss_seeded = true;
d6e8d8
	}
d6e8d8
d6e8d8
	return substr($val, 4, 16);
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Return formatted string for filesizes
d6e8d8
*/
d6e8d8
function get_formatted_filesize($bytes, $add_size_lang = true)
d6e8d8
{
d6e8d8
	global $user;
d6e8d8
d6e8d8
	if ($bytes >= pow(2, 20))
d6e8d8
	{
d6e8d8
		return ($add_size_lang) ? round($bytes / 1024 / 1024, 2) . ' ' . $user->lang['MIB'] : round($bytes / 1024 / 1024, 2);
d6e8d8
	}
d6e8d8
d6e8d8
	if ($bytes >= pow(2, 10))
d6e8d8
	{
d6e8d8
		return ($add_size_lang) ? round($bytes / 1024, 2) . ' ' . $user->lang['KIB'] : round($bytes / 1024, 2);
d6e8d8
	}
d6e8d8
d6e8d8
	return ($add_size_lang) ? ($bytes) . ' ' . $user->lang['BYTES'] : ($bytes);
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Determine whether we are approaching the maximum execution time. Should be called once
d6e8d8
* at the beginning of the script in which it's used.
d6e8d8
* @return	bool	Either true if the maximum execution time is nearly reached, or false
d6e8d8
*					if some time is still left.
d6e8d8
*/
d6e8d8
function still_on_time($extra_time = 15)
d6e8d8
{
d6e8d8
	static $max_execution_time, $start_time;
d6e8d8
d6e8d8
	$time = explode(' ', microtime());
d6e8d8
	$current_time = $time[0] + $time[1];
d6e8d8
d6e8d8
	if (empty($max_execution_time))
d6e8d8
	{
d6e8d8
		$max_execution_time = (function_exists('ini_get')) ? (int) @ini_get('max_execution_time') : (int) @get_cfg_var('max_execution_time');
d6e8d8
d6e8d8
		// If zero, then set to something higher to not let the user catch the ten seconds barrier.
d6e8d8
		if ($max_execution_time === 0)
d6e8d8
		{
d6e8d8
			$max_execution_time = 50 + $extra_time;
d6e8d8
		}
d6e8d8
d6e8d8
		$max_execution_time = min(max(10, ($max_execution_time - $extra_time)), 50);
d6e8d8
d6e8d8
		// For debugging purposes
d6e8d8
		// $max_execution_time = 10;
d6e8d8
d6e8d8
		global $starttime;
d6e8d8
		$start_time = (empty($starttime)) ? $current_time : $starttime;
d6e8d8
	}
d6e8d8
d6e8d8
	return (ceil($current_time - $start_time) < $max_execution_time) ? true : false;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
*
d6e8d8
* @version Version 0.1 / slightly modified for phpBB 3.0.x (using $H$ as hash type identifier)
d6e8d8
*
d6e8d8
* Portable PHP password hashing framework.
d6e8d8
*
d6e8d8
* Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
d6e8d8
* the public domain.
d6e8d8
*
d6e8d8
* There's absolutely no warranty.
d6e8d8
*
d6e8d8
* The homepage URL for this framework is:
d6e8d8
*
d6e8d8
*	http://www.openwall.com/phpass/
d6e8d8
*
d6e8d8
* Please be sure to update the Version line if you edit this file in any way.
d6e8d8
* It is suggested that you leave the main version number intact, but indicate
d6e8d8
* your project name (after the slash) and add your own revision information.
d6e8d8
*
d6e8d8
* Please do not change the "private" password hashing method implemented in
d6e8d8
* here, thereby making your hashes incompatible.  However, if you must, please
d6e8d8
* change the hash type identifier (the "$P$") to something different.
d6e8d8
*
d6e8d8
* Obviously, since this code is in the public domain, the above are not
d6e8d8
* requirements (there can be none), but merely suggestions.
d6e8d8
*
d6e8d8
*
d6e8d8
* Hash the password
d6e8d8
*/
d6e8d8
function phpbb_hash($password)
d6e8d8
{
d6e8d8
	$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
d6e8d8
d6e8d8
	$random_state = unique_id();
d6e8d8
	$random = '';
d6e8d8
	$count = 6;
d6e8d8
d6e8d8
	if (($fh = @fopen('/dev/urandom', 'rb')))
d6e8d8
	{
d6e8d8
		$random = fread($fh, $count);
d6e8d8
		fclose($fh);
d6e8d8
	}
d6e8d8
d6e8d8
	if (strlen($random) < $count)
d6e8d8
	{
d6e8d8
		$random = '';
d6e8d8
d6e8d8
		for ($i = 0; $i < $count; $i += 16)
d6e8d8
		{
d6e8d8
			$random_state = md5(unique_id() . $random_state);
d6e8d8
			$random .= pack('H*', md5($random_state));
d6e8d8
		}
d6e8d8
		$random = substr($random, 0, $count);
d6e8d8
	}
d6e8d8
d6e8d8
	$hash = _hash_crypt_private($password, _hash_gensalt_private($random, $itoa64), $itoa64);
d6e8d8
d6e8d8
	if (strlen($hash) == 34)
d6e8d8
	{
d6e8d8
		return $hash;
d6e8d8
	}
d6e8d8
d6e8d8
	return md5($password);
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Check for correct password
d6e8d8
*
d6e8d8
* @param string $password The password in plain text
d6e8d8
* @param string $hash The stored password hash
d6e8d8
*
d6e8d8
* @return bool Returns true if the password is correct, false if not.
d6e8d8
*/
d6e8d8
function phpbb_check_hash($password, $hash)
d6e8d8
{
d6e8d8
	$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
d6e8d8
	if (strlen($hash) == 34)
d6e8d8
	{
d6e8d8
		return (_hash_crypt_private($password, $hash, $itoa64) === $hash) ? true : false;
d6e8d8
	}
d6e8d8
d6e8d8
	return (md5($password) === $hash) ? true : false;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Generate salt for hash generation
d6e8d8
*/
d6e8d8
function _hash_gensalt_private($input, &$itoa64, $iteration_count_log2 = 6)
d6e8d8
{
d6e8d8
	if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
d6e8d8
	{
d6e8d8
		$iteration_count_log2 = 8;
d6e8d8
	}
d6e8d8
d6e8d8
	$output = '$H$';
d6e8d8
	$output .= $itoa64[min($iteration_count_log2 + ((PHP_VERSION >= 5) ? 5 : 3), 30)];
d6e8d8
	$output .= _hash_encode64($input, 6, $itoa64);
d6e8d8
d6e8d8
	return $output;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Encode hash
d6e8d8
*/
d6e8d8
function _hash_encode64($input, $count, &$itoa64)
d6e8d8
{
d6e8d8
	$output = '';
d6e8d8
	$i = 0;
d6e8d8
d6e8d8
	do
d6e8d8
	{
d6e8d8
		$value = ord($input[$i++]);
d6e8d8
		$output .= $itoa64[$value & 0x3f];
d6e8d8
d6e8d8
		if ($i < $count)
d6e8d8
		{
d6e8d8
			$value |= ord($input[$i]) << 8;
d6e8d8
		}
d6e8d8
d6e8d8
		$output .= $itoa64[($value >> 6) & 0x3f];
d6e8d8
d6e8d8
		if ($i++ >= $count)
d6e8d8
		{
d6e8d8
			break;
d6e8d8
		}
d6e8d8
d6e8d8
		if ($i < $count)
d6e8d8
		{
d6e8d8
			$value |= ord($input[$i]) << 16;
d6e8d8
		}
d6e8d8
d6e8d8
		$output .= $itoa64[($value >> 12) & 0x3f];
d6e8d8
d6e8d8
		if ($i++ >= $count)
d6e8d8
		{
d6e8d8
			break;
d6e8d8
		}
d6e8d8
d6e8d8
		$output .= $itoa64[($value >> 18) & 0x3f];
d6e8d8
	}
d6e8d8
	while ($i < $count);
d6e8d8
d6e8d8
	return $output;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* The crypt function/replacement
d6e8d8
*/
d6e8d8
function _hash_crypt_private($password, $setting, &$itoa64)
d6e8d8
{
d6e8d8
	$output = '*';
d6e8d8
d6e8d8
	// Check for correct hash
d6e8d8
	if (substr($setting, 0, 3) != '$H$')
d6e8d8
	{
d6e8d8
		return $output;
d6e8d8
	}
d6e8d8
d6e8d8
	$count_log2 = strpos($itoa64, $setting[3]);
d6e8d8
d6e8d8
	if ($count_log2 < 7 || $count_log2 > 30)
d6e8d8
	{
d6e8d8
		return $output;
d6e8d8
	}
d6e8d8
d6e8d8
	$count = 1 << $count_log2;
d6e8d8
	$salt = substr($setting, 4, 8);
d6e8d8
d6e8d8
	if (strlen($salt) != 8)
d6e8d8
	{
d6e8d8
		return $output;
d6e8d8
	}
d6e8d8
d6e8d8
	/**
d6e8d8
	* We're kind of forced to use MD5 here since it's the only
d6e8d8
	* cryptographic primitive available in all versions of PHP
d6e8d8
	* currently in use.  To implement our own low-level crypto
d6e8d8
	* in PHP would result in much worse performance and
d6e8d8
	* consequently in lower iteration counts and hashes that are
d6e8d8
	* quicker to crack (by non-PHP code).
d6e8d8
	*/
d6e8d8
	if (PHP_VERSION >= 5)
d6e8d8
	{
d6e8d8
		$hash = md5($salt . $password, true);
d6e8d8
		do
d6e8d8
		{
d6e8d8
			$hash = md5($hash . $password, true);
d6e8d8
		}
d6e8d8
		while (--$count);
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		$hash = pack('H*', md5($salt . $password));
d6e8d8
		do
d6e8d8
		{
d6e8d8
			$hash = pack('H*', md5($hash . $password));
d6e8d8
		}
d6e8d8
		while (--$count);
d6e8d8
	}
d6e8d8
d6e8d8
	$output = substr($setting, 0, 12);
d6e8d8
	$output .= _hash_encode64($hash, 16, $itoa64);
d6e8d8
d6e8d8
	return $output;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Global function for chmodding directories and files for internal use
d6e8d8
* This function determines owner and group whom the file belongs to and user and group of PHP and then set safest possible file permissions.
d6e8d8
* The function determines owner and group from common.php file and sets the same to the provided file. Permissions are mapped to the group, user always has rw(x) permission.
d6e8d8
* The function uses bit fields to build the permissions.
d6e8d8
* The function sets the appropiate execute bit on directories.
d6e8d8
*
d6e8d8
* Supported constants representing bit fields are:
d6e8d8
*
d6e8d8
* CHMOD_ALL - all permissions (7)
d6e8d8
* CHMOD_READ - read permission (4)
d6e8d8
* CHMOD_WRITE - write permission (2)
d6e8d8
* CHMOD_EXECUTE - execute permission (1)
d6e8d8
*
d6e8d8
* NOTE: The function uses POSIX extension and fileowner()/filegroup() functions. If any of them is disabled, this function tries to build proper permissions, by calling is_readable() and is_writable() functions.
d6e8d8
*
d6e8d8
* @param $filename The file/directory to be chmodded
d6e8d8
* @param $perms Permissions to set
d6e8d8
* @return true on success, otherwise false
d6e8d8
*
d6e8d8
* @author faw, phpBB Group
d6e8d8
*/
d6e8d8
function phpbb_chmod($filename, $perms = CHMOD_READ)
d6e8d8
{
d6e8d8
	// Return if the file no longer exists.
d6e8d8
	if (!file_exists($filename))
d6e8d8
	{
d6e8d8
		return false;
d6e8d8
	}
d6e8d8
d6e8d8
	if (!function_exists('fileowner') || !function_exists('filegroup'))
d6e8d8
	{
d6e8d8
		$file_uid = $file_gid = false;
d6e8d8
		$common_php_owner = $common_php_group = false;
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		global $phpbb_root_path, $phpEx;
d6e8d8
d6e8d8
		// Determine owner/group of common.php file and the filename we want to change here
d6e8d8
		$common_php_owner = fileowner($phpbb_root_path . 'common.' . $phpEx);
d6e8d8
		$common_php_group = filegroup($phpbb_root_path . 'common.' . $phpEx);
d6e8d8
d6e8d8
		$file_uid = fileowner($filename);
d6e8d8
		$file_gid = filegroup($filename);
d6e8d8
d6e8d8
		// Try to set the owner to the same common.php has
d6e8d8
		if ($common_php_owner !== $file_uid && $common_php_owner !== false && $file_uid !== false)
d6e8d8
		{
d6e8d8
			// Will most likely not work
d6e8d8
			if (@chown($filename, $common_php_owner));
d6e8d8
			{
d6e8d8
				clearstatcache();
d6e8d8
				$file_uid = fileowner($filename);
d6e8d8
			}
d6e8d8
		}
d6e8d8
d6e8d8
		// Try to set the group to the same common.php has
d6e8d8
		if ($common_php_group !== $file_gid && $common_php_group !== false && $file_gid !== false)
d6e8d8
		{
d6e8d8
			if (@chgrp($filename, $common_php_group));
d6e8d8
			{
d6e8d8
				clearstatcache();
d6e8d8
				$file_gid = filegroup($filename);
d6e8d8
			}
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	// And the owner and the groups PHP is running under.
d6e8d8
	$php_uid = (function_exists('posix_getuid')) ? @posix_getuid() : false;
d6e8d8
	$php_gids = (function_exists('posix_getgroups')) ? @posix_getgroups() : false;
d6e8d8
d6e8d8
	// Who is PHP?
d6e8d8
	if ($file_uid === false || $file_gid === false || $php_uid === false || $php_gids === false)
d6e8d8
	{
d6e8d8
		$php = NULL;
d6e8d8
	}
d6e8d8
	else if ($file_uid == $php_uid /* && $common_php_owner !== false && $common_php_owner === $file_uid*/)
d6e8d8
	{
d6e8d8
		$php = 'owner';
d6e8d8
	}
d6e8d8
	else if (in_array($file_gid, $php_gids))
d6e8d8
	{
d6e8d8
		$php = 'group';
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		$php = 'other';
d6e8d8
	}
d6e8d8
d6e8d8
	// Owner always has read/write permission
d6e8d8
	$owner = CHMOD_READ | CHMOD_WRITE;
d6e8d8
	if (is_dir($filename))
d6e8d8
	{
d6e8d8
		$owner |= CHMOD_EXECUTE;
d6e8d8
d6e8d8
		// Only add execute bit to the permission if the dir needs to be readable
d6e8d8
		if ($perms & CHMOD_READ)
d6e8d8
		{
d6e8d8
			$perms |= CHMOD_EXECUTE;
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	switch ($php)
d6e8d8
	{
d6e8d8
		case null:
d6e8d8
		case 'owner':
d6e8d8
			/* ATTENTION: if php is owner or NULL we set it to group here. This is the most failsafe combination for the vast majority of server setups.
d6e8d8
d6e8d8
			$result = @chmod($filename, ($owner << 6) + (0 << 3) + (0 << 0));
d6e8d8
d6e8d8
			clearstatcache();
d6e8d8
d6e8d8
			if (!is_null($php) || (is_readable($filename) && is_writable($filename)))
d6e8d8
			{
d6e8d8
				break;
d6e8d8
			}
d6e8d8
		*/
d6e8d8
d6e8d8
		case 'group':
d6e8d8
			$result = @chmod($filename, ($owner << 6) + ($perms << 3) + (0 << 0));
d6e8d8
d6e8d8
			clearstatcache();
d6e8d8
d6e8d8
			if (!is_null($php) || ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || is_writable($filename))))
d6e8d8
			{
d6e8d8
				break;
d6e8d8
			}
d6e8d8
d6e8d8
		case 'other':
d6e8d8
			$result = @chmod($filename, ($owner << 6) + ($perms << 3) + ($perms << 0));
d6e8d8
d6e8d8
			clearstatcache();
d6e8d8
d6e8d8
			if (!is_null($php) || ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || is_writable($filename))))
d6e8d8
			{
d6e8d8
				break;
d6e8d8
			}
d6e8d8
d6e8d8
		default:
d6e8d8
			return false;
d6e8d8
		break;
d6e8d8
	}
d6e8d8
d6e8d8
	return $result;
d6e8d8
}
d6e8d8
d6e8d8
// Compatibility functions
d6e8d8
d6e8d8
if (!function_exists('array_combine'))
d6e8d8
{
d6e8d8
	/**
d6e8d8
	* A wrapper for the PHP5 function array_combine()
d6e8d8
	* @param array $keys contains keys for the resulting array
d6e8d8
	* @param array $values contains values for the resulting array
d6e8d8
	*
d6e8d8
	* @return Returns an array by using the values from the keys array as keys and the
d6e8d8
	* 	values from the values array as the corresponding values. Returns false if the
d6e8d8
	* 	number of elements for each array isn't equal or if the arrays are empty.
d6e8d8
	*/
d6e8d8
	function array_combine($keys, $values)
d6e8d8
	{
d6e8d8
		$keys = array_values($keys);
d6e8d8
		$values = array_values($values);
d6e8d8
d6e8d8
		$n = sizeof($keys);
d6e8d8
		$m = sizeof($values);
d6e8d8
		if (!$n || !$m || ($n != $m))
d6e8d8
		{
d6e8d8
			return false;
d6e8d8
		}
d6e8d8
d6e8d8
		$combined = array();
d6e8d8
		for ($i = 0; $i < $n; $i++)
d6e8d8
		{
d6e8d8
			$combined[$keys[$i]] = $values[$i];
d6e8d8
		}
d6e8d8
		return $combined;
d6e8d8
	}
d6e8d8
}
d6e8d8
d6e8d8
if (!function_exists('str_split'))
d6e8d8
{
d6e8d8
	/**
d6e8d8
	* A wrapper for the PHP5 function str_split()
d6e8d8
	* @param array $string contains the string to be converted
d6e8d8
	* @param array $split_length contains the length of each chunk
d6e8d8
	*
d6e8d8
	* @return  Converts a string to an array. If the optional split_length parameter is specified,
d6e8d8
	*  	the returned array will be broken down into chunks with each being split_length in length,
d6e8d8
	*  	otherwise each chunk will be one character in length. FALSE is returned if split_length is
d6e8d8
	*  	less than 1. If the split_length length exceeds the length of string, the entire string is
d6e8d8
	*  	returned as the first (and only) array element.
d6e8d8
	*/
d6e8d8
	function str_split($string, $split_length = 1)
d6e8d8
	{
d6e8d8
		if ($split_length < 1)
d6e8d8
		{
d6e8d8
			return false;
d6e8d8
		}
d6e8d8
		else if ($split_length >= strlen($string))
d6e8d8
		{
d6e8d8
			return array($string);
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			preg_match_all('#.{1,' . $split_length . '}#s', $string, $matches);
d6e8d8
			return $matches[0];
d6e8d8
		}
d6e8d8
	}
d6e8d8
}
d6e8d8
d6e8d8
if (!function_exists('stripos'))
d6e8d8
{
d6e8d8
	/**
d6e8d8
	* A wrapper for the PHP5 function stripos
d6e8d8
	* Find position of first occurrence of a case-insensitive string
d6e8d8
	*
d6e8d8
	* @param string $haystack is the string to search in
d6e8d8
	* @param string $needle is the string to search for
d6e8d8
	*
d6e8d8
	* @return mixed Returns the numeric position of the first occurrence of needle in the haystack string. Unlike strpos(), stripos() is case-insensitive.
d6e8d8
	* Note that the needle may be a string of one or more characters.
d6e8d8
	* If needle is not found, stripos() will return boolean FALSE.
d6e8d8
	*/
d6e8d8
	function stripos($haystack, $needle)
d6e8d8
	{
d6e8d8
		if (preg_match('#' . preg_quote($needle, '#') . '#i', $haystack, $m))
d6e8d8
		{
d6e8d8
			return strpos($haystack, $m[0]);
d6e8d8
		}
d6e8d8
d6e8d8
		return false;
d6e8d8
	}
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Checks if a path ($path) is absolute or relative
d6e8d8
*
d6e8d8
* @param string $path Path to check absoluteness of
d6e8d8
* @return boolean
d6e8d8
*/
d6e8d8
function is_absolute($path)
d6e8d8
{
d6e8d8
	return ($path[0] == '/' || (DIRECTORY_SEPARATOR == '\\' && preg_match('#^[a-z]:/#i', $path))) ? true : false;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* @author Chris Smith <chris@project-minerva.org>
d6e8d8
* @copyright 2006 Project Minerva Team
d6e8d8
* @param string $path The path which we should attempt to resolve.
d6e8d8
* @return mixed
d6e8d8
*/
d6e8d8
function phpbb_own_realpath($path)
d6e8d8
{
d6e8d8
	// Now to perform funky shizzle
d6e8d8
d6e8d8
	// Switch to use UNIX slashes
d6e8d8
	$path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
d6e8d8
	$path_prefix = '';
d6e8d8
d6e8d8
	// Determine what sort of path we have
d6e8d8
	if (is_absolute($path))
d6e8d8
	{
d6e8d8
		$absolute = true;
d6e8d8
d6e8d8
		if ($path[0] == '/')
d6e8d8
		{
d6e8d8
			// Absolute path, *NIX style
d6e8d8
			$path_prefix = '';
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			// Absolute path, Windows style
d6e8d8
			// Remove the drive letter and colon
d6e8d8
			$path_prefix = $path[0] . ':';
d6e8d8
			$path = substr($path, 2);
d6e8d8
		}
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		// Relative Path
d6e8d8
		// Prepend the current working directory
d6e8d8
		if (function_exists('getcwd'))
d6e8d8
		{
d6e8d8
			// This is the best method, hopefully it is enabled!
d6e8d8
			$path = str_replace(DIRECTORY_SEPARATOR, '/', getcwd()) . '/' . $path;
d6e8d8
			$absolute = true;
d6e8d8
			if (preg_match('#^[a-z]:#i', $path))
d6e8d8
			{
d6e8d8
				$path_prefix = $path[0] . ':';
d6e8d8
				$path = substr($path, 2);
d6e8d8
			}
d6e8d8
			else
d6e8d8
			{
d6e8d8
				$path_prefix = '';
d6e8d8
			}
d6e8d8
		}
d6e8d8
		else if (isset($_SERVER['SCRIPT_FILENAME']) && !empty($_SERVER['SCRIPT_FILENAME']))
d6e8d8
		{
d6e8d8
			// Warning: If chdir() has been used this will lie!
d6e8d8
			// Warning: This has some problems sometime (CLI can create them easily)
d6e8d8
			$path = str_replace(DIRECTORY_SEPARATOR, '/', dirname($_SERVER['SCRIPT_FILENAME'])) . '/' . $path;
d6e8d8
			$absolute = true;
d6e8d8
			$path_prefix = '';
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			// We have no way of getting the absolute path, just run on using relative ones.
d6e8d8
			$absolute = false;
d6e8d8
			$path_prefix = '.';
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	// Remove any repeated slashes
d6e8d8
	$path = preg_replace('#/{2,}#', '/', $path);
d6e8d8
d6e8d8
	// Remove the slashes from the start and end of the path
d6e8d8
	$path = trim($path, '/');
d6e8d8
d6e8d8
	// Break the string into little bits for us to nibble on
d6e8d8
	$bits = explode('/', $path);
d6e8d8
d6e8d8
	// Remove any . in the path, renumber array for the loop below
d6e8d8
	$bits = array_values(array_diff($bits, array('.')));
d6e8d8
d6e8d8
	// Lets get looping, run over and resolve any .. (up directory)
d6e8d8
	for ($i = 0, $max = sizeof($bits); $i < $max; $i++)
d6e8d8
	{
d6e8d8
		// @todo Optimise
d6e8d8
		if ($bits[$i] == '..' )
d6e8d8
		{
d6e8d8
			if (isset($bits[$i - 1]))
d6e8d8
			{
d6e8d8
				if ($bits[$i - 1] != '..')
d6e8d8
				{
d6e8d8
					// We found a .. and we are able to traverse upwards, lets do it!
d6e8d8
					unset($bits[$i]);
d6e8d8
					unset($bits[$i - 1]);
d6e8d8
					$i -= 2;
d6e8d8
					$max -= 2;
d6e8d8
					$bits = array_values($bits);
d6e8d8
				}
d6e8d8
			}
d6e8d8
			else if ($absolute) // ie. !isset($bits[$i - 1]) && $absolute
d6e8d8
			{
d6e8d8
				// We have an absolute path trying to descend above the root of the filesystem
d6e8d8
				// ... Error!
d6e8d8
				return false;
d6e8d8
			}
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	// Prepend the path prefix
d6e8d8
	array_unshift($bits, $path_prefix);
d6e8d8
d6e8d8
	$resolved = '';
d6e8d8
d6e8d8
	$max = sizeof($bits) - 1;
d6e8d8
d6e8d8
	// Check if we are able to resolve symlinks, Windows cannot.
d6e8d8
	$symlink_resolve = (function_exists('readlink')) ? true : false;
d6e8d8
d6e8d8
	foreach ($bits as $i => $bit)
d6e8d8
	{
d6e8d8
		if (@is_dir("$resolved/$bit") || ($i == $max && @is_file("$resolved/$bit")))
d6e8d8
		{
d6e8d8
			// Path Exists
d6e8d8
			if ($symlink_resolve && is_link("$resolved/$bit") && ($link = readlink("$resolved/$bit")))
d6e8d8
			{
d6e8d8
				// Resolved a symlink.
d6e8d8
				$resolved = $link . (($i == $max) ? '' : '/');
d6e8d8
				continue;
d6e8d8
			}
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			// Something doesn't exist here!
d6e8d8
			// This is correct realpath() behaviour but sadly open_basedir and safe_mode make this problematic
d6e8d8
			// return false;
d6e8d8
		}
d6e8d8
		$resolved .= $bit . (($i == $max) ? '' : '/');
d6e8d8
	}
d6e8d8
d6e8d8
	// @todo If the file exists fine and open_basedir only has one path we should be able to prepend it
d6e8d8
	// because we must be inside that basedir, the question is where...
d6e8d8
	// @internal The slash in is_dir() gets around an open_basedir restriction
d6e8d8
	if (!@file_exists($resolved) || (!is_dir($resolved . '/') && !is_file($resolved)))
d6e8d8
	{
d6e8d8
		return false;
d6e8d8
	}
d6e8d8
d6e8d8
	// Put the slashes back to the native operating systems slashes
d6e8d8
	$resolved = str_replace('/', DIRECTORY_SEPARATOR, $resolved);
d6e8d8
d6e8d8
	// Check for DIRECTORY_SEPARATOR at the end (and remove it!)
d6e8d8
	if (substr($resolved, -1) == DIRECTORY_SEPARATOR)
d6e8d8
	{
d6e8d8
		return substr($resolved, 0, -1);
d6e8d8
	}
d6e8d8
d6e8d8
	return $resolved; // We got here, in the end!
d6e8d8
}
d6e8d8
d6e8d8
if (!function_exists('realpath'))
d6e8d8
{
d6e8d8
	/**
d6e8d8
	* A wrapper for realpath
d6e8d8
	* @ignore
d6e8d8
	*/
d6e8d8
	function phpbb_realpath($path)
d6e8d8
	{
d6e8d8
		return phpbb_own_realpath($path);
d6e8d8
	}
d6e8d8
}
d6e8d8
else
d6e8d8
{
d6e8d8
	/**
d6e8d8
	* A wrapper for realpath
d6e8d8
	*/
d6e8d8
	function phpbb_realpath($path)
d6e8d8
	{
d6e8d8
		$realpath = realpath($path);
d6e8d8
d6e8d8
		// Strangely there are provider not disabling realpath but returning strange values. :o
d6e8d8
		// We at least try to cope with them.
d6e8d8
		if ($realpath === $path || $realpath === false)
d6e8d8
		{
d6e8d8
			return phpbb_own_realpath($path);
d6e8d8
		}
d6e8d8
d6e8d8
		// Check for DIRECTORY_SEPARATOR at the end (and remove it!)
d6e8d8
		if (substr($realpath, -1) == DIRECTORY_SEPARATOR)
d6e8d8
		{
d6e8d8
			$realpath = substr($realpath, 0, -1);
d6e8d8
		}
d6e8d8
d6e8d8
		return $realpath;
d6e8d8
	}
d6e8d8
}
d6e8d8
d6e8d8
if (!function_exists('htmlspecialchars_decode'))
d6e8d8
{
d6e8d8
	/**
d6e8d8
	* A wrapper for htmlspecialchars_decode
d6e8d8
	* @ignore
d6e8d8
	*/
d6e8d8
	function htmlspecialchars_decode($string, $quote_style = ENT_COMPAT)
d6e8d8
	{
d6e8d8
		return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
d6e8d8
	}
d6e8d8
}
d6e8d8
d6e8d8
// functions used for building option fields
d6e8d8
d6e8d8
/**
d6e8d8
* Pick a language, any language ...
d6e8d8
*/
d6e8d8
function language_select($default = '')
d6e8d8
{
d6e8d8
	global $db;
d6e8d8
d6e8d8
	$sql = 'SELECT lang_iso, lang_local_name
d6e8d8
		FROM ' . LANG_TABLE . '
d6e8d8
		ORDER BY lang_english_name';
d6e8d8
	$result = $db->sql_query($sql);
d6e8d8
d6e8d8
	$lang_options = '';
d6e8d8
	while ($row = $db->sql_fetchrow($result))
d6e8d8
	{
d6e8d8
		$selected = ($row['lang_iso'] == $default) ? ' selected="selected"' : '';
d6e8d8
		$lang_options .= '<option value="' . $row['lang_iso'] . '"' . $selected . '>' . $row['lang_local_name'] . '</option>';
d6e8d8
	}
d6e8d8
	$db->sql_freeresult($result);
d6e8d8
d6e8d8
	return $lang_options;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Pick a template/theme combo,
d6e8d8
*/
d6e8d8
function style_select($default = '', $all = false)
d6e8d8
{
d6e8d8
	global $db;
d6e8d8
d6e8d8
	$sql_where = (!$all) ? 'WHERE style_active = 1 ' : '';
d6e8d8
	$sql = 'SELECT style_id, style_name
d6e8d8
		FROM ' . STYLES_TABLE . "
d6e8d8
		$sql_where
d6e8d8
		ORDER BY style_name";
d6e8d8
	$result = $db->sql_query($sql);
d6e8d8
d6e8d8
	$style_options = '';
d6e8d8
	while ($row = $db->sql_fetchrow($result))
d6e8d8
	{
d6e8d8
		$selected = ($row['style_id'] == $default) ? ' selected="selected"' : '';
d6e8d8
		$style_options .= '<option value="' . $row['style_id'] . '"' . $selected . '>' . $row['style_name'] . '</option>';
d6e8d8
	}
d6e8d8
	$db->sql_freeresult($result);
d6e8d8
d6e8d8
	return $style_options;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Pick a timezone
d6e8d8
*/
d6e8d8
function tz_select($default = '', $truncate = false)
d6e8d8
{
d6e8d8
	global $user;
d6e8d8
d6e8d8
	$tz_select = '';
d6e8d8
	foreach ($user->lang['tz_zones'] as $offset => $zone)
d6e8d8
	{
d6e8d8
		if ($truncate)
d6e8d8
		{
d6e8d8
			$zone_trunc = truncate_string($zone, 50, 255, false, '...');
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			$zone_trunc = $zone;
d6e8d8
		}
d6e8d8
d6e8d8
		if (is_numeric($offset))
d6e8d8
		{
d6e8d8
			$selected = ($offset == $default) ? ' selected="selected"' : '';
d6e8d8
			$tz_select .= '<option title="'.$zone.'" value="' . $offset . '"' . $selected . '>' . $zone_trunc . '</option>';
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	return $tz_select;
d6e8d8
}
d6e8d8
d6e8d8
// Functions handling topic/post tracking/marking
d6e8d8
d6e8d8
/**
d6e8d8
* Marks a topic/forum as read
d6e8d8
* Marks a topic as posted to
d6e8d8
*
d6e8d8
* @param int $user_id can only be used with $mode == 'post'
d6e8d8
*/
d6e8d8
function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $user_id = 0)
d6e8d8
{
d6e8d8
	global $db, $user, $config;
d6e8d8
d6e8d8
	if ($mode == 'all')
d6e8d8
	{
d6e8d8
		if ($forum_id === false || !sizeof($forum_id))
d6e8d8
		{
d6e8d8
			if ($config['load_db_lastread'] && $user->data['is_registered'])
d6e8d8
			{
d6e8d8
				// Mark all forums read (index page)
d6e8d8
				$db->sql_query('DELETE FROM ' . TOPICS_TRACK_TABLE . " WHERE user_id = {$user->data['user_id']}");
d6e8d8
				$db->sql_query('DELETE FROM ' . FORUMS_TRACK_TABLE . " WHERE user_id = {$user->data['user_id']}");
d6e8d8
				$db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_lastmark = ' . time() . " WHERE user_id = {$user->data['user_id']}");
d6e8d8
			}
d6e8d8
			else if ($config['load_anon_lastread'] || $user->data['is_registered'])
d6e8d8
			{
d6e8d8
				$tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
d6e8d8
				$tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array();
d6e8d8
d6e8d8
				unset($tracking_topics['tf']);
d6e8d8
				unset($tracking_topics['t']);
d6e8d8
				unset($tracking_topics['f']);
d6e8d8
				$tracking_topics['l'] = base_convert(time() - $config['board_startdate'], 10, 36);
d6e8d8
d6e8d8
				$user->set_cookie('track', tracking_serialize($tracking_topics), time() + 31536000);
d6e8d8
				$_COOKIE[$config['cookie_name'] . '_track'] = (STRIP) ? addslashes(tracking_serialize($tracking_topics)) : tracking_serialize($tracking_topics);
d6e8d8
d6e8d8
				unset($tracking_topics);
d6e8d8
d6e8d8
				if ($user->data['is_registered'])
d6e8d8
				{
d6e8d8
					$db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_lastmark = ' . time() . " WHERE user_id = {$user->data['user_id']}");
d6e8d8
				}
d6e8d8
			}
d6e8d8
		}
d6e8d8
d6e8d8
		return;
d6e8d8
	}
d6e8d8
	else if ($mode == 'topics')
d6e8d8
	{
d6e8d8
		// Mark all topics in forums read
d6e8d8
		if (!is_array($forum_id))
d6e8d8
		{
d6e8d8
			$forum_id = array($forum_id);
d6e8d8
		}
d6e8d8
d6e8d8
		// Add 0 to forums array to mark global announcements correctly
d6e8d8
		$forum_id[] = 0;
d6e8d8
d6e8d8
		if ($config['load_db_lastread'] && $user->data['is_registered'])
d6e8d8
		{
d6e8d8
			$sql = 'DELETE FROM ' . TOPICS_TRACK_TABLE . "
d6e8d8
				WHERE user_id = {$user->data['user_id']}
d6e8d8
					AND " . $db->sql_in_set('forum_id', $forum_id);
d6e8d8
			$db->sql_query($sql);
d6e8d8
d6e8d8
			$sql = 'SELECT forum_id
d6e8d8
				FROM ' . FORUMS_TRACK_TABLE . "
d6e8d8
				WHERE user_id = {$user->data['user_id']}
d6e8d8
					AND " . $db->sql_in_set('forum_id', $forum_id);
d6e8d8
			$result = $db->sql_query($sql);
d6e8d8
d6e8d8
			$sql_update = array();
d6e8d8
			while ($row = $db->sql_fetchrow($result))
d6e8d8
			{
d6e8d8
				$sql_update[] = $row['forum_id'];
d6e8d8
			}
d6e8d8
			$db->sql_freeresult($result);
d6e8d8
d6e8d8
			if (sizeof($sql_update))
d6e8d8
			{
d6e8d8
				$sql = 'UPDATE ' . FORUMS_TRACK_TABLE . '
d6e8d8
					SET mark_time = ' . time() . "
d6e8d8
					WHERE user_id = {$user->data['user_id']}
d6e8d8
						AND " . $db->sql_in_set('forum_id', $sql_update);
d6e8d8
				$db->sql_query($sql);
d6e8d8
			}
d6e8d8
d6e8d8
			if ($sql_insert = array_diff($forum_id, $sql_update))
d6e8d8
			{
d6e8d8
				$sql_ary = array();
d6e8d8
				foreach ($sql_insert as $f_id)
d6e8d8
				{
d6e8d8
					$sql_ary[] = array(
d6e8d8
						'user_id'	=> (int) $user->data['user_id'],
d6e8d8
						'forum_id'	=> (int) $f_id,
d6e8d8
						'mark_time'	=> time()
d6e8d8
					);
d6e8d8
				}
d6e8d8
d6e8d8
				$db->sql_multi_insert(FORUMS_TRACK_TABLE, $sql_ary);
d6e8d8
			}
d6e8d8
		}
d6e8d8
		else if ($config['load_anon_lastread'] || $user->data['is_registered'])
d6e8d8
		{
d6e8d8
			$tracking = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
d6e8d8
			$tracking = ($tracking) ? tracking_unserialize($tracking) : array();
d6e8d8
d6e8d8
			foreach ($forum_id as $f_id)
d6e8d8
			{
d6e8d8
				$topic_ids36 = (isset($tracking['tf'][$f_id])) ? $tracking['tf'][$f_id] : array();
d6e8d8
d6e8d8
				if (isset($tracking['tf'][$f_id]))
d6e8d8
				{
d6e8d8
					unset($tracking['tf'][$f_id]);
d6e8d8
				}
d6e8d8
d6e8d8
				foreach ($topic_ids36 as $topic_id36)
d6e8d8
				{
d6e8d8
					unset($tracking['t'][$topic_id36]);
d6e8d8
				}
d6e8d8
d6e8d8
				if (isset($tracking['f'][$f_id]))
d6e8d8
				{
d6e8d8
					unset($tracking['f'][$f_id]);
d6e8d8
				}
d6e8d8
d6e8d8
				$tracking['f'][$f_id] = base_convert(time() - $config['board_startdate'], 10, 36);
d6e8d8
			}
d6e8d8
d6e8d8
			if (isset($tracking['tf']) && empty($tracking['tf']))
d6e8d8
			{
d6e8d8
				unset($tracking['tf']);
d6e8d8
			}
d6e8d8
d6e8d8
			$user->set_cookie('track', tracking_serialize($tracking), time() + 31536000);
d6e8d8
			$_COOKIE[$config['cookie_name'] . '_track'] = (STRIP) ? addslashes(tracking_serialize($tracking)) : tracking_serialize($tracking);
d6e8d8
d6e8d8
			unset($tracking);
d6e8d8
		}
d6e8d8
d6e8d8
		return;
d6e8d8
	}
d6e8d8
	else if ($mode == 'topic')
d6e8d8
	{
d6e8d8
		if ($topic_id === false || $forum_id === false)
d6e8d8
		{
d6e8d8
			return;
d6e8d8
		}
d6e8d8
d6e8d8
		if ($config['load_db_lastread'] && $user->data['is_registered'])
d6e8d8
		{
d6e8d8
			$sql = 'UPDATE ' . TOPICS_TRACK_TABLE . '
d6e8d8
				SET mark_time = ' . (($post_time) ? $post_time : time()) . "
d6e8d8
				WHERE user_id = {$user->data['user_id']}
d6e8d8
					AND topic_id = $topic_id";
d6e8d8
			$db->sql_query($sql);
d6e8d8
d6e8d8
			// insert row
d6e8d8
			if (!$db->sql_affectedrows())
d6e8d8
			{
d6e8d8
				$db->sql_return_on_error(true);
d6e8d8
d6e8d8
				$sql_ary = array(
d6e8d8
					'user_id'		=> (int) $user->data['user_id'],
d6e8d8
					'topic_id'		=> (int) $topic_id,
d6e8d8
					'forum_id'		=> (int) $forum_id,
d6e8d8
					'mark_time'		=> ($post_time) ? (int) $post_time : time(),
d6e8d8
				);
d6e8d8
d6e8d8
				$db->sql_query('INSERT INTO ' . TOPICS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
d6e8d8
d6e8d8
				$db->sql_return_on_error(false);
d6e8d8
			}
d6e8d8
		}
d6e8d8
		else if ($config['load_anon_lastread'] || $user->data['is_registered'])
d6e8d8
		{
d6e8d8
			$tracking = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
d6e8d8
			$tracking = ($tracking) ? tracking_unserialize($tracking) : array();
d6e8d8
d6e8d8
			$topic_id36 = base_convert($topic_id, 10, 36);
d6e8d8
d6e8d8
			if (!isset($tracking['t'][$topic_id36]))
d6e8d8
			{
d6e8d8
				$tracking['tf'][$forum_id][$topic_id36] = true;
d6e8d8
			}
d6e8d8
d6e8d8
			$post_time = ($post_time) ? $post_time : time();
d6e8d8
			$tracking['t'][$topic_id36] = base_convert($post_time - $config['board_startdate'], 10, 36);
d6e8d8
d6e8d8
			// If the cookie grows larger than 10000 characters we will remove the smallest value
d6e8d8
			// This can result in old topics being unread - but most of the time it should be accurate...
d6e8d8
			if (isset($_COOKIE[$config['cookie_name'] . '_track']) && strlen($_COOKIE[$config['cookie_name'] . '_track']) > 10000)
d6e8d8
			{
d6e8d8
				//echo 'Cookie grown too large' . print_r($tracking, true);
d6e8d8
d6e8d8
				// We get the ten most minimum stored time offsets and its associated topic ids
d6e8d8
				$time_keys = array();
d6e8d8
				for ($i = 0; $i < 10 && sizeof($tracking['t']); $i++)
d6e8d8
				{
d6e8d8
					$min_value = min($tracking['t']);
d6e8d8
					$m_tkey = array_search($min_value, $tracking['t']);
d6e8d8
					unset($tracking['t'][$m_tkey]);
d6e8d8
d6e8d8
					$time_keys[$m_tkey] = $min_value;
d6e8d8
				}
d6e8d8
d6e8d8
				// Now remove the topic ids from the array...
d6e8d8
				foreach ($tracking['tf'] as $f_id => $topic_id_ary)
d6e8d8
				{
d6e8d8
					foreach ($time_keys as $m_tkey => $min_value)
d6e8d8
					{
d6e8d8
						if (isset($topic_id_ary[$m_tkey]))
d6e8d8
						{
d6e8d8
							$tracking['f'][$f_id] = $min_value;
d6e8d8
							unset($tracking['tf'][$f_id][$m_tkey]);
d6e8d8
						}
d6e8d8
					}
d6e8d8
				}
d6e8d8
d6e8d8
				if ($user->data['is_registered'])
d6e8d8
				{
d6e8d8
					$user->data['user_lastmark'] = intval(base_convert(max($time_keys) + $config['board_startdate'], 36, 10));
d6e8d8
					$db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_lastmark = ' . $user->data['user_lastmark'] . " WHERE user_id = {$user->data['user_id']}");
d6e8d8
				}
d6e8d8
				else
d6e8d8
				{
d6e8d8
					$tracking['l'] = max($time_keys);
d6e8d8
				}
d6e8d8
			}
d6e8d8
d6e8d8
			$user->set_cookie('track', tracking_serialize($tracking), time() + 31536000);
d6e8d8
			$_COOKIE[$config['cookie_name'] . '_track'] = (STRIP) ? addslashes(tracking_serialize($tracking)) : tracking_serialize($tracking);
d6e8d8
		}
d6e8d8
d6e8d8
		return;
d6e8d8
	}
d6e8d8
	else if ($mode == 'post')
d6e8d8
	{
d6e8d8
		if ($topic_id === false)
d6e8d8
		{
d6e8d8
			return;
d6e8d8
		}
d6e8d8
d6e8d8
		$use_user_id = (!$user_id) ? $user->data['user_id'] : $user_id;
d6e8d8
d6e8d8
		if ($config['load_db_track'] && $use_user_id != ANONYMOUS)
d6e8d8
		{
d6e8d8
			$db->sql_return_on_error(true);
d6e8d8
d6e8d8
			$sql_ary = array(
d6e8d8
				'user_id'		=> (int) $use_user_id,
d6e8d8
				'topic_id'		=> (int) $topic_id,
d6e8d8
				'topic_posted'	=> 1
d6e8d8
			);
d6e8d8
d6e8d8
			$db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
d6e8d8
d6e8d8
			$db->sql_return_on_error(false);
d6e8d8
		}
d6e8d8
d6e8d8
		return;
d6e8d8
	}
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Get topic tracking info by using already fetched info
d6e8d8
*/
d6e8d8
function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $global_announce_list = false)
d6e8d8
{
d6e8d8
	global $config, $user;
d6e8d8
d6e8d8
	$last_read = array();
d6e8d8
d6e8d8
	if (!is_array($topic_ids))
d6e8d8
	{
d6e8d8
		$topic_ids = array($topic_ids);
d6e8d8
	}
d6e8d8
d6e8d8
	foreach ($topic_ids as $topic_id)
d6e8d8
	{
d6e8d8
		if (!empty($rowset[$topic_id]['mark_time']))
d6e8d8
		{
d6e8d8
			$last_read[$topic_id] = $rowset[$topic_id]['mark_time'];
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	$topic_ids = array_diff($topic_ids, array_keys($last_read));
d6e8d8
d6e8d8
	if (sizeof($topic_ids))
d6e8d8
	{
d6e8d8
		$mark_time = array();
d6e8d8
d6e8d8
		// Get global announcement info
d6e8d8
		if ($global_announce_list && sizeof($global_announce_list))
d6e8d8
		{
d6e8d8
			if (!isset($forum_mark_time[0]))
d6e8d8
			{
d6e8d8
				global $db;
d6e8d8
d6e8d8
				$sql = 'SELECT mark_time
d6e8d8
					FROM ' . FORUMS_TRACK_TABLE . "
d6e8d8
					WHERE user_id = {$user->data['user_id']}
d6e8d8
						AND forum_id = 0";
d6e8d8
				$result = $db->sql_query($sql);
d6e8d8
				$row = $db->sql_fetchrow($result);
d6e8d8
				$db->sql_freeresult($result);
d6e8d8
d6e8d8
				if ($row)
d6e8d8
				{
d6e8d8
					$mark_time[0] = $row['mark_time'];
d6e8d8
				}
d6e8d8
			}
d6e8d8
			else
d6e8d8
			{
d6e8d8
				if ($forum_mark_time[0] !== false)
d6e8d8
				{
d6e8d8
					$mark_time[0] = $forum_mark_time[0];
d6e8d8
				}
d6e8d8
			}
d6e8d8
		}
d6e8d8
d6e8d8
		if (!empty($forum_mark_time[$forum_id]) && $forum_mark_time[$forum_id] !== false)
d6e8d8
		{
d6e8d8
			$mark_time[$forum_id] = $forum_mark_time[$forum_id];
d6e8d8
		}
d6e8d8
d6e8d8
		$user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user->data['user_lastmark'];
d6e8d8
d6e8d8
		foreach ($topic_ids as $topic_id)
d6e8d8
		{
d6e8d8
			if ($global_announce_list && isset($global_announce_list[$topic_id]))
d6e8d8
			{
d6e8d8
				$last_read[$topic_id] = (isset($mark_time[0])) ? $mark_time[0] : $user_lastmark;
d6e8d8
			}
d6e8d8
			else
d6e8d8
			{
d6e8d8
				$last_read[$topic_id] = $user_lastmark;
d6e8d8
			}
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	return $last_read;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Get topic tracking info from db (for cookie based tracking only this function is used)
d6e8d8
*/
d6e8d8
function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_list = false)
d6e8d8
{
d6e8d8
	global $config, $user;
d6e8d8
d6e8d8
	$last_read = array();
d6e8d8
d6e8d8
	if (!is_array($topic_ids))
d6e8d8
	{
d6e8d8
		$topic_ids = array($topic_ids);
d6e8d8
	}
d6e8d8
d6e8d8
	if ($config['load_db_lastread'] && $user->data['is_registered'])
d6e8d8
	{
d6e8d8
		global $db;
d6e8d8
d6e8d8
		$sql = 'SELECT topic_id, mark_time
d6e8d8
			FROM ' . TOPICS_TRACK_TABLE . "
d6e8d8
			WHERE user_id = {$user->data['user_id']}
d6e8d8
				AND " . $db->sql_in_set('topic_id', $topic_ids);
d6e8d8
		$result = $db->sql_query($sql);
d6e8d8
d6e8d8
		while ($row = $db->sql_fetchrow($result))
d6e8d8
		{
d6e8d8
			$last_read[$row['topic_id']] = $row['mark_time'];
d6e8d8
		}
d6e8d8
		$db->sql_freeresult($result);
d6e8d8
d6e8d8
		$topic_ids = array_diff($topic_ids, array_keys($last_read));
d6e8d8
d6e8d8
		if (sizeof($topic_ids))
d6e8d8
		{
d6e8d8
			$sql = 'SELECT forum_id, mark_time
d6e8d8
				FROM ' . FORUMS_TRACK_TABLE . "
d6e8d8
				WHERE user_id = {$user->data['user_id']}
d6e8d8
					AND forum_id " .
d6e8d8
					(($global_announce_list && sizeof($global_announce_list)) ? "IN (0, $forum_id)" : "= $forum_id");
d6e8d8
			$result = $db->sql_query($sql);
d6e8d8
d6e8d8
			$mark_time = array();
d6e8d8
			while ($row = $db->sql_fetchrow($result))
d6e8d8
			{
d6e8d8
				$mark_time[$row['forum_id']] = $row['mark_time'];
d6e8d8
			}
d6e8d8
			$db->sql_freeresult($result);
d6e8d8
d6e8d8
			$user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user->data['user_lastmark'];
d6e8d8
d6e8d8
			foreach ($topic_ids as $topic_id)
d6e8d8
			{
d6e8d8
				if ($global_announce_list && isset($global_announce_list[$topic_id]))
d6e8d8
				{
d6e8d8
					$last_read[$topic_id] = (isset($mark_time[0])) ? $mark_time[0] : $user_lastmark;
d6e8d8
				}
d6e8d8
				else
d6e8d8
				{
d6e8d8
					$last_read[$topic_id] = $user_lastmark;
d6e8d8
				}
d6e8d8
			}
d6e8d8
		}
d6e8d8
	}
d6e8d8
	else if ($config['load_anon_lastread'] || $user->data['is_registered'])
d6e8d8
	{
d6e8d8
		global $tracking_topics;
d6e8d8
d6e8d8
		if (!isset($tracking_topics) || !sizeof($tracking_topics))
d6e8d8
		{
d6e8d8
			$tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
d6e8d8
			$tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array();
d6e8d8
		}
d6e8d8
d6e8d8
		if (!$user->data['is_registered'])
d6e8d8
		{
d6e8d8
			$user_lastmark = (isset($tracking_topics['l'])) ? base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate'] : 0;
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			$user_lastmark = $user->data['user_lastmark'];
d6e8d8
		}
d6e8d8
d6e8d8
		foreach ($topic_ids as $topic_id)
d6e8d8
		{
d6e8d8
			$topic_id36 = base_convert($topic_id, 10, 36);
d6e8d8
d6e8d8
			if (isset($tracking_topics['t'][$topic_id36]))
d6e8d8
			{
d6e8d8
				$last_read[$topic_id] = base_convert($tracking_topics['t'][$topic_id36], 36, 10) + $config['board_startdate'];
d6e8d8
			}
d6e8d8
		}
d6e8d8
d6e8d8
		$topic_ids = array_diff($topic_ids, array_keys($last_read));
d6e8d8
d6e8d8
		if (sizeof($topic_ids))
d6e8d8
		{
d6e8d8
			$mark_time = array();
d6e8d8
			if ($global_announce_list && sizeof($global_announce_list))
d6e8d8
			{
d6e8d8
				if (isset($tracking_topics['f'][0]))
d6e8d8
				{
d6e8d8
					$mark_time[0] = base_convert($tracking_topics['f'][0], 36, 10) + $config['board_startdate'];
d6e8d8
				}
d6e8d8
			}
d6e8d8
d6e8d8
			if (isset($tracking_topics['f'][$forum_id]))
d6e8d8
			{
d6e8d8
				$mark_time[$forum_id] = base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate'];
d6e8d8
			}
d6e8d8
d6e8d8
			$user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user_lastmark;
d6e8d8
d6e8d8
			foreach ($topic_ids as $topic_id)
d6e8d8
			{
d6e8d8
				if ($global_announce_list && isset($global_announce_list[$topic_id]))
d6e8d8
				{
d6e8d8
					$last_read[$topic_id] = (isset($mark_time[0])) ? $mark_time[0] : $user_lastmark;
d6e8d8
				}
d6e8d8
				else
d6e8d8
				{
d6e8d8
					$last_read[$topic_id] = $user_lastmark;
d6e8d8
				}
d6e8d8
			}
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	return $last_read;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Check for read forums and update topic tracking info accordingly
d6e8d8
*
d6e8d8
* @param int $forum_id the forum id to check
d6e8d8
* @param int $forum_last_post_time the forums last post time
d6e8d8
* @param int $f_mark_time the forums last mark time if user is registered and load_db_lastread enabled
d6e8d8
* @param int $mark_time_forum false if the mark time needs to be obtained, else the last users forum mark time
d6e8d8
*
d6e8d8
* @return true if complete forum got marked read, else false.
d6e8d8
*/
d6e8d8
function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time = false, $mark_time_forum = false)
d6e8d8
{
d6e8d8
	global $db, $tracking_topics, $user, $config;
d6e8d8
d6e8d8
	// Determine the users last forum mark time if not given.
d6e8d8
	if ($mark_time_forum === false)
d6e8d8
	{
d6e8d8
		if ($config['load_db_lastread'] && $user->data['is_registered'])
d6e8d8
		{
d6e8d8
			$mark_time_forum = (!empty($f_mark_time)) ? $f_mark_time : $user->data['user_lastmark'];
d6e8d8
		}
d6e8d8
		else if ($config['load_anon_lastread'] || $user->data['is_registered'])
d6e8d8
		{
d6e8d8
			$tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : '';
d6e8d8
			$tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array();
d6e8d8
d6e8d8
			if (!$user->data['is_registered'])
d6e8d8
			{
d6e8d8
				$user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0;
d6e8d8
			}
d6e8d8
d6e8d8
			$mark_time_forum = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark'];
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	// Check the forum for any left unread topics.
d6e8d8
	// If there are none, we mark the forum as read.
d6e8d8
	if ($config['load_db_lastread'] && $user->data['is_registered'])
d6e8d8
	{
d6e8d8
		if ($mark_time_forum >= $forum_last_post_time)
d6e8d8
		{
d6e8d8
			// We do not need to mark read, this happened before. Therefore setting this to true
d6e8d8
			$row = true;
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			$sql = 'SELECT t.forum_id FROM ' . TOPICS_TABLE . ' t
d6e8d8
				LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (tt.topic_id = t.topic_id AND tt.user_id = ' . $user->data['user_id'] . ')
d6e8d8
				WHERE t.forum_id = ' . $forum_id . '
d6e8d8
					AND t.topic_last_post_time > ' . $mark_time_forum . '
d6e8d8
					AND t.topic_moved_id = 0
d6e8d8
					AND (tt.topic_id IS NULL OR tt.mark_time < t.topic_last_post_time)
d6e8d8
				GROUP BY t.forum_id';
d6e8d8
			$result = $db->sql_query_limit($sql, 1);
d6e8d8
			$row = $db->sql_fetchrow($result);
d6e8d8
			$db->sql_freeresult($result);
d6e8d8
		}
d6e8d8
	}
d6e8d8
	else if ($config['load_anon_lastread'] || $user->data['is_registered'])
d6e8d8
	{
d6e8d8
		// Get information from cookie
d6e8d8
		$row = false;
d6e8d8
d6e8d8
		if (!isset($tracking_topics['tf'][$forum_id]))
d6e8d8
		{
d6e8d8
			// We do not need to mark read, this happened before. Therefore setting this to true
d6e8d8
			$row = true;
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			$sql = 'SELECT topic_id
d6e8d8
				FROM ' . TOPICS_TABLE . '
d6e8d8
				WHERE forum_id = ' . $forum_id . '
d6e8d8
					AND topic_last_post_time > ' . $mark_time_forum . '
d6e8d8
					AND topic_moved_id = 0';
d6e8d8
			$result = $db->sql_query($sql);
d6e8d8
d6e8d8
			$check_forum = $tracking_topics['tf'][$forum_id];
d6e8d8
			$unread = false;
d6e8d8
d6e8d8
			while ($row = $db->sql_fetchrow($result))
d6e8d8
			{
d6e8d8
				if (!isset($check_forum[base_convert($row['topic_id'], 10, 36)]))
d6e8d8
				{
d6e8d8
					$unread = true;
d6e8d8
					break;
d6e8d8
				}
d6e8d8
			}
d6e8d8
			$db->sql_freeresult($result);
d6e8d8
d6e8d8
			$row = $unread;
d6e8d8
		}
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		$row = true;
d6e8d8
	}
d6e8d8
d6e8d8
	if (!$row)
d6e8d8
	{
d6e8d8
		markread('topics', $forum_id);
d6e8d8
		return true;
d6e8d8
	}
d6e8d8
d6e8d8
	return false;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Transform an array into a serialized format
d6e8d8
*/
d6e8d8
function tracking_serialize($input)
d6e8d8
{
d6e8d8
	$out = '';
d6e8d8
	foreach ($input as $key => $value)
d6e8d8
	{
d6e8d8
		if (is_array($value))
d6e8d8
		{
d6e8d8
			$out .= $key . ':(' . tracking_serialize($value) . ');';
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			$out .= $key . ':' . $value . ';';
d6e8d8
		}
d6e8d8
	}
d6e8d8
	return $out;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Transform a serialized array into an actual array
d6e8d8
*/
d6e8d8
function tracking_unserialize($string, $max_depth = 3)
d6e8d8
{
d6e8d8
	$n = strlen($string);
d6e8d8
	if ($n > 10010)
d6e8d8
	{
d6e8d8
		die('Invalid data supplied');
d6e8d8
	}
d6e8d8
	$data = $stack = array();
d6e8d8
	$key = '';
d6e8d8
	$mode = 0;
d6e8d8
	$level = &$data;
d6e8d8
	for ($i = 0; $i < $n; ++$i)
d6e8d8
	{
d6e8d8
		switch ($mode)
d6e8d8
		{
d6e8d8
			case 0:
d6e8d8
				switch ($string[$i])
d6e8d8
				{
d6e8d8
					case ':':
d6e8d8
						$level[$key] = 0;
d6e8d8
						$mode = 1;
d6e8d8
					break;
d6e8d8
					case ')':
d6e8d8
						unset($level);
d6e8d8
						$level = array_pop($stack);
d6e8d8
						$mode = 3;
d6e8d8
					break;
d6e8d8
					default:
d6e8d8
						$key .= $string[$i];
d6e8d8
				}
d6e8d8
			break;
d6e8d8
d6e8d8
			case 1:
d6e8d8
				switch ($string[$i])
d6e8d8
				{
d6e8d8
					case '(':
d6e8d8
						if (sizeof($stack) >= $max_depth)
d6e8d8
						{
d6e8d8
							die('Invalid data supplied');
d6e8d8
						}
d6e8d8
						$stack[] = &$level;
d6e8d8
						$level[$key] = array();
d6e8d8
						$level = &$level[$key];
d6e8d8
						$key = '';
d6e8d8
						$mode = 0;
d6e8d8
					break;
d6e8d8
					default:
d6e8d8
						$level[$key] = $string[$i];
d6e8d8
						$mode = 2;
d6e8d8
					break;
d6e8d8
				}
d6e8d8
			break;
d6e8d8
d6e8d8
			case 2:
d6e8d8
				switch ($string[$i])
d6e8d8
				{
d6e8d8
					case ')':
d6e8d8
						unset($level);
d6e8d8
						$level = array_pop($stack);
d6e8d8
						$mode = 3;
d6e8d8
					break;
d6e8d8
					case ';':
d6e8d8
						$key = '';
d6e8d8
						$mode = 0;
d6e8d8
					break;
d6e8d8
					default:
d6e8d8
						$level[$key] .= $string[$i];
d6e8d8
					break;
d6e8d8
				}
d6e8d8
			break;
d6e8d8
d6e8d8
			case 3:
d6e8d8
				switch ($string[$i])
d6e8d8
				{
d6e8d8
					case ')':
d6e8d8
						unset($level);
d6e8d8
						$level = array_pop($stack);
d6e8d8
					break;
d6e8d8
					case ';':
d6e8d8
						$key = '';
d6e8d8
						$mode = 0;
d6e8d8
					break;
d6e8d8
					default:
d6e8d8
						die('Invalid data supplied');
d6e8d8
					break;
d6e8d8
				}
d6e8d8
			break;
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	if (sizeof($stack) != 0 || ($mode != 0 && $mode != 3))
d6e8d8
	{
d6e8d8
		die('Invalid data supplied');
d6e8d8
	}
d6e8d8
d6e8d8
	return $level;
d6e8d8
}
d6e8d8
d6e8d8
// Pagination functions
d6e8d8
d6e8d8
/**
d6e8d8
* Pagination routine, generates page number sequence
d6e8d8
* tpl_prefix is for using different pagination blocks at one page
d6e8d8
*/
d6e8d8
function generate_pagination($base_url, $num_items, $per_page, $start_item, $add_prevnext_text = false, $tpl_prefix = '')
d6e8d8
{
d6e8d8
	global $template, $user;
d6e8d8
d6e8d8
	// Make sure $per_page is a valid value
d6e8d8
	$per_page = ($per_page <= 0) ? 1 : $per_page;
d6e8d8
d6e8d8
	$seperator = '' . $user->lang['COMMA_SEPARATOR'] . '';
d6e8d8
	$total_pages = ceil($num_items / $per_page);
d6e8d8
d6e8d8
	if ($total_pages == 1 || !$num_items)
d6e8d8
	{
d6e8d8
		return false;
d6e8d8
	}
d6e8d8
d6e8d8
	$on_page = floor($start_item / $per_page) + 1;
d6e8d8
	$url_delim = (strpos($base_url, '?') === false) ? '?' : '&';
d6e8d8
d6e8d8
	$page_string = ($on_page == 1) ? '1' : '1';
d6e8d8
d6e8d8
	if ($total_pages > 5)
d6e8d8
	{
d6e8d8
		$start_cnt = min(max(1, $on_page - 4), $total_pages - 5);
d6e8d8
		$end_cnt = max(min($total_pages, $on_page + 4), 6);
d6e8d8
d6e8d8
		$page_string .= ($start_cnt > 1) ? ' ... ' : $seperator;
d6e8d8
d6e8d8
		for ($i = $start_cnt + 1; $i < $end_cnt; $i++)
d6e8d8
		{
d6e8d8
			$page_string .= ($i == $on_page) ? '' . $i . '' : '' . $i . '';
d6e8d8
			if ($i < $end_cnt - 1)
d6e8d8
			{
d6e8d8
				$page_string .= $seperator;
d6e8d8
			}
d6e8d8
		}
d6e8d8
d6e8d8
		$page_string .= ($end_cnt < $total_pages) ? ' ... ' : $seperator;
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		$page_string .= $seperator;
d6e8d8
d6e8d8
		for ($i = 2; $i < $total_pages; $i++)
d6e8d8
		{
d6e8d8
			$page_string .= ($i == $on_page) ? '' . $i . '' : '' . $i . '';
d6e8d8
			if ($i < $total_pages)
d6e8d8
			{
d6e8d8
				$page_string .= $seperator;
d6e8d8
			}
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	$page_string .= ($on_page == $total_pages) ? '' . $total_pages . '' : '' . $total_pages . '';
d6e8d8
d6e8d8
	if ($add_prevnext_text)
d6e8d8
	{
d6e8d8
		if ($on_page != 1)
d6e8d8
		{
d6e8d8
			$page_string = '' . $user->lang['PREVIOUS'] . '  ' . $page_string;
d6e8d8
		}
d6e8d8
d6e8d8
		if ($on_page != $total_pages)
d6e8d8
		{
d6e8d8
			$page_string .= '  ' . $user->lang['NEXT'] . '';
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	$template->assign_vars(array(
d6e8d8
		$tpl_prefix . 'BASE_URL'		=> $base_url,
d6e8d8
		'A_' . $tpl_prefix . 'BASE_URL'	=> addslashes($base_url),
d6e8d8
		$tpl_prefix . 'PER_PAGE'		=> $per_page,
d6e8d8
d6e8d8
		$tpl_prefix . 'PREVIOUS_PAGE'	=> ($on_page == 1) ? '' : $base_url . "{$url_delim}start=" . (($on_page - 2) * $per_page),
d6e8d8
		$tpl_prefix . 'NEXT_PAGE'		=> ($on_page == $total_pages) ? '' : $base_url . "{$url_delim}start=" . ($on_page * $per_page),
d6e8d8
		$tpl_prefix . 'TOTAL_PAGES'		=> $total_pages,
d6e8d8
	));
d6e8d8
d6e8d8
	return $page_string;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Return current page (pagination)
d6e8d8
*/
d6e8d8
function on_page($num_items, $per_page, $start)
d6e8d8
{
d6e8d8
	global $template, $user;
d6e8d8
d6e8d8
	// Make sure $per_page is a valid value
d6e8d8
	$per_page = ($per_page <= 0) ? 1 : $per_page;
d6e8d8
d6e8d8
	$on_page = floor($start / $per_page) + 1;
d6e8d8
d6e8d8
	$template->assign_vars(array(
d6e8d8
		'ON_PAGE'		=> $on_page)
d6e8d8
	);
d6e8d8
d6e8d8
	return sprintf($user->lang['PAGE_OF'], $on_page, max(ceil($num_items / $per_page), 1));
d6e8d8
}
d6e8d8
d6e8d8
// Server functions (building urls, redirecting...)
d6e8d8
d6e8d8
/**
d6e8d8
* Append session id to url.
d6e8d8
* This function supports hooks.
d6e8d8
*
d6e8d8
* @param string $url The url the session id needs to be appended to (can have params)
d6e8d8
* @param mixed $params String or array of additional url parameters
d6e8d8
* @param bool $is_amp Is url using & (true) or & (false)
d6e8d8
* @param string $session_id Possibility to use a custom session id instead of the global one
d6e8d8
*
d6e8d8
* Examples:
d6e8d8
* 
d6e8d8
* append_sid("{$phpbb_root_path}viewtopic.$phpEx?t=1&f=2");
d6e8d8
* append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&f=2');
d6e8d8
* append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&f=2', false);
d6e8d8
* append_sid("{$phpbb_root_path}viewtopic.$phpEx", array('t' => 1, 'f' => 2));
d6e8d8
* 
d6e8d8
*
d6e8d8
*/
d6e8d8
function append_sid($url, $params = false, $is_amp = true, $session_id = false)
d6e8d8
{
d6e8d8
	global $_SID, $_EXTRA_URL, $phpbb_hook;
d6e8d8
d6e8d8
	// Developers using the hook function need to globalise the $_SID and $_EXTRA_URL on their own and also handle it appropiatly.
d6e8d8
	// They could mimick most of what is within this function
d6e8d8
	if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__, $url, $params, $is_amp, $session_id))
d6e8d8
	{
d6e8d8
		if ($phpbb_hook->hook_return(__FUNCTION__))
d6e8d8
		{
d6e8d8
			return $phpbb_hook->hook_return_result(__FUNCTION__);
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	$params_is_array = is_array($params);
d6e8d8
d6e8d8
	// Get anchor
d6e8d8
	$anchor = '';
d6e8d8
	if (strpos($url, '#') !== false)
d6e8d8
	{
d6e8d8
		list($url, $anchor) = explode('#', $url, 2);
d6e8d8
		$anchor = '#' . $anchor;
d6e8d8
	}
d6e8d8
	else if (!$params_is_array && strpos($params, '#') !== false)
d6e8d8
	{
d6e8d8
		list($params, $anchor) = explode('#', $params, 2);
d6e8d8
		$anchor = '#' . $anchor;
d6e8d8
	}
d6e8d8
d6e8d8
	// Handle really simple cases quickly
d6e8d8
	if ($_SID == '' && $session_id === false && empty($_EXTRA_URL) && !$params_is_array && !$anchor)
d6e8d8
	{
d6e8d8
		if ($params === false)
d6e8d8
		{
d6e8d8
			return $url;
d6e8d8
		}
d6e8d8
d6e8d8
		$url_delim = (strpos($url, '?') === false) ? '?' : (($is_amp) ? '&' : '&';;
d6e8d8
		return $url . ($params !== false ? $url_delim. $params : '');
d6e8d8
	}
d6e8d8
d6e8d8
	// Assign sid if session id is not specified
d6e8d8
	if ($session_id === false)
d6e8d8
	{
d6e8d8
		$session_id = $_SID;
d6e8d8
	}
d6e8d8
d6e8d8
	$amp_delim = ($is_amp) ? '&' : '&';
d6e8d8
	$url_delim = (strpos($url, '?') === false) ? '?' : $amp_delim;
d6e8d8
d6e8d8
	// Appending custom url parameter?
d6e8d8
	$append_url = (!empty($_EXTRA_URL)) ? implode($amp_delim, $_EXTRA_URL) : '';
d6e8d8
d6e8d8
	// Use the short variant if possible ;)
d6e8d8
	if ($params === false)
d6e8d8
	{
d6e8d8
		// Append session id
d6e8d8
		if (!$session_id)
d6e8d8
		{
d6e8d8
			return $url . (($append_url) ? $url_delim . $append_url : '') . $anchor;
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			return $url . (($append_url) ? $url_delim . $append_url . $amp_delim : $url_delim) . 'sid=' . $session_id . $anchor;
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	// Build string if parameters are specified as array
d6e8d8
	if (is_array($params))
d6e8d8
	{
d6e8d8
		$output = array();
d6e8d8
d6e8d8
		foreach ($params as $key => $item)
d6e8d8
		{
d6e8d8
			if ($item === NULL)
d6e8d8
			{
d6e8d8
				continue;
d6e8d8
			}
d6e8d8
d6e8d8
			if ($key == '#')
d6e8d8
			{
d6e8d8
				$anchor = '#' . $item;
d6e8d8
				continue;
d6e8d8
			}
d6e8d8
d6e8d8
			$output[] = $key . '=' . $item;
d6e8d8
		}
d6e8d8
d6e8d8
		$params = implode($amp_delim, $output);
d6e8d8
	}
d6e8d8
d6e8d8
	// Append session id and parameters (even if they are empty)
d6e8d8
	// If parameters are empty, the developer can still append his/her parameters without caring about the delimiter
d6e8d8
	return $url . (($append_url) ? $url_delim . $append_url . $amp_delim : $url_delim) . $params . ((!$session_id) ? '' : $amp_delim . 'sid=' . $session_id) . $anchor;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Generate board url (example: http://www.example.com/phpBB)
d6e8d8
* @param bool $without_script_path if set to true the script path gets not appended (example: http://www.example.com)
d6e8d8
*/
d6e8d8
function generate_board_url($without_script_path = false)
d6e8d8
{
d6e8d8
	global $config, $user;
d6e8d8
d6e8d8
	$server_name = $user->host;
d6e8d8
	$server_port = (!empty($_SERVER['SERVER_PORT'])) ? (int) $_SERVER['SERVER_PORT'] : (int) getenv('SERVER_PORT');
d6e8d8
d6e8d8
	// Forcing server vars is the only way to specify/override the protocol
d6e8d8
	if ($config['force_server_vars'] || !$server_name)
d6e8d8
	{
d6e8d8
		$server_protocol = ($config['server_protocol']) ? $config['server_protocol'] : (($config['cookie_secure']) ? 'https://' : 'http://');
d6e8d8
		$server_name = $config['server_name'];
d6e8d8
		$server_port = (int) $config['server_port'];
d6e8d8
		$script_path = $config['script_path'];
d6e8d8
d6e8d8
		$url = $server_protocol . $server_name;
d6e8d8
		$cookie_secure = $config['cookie_secure'];
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		// Do not rely on cookie_secure, users seem to think that it means a secured cookie instead of an encrypted connection
d6e8d8
		$cookie_secure = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 1 : 0;
d6e8d8
		$url = (($cookie_secure) ? 'https://' : 'http://') . $server_name;
d6e8d8
d6e8d8
		$script_path = $user->page['root_script_path'];
d6e8d8
	}
d6e8d8
d6e8d8
	if ($server_port && (($cookie_secure && $server_port <> 443) || (!$cookie_secure && $server_port <> 80)))
d6e8d8
	{
d6e8d8
		// HTTP HOST can carry a port number (we fetch $user->host, but for old versions this may be true)
d6e8d8
		if (strpos($server_name, ':') === false)
d6e8d8
		{
d6e8d8
			$url .= ':' . $server_port;
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	if (!$without_script_path)
d6e8d8
	{
d6e8d8
		$url .= $script_path;
d6e8d8
	}
d6e8d8
d6e8d8
	// Strip / from the end
d6e8d8
	if (substr($url, -1, 1) == '/')
d6e8d8
	{
d6e8d8
		$url = substr($url, 0, -1);
d6e8d8
	}
d6e8d8
d6e8d8
	return $url;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Redirects the user to another page then exits the script nicely
d6e8d8
* This function is intended for urls within the board. It's not meant to redirect to cross-domains.
d6e8d8
*
d6e8d8
* @param string $url The url to redirect to
d6e8d8
* @param bool $return If true, do not redirect but return the sanitized URL. Default is no return.
d6e8d8
* @param bool $disable_cd_check If true, redirect() will redirect to an external domain. If false, the redirect point to the boards url if it does not match the current domain. Default is false.
d6e8d8
*/
d6e8d8
function redirect($url, $return = false, $disable_cd_check = false)
d6e8d8
{
d6e8d8
	global $db, $cache, $config, $user, $phpbb_root_path;
d6e8d8
d6e8d8
	if (empty($user->lang))
d6e8d8
	{
d6e8d8
		$user->add_lang('common');
d6e8d8
	}
d6e8d8
d6e8d8
	if (!$return)
d6e8d8
	{
d6e8d8
		garbage_collection();
d6e8d8
	}
d6e8d8
d6e8d8
	// Make sure no &'s are in, this will break the redirect
d6e8d8
	$url = str_replace('&', '&', $url);
d6e8d8
d6e8d8
	// Determine which type of redirect we need to handle...
d6e8d8
	$url_parts = parse_url($url);
d6e8d8
d6e8d8
	if ($url_parts === false)
d6e8d8
	{
d6e8d8
		// Malformed url, redirect to current page...
d6e8d8
		$url = generate_board_url() . '/' . $user->page['page'];
d6e8d8
	}
d6e8d8
	else if (!empty($url_parts['scheme']) && !empty($url_parts['host']))
d6e8d8
	{
d6e8d8
		// Attention: only able to redirect within the same domain if $disable_cd_check is false (yourdomain.com -> www.yourdomain.com will not work)
d6e8d8
		if (!$disable_cd_check && $url_parts['host'] !== $user->host)
d6e8d8
		{
d6e8d8
			$url = generate_board_url();
d6e8d8
		}
d6e8d8
	}
d6e8d8
	else if ($url[0] == '/')
d6e8d8
	{
d6e8d8
		// Absolute uri, prepend direct url...
d6e8d8
		$url = generate_board_url(true) . $url;
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		// Relative uri
d6e8d8
		$pathinfo = pathinfo($url);
d6e8d8
d6e8d8
		// Is the uri pointing to the current directory?
d6e8d8
		if ($pathinfo['dirname'] == '.')
d6e8d8
		{
d6e8d8
			$url = str_replace('./', '', $url);
d6e8d8
d6e8d8
			// Strip / from the beginning
d6e8d8
			if ($url && substr($url, 0, 1) == '/')
d6e8d8
			{
d6e8d8
				$url = substr($url, 1);
d6e8d8
			}
d6e8d8
d6e8d8
			if ($user->page['page_dir'])
d6e8d8
			{
d6e8d8
				$url = generate_board_url() . '/' . $user->page['page_dir'] . '/' . $url;
d6e8d8
			}
d6e8d8
			else
d6e8d8
			{
d6e8d8
				$url = generate_board_url() . '/' . $url;
d6e8d8
			}
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			// Used ./ before, but $phpbb_root_path is working better with urls within another root path
d6e8d8
			$root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($phpbb_root_path)));
d6e8d8
			$page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($pathinfo['dirname'])));
d6e8d8
			$intersection = array_intersect_assoc($root_dirs, $page_dirs);
d6e8d8
d6e8d8
			$root_dirs = array_diff_assoc($root_dirs, $intersection);
d6e8d8
			$page_dirs = array_diff_assoc($page_dirs, $intersection);
d6e8d8
d6e8d8
			$dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs);
d6e8d8
d6e8d8
			// Strip / from the end
d6e8d8
			if ($dir && substr($dir, -1, 1) == '/')
d6e8d8
			{
d6e8d8
				$dir = substr($dir, 0, -1);
d6e8d8
			}
d6e8d8
d6e8d8
			// Strip / from the beginning
d6e8d8
			if ($dir && substr($dir, 0, 1) == '/')
d6e8d8
			{
d6e8d8
				$dir = substr($dir, 1);
d6e8d8
			}
d6e8d8
d6e8d8
			$url = str_replace($pathinfo['dirname'] . '/', '', $url);
d6e8d8
d6e8d8
			// Strip / from the beginning
d6e8d8
			if (substr($url, 0, 1) == '/')
d6e8d8
			{
d6e8d8
				$url = substr($url, 1);
d6e8d8
			}
d6e8d8
d6e8d8
			$url = (!empty($dir) ? $dir . '/' : '') . $url;
d6e8d8
			$url = generate_board_url() . '/' . $url;
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	// Make sure no linebreaks are there... to prevent http response splitting for PHP < 4.4.2
d6e8d8
	if (strpos(urldecode($url), "\n") !== false || strpos(urldecode($url), "\r") !== false || strpos($url, ';') !== false)
d6e8d8
	{
d6e8d8
		trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR);
d6e8d8
	}
d6e8d8
d6e8d8
	// Now, also check the protocol and for a valid url the last time...
d6e8d8
	$allowed_protocols = array('http', 'https', 'ftp', 'ftps');
d6e8d8
	$url_parts = parse_url($url);
d6e8d8
d6e8d8
	if ($url_parts === false || empty($url_parts['scheme']) || !in_array($url_parts['scheme'], $allowed_protocols))
d6e8d8
	{
d6e8d8
		trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR);
d6e8d8
	}
d6e8d8
d6e8d8
	if ($return)
d6e8d8
	{
d6e8d8
		return $url;
d6e8d8
	}
d6e8d8
d6e8d8
	// Redirect via an HTML form for PITA webservers
d6e8d8
	if (@preg_match('#Microsoft|WebSTAR|Xitami#', getenv('SERVER_SOFTWARE')))
d6e8d8
	{
d6e8d8
		header('Refresh: 0; URL=' . $url);
d6e8d8
d6e8d8
		echo '';
d6e8d8
		echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="' . $user->lang['DIRECTION'] . '" lang="' . $user->lang['USER_LANG'] . '" xml:lang="' . $user->lang['USER_LANG'] . '">';
d6e8d8
		echo '<head>';
d6e8d8
		echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />';
d6e8d8
		echo '<meta http-equiv="refresh" content="0; url=' . str_replace('&', '&', $url) . '" />';
d6e8d8
		echo '<title>' . $user->lang['REDIRECT'] . '</title>';
d6e8d8
		echo '</head>';
d6e8d8
		echo '<body>';
d6e8d8
		echo '
' . sprintf($user->lang['URL_REDIRECT'], '', '') . '
';
d6e8d8
		echo '</body>';
d6e8d8
		echo '</html>';
d6e8d8
d6e8d8
		exit;
d6e8d8
	}
d6e8d8
d6e8d8
	// Behave as per HTTP/1.1 spec for others
d6e8d8
	header('Location: ' . $url);
d6e8d8
	exit;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Re-Apply session id after page reloads
d6e8d8
*/
d6e8d8
function reapply_sid($url)
d6e8d8
{
d6e8d8
	global $phpEx, $phpbb_root_path;
d6e8d8
d6e8d8
	if ($url === "index.$phpEx")
d6e8d8
	{
d6e8d8
		return append_sid("index.$phpEx");
d6e8d8
	}
d6e8d8
	else if ($url === "{$phpbb_root_path}index.$phpEx")
d6e8d8
	{
d6e8d8
		return append_sid("{$phpbb_root_path}index.$phpEx");
d6e8d8
	}
d6e8d8
d6e8d8
	// Remove previously added sid
d6e8d8
	if (strpos($url, '?sid=') !== false)
d6e8d8
	{
d6e8d8
		$url = preg_replace('/(\?)sid=[a-z0-9]+(&|&)?/', '\1', $url);
d6e8d8
	}
d6e8d8
	else if (strpos($url, '&sid=') !== false)
d6e8d8
	{
d6e8d8
		$url = preg_replace('/&sid=[a-z0-9]+(&)?/', '\1', $url);
d6e8d8
	}
d6e8d8
	else if (strpos($url, '&sid=') !== false)
d6e8d8
	{
d6e8d8
		$url = preg_replace('/&sid=[a-z0-9]+(&)?/', '\1', $url);
d6e8d8
	}
d6e8d8
d6e8d8
	return append_sid($url);
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Returns url from the session/current page with an re-appended SID with optionally stripping vars from the url
d6e8d8
*/
d6e8d8
function build_url($strip_vars = false)
d6e8d8
{
d6e8d8
	global $user, $phpbb_root_path;
d6e8d8
d6e8d8
	// Append SID
d6e8d8
	$redirect = append_sid($user->page['page'], false, false);
d6e8d8
d6e8d8
	// Add delimiter if not there...
d6e8d8
	if (strpos($redirect, '?') === false)
d6e8d8
	{
d6e8d8
		$redirect .= '?';
d6e8d8
	}
d6e8d8
d6e8d8
	// Strip vars...
d6e8d8
	if ($strip_vars !== false && strpos($redirect, '?') !== false)
d6e8d8
	{
d6e8d8
		if (!is_array($strip_vars))
d6e8d8
		{
d6e8d8
			$strip_vars = array($strip_vars);
d6e8d8
		}
d6e8d8
d6e8d8
		$query = $_query = array();
d6e8d8
d6e8d8
		$args = substr($redirect, strpos($redirect, '?') + 1);
d6e8d8
		$args = ($args) ? explode('&', $args) : array();
d6e8d8
		$redirect = substr($redirect, 0, strpos($redirect, '?'));
d6e8d8
d6e8d8
		foreach ($args as $argument)
d6e8d8
		{
d6e8d8
			$arguments = explode('=', $argument);
d6e8d8
			$key = $arguments[0];
d6e8d8
			unset($arguments[0]);
d6e8d8
d6e8d8
			$query[$key] = implode('=', $arguments);
d6e8d8
		}
d6e8d8
d6e8d8
		// Strip the vars off
d6e8d8
		foreach ($strip_vars as $strip)
d6e8d8
		{
d6e8d8
			if (isset($query[$strip]))
d6e8d8
			{
d6e8d8
				unset($query[$strip]);
d6e8d8
			}
d6e8d8
		}
d6e8d8
d6e8d8
		// Glue the remaining parts together... already urlencoded
d6e8d8
		foreach ($query as $key => $value)
d6e8d8
		{
d6e8d8
			$_query[] = $key . '=' . $value;
d6e8d8
		}
d6e8d8
		$query = implode('&', $_query);
d6e8d8
d6e8d8
		$redirect .= ($query) ? '?' . $query : '';
d6e8d8
	}
d6e8d8
d6e8d8
	return $phpbb_root_path . str_replace('&', '&', $redirect);
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Meta refresh assignment
d6e8d8
* Adds META template variable with meta http tag.
d6e8d8
*
d6e8d8
* @param int $time Time in seconds for meta refresh tag
d6e8d8
* @param string $url URL to redirect to. The url will go through redirect() first before the template variable is assigned
d6e8d8
* @param bool $disable_cd_check If true, meta_refresh() will redirect to an external domain. If false, the redirect point to the boards url if it does not match the current domain. Default is false.
d6e8d8
*/
d6e8d8
function meta_refresh($time, $url, $disable_cd_check = false)
d6e8d8
{
d6e8d8
	global $template;
d6e8d8
d6e8d8
	$url = redirect($url, true, $disable_cd_check);
d6e8d8
	$url = str_replace('&', '&', $url);
d6e8d8
d6e8d8
	// For XHTML compatibility we change back & to &
d6e8d8
	$template->assign_vars(array(
d6e8d8
		'META' => '<meta http-equiv="refresh" content="' . $time . ';url=' . $url . '" />')
d6e8d8
	);
d6e8d8
d6e8d8
	return $url;
d6e8d8
}
d6e8d8
d6e8d8
//Form validation
d6e8d8
d6e8d8
d6e8d8
/**
d6e8d8
* Add a secret hash   for use in links/GET requests
d6e8d8
* @param string  $link_name The name of the link; has to match the name used in check_link_hash, otherwise no restrictions apply
d6e8d8
* @return string the hash
d6e8d8
d6e8d8
*/
d6e8d8
function generate_link_hash($link_name)
d6e8d8
{
d6e8d8
	global $user;
d6e8d8
d6e8d8
	if (!isset($user->data["hash_$link_name"]))
d6e8d8
	{
d6e8d8
		$user->data["hash_$link_name"] = substr(sha1($user->data['user_form_salt'] . $link_name), 0, 8);
d6e8d8
	}
d6e8d8
d6e8d8
	return $user->data["hash_$link_name"];
d6e8d8
}
d6e8d8
d6e8d8
d6e8d8
/**
d6e8d8
* checks a link hash - for GET requests
d6e8d8
* @param string $token the submitted token
d6e8d8
* @param string $link_name The name of the link
d6e8d8
* @return boolean true if all is fine
d6e8d8
*/
d6e8d8
function check_link_hash($token, $link_name)
d6e8d8
{
d6e8d8
	return $token === generate_link_hash($link_name);
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Add a secret token to the form (requires the S_FORM_TOKEN template variable)
d6e8d8
* @param string  $form_name The name of the form; has to match the name used in check_form_key, otherwise no restrictions apply
d6e8d8
*/
d6e8d8
function add_form_key($form_name)
d6e8d8
{
d6e8d8
	global $config, $template, $user;
d6e8d8
d6e8d8
	$now = time();
d6e8d8
	$token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : '';
d6e8d8
	$token = sha1($now . $user->data['user_form_salt'] . $form_name . $token_sid);
d6e8d8
d6e8d8
	$s_fields = build_hidden_fields(array(
d6e8d8
		'creation_time' => $now,
d6e8d8
		'form_token'	=> $token,
d6e8d8
	));
d6e8d8
d6e8d8
	$template->assign_vars(array(
d6e8d8
		'S_FORM_TOKEN'	=> $s_fields,
d6e8d8
	));
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Check the form key. Required for all altering actions not secured by confirm_box
d6e8d8
* @param string  $form_name The name of the form; has to match the name used in add_form_key, otherwise no restrictions apply
d6e8d8
* @param int $timespan The maximum acceptable age for a submitted form in seconds. Defaults to the config setting.
d6e8d8
* @param string $return_page The address for the return link
d6e8d8
* @param bool $trigger If true, the function will triger an error when encountering an invalid form
d6e8d8
*/
d6e8d8
function check_form_key($form_name, $timespan = false, $return_page = '', $trigger = false)
d6e8d8
{
d6e8d8
	global $config, $user;
d6e8d8
d6e8d8
	if ($timespan === false)
d6e8d8
	{
d6e8d8
		// we enforce a minimum value of half a minute here.
d6e8d8
		$timespan = ($config['form_token_lifetime'] == -1) ? -1 : max(30, $config['form_token_lifetime']);
d6e8d8
	}
d6e8d8
d6e8d8
	if (isset($_POST['creation_time']) && isset($_POST['form_token']))
d6e8d8
	{
d6e8d8
		$creation_time	= abs(request_var('creation_time', 0));
d6e8d8
		$token = request_var('form_token', '');
d6e8d8
d6e8d8
		$diff = time() - $creation_time;
d6e8d8
d6e8d8
		// If creation_time and the time() now is zero we can assume it was not a human doing this (the check for if ($diff)...
d6e8d8
		if ($diff && ($diff <= $timespan || $timespan === -1))
d6e8d8
		{
d6e8d8
			$token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : '';
d6e8d8
			$key = sha1($creation_time . $user->data['user_form_salt'] . $form_name . $token_sid);
d6e8d8
d6e8d8
			if ($key === $token)
d6e8d8
			{
d6e8d8
				return true;
d6e8d8
			}
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	if ($trigger)
d6e8d8
	{
d6e8d8
		trigger_error($user->lang['FORM_INVALID'] . $return_page);
d6e8d8
	}
d6e8d8
d6e8d8
	return false;
d6e8d8
}
d6e8d8
d6e8d8
// Message/Login boxes
d6e8d8
d6e8d8
/**
d6e8d8
* Build Confirm box
d6e8d8
* @param boolean $check True for checking if confirmed (without any additional parameters) and false for displaying the confirm box
d6e8d8
* @param string $title Title/Message used for confirm box.
d6e8d8
*		message text is _CONFIRM appended to title.
d6e8d8
*		If title cannot be found in user->lang a default one is displayed
d6e8d8
*		If title_CONFIRM cannot be found in user->lang the text given is used.
d6e8d8
* @param string $hidden Hidden variables
d6e8d8
* @param string $html_body Template used for confirm box
d6e8d8
* @param string $u_action Custom form action
d6e8d8
*/
d6e8d8
function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_body.html', $u_action = '')
d6e8d8
{
d6e8d8
	global $user, $template, $db;
d6e8d8
	global $phpEx, $phpbb_root_path;
d6e8d8
d6e8d8
	if (isset($_POST['cancel']))
d6e8d8
	{
d6e8d8
		return false;
d6e8d8
	}
d6e8d8
d6e8d8
	$confirm = false;
d6e8d8
	if (isset($_POST['confirm']))
d6e8d8
	{
d6e8d8
		// language frontier
d6e8d8
		if ($_POST['confirm'] === $user->lang['YES'])
d6e8d8
		{
d6e8d8
			$confirm = true;
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	if ($check && $confirm)
d6e8d8
	{
d6e8d8
		$user_id = request_var('user_id', 0);
d6e8d8
		$session_id = request_var('sess', '');
d6e8d8
		$confirm_key = request_var('confirm_key', '');
d6e8d8
d6e8d8
		if ($user_id != $user->data['user_id'] || $session_id != $user->session_id || !$confirm_key || !$user->data['user_last_confirm_key'] || $confirm_key != $user->data['user_last_confirm_key'])
d6e8d8
		{
d6e8d8
			return false;
d6e8d8
		}
d6e8d8
d6e8d8
		// Reset user_last_confirm_key
d6e8d8
		$sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = ''
d6e8d8
			WHERE user_id = " . $user->data['user_id'];
d6e8d8
		$db->sql_query($sql);
d6e8d8
d6e8d8
		return true;
d6e8d8
	}
d6e8d8
	else if ($check)
d6e8d8
	{
d6e8d8
		return false;
d6e8d8
	}
d6e8d8
d6e8d8
	$s_hidden_fields = build_hidden_fields(array(
d6e8d8
		'user_id'	=> $user->data['user_id'],
d6e8d8
		'sess'		=> $user->session_id,
d6e8d8
		'sid'		=> $user->session_id)
d6e8d8
	);
d6e8d8
d6e8d8
	// generate activation key
d6e8d8
	$confirm_key = gen_rand_string(10);
d6e8d8
d6e8d8
	if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
d6e8d8
	{
d6e8d8
		adm_page_header((!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title]);
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		page_header((!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title]);
d6e8d8
	}
d6e8d8
d6e8d8
	$template->set_filenames(array(
d6e8d8
		'body' => $html_body)
d6e8d8
	);
d6e8d8
d6e8d8
	// If activation key already exist, we better do not re-use the key (something very strange is going on...)
d6e8d8
	if (request_var('confirm_key', ''))
d6e8d8
	{
d6e8d8
		// This should not occur, therefore we cancel the operation to safe the user
d6e8d8
		return false;
d6e8d8
	}
d6e8d8
d6e8d8
	// re-add sid / transform & to & for user->page (user->page is always using &)
d6e8d8
	$use_page = ($u_action) ? $phpbb_root_path . $u_action : $phpbb_root_path . str_replace('&', '&', $user->page['page']);
d6e8d8
	$u_action = reapply_sid($use_page);
d6e8d8
	$u_action .= ((strpos($u_action, '?') === false) ? '?' : '&') . 'confirm_key=' . $confirm_key;
d6e8d8
d6e8d8
	$template->assign_vars(array(
d6e8d8
		'MESSAGE_TITLE'		=> (!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title],
d6e8d8
		'MESSAGE_TEXT'		=> (!isset($user->lang[$title . '_CONFIRM'])) ? $title : $user->lang[$title . '_CONFIRM'],
d6e8d8
d6e8d8
		'YES_VALUE'			=> $user->lang['YES'],
d6e8d8
		'S_CONFIRM_ACTION'	=> $u_action,
d6e8d8
		'S_HIDDEN_FIELDS'	=> $hidden . $s_hidden_fields)
d6e8d8
	);
d6e8d8
d6e8d8
	$sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = '" . $db->sql_escape($confirm_key) . "'
d6e8d8
		WHERE user_id = " . $user->data['user_id'];
d6e8d8
	$db->sql_query($sql);
d6e8d8
d6e8d8
	if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
d6e8d8
	{
d6e8d8
		adm_page_footer();
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		page_footer();
d6e8d8
	}
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Generate login box or verify password
d6e8d8
*/
d6e8d8
function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = false, $s_display = true)
d6e8d8
{
d6e8d8
	global $db, $user, $template, $auth, $phpEx, $phpbb_root_path, $config;
d6e8d8
d6e8d8
	$err = '';
d6e8d8
d6e8d8
	// Make sure user->setup() has been called
d6e8d8
	if (empty($user->lang))
d6e8d8
	{
d6e8d8
		$user->setup();
d6e8d8
	}
d6e8d8
d6e8d8
	// Print out error if user tries to authenticate as an administrator without having the privileges...
d6e8d8
	if ($admin && !$auth->acl_get('a_'))
d6e8d8
	{
d6e8d8
		// Not authd
d6e8d8
		// anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
d6e8d8
		if ($user->data['is_registered'])
d6e8d8
		{
d6e8d8
			add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
d6e8d8
		}
d6e8d8
		trigger_error('NO_AUTH_ADMIN');
d6e8d8
	}
d6e8d8
d6e8d8
	if (isset($_POST['login']))
d6e8d8
	{
d6e8d8
		// Get credential
d6e8d8
		if ($admin)
d6e8d8
		{
d6e8d8
			$credential = request_var('credential', '');
d6e8d8
d6e8d8
			if (strspn($credential, 'abcdef0123456789') !== strlen($credential) || strlen($credential) != 32)
d6e8d8
			{
d6e8d8
				if ($user->data['is_registered'])
d6e8d8
				{
d6e8d8
					add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
d6e8d8
				}
d6e8d8
				trigger_error('NO_AUTH_ADMIN');
d6e8d8
			}
d6e8d8
d6e8d8
			$password	= request_var('password_' . $credential, '', true);
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			$password	= request_var('password', '', true);
d6e8d8
		}
d6e8d8
d6e8d8
		$username	= request_var('username', '', true);
d6e8d8
		$autologin	= (!empty($_POST['autologin'])) ? true : false;
d6e8d8
		$viewonline = (!empty($_POST['viewonline'])) ? 0 : 1;
d6e8d8
		$admin 		= ($admin) ? 1 : 0;
d6e8d8
		$viewonline = ($admin) ? $user->data['session_viewonline'] : $viewonline;
d6e8d8
d6e8d8
		// Check if the supplied username is equal to the one stored within the database if re-authenticating
d6e8d8
		if ($admin && utf8_clean_string($username) != utf8_clean_string($user->data['username']))
d6e8d8
		{
d6e8d8
			// We log the attempt to use a different username...
d6e8d8
			add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
d6e8d8
			trigger_error('NO_AUTH_ADMIN_USER_DIFFER');
d6e8d8
		}
d6e8d8
d6e8d8
		// If authentication is successful we redirect user to previous page
d6e8d8
		$result = $auth->login($username, $password, $autologin, $viewonline, $admin);
d6e8d8
d6e8d8
		// If admin authentication and login, we will log if it was a success or not...
d6e8d8
		// We also break the operation on the first non-success login - it could be argued that the user already knows
d6e8d8
		if ($admin)
d6e8d8
		{
d6e8d8
			if ($result['status'] == LOGIN_SUCCESS)
d6e8d8
			{
d6e8d8
				add_log('admin', 'LOG_ADMIN_AUTH_SUCCESS');
d6e8d8
			}
d6e8d8
			else
d6e8d8
			{
d6e8d8
				// Only log the failed attempt if a real user tried to.
d6e8d8
				// anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
d6e8d8
				if ($user->data['is_registered'])
d6e8d8
				{
d6e8d8
					add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
d6e8d8
				}
d6e8d8
			}
d6e8d8
		}
d6e8d8
d6e8d8
		// The result parameter is always an array, holding the relevant information...
d6e8d8
		if ($result['status'] == LOGIN_SUCCESS)
d6e8d8
		{
d6e8d8
			$redirect = request_var('redirect', "{$phpbb_root_path}index.$phpEx");
d6e8d8
			$message = ($l_success) ? $l_success : $user->lang['LOGIN_REDIRECT'];
d6e8d8
			$l_redirect = ($admin) ? $user->lang['PROCEED_TO_ACP'] : (($redirect === "{$phpbb_root_path}index.$phpEx" || $redirect === "index.$phpEx") ? $user->lang['RETURN_INDEX'] : $user->lang['RETURN_PAGE']);
d6e8d8
d6e8d8
			// append/replace SID (may change during the session for AOL users)
d6e8d8
			$redirect = reapply_sid($redirect);
d6e8d8
d6e8d8
			// Special case... the user is effectively banned, but we allow founders to login
d6e8d8
			if (defined('IN_CHECK_BAN') && $result['user_row']['user_type'] != USER_FOUNDER)
d6e8d8
			{
d6e8d8
				return;
d6e8d8
			}
d6e8d8
d6e8d8
			$redirect = meta_refresh(3, $redirect);
d6e8d8
			trigger_error($message . '

' . sprintf($l_redirect, '', ''));
d6e8d8
		}
d6e8d8
d6e8d8
		// Something failed, determine what...
d6e8d8
		if ($result['status'] == LOGIN_BREAK)
d6e8d8
		{
d6e8d8
			trigger_error($result['error_msg']);
d6e8d8
		}
d6e8d8
d6e8d8
		// Special cases... determine
d6e8d8
		switch ($result['status'])
d6e8d8
		{
d6e8d8
			case LOGIN_ERROR_ATTEMPTS:
d6e8d8
d6e8d8
				// Show confirm image
d6e8d8
				$sql = 'DELETE FROM ' . CONFIRM_TABLE . "
d6e8d8
					WHERE session_id = '" . $db->sql_escape($user->session_id) . "'
d6e8d8
						AND confirm_type = " . CONFIRM_LOGIN;
d6e8d8
				$db->sql_query($sql);
d6e8d8
d6e8d8
				// Generate code
d6e8d8
				$code = gen_rand_string(mt_rand(5, 8));
d6e8d8
				$confirm_id = md5(unique_id($user->ip));
d6e8d8
				$seed = hexdec(substr(unique_id(), 4, 10));
d6e8d8
d6e8d8
				// compute $seed % 0x7fffffff
d6e8d8
				$seed -= 0x7fffffff * floor($seed / 0x7fffffff);
d6e8d8
d6e8d8
				$sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array(
d6e8d8
					'confirm_id'	=> (string) $confirm_id,
d6e8d8
					'session_id'	=> (string) $user->session_id,
d6e8d8
					'confirm_type'	=> (int) CONFIRM_LOGIN,
d6e8d8
					'code'			=> (string) $code,
d6e8d8
					'seed'			=> (int) $seed)
d6e8d8
				);
d6e8d8
				$db->sql_query($sql);
d6e8d8
d6e8d8
				$template->assign_vars(array(
d6e8d8
					'S_CONFIRM_CODE'			=> true,
d6e8d8
					'CONFIRM_ID'				=> $confirm_id,
d6e8d8
					'CONFIRM_IMAGE'				=> '',
d6e8d8
					'L_LOGIN_CONFIRM_EXPLAIN'	=> sprintf($user->lang['LOGIN_CONFIRM_EXPLAIN'], '', ''),
d6e8d8
				));
d6e8d8
d6e8d8
				$err = $user->lang[$result['error_msg']];
d6e8d8
d6e8d8
			break;
d6e8d8
d6e8d8
			case LOGIN_ERROR_PASSWORD_CONVERT:
d6e8d8
				$err = sprintf(
d6e8d8
					$user->lang[$result['error_msg']],
d6e8d8
					($config['email_enable']) ? '' : '',
d6e8d8
					($config['email_enable']) ? '' : '',
d6e8d8
					($config['board_contact']) ? '' : '',
d6e8d8
					($config['board_contact']) ? '' : ''
d6e8d8
				);
d6e8d8
			break;
d6e8d8
d6e8d8
			// Username, password, etc...
d6e8d8
			default:
d6e8d8
				$err = $user->lang[$result['error_msg']];
d6e8d8
d6e8d8
				// Assign admin contact to some error messages
d6e8d8
				if ($result['error_msg'] == 'LOGIN_ERROR_USERNAME' || $result['error_msg'] == 'LOGIN_ERROR_PASSWORD')
d6e8d8
				{
d6e8d8
					$err = (!$config['board_contact']) ? sprintf($user->lang[$result['error_msg']], '', '') : sprintf($user->lang[$result['error_msg']], '', '');
d6e8d8
				}
d6e8d8
d6e8d8
			break;
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	if (!$redirect)
d6e8d8
	{
d6e8d8
		// We just use what the session code determined...
d6e8d8
		// If we are not within the admin directory we use the page dir...
d6e8d8
		$redirect = '';
d6e8d8
d6e8d8
		if (!$admin)
d6e8d8
		{
d6e8d8
			$redirect .= ($user->page['page_dir']) ? $user->page['page_dir'] . '/' : '';
d6e8d8
		}
d6e8d8
d6e8d8
		$redirect .= $user->page['page_name'] . (($user->page['query_string']) ? '?' . htmlspecialchars($user->page['query_string']) : '');
d6e8d8
	}
d6e8d8
d6e8d8
	// Assign credential for username/password pair
d6e8d8
	$credential = ($admin) ? md5(unique_id()) : false;
d6e8d8
d6e8d8
	$s_hidden_fields = array(
d6e8d8
		'redirect'	=> $redirect,
d6e8d8
		'sid'		=> $user->session_id,
d6e8d8
	);
d6e8d8
d6e8d8
	if ($admin)
d6e8d8
	{
d6e8d8
		$s_hidden_fields['credential'] = $credential;
d6e8d8
	}
d6e8d8
d6e8d8
	$s_hidden_fields = build_hidden_fields($s_hidden_fields);
d6e8d8
d6e8d8
	$template->assign_vars(array(
d6e8d8
		'LOGIN_ERROR'		=> $err,
d6e8d8
		'LOGIN_EXPLAIN'		=> $l_explain,
d6e8d8
d6e8d8
		'U_SEND_PASSWORD' 		=> ($config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') : '',
d6e8d8
		'U_RESEND_ACTIVATION'	=> ($config['require_activation'] != USER_ACTIVATION_NONE && $config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=resend_act') : '',
d6e8d8
		'U_TERMS_USE'			=> append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'),
d6e8d8
		'U_PRIVACY'				=> append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'),
d6e8d8
d6e8d8
		'S_DISPLAY_FULL_LOGIN'	=> ($s_display) ? true : false,
d6e8d8
		'S_LOGIN_ACTION'		=> (!$admin) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') : append_sid("index.$phpEx", false, true, $user->session_id), // Needs to stay index.$phpEx because we are within the admin directory
d6e8d8
		'S_HIDDEN_FIELDS' 		=> $s_hidden_fields,
d6e8d8
d6e8d8
		'S_ADMIN_AUTH'			=> $admin,
d6e8d8
		'USERNAME'				=> ($admin) ? $user->data['username'] : '',
d6e8d8
d6e8d8
		'USERNAME_CREDENTIAL'	=> 'username',
d6e8d8
		'PASSWORD_CREDENTIAL'	=> ($admin) ? 'password_' . $credential : 'password',
d6e8d8
	));
d6e8d8
d6e8d8
	page_header($user->lang['LOGIN'], false);
d6e8d8
d6e8d8
	$template->set_filenames(array(
d6e8d8
		'body' => 'login_body.html')
d6e8d8
	);
d6e8d8
	make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));
d6e8d8
d6e8d8
	page_footer();
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Generate forum login box
d6e8d8
*/
d6e8d8
function login_forum_box($forum_data)
d6e8d8
{
d6e8d8
	global $db, $config, $user, $template, $phpEx;
d6e8d8
d6e8d8
	$password = request_var('password', '', true);
d6e8d8
d6e8d8
	$sql = 'SELECT forum_id
d6e8d8
		FROM ' . FORUMS_ACCESS_TABLE . '
d6e8d8
		WHERE forum_id = ' . $forum_data['forum_id'] . '
d6e8d8
			AND user_id = ' . $user->data['user_id'] . "
d6e8d8
			AND session_id = '" . $db->sql_escape($user->session_id) . "'";
d6e8d8
	$result = $db->sql_query($sql);
d6e8d8
	$row = $db->sql_fetchrow($result);
d6e8d8
	$db->sql_freeresult($result);
d6e8d8
d6e8d8
	if ($row)
d6e8d8
	{
d6e8d8
		return true;
d6e8d8
	}
d6e8d8
d6e8d8
	if ($password)
d6e8d8
	{
d6e8d8
		// Remove expired authorised sessions
d6e8d8
		$sql = 'SELECT f.session_id
d6e8d8
			FROM ' . FORUMS_ACCESS_TABLE . ' f
d6e8d8
			LEFT JOIN ' . SESSIONS_TABLE . ' s ON (f.session_id = s.session_id)
d6e8d8
			WHERE s.session_id IS NULL';
d6e8d8
		$result = $db->sql_query($sql);
d6e8d8
d6e8d8
		if ($row = $db->sql_fetchrow($result))
d6e8d8
		{
d6e8d8
			$sql_in = array();
d6e8d8
			do
d6e8d8
			{
d6e8d8
				$sql_in[] = (string) $row['session_id'];
d6e8d8
			}
d6e8d8
			while ($row = $db->sql_fetchrow($result));
d6e8d8
d6e8d8
			// Remove expired sessions
d6e8d8
			$sql = 'DELETE FROM ' . FORUMS_ACCESS_TABLE . '
d6e8d8
				WHERE ' . $db->sql_in_set('session_id', $sql_in);
d6e8d8
			$db->sql_query($sql);
d6e8d8
		}
d6e8d8
		$db->sql_freeresult($result);
d6e8d8
d6e8d8
		if (phpbb_check_hash($password, $forum_data['forum_password']))
d6e8d8
		{
d6e8d8
			$sql_ary = array(
d6e8d8
				'forum_id'		=> (int) $forum_data['forum_id'],
d6e8d8
				'user_id'		=> (int) $user->data['user_id'],
d6e8d8
				'session_id'	=> (string) $user->session_id,
d6e8d8
			);
d6e8d8
d6e8d8
			$db->sql_query('INSERT INTO ' . FORUMS_ACCESS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
d6e8d8
d6e8d8
			return true;
d6e8d8
		}
d6e8d8
d6e8d8
		$template->assign_var('LOGIN_ERROR', $user->lang['WRONG_PASSWORD']);
d6e8d8
	}
d6e8d8
d6e8d8
	page_header($user->lang['LOGIN']);
d6e8d8
d6e8d8
	$template->assign_vars(array(
d6e8d8
		'S_HIDDEN_FIELDS'		=> build_hidden_fields(array('f' => $forum_data['forum_id'])))
d6e8d8
	);
d6e8d8
d6e8d8
	$template->set_filenames(array(
d6e8d8
		'body' => 'login_forum.html')
d6e8d8
	);
d6e8d8
d6e8d8
	page_footer();
d6e8d8
}
d6e8d8
d6e8d8
// Little helpers
d6e8d8
d6e8d8
/**
d6e8d8
* Little helper for the build_hidden_fields function
d6e8d8
*/
d6e8d8
function _build_hidden_fields($key, $value, $specialchar, $stripslashes)
d6e8d8
{
d6e8d8
	$hidden_fields = '';
d6e8d8
d6e8d8
	if (!is_array($value))
d6e8d8
	{
d6e8d8
		$value = ($stripslashes) ? stripslashes($value) : $value;
d6e8d8
		$value = ($specialchar) ? htmlspecialchars($value, ENT_COMPAT, 'UTF-8') : $value;
d6e8d8
d6e8d8
		$hidden_fields .= '<input type="hidden" name="' . $key . '" value="' . $value . '" />' . "\n";
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		foreach ($value as $_key => $_value)
d6e8d8
		{
d6e8d8
			$_key = ($stripslashes) ? stripslashes($_key) : $_key;
d6e8d8
			$_key = ($specialchar) ? htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') : $_key;
d6e8d8
d6e8d8
			$hidden_fields .= _build_hidden_fields($key . '[' . $_key . ']', $_value, $specialchar, $stripslashes);
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	return $hidden_fields;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Build simple hidden fields from array
d6e8d8
*
d6e8d8
* @param array $field_ary an array of values to build the hidden field from
d6e8d8
* @param bool $specialchar if true, keys and values get specialchared
d6e8d8
* @param bool $stripslashes if true, keys and values get stripslashed
d6e8d8
*
d6e8d8
* @return string the hidden fields
d6e8d8
*/
d6e8d8
function build_hidden_fields($field_ary, $specialchar = false, $stripslashes = false)
d6e8d8
{
d6e8d8
	$s_hidden_fields = '';
d6e8d8
d6e8d8
	foreach ($field_ary as $name => $vars)
d6e8d8
	{
d6e8d8
		$name = ($stripslashes) ? stripslashes($name) : $name;
d6e8d8
		$name = ($specialchar) ? htmlspecialchars($name, ENT_COMPAT, 'UTF-8') : $name;
d6e8d8
d6e8d8
		$s_hidden_fields .= _build_hidden_fields($name, $vars, $specialchar, $stripslashes);
d6e8d8
	}
d6e8d8
d6e8d8
	return $s_hidden_fields;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Parse cfg file
d6e8d8
*/
d6e8d8
function parse_cfg_file($filename, $lines = false)
d6e8d8
{
d6e8d8
	$parsed_items = array();
d6e8d8
d6e8d8
	if ($lines === false)
d6e8d8
	{
d6e8d8
		$lines = file($filename);
d6e8d8
	}
d6e8d8
d6e8d8
	foreach ($lines as $line)
d6e8d8
	{
d6e8d8
		$line = trim($line);
d6e8d8
d6e8d8
		if (!$line || $line[0] == '#' || ($delim_pos = strpos($line, '=')) === false)
d6e8d8
		{
d6e8d8
			continue;
d6e8d8
		}
d6e8d8
d6e8d8
		// Determine first occurrence, since in values the equal sign is allowed
d6e8d8
		$key = strtolower(trim(substr($line, 0, $delim_pos)));
d6e8d8
		$value = trim(substr($line, $delim_pos + 1));
d6e8d8
d6e8d8
		if (in_array($value, array('off', 'false', '0')))
d6e8d8
		{
d6e8d8
			$value = false;
d6e8d8
		}
d6e8d8
		else if (in_array($value, array('on', 'true', '1')))
d6e8d8
		{
d6e8d8
			$value = true;
d6e8d8
		}
d6e8d8
		else if (!trim($value))
d6e8d8
		{
d6e8d8
			$value = '';
d6e8d8
		}
d6e8d8
		else if (($value[0] == "'" && $value[sizeof($value) - 1] == "'") || ($value[0] == '"' && $value[sizeof($value) - 1] == '"'))
d6e8d8
		{
d6e8d8
			$value = substr($value, 1, sizeof($value)-2);
d6e8d8
		}
d6e8d8
d6e8d8
		$parsed_items[$key] = $value;
d6e8d8
	}
d6e8d8
d6e8d8
	return $parsed_items;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Add log event
d6e8d8
*/
d6e8d8
function add_log()
d6e8d8
{
d6e8d8
	global $db, $user;
d6e8d8
d6e8d8
	$args = func_get_args();
d6e8d8
d6e8d8
	$mode			= array_shift($args);
d6e8d8
	$reportee_id	= ($mode == 'user') ? intval(array_shift($args)) : '';
d6e8d8
	$forum_id		= ($mode == 'mod') ? intval(array_shift($args)) : '';
d6e8d8
	$topic_id		= ($mode == 'mod') ? intval(array_shift($args)) : '';
d6e8d8
	$action			= array_shift($args);
d6e8d8
	$data			= (!sizeof($args)) ? '' : serialize($args);
d6e8d8
d6e8d8
	$sql_ary = array(
d6e8d8
		'user_id'		=> (empty($user->data)) ? ANONYMOUS : $user->data['user_id'],
d6e8d8
		'log_ip'		=> $user->ip,
d6e8d8
		'log_time'		=> time(),
d6e8d8
		'log_operation'	=> $action,
d6e8d8
		'log_data'		=> $data,
d6e8d8
	);
d6e8d8
d6e8d8
	switch ($mode)
d6e8d8
	{
d6e8d8
		case 'admin':
d6e8d8
			$sql_ary['log_type'] = LOG_ADMIN;
d6e8d8
		break;
d6e8d8
d6e8d8
		case 'mod':
d6e8d8
			$sql_ary += array(
d6e8d8
				'log_type'	=> LOG_MOD,
d6e8d8
				'forum_id'	=> $forum_id,
d6e8d8
				'topic_id'	=> $topic_id
d6e8d8
			);
d6e8d8
		break;
d6e8d8
d6e8d8
		case 'user':
d6e8d8
			$sql_ary += array(
d6e8d8
				'log_type'		=> LOG_USERS,
d6e8d8
				'reportee_id'	=> $reportee_id
d6e8d8
			);
d6e8d8
		break;
d6e8d8
d6e8d8
		case 'critical':
d6e8d8
			$sql_ary['log_type'] = LOG_CRITICAL;
d6e8d8
		break;
d6e8d8
d6e8d8
		default:
d6e8d8
			return false;
d6e8d8
	}
d6e8d8
d6e8d8
	$db->sql_query('INSERT INTO ' . LOG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
d6e8d8
d6e8d8
	return $db->sql_nextid();
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Return a nicely formatted backtrace (parts from the php manual by diz at ysagoon dot com)
d6e8d8
*/
d6e8d8
function get_backtrace()
d6e8d8
{
d6e8d8
	global $phpbb_root_path;
d6e8d8
d6e8d8
	$output = '
';
d6e8d8
	$backtrace = debug_backtrace();
d6e8d8
	$path = phpbb_realpath($phpbb_root_path);
d6e8d8
d6e8d8
	foreach ($backtrace as $number => $trace)
d6e8d8
	{
d6e8d8
		// We skip the first one, because it only shows this file/function
d6e8d8
		if ($number == 0)
d6e8d8
		{
d6e8d8
			continue;
d6e8d8
		}
d6e8d8
d6e8d8
		// Strip the current directory from path
d6e8d8
		if (empty($trace['file']))
d6e8d8
		{
d6e8d8
			$trace['file'] = '';
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			$trace['file'] = str_replace(array($path, '\\'), array('', '/'), $trace['file']);
d6e8d8
			$trace['file'] = substr($trace['file'], 1);
d6e8d8
		}
d6e8d8
		$args = array();
d6e8d8
d6e8d8
		// If include/require/include_once is not called, do not show arguments - they may contain sensible information
d6e8d8
		if (!in_array($trace['function'], array('include', 'require', 'include_once')))
d6e8d8
		{
d6e8d8
			unset($trace['args']);
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			// Path...
d6e8d8
			if (!empty($trace['args'][0]))
d6e8d8
			{
d6e8d8
				$argument = htmlspecialchars($trace['args'][0]);
d6e8d8
				$argument = str_replace(array($path, '\\'), array('', '/'), $argument);
d6e8d8
				$argument = substr($argument, 1);
d6e8d8
				$args[] = "'{$argument}'";
d6e8d8
			}
d6e8d8
		}
d6e8d8
d6e8d8
		$trace['class'] = (!isset($trace['class'])) ? '' : $trace['class'];
d6e8d8
		$trace['type'] = (!isset($trace['type'])) ? '' : $trace['type'];
d6e8d8
d6e8d8
		$output .= '
';
d6e8d8
		$output .= 'FILE: ' . htmlspecialchars($trace['file']) . '
';
d6e8d8
		$output .= 'LINE: ' . ((!empty($trace['line'])) ? $trace['line'] : '') . '
';
d6e8d8
d6e8d8
		$output .= 'CALL: ' . htmlspecialchars($trace['class'] . $trace['type'] . $trace['function']) . '(' . ((sizeof($args)) ? implode(', ', $args) : '') . ')
';
d6e8d8
	}
d6e8d8
	$output .= '';
d6e8d8
	return $output;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* This function returns a regular expression pattern for commonly used expressions
d6e8d8
* Use with / as delimiter for email mode and # for url modes
d6e8d8
* mode can be: email|bbcode_htm|url|url_inline|www_url|www_url_inline|relative_url|relative_url_inline|ipv4|ipv6
d6e8d8
*/
d6e8d8
function get_preg_expression($mode)
d6e8d8
{
d6e8d8
	switch ($mode)
d6e8d8
	{
d6e8d8
		case 'email':
d6e8d8
			return '(?:[a-z0-9\'\.\-_\+\|]++|&)+@[a-z0-9\-]+\.(?:[a-z0-9\-]+\.)*[a-z]+';
d6e8d8
		break;
d6e8d8
d6e8d8
		case 'bbcode_htm':
d6e8d8
			return array(
d6e8d8
				'#.*?#',
d6e8d8
				'#.*?#',
d6e8d8
				'#.*?#',
d6e8d8
				'#
d6e8d8
				'##s',
d6e8d8
				'#<.*?>#s',
d6e8d8
			);
d6e8d8
		break;
d6e8d8
d6e8d8
		// Whoa these look impressive!
d6e8d8
		// The code to generate the following two regular expressions which match valid IPv4/IPv6 addresses
d6e8d8
		// can be found in the develop directory
d6e8d8
		case 'ipv4':
d6e8d8
			return '#^(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$#';
d6e8d8
		break;
d6e8d8
d6e8d8
		case 'ipv6':
d6e8d8
			return '#^(?:(?:(?:[\dA-F]{1,4}:){6}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:::(?:[\dA-F]{1,4}:){5}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:):(?:[\dA-F]{1,4}:){4}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,2}:(?:[\dA-F]{1,4}:){3}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,3}:(?:[\dA-F]{1,4}:){2}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,4}:(?:[\dA-F]{1,4}:)(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,5}:(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,6}:[\dA-F]{1,4})|(?:(?:[\dA-F]{1,4}:){1,7}:))$#i';
d6e8d8
		break;
d6e8d8
d6e8d8
		case 'url':
d6e8d8
		case 'url_inline':
d6e8d8
			$inline = ($mode == 'url') ? ')' : '';
d6e8d8
			$scheme = ($mode == 'url') ? '[a-z\d+\-.]' : '[a-z\d+]'; // avoid automatic parsing of "word" in "last word.http://..."
d6e8d8
			// generated with regex generation file in the develop folder
d6e8d8
			return "[a-z]$scheme*:/{2}(?:(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?";
d6e8d8
		break;
d6e8d8
d6e8d8
		case 'www_url':
d6e8d8
		case 'www_url_inline':
d6e8d8
			$inline = ($mode == 'www_url') ? ')' : '';
d6e8d8
			return "www\.(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?";
d6e8d8
		break;
d6e8d8
d6e8d8
		case 'relative_url':
d6e8d8
		case 'relative_url_inline':
d6e8d8
			$inline = ($mode == 'relative_url') ? ')' : '';
d6e8d8
			return "(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?";
d6e8d8
		break;
d6e8d8
	}
d6e8d8
d6e8d8
	return '';
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Returns the first block of the specified IPv6 address and as many additional
d6e8d8
* ones as specified in the length paramater.
d6e8d8
* If length is zero, then an empty string is returned.
d6e8d8
* If length is greater than 3 the complete IP will be returned
d6e8d8
*/
d6e8d8
function short_ipv6($ip, $length)
d6e8d8
{
d6e8d8
	if ($length < 1)
d6e8d8
	{
d6e8d8
		return '';
d6e8d8
	}
d6e8d8
d6e8d8
	// extend IPv6 addresses
d6e8d8
	$blocks = substr_count($ip, ':') + 1;
d6e8d8
	if ($blocks < 9)
d6e8d8
	{
d6e8d8
		$ip = str_replace('::', ':' . str_repeat('0000:', 9 - $blocks), $ip);
d6e8d8
	}
d6e8d8
	if ($ip[0] == ':')
d6e8d8
	{
d6e8d8
		$ip = '0000' . $ip;
d6e8d8
	}
d6e8d8
	if ($length < 4)
d6e8d8
	{
d6e8d8
		$ip = implode(':', array_slice(explode(':', $ip), 0, 1 + $length));
d6e8d8
	}
d6e8d8
d6e8d8
	return $ip;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Wrapper for php's checkdnsrr function.
d6e8d8
*
d6e8d8
* The windows failover is from the php manual
d6e8d8
* Please make sure to check the return value for === true and === false, since NULL could
d6e8d8
* be returned too.
d6e8d8
*
d6e8d8
* @return true if entry found, false if not, NULL if this function is not supported by this environment
d6e8d8
*/
d6e8d8
function phpbb_checkdnsrr($host, $type = '')
d6e8d8
{
d6e8d8
	$type = (!$type) ? 'MX' : $type;
d6e8d8
d6e8d8
	if (DIRECTORY_SEPARATOR == '\\')
d6e8d8
	{
d6e8d8
		if (!function_exists('exec'))
d6e8d8
		{
d6e8d8
			return NULL;
d6e8d8
		}
d6e8d8
d6e8d8
		// @exec('nslookup -retry=1 -timout=1 -type=' . escapeshellarg($type) . ' ' . escapeshellarg($host), $output);
d6e8d8
		@exec('nslookup -type=' . escapeshellarg($type) . ' ' . escapeshellarg($host) . '.', $output);
d6e8d8
d6e8d8
		// If output is empty, the nslookup failed
d6e8d8
		if (empty($output))
d6e8d8
		{
d6e8d8
			return NULL;
d6e8d8
		}
d6e8d8
d6e8d8
		foreach ($output as $line)
d6e8d8
		{
d6e8d8
			if (!trim($line))
d6e8d8
			{
d6e8d8
				continue;
d6e8d8
			}
d6e8d8
d6e8d8
			// Valid records begin with host name:
d6e8d8
			if (strpos($line, $host) === 0)
d6e8d8
			{
d6e8d8
				return true;
d6e8d8
			}
d6e8d8
		}
d6e8d8
d6e8d8
		return false;
d6e8d8
	}
d6e8d8
	else if (function_exists('checkdnsrr'))
d6e8d8
	{
d6e8d8
		// The dot indicates to search the DNS root (helps those having DNS prefixes on the same domain)
d6e8d8
		return (checkdnsrr($host . '.', $type)) ? true : false;
d6e8d8
	}
d6e8d8
d6e8d8
	return NULL;
d6e8d8
}
d6e8d8
d6e8d8
// Handler, header and footer
d6e8d8
d6e8d8
/**
d6e8d8
* Error and message handler, call with trigger_error if reqd
d6e8d8
*/
d6e8d8
function msg_handler($errno, $msg_text, $errfile, $errline)
d6e8d8
{
d6e8d8
	global $cache, $db, $auth, $template, $config, $user;
d6e8d8
	global $phpEx, $phpbb_root_path, $msg_title, $msg_long_text;
d6e8d8
d6e8d8
	// Do not display notices if we suppress them via @
d6e8d8
	if (error_reporting() == 0)
d6e8d8
	{
d6e8d8
		return;
d6e8d8
	}
d6e8d8
d6e8d8
	// Message handler is stripping text. In case we need it, we are possible to define long text...
d6e8d8
	if (isset($msg_long_text) && $msg_long_text && !$msg_text)
d6e8d8
	{
d6e8d8
		$msg_text = $msg_long_text;
d6e8d8
	}
d6e8d8
d6e8d8
	switch ($errno)
d6e8d8
	{
d6e8d8
		case E_NOTICE:
d6e8d8
		case E_WARNING:
d6e8d8
d6e8d8
			// Check the error reporting level and return if the error level does not match
d6e8d8
			// If DEBUG is defined the default level is E_ALL
d6e8d8
			if (($errno & ((defined('DEBUG')) ? E_ALL : error_reporting())) == 0)
d6e8d8
			{
d6e8d8
				return;
d6e8d8
			}
d6e8d8
d6e8d8
			if (strpos($errfile, 'cache') === false && strpos($errfile, 'template.') === false)
d6e8d8
			{
d6e8d8
				// flush the content, else we get a white page if output buffering is on
d6e8d8
				if ((int) @ini_get('output_buffering') === 1 || strtolower(@ini_get('output_buffering')) === 'on')
d6e8d8
				{
d6e8d8
					@ob_flush();
d6e8d8
				}
d6e8d8
d6e8d8
				// Another quick fix for those having gzip compression enabled, but do not flush if the coder wants to catch "something". ;)
d6e8d8
				if (!empty($config['gzip_compress']))
d6e8d8
				{
d6e8d8
					if (@extension_loaded('zlib') && !headers_sent() && !ob_get_level())
d6e8d8
					{
d6e8d8
						@ob_flush();
d6e8d8
					}
d6e8d8
				}
d6e8d8
d6e8d8
				// remove complete path to installation, with the risk of changing backslashes meant to be there
d6e8d8
				$errfile = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $errfile);
d6e8d8
				$msg_text = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $msg_text);
d6e8d8
d6e8d8
				echo '[phpBB Debug] PHP Notice: in file ' . $errfile . ' on line ' . $errline . ': ' . $msg_text . '
' . "\n";
d6e8d8
			}
d6e8d8
d6e8d8
			return;
d6e8d8
d6e8d8
		break;
d6e8d8
d6e8d8
		case E_USER_ERROR:
d6e8d8
d6e8d8
			if (!empty($user) && !empty($user->lang))
d6e8d8
			{
d6e8d8
				$msg_text = (!empty($user->lang[$msg_text])) ? $user->lang[$msg_text] : $msg_text;
d6e8d8
				$msg_title = (!isset($msg_title)) ? $user->lang['GENERAL_ERROR'] : ((!empty($user->lang[$msg_title])) ? $user->lang[$msg_title] : $msg_title);
d6e8d8
d6e8d8
				$l_return_index = sprintf($user->lang['RETURN_INDEX'], '', '');
d6e8d8
				$l_notify = '';
d6e8d8
d6e8d8
				if (!empty($config['board_contact']))
d6e8d8
				{
d6e8d8
					$l_notify = '

' . sprintf($user->lang['NOTIFY_ADMIN_EMAIL'], $config['board_contact']) . '

';
d6e8d8
				}
d6e8d8
			}
d6e8d8
			else
d6e8d8
			{
d6e8d8
				$msg_title = 'General Error';
d6e8d8
				$l_return_index = 'Return to index page';
d6e8d8
				$l_notify = '';
d6e8d8
d6e8d8
				if (!empty($config['board_contact']))
d6e8d8
				{
d6e8d8
					$l_notify = '

Please notify the board administrator or webmaster: ' . $config['board_contact'] . '

';
d6e8d8
				}
d6e8d8
			}
d6e8d8
d6e8d8
			garbage_collection();
d6e8d8
d6e8d8
			// Try to not call the adm page data...
d6e8d8
d6e8d8
			echo '';
d6e8d8
			echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">';
d6e8d8
			echo '<head>';
d6e8d8
			echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />';
d6e8d8
			echo '<title>' . $msg_title . '</title>';
d6e8d8
			echo '<style type="text/css">' . "\n" . '/* 
d6e8d8
			echo '* { margin: 0; padding: 0; } html { font-size: 100%; height: 100%; margin-bottom: 1px; background-color: #E4EDF0; } body { font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; color: #536482; background: #E4EDF0; font-size: 62.5%; margin: 0; } ';
d6e8d8
			echo 'a:link, a:active, a:visited { color: #006699; text-decoration: none; } a:hover { color: #DD6900; text-decoration: underline; } ';
d6e8d8
			echo '#wrap { padding: 0 20px 15px 20px; min-width: 615px; } #page-header { text-align: right; height: 40px; } #page-footer { clear: both; font-size: 1em; text-align: center; } ';
d6e8d8
			echo '.panel { margin: 4px 0; background-color: #FFFFFF; border: solid 1px  #A9B8C2; } ';
d6e8d8
			echo '#errorpage #page-header a { font-weight: bold; line-height: 6em; } #errorpage #content { padding: 10px; } #errorpage #content h1 { line-height: 1.2em; margin-bottom: 0; color: #DF075C; } ';
d6e8d8
			echo '#errorpage #content div { margin-top: 20px; margin-bottom: 5px; border-bottom: 1px solid #CCCCCC; padding-bottom: 5px; color: #333333; font: bold 1.2em "Lucida Grande", Arial, Helvetica, sans-serif; text-decoration: none; line-height: 120%; text-align: left; } ';
d6e8d8
			echo "\n" . '/* ]]> */' . "\n";
d6e8d8
			echo '</style>';
d6e8d8
			echo '</head>';
d6e8d8
			echo '<body id="errorpage">';
d6e8d8
			echo '
';
d6e8d8
			echo '	
d6e8d8
			echo '		' . $l_return_index;
d6e8d8
			echo '	';
d6e8d8
			echo '	
';
d6e8d8
			echo '	
';
d6e8d8
			echo '		
';
d6e8d8
			echo '			

' . $msg_title . '

';
d6e8d8
d6e8d8
			echo '			
' . $msg_text . '
';
d6e8d8
d6e8d8
			echo $l_notify;
d6e8d8
d6e8d8
			echo '		';
d6e8d8
			echo '	';
d6e8d8
			echo '	';
d6e8d8
			echo '	
d6e8d8
			echo '		Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group';
d6e8d8
			echo '	';
d6e8d8
			echo '';
d6e8d8
			echo '</body>';
d6e8d8
			echo '</html>';
d6e8d8
d6e8d8
			exit_handler();
d6e8d8
d6e8d8
			// On a fatal error (and E_USER_ERROR *is* fatal) we never want other scripts to continue and force an exit here.
d6e8d8
			exit;
d6e8d8
		break;
d6e8d8
d6e8d8
		case E_USER_WARNING:
d6e8d8
		case E_USER_NOTICE:
d6e8d8
d6e8d8
			define('IN_ERROR_HANDLER', true);
d6e8d8
d6e8d8
			if (empty($user->data))
d6e8d8
			{
d6e8d8
				$user->session_begin();
d6e8d8
			}
d6e8d8
d6e8d8
			// We re-init the auth array to get correct results on login/logout
d6e8d8
			$auth->acl($user->data);
d6e8d8
d6e8d8
			if (empty($user->lang))
d6e8d8
			{
d6e8d8
				$user->setup();
d6e8d8
			}
d6e8d8
d6e8d8
			$msg_text = (!empty($user->lang[$msg_text])) ? $user->lang[$msg_text] : $msg_text;
d6e8d8
			$msg_title = (!isset($msg_title)) ? $user->lang['INFORMATION'] : ((!empty($user->lang[$msg_title])) ? $user->lang[$msg_title] : $msg_title);
d6e8d8
d6e8d8
			if (!defined('HEADER_INC'))
d6e8d8
			{
d6e8d8
				if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
d6e8d8
				{
d6e8d8
					adm_page_header($msg_title);
d6e8d8
				}
d6e8d8
				else
d6e8d8
				{
d6e8d8
					page_header($msg_title);
d6e8d8
				}
d6e8d8
			}
d6e8d8
d6e8d8
			$template->set_filenames(array(
d6e8d8
				'body' => 'message_body.html')
d6e8d8
			);
d6e8d8
d6e8d8
			$template->assign_vars(array(
d6e8d8
				'MESSAGE_TITLE'		=> $msg_title,
d6e8d8
				'MESSAGE_TEXT'		=> $msg_text,
d6e8d8
				'S_USER_WARNING'	=> ($errno == E_USER_WARNING) ? true : false,
d6e8d8
				'S_USER_NOTICE'		=> ($errno == E_USER_NOTICE) ? true : false)
d6e8d8
			);
d6e8d8
d6e8d8
			// We do not want the cron script to be called on error messages
d6e8d8
			define('IN_CRON', true);
d6e8d8
d6e8d8
			if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
d6e8d8
			{
d6e8d8
				adm_page_footer();
d6e8d8
			}
d6e8d8
			else
d6e8d8
			{
d6e8d8
				page_footer();
d6e8d8
			}
d6e8d8
d6e8d8
			exit_handler();
d6e8d8
		break;
d6e8d8
	}
d6e8d8
d6e8d8
	// If we notice an error not handled here we pass this back to PHP by returning false
d6e8d8
	// This may not work for all php versions
d6e8d8
	return false;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Queries the session table to get information about online guests
d6e8d8
* @param int $forum_id Limits the search to the forum with this id
d6e8d8
* @return int The number of active distinct guest sessions
d6e8d8
*/
d6e8d8
function obtain_guest_count($forum_id = 0)
d6e8d8
{
d6e8d8
	global $db, $config;
d6e8d8
d6e8d8
	if ($forum_id)
d6e8d8
	{
d6e8d8
		$reading_sql = ' AND s.session_forum_id = ' . (int) $forum_id;
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		$reading_sql = '';
d6e8d8
	}
d6e8d8
	$time = (time() - (intval($config['load_online_time']) * 60));
d6e8d8
d6e8d8
	// Get number of online guests
d6e8d8
d6e8d8
	if ($db->sql_layer === 'sqlite')
d6e8d8
	{
d6e8d8
		$sql = 'SELECT COUNT(session_ip) as num_guests
d6e8d8
			FROM (
d6e8d8
				SELECT DISTINCT s.session_ip
d6e8d8
				FROM ' . SESSIONS_TABLE . ' s
d6e8d8
				WHERE s.session_user_id = ' . ANONYMOUS . '
d6e8d8
					AND s.session_time >= ' . ($time - ((int) ($time % 60))) .
d6e8d8
				$reading_sql .
d6e8d8
			')';
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		$sql = 'SELECT COUNT(DISTINCT s.session_ip) as num_guests
d6e8d8
			FROM ' . SESSIONS_TABLE . ' s
d6e8d8
			WHERE s.session_user_id = ' . ANONYMOUS . '
d6e8d8
				AND s.session_time >= ' . ($time - ((int) ($time % 60))) .
d6e8d8
			$reading_sql;
d6e8d8
	}
d6e8d8
	$result = $db->sql_query($sql, 60);
d6e8d8
	$guests_online = (int) $db->sql_fetchfield('num_guests');
d6e8d8
	$db->sql_freeresult($result);
d6e8d8
d6e8d8
	return $guests_online;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Queries the session table to get information about online users
d6e8d8
* @param int $forum_id Limits the search to the forum with this id
d6e8d8
* @return array An array containing the ids of online, hidden and visible users, as well as statistical info
d6e8d8
*/
d6e8d8
function obtain_users_online($forum_id = 0)
d6e8d8
{
d6e8d8
	global $db, $config, $user;
d6e8d8
d6e8d8
	$reading_sql = '';
d6e8d8
	if ($forum_id !== 0)
d6e8d8
	{
d6e8d8
		$reading_sql = ' AND s.session_forum_id = ' . (int) $forum_id;
d6e8d8
	}
d6e8d8
d6e8d8
	$online_users = array(
d6e8d8
		'online_users'			=> array(),
d6e8d8
		'hidden_users'			=> array(),
d6e8d8
		'total_online'			=> 0,
d6e8d8
		'visible_online'		=> 0,
d6e8d8
		'hidden_online'			=> 0,
d6e8d8
		'guests_online'			=> 0,
d6e8d8
	);
d6e8d8
d6e8d8
	if ($config['load_online_guests'])
d6e8d8
	{
d6e8d8
		$online_users['guests_online'] = obtain_guest_count($forum_id);
d6e8d8
	}
d6e8d8
d6e8d8
	// a little discrete magic to cache this for 30 seconds
d6e8d8
	$time = (time() - (intval($config['load_online_time']) * 60));
d6e8d8
d6e8d8
	$sql = 'SELECT s.session_user_id, s.session_ip, s.session_viewonline
d6e8d8
		FROM ' . SESSIONS_TABLE . ' s
d6e8d8
		WHERE s.session_time >= ' . ($time - ((int) ($time % 30))) .
d6e8d8
			$reading_sql .
d6e8d8
		' AND s.session_user_id <> ' . ANONYMOUS;
d6e8d8
	$result = $db->sql_query($sql);
d6e8d8
d6e8d8
	while ($row = $db->sql_fetchrow($result))
d6e8d8
	{
d6e8d8
		// Skip multiple sessions for one user
d6e8d8
		if (!isset($online_users['online_users'][$row['session_user_id']]))
d6e8d8
		{
d6e8d8
			$online_users['online_users'][$row['session_user_id']] = (int) $row['session_user_id'];
d6e8d8
			if ($row['session_viewonline'])
d6e8d8
			{
d6e8d8
				$online_users['visible_online']++;
d6e8d8
			}
d6e8d8
			else
d6e8d8
			{
d6e8d8
				$online_users['hidden_users'][$row['session_user_id']] = (int) $row['session_user_id'];
d6e8d8
				$online_users['hidden_online']++;
d6e8d8
			}
d6e8d8
		}
d6e8d8
	}
d6e8d8
	$online_users['total_online'] = $online_users['guests_online'] + $online_users['visible_online'] + $online_users['hidden_online'];
d6e8d8
	$db->sql_freeresult($result);
d6e8d8
d6e8d8
	return $online_users;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Uses the result of obtain_users_online to generate a localized, readable representation.
d6e8d8
* @param mixed $online_users result of obtain_users_online - array with user_id lists for total, hidden and visible users, and statistics
d6e8d8
* @param int $forum_id Indicate that the data is limited to one forum and not global.
d6e8d8
* @return array An array containing the string for output to the template
d6e8d8
*/
d6e8d8
function obtain_users_online_string($online_users, $forum_id = 0)
d6e8d8
{
d6e8d8
	global $config, $db, $user, $auth;
d6e8d8
d6e8d8
	$user_online_link = $online_userlist = '';
d6e8d8
d6e8d8
	if (sizeof($online_users['online_users']))
d6e8d8
	{
d6e8d8
		$sql = 'SELECT username, username_clean, user_id, user_type, user_allow_viewonline, user_colour
d6e8d8
				FROM ' . USERS_TABLE . '
d6e8d8
				WHERE ' . $db->sql_in_set('user_id', $online_users['online_users']) . '
d6e8d8
				ORDER BY username_clean ASC';
d6e8d8
		$result = $db->sql_query($sql);
d6e8d8
d6e8d8
		while ($row = $db->sql_fetchrow($result))
d6e8d8
		{
d6e8d8
			// User is logged in and therefore not a guest
d6e8d8
			if ($row['user_id'] != ANONYMOUS)
d6e8d8
			{
d6e8d8
				if (isset($online_users['hidden_users'][$row['user_id']]))
d6e8d8
				{
d6e8d8
					$row['username'] = '' . $row['username'] . '';
d6e8d8
				}
d6e8d8
d6e8d8
				if (!isset($online_users['hidden_users'][$row['user_id']]) || $auth->acl_get('u_viewonline'))
d6e8d8
				{
d6e8d8
					$user_online_link = get_username_string(($row['user_type'] <> USER_IGNORE) ? 'full' : 'no_profile', $row['user_id'], $row['username'], $row['user_colour']);
d6e8d8
					$online_userlist .= ($online_userlist != '') ? ', ' . $user_online_link : $user_online_link;
d6e8d8
				}
d6e8d8
			}
d6e8d8
		}
d6e8d8
		$db->sql_freeresult($result);
d6e8d8
	}
d6e8d8
d6e8d8
	if (!$online_userlist)
d6e8d8
	{
d6e8d8
		$online_userlist = $user->lang['NO_ONLINE_USERS'];
d6e8d8
	}
d6e8d8
d6e8d8
	if ($forum_id === 0)
d6e8d8
	{
d6e8d8
		$online_userlist = $user->lang['REGISTERED_USERS'] . ' ' . $online_userlist;
d6e8d8
	}
d6e8d8
	else if ($config['load_online_guests'])
d6e8d8
	{
d6e8d8
		$l_online = ($online_users['guests_online'] === 1) ? $user->lang['BROWSING_FORUM_GUEST'] : $user->lang['BROWSING_FORUM_GUESTS'];
d6e8d8
		$online_userlist = sprintf($l_online, $online_userlist, $online_users['guests_online']);
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		$online_userlist = sprintf($user->lang['BROWSING_FORUM'], $online_userlist);
d6e8d8
	}
d6e8d8
	// Build online listing
d6e8d8
	$vars_online = array(
d6e8d8
		'ONLINE'	=> array('total_online', 'l_t_user_s', 0),
d6e8d8
		'REG'		=> array('visible_online', 'l_r_user_s', !$config['load_online_guests']),
d6e8d8
		'HIDDEN'	=> array('hidden_online', 'l_h_user_s', $config['load_online_guests']),
d6e8d8
		'GUEST'		=> array('guests_online', 'l_g_user_s', 0)
d6e8d8
	);
d6e8d8
d6e8d8
	foreach ($vars_online as $l_prefix => $var_ary)
d6e8d8
	{
d6e8d8
		if ($var_ary[2])
d6e8d8
		{
d6e8d8
			$l_suffix = '_AND';
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			$l_suffix = '';
d6e8d8
		}
d6e8d8
		switch ($online_users[$var_ary[0]])
d6e8d8
		{
d6e8d8
			case 0:
d6e8d8
				${$var_ary[1]} = $user->lang[$l_prefix . '_USERS_ZERO_TOTAL' . $l_suffix];
d6e8d8
			break;
d6e8d8
d6e8d8
			case 1:
d6e8d8
				${$var_ary[1]} = $user->lang[$l_prefix . '_USER_TOTAL' . $l_suffix];
d6e8d8
			break;
d6e8d8
d6e8d8
			default:
d6e8d8
				${$var_ary[1]} = $user->lang[$l_prefix . '_USERS_TOTAL' . $l_suffix];
d6e8d8
			break;
d6e8d8
		}
d6e8d8
	}
d6e8d8
	unset($vars_online);
d6e8d8
d6e8d8
	$l_online_users = sprintf($l_t_user_s, $online_users['total_online']);
d6e8d8
	$l_online_users .= sprintf($l_r_user_s, $online_users['visible_online']);
d6e8d8
	$l_online_users .= sprintf($l_h_user_s, $online_users['hidden_online']);
d6e8d8
d6e8d8
	if ($config['load_online_guests'])
d6e8d8
	{
d6e8d8
		$l_online_users .= sprintf($l_g_user_s, $online_users['guests_online']);
d6e8d8
	}
d6e8d8
d6e8d8
d6e8d8
d6e8d8
	return array(
d6e8d8
		'online_userlist'	=> $online_userlist,
d6e8d8
		'l_online_users'	=> $l_online_users,
d6e8d8
	);
d6e8d8
}
d6e8d8
d6e8d8
d6e8d8
/**
d6e8d8
* Generate page header
d6e8d8
*/
d6e8d8
function page_header($page_title = '', $display_online_list = true)
d6e8d8
{
d6e8d8
	global $db, $config, $template, $SID, $_SID, $user, $auth, $phpEx, $phpbb_root_path;
d6e8d8
d6e8d8
	if (defined('HEADER_INC'))
d6e8d8
	{
d6e8d8
		return;
d6e8d8
	}
d6e8d8
d6e8d8
	define('HEADER_INC', true);
d6e8d8
d6e8d8
	// gzip_compression
d6e8d8
	if ($config['gzip_compress'])
d6e8d8
	{
d6e8d8
		if (@extension_loaded('zlib') && !headers_sent())
d6e8d8
		{
d6e8d8
			ob_start('ob_gzhandler');
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	// Generate logged in/logged out status
d6e8d8
	if ($user->data['user_id'] != ANONYMOUS)
d6e8d8
	{
d6e8d8
		$u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout', true, $user->session_id);
d6e8d8
		$l_login_logout = sprintf($user->lang['LOGOUT_USER'], $user->data['username']);
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		$u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login');
d6e8d8
		$l_login_logout = $user->lang['LOGIN'];
d6e8d8
	}
d6e8d8
d6e8d8
	// Last visit date/time
d6e8d8
	$s_last_visit = ($user->data['user_id'] != ANONYMOUS) ? $user->format_date($user->data['session_last_visit']) : '';
d6e8d8
d6e8d8
	// Get users online list ... if required
d6e8d8
	$l_online_users = $online_userlist = $l_online_record = '';
d6e8d8
d6e8d8
	if ($config['load_online'] && $config['load_online_time'] && $display_online_list)
d6e8d8
	{
d6e8d8
		$f = request_var('f', 0);
d6e8d8
		$f = max($f, 0);
d6e8d8
		$online_users = obtain_users_online($f);
d6e8d8
		$user_online_strings = obtain_users_online_string($online_users, $f);
d6e8d8
d6e8d8
		$l_online_users = $user_online_strings['l_online_users'];
d6e8d8
		$online_userlist = $user_online_strings['online_userlist'];
d6e8d8
		$total_online_users = $online_users['total_online'];
d6e8d8
d6e8d8
		if ($total_online_users > $config['record_online_users'])
d6e8d8
		{
d6e8d8
			set_config('record_online_users', $total_online_users, true);
d6e8d8
			set_config('record_online_date', time(), true);
d6e8d8
		}
d6e8d8
d6e8d8
		$l_online_record = sprintf($user->lang['RECORD_ONLINE_USERS'], $config['record_online_users'], $user->format_date($config['record_online_date']));
d6e8d8
d6e8d8
		$l_online_time = ($config['load_online_time'] == 1) ? 'VIEW_ONLINE_TIME' : 'VIEW_ONLINE_TIMES';
d6e8d8
		$l_online_time = sprintf($user->lang[$l_online_time], $config['load_online_time']);
d6e8d8
	}
d6e8d8
	else
d6e8d8
	{
d6e8d8
		$l_online_time = '';
d6e8d8
	}
d6e8d8
d6e8d8
	$l_privmsgs_text = $l_privmsgs_text_unread = '';
d6e8d8
	$s_privmsg_new = false;
d6e8d8
d6e8d8
	// Obtain number of new private messages if user is logged in
d6e8d8
	if (!empty($user->data['is_registered']))
d6e8d8
	{
d6e8d8
		if ($user->data['user_new_privmsg'])
d6e8d8
		{
d6e8d8
			$l_message_new = ($user->data['user_new_privmsg'] == 1) ? $user->lang['NEW_PM'] : $user->lang['NEW_PMS'];
d6e8d8
			$l_privmsgs_text = sprintf($l_message_new, $user->data['user_new_privmsg']);
d6e8d8
d6e8d8
			if (!$user->data['user_last_privmsg'] || $user->data['user_last_privmsg'] > $user->data['session_last_visit'])
d6e8d8
			{
d6e8d8
				$sql = 'UPDATE ' . USERS_TABLE . '
d6e8d8
					SET user_last_privmsg = ' . $user->data['session_last_visit'] . '
d6e8d8
					WHERE user_id = ' . $user->data['user_id'];
d6e8d8
				$db->sql_query($sql);
d6e8d8
d6e8d8
				$s_privmsg_new = true;
d6e8d8
			}
d6e8d8
			else
d6e8d8
			{
d6e8d8
				$s_privmsg_new = false;
d6e8d8
			}
d6e8d8
		}
d6e8d8
		else
d6e8d8
		{
d6e8d8
			$l_privmsgs_text = $user->lang['NO_NEW_PM'];
d6e8d8
			$s_privmsg_new = false;
d6e8d8
		}
d6e8d8
d6e8d8
		$l_privmsgs_text_unread = '';
d6e8d8
d6e8d8
		if ($user->data['user_unread_privmsg'] && $user->data['user_unread_privmsg'] != $user->data['user_new_privmsg'])
d6e8d8
		{
d6e8d8
			$l_message_unread = ($user->data['user_unread_privmsg'] == 1) ? $user->lang['UNREAD_PM'] : $user->lang['UNREAD_PMS'];
d6e8d8
			$l_privmsgs_text_unread = sprintf($l_message_unread, $user->data['user_unread_privmsg']);
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	// Which timezone?
d6e8d8
	$tz = ($user->data['user_id'] != ANONYMOUS) ? strval(doubleval($user->data['user_timezone'])) : strval(doubleval($config['board_timezone']));
d6e8d8
d6e8d8
	// Send a proper content-language to the output
d6e8d8
	$user_lang = $user->lang['USER_LANG'];
d6e8d8
	if (strpos($user_lang, '-x-') !== false)
d6e8d8
	{
d6e8d8
		$user_lang = substr($user_lang, 0, strpos($user_lang, '-x-'));
d6e8d8
	}
d6e8d8
d6e8d8
	// The following assigns all _common_ variables that may be used at any point in a template.
d6e8d8
	$template->assign_vars(array(
d6e8d8
		'SITENAME'						=> $config['sitename'],
d6e8d8
		'SITE_DESCRIPTION'				=> $config['site_desc'],
d6e8d8
		'PAGE_TITLE'					=> $page_title,
d6e8d8
		'SCRIPT_NAME'					=> str_replace('.' . $phpEx, '', $user->page['page_name']),
d6e8d8
		'LAST_VISIT_DATE'				=> sprintf($user->lang['YOU_LAST_VISIT'], $s_last_visit),
d6e8d8
		'LAST_VISIT_YOU'				=> $s_last_visit,
d6e8d8
		'CURRENT_TIME'					=> sprintf($user->lang['CURRENT_TIME'], $user->format_date(time(), false, true)),
d6e8d8
		'TOTAL_USERS_ONLINE'			=> $l_online_users,
d6e8d8
		'LOGGED_IN_USER_LIST'			=> $online_userlist,
d6e8d8
		'RECORD_USERS'					=> $l_online_record,
d6e8d8
		'PRIVATE_MESSAGE_INFO'			=> $l_privmsgs_text,
d6e8d8
		'PRIVATE_MESSAGE_INFO_UNREAD'	=> $l_privmsgs_text_unread,
d6e8d8
d6e8d8
		'S_USER_NEW_PRIVMSG'			=> $user->data['user_new_privmsg'],
d6e8d8
		'S_USER_UNREAD_PRIVMSG'			=> $user->data['user_unread_privmsg'],
d6e8d8
d6e8d8
		'SID'				=> $SID,
d6e8d8
		'_SID'				=> $_SID,
d6e8d8
		'SESSION_ID'		=> $user->session_id,
d6e8d8
		'ROOT_PATH'			=> $phpbb_root_path,
d6e8d8
d6e8d8
		'L_LOGIN_LOGOUT'	=> $l_login_logout,
d6e8d8
		'L_INDEX'			=> $user->lang['FORUM_INDEX'],
d6e8d8
		'L_ONLINE_EXPLAIN'	=> $l_online_time,
d6e8d8
d6e8d8
		'U_PRIVATEMSGS'			=> append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'),
d6e8d8
		'U_RETURN_INBOX'		=> append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'),
d6e8d8
		'U_POPUP_PM'			=> append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=popup'),
d6e8d8
		'UA_POPUP_PM'			=> addslashes(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=popup')),
d6e8d8
		'U_MEMBERLIST'			=> append_sid("{$phpbb_root_path}memberlist.$phpEx"),
d6e8d8
		'U_VIEWONLINE'			=> ($auth->acl_gets('u_viewprofile', 'a_user', 'a_useradd', 'a_userdel')) ? append_sid("{$phpbb_root_path}viewonline.$phpEx") : '',
d6e8d8
		'U_LOGIN_LOGOUT'		=> $u_login_logout,
d6e8d8
		'U_INDEX'				=> append_sid("{$phpbb_root_path}index.$phpEx"),
d6e8d8
		'U_SEARCH'				=> append_sid("{$phpbb_root_path}search.$phpEx"),
d6e8d8
		'U_REGISTER'			=> append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'),
d6e8d8
		'U_PROFILE'				=> append_sid("{$phpbb_root_path}ucp.$phpEx"),
d6e8d8
		'U_MODCP'				=> append_sid("{$phpbb_root_path}mcp.$phpEx", false, true, $user->session_id),
d6e8d8
		'U_FAQ'					=> append_sid("{$phpbb_root_path}faq.$phpEx"),
d6e8d8
		'U_SEARCH_SELF'			=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=egosearch'),
d6e8d8
		'U_SEARCH_NEW'			=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=newposts'),
d6e8d8
		'U_SEARCH_UNANSWERED'	=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unanswered'),
d6e8d8
		'U_SEARCH_ACTIVE_TOPICS'=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=active_topics'),
d6e8d8
		'U_DELETE_COOKIES'		=> append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=delete_cookies'),
d6e8d8
		'U_TEAM'				=> ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile')) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=leaders'),
d6e8d8
		'U_RESTORE_PERMISSIONS'	=> ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm') : '',
d6e8d8
d6e8d8
		'S_USER_LOGGED_IN'		=> ($user->data['user_id'] != ANONYMOUS) ? true : false,
d6e8d8
		'S_AUTOLOGIN_ENABLED'	=> ($config['allow_autologin']) ? true : false,
d6e8d8
		'S_BOARD_DISABLED'		=> ($config['board_disable']) ? true : false,
d6e8d8
		'S_REGISTERED_USER'		=> (!empty($user->data['is_registered'])) ? true : false,
d6e8d8
		'S_IS_BOT'				=> (!empty($user->data['is_bot'])) ? true : false,
d6e8d8
		'S_USER_PM_POPUP'		=> $user->optionget('popuppm'),
d6e8d8
		'S_USER_LANG'			=> $user_lang,
d6e8d8
		'S_USER_BROWSER'		=> (isset($user->data['session_browser'])) ? $user->data['session_browser'] : $user->lang['UNKNOWN_BROWSER'],
d6e8d8
		'S_USERNAME'			=> $user->data['username'],
d6e8d8
		'S_CONTENT_DIRECTION'	=> $user->lang['DIRECTION'],
d6e8d8
		'S_CONTENT_FLOW_BEGIN'	=> ($user->lang['DIRECTION'] == 'ltr') ? 'left' : 'right',
d6e8d8
		'S_CONTENT_FLOW_END'	=> ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left',
d6e8d8
		'S_CONTENT_ENCODING'	=> 'UTF-8',
d6e8d8
		'S_TIMEZONE'			=> ($user->data['user_dst'] || ($user->data['user_id'] == ANONYMOUS && $config['board_dst'])) ? sprintf($user->lang['ALL_TIMES'], $user->lang['tz'][$tz], $user->lang['tz']['dst']) : sprintf($user->lang['ALL_TIMES'], $user->lang['tz'][$tz], ''),
d6e8d8
		'S_DISPLAY_ONLINE_LIST'	=> ($l_online_time) ? 1 : 0,
d6e8d8
		'S_DISPLAY_SEARCH'		=> (!$config['load_search']) ? 0 : (isset($auth) ? ($auth->acl_get('u_search') && $auth->acl_getf_global('f_search')) : 1),
d6e8d8
		'S_DISPLAY_PM'			=> ($config['allow_privmsg'] && !empty($user->data['is_registered']) && ($auth->acl_get('u_readpm') || $auth->acl_get('u_sendpm'))) ? true : false,
d6e8d8
		'S_DISPLAY_MEMBERLIST'	=> (isset($auth)) ? $auth->acl_get('u_viewprofile') : 0,
d6e8d8
		'S_NEW_PM'				=> ($s_privmsg_new) ? 1 : 0,
d6e8d8
		'S_REGISTER_ENABLED'	=> ($config['require_activation'] != USER_ACTIVATION_DISABLE) ? true : false,
d6e8d8
d6e8d8
		'T_THEME_PATH'			=> "{$phpbb_root_path}styles/" . $user->theme['theme_path'] . '/theme',
d6e8d8
		'T_TEMPLATE_PATH'		=> "{$phpbb_root_path}styles/" . $user->theme['template_path'] . '/template',
d6e8d8
		'T_SUPER_TEMPLATE_PATH'	=> (isset($user->theme['template_inherit_path']) && $user->theme['template_inherit_path']) ? "{$phpbb_root_path}styles/" . $user->theme['template_inherit_path'] . '/template' : "{$phpbb_root_path}styles/" . $user->theme['template_path'] . '/template',
d6e8d8
		'T_IMAGESET_PATH'		=> "{$phpbb_root_path}styles/" . $user->theme['imageset_path'] . '/imageset',
d6e8d8
		'T_IMAGESET_LANG_PATH'	=> "{$phpbb_root_path}styles/" . $user->theme['imageset_path'] . '/imageset/' . $user->data['user_lang'],
d6e8d8
		'T_IMAGES_PATH'			=> "{$phpbb_root_path}images/",
d6e8d8
		'T_SMILIES_PATH'		=> "{$phpbb_root_path}{$config['smilies_path']}/",
d6e8d8
		'T_AVATAR_PATH'			=> "{$phpbb_root_path}{$config['avatar_path']}/",
d6e8d8
		'T_AVATAR_GALLERY_PATH'	=> "{$phpbb_root_path}{$config['avatar_gallery_path']}/",
d6e8d8
		'T_ICONS_PATH'			=> "{$phpbb_root_path}{$config['icons_path']}/",
d6e8d8
		'T_RANKS_PATH'			=> "{$phpbb_root_path}{$config['ranks_path']}/",
d6e8d8
		'T_UPLOAD_PATH'			=> "{$phpbb_root_path}{$config['upload_path']}/",
d6e8d8
		'T_STYLESHEET_LINK'		=> (!$user->theme['theme_storedb']) ? "{$phpbb_root_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : "{$phpbb_root_path}style.$phpEx?sid=$user->session_id&id=" . $user->theme['style_id'] . '&lang=' . $user->data['user_lang'],
d6e8d8
		'T_STYLESHEET_NAME'		=> $user->theme['theme_name'],
d6e8d8
d6e8d8
		'SITE_LOGO_IMG'			=> $user->img('site_logo'),
d6e8d8
d6e8d8
		'A_COOKIE_SETTINGS'		=> addslashes('; path=' . $config['cookie_path'] . ((!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain']) . ((!$config['cookie_secure']) ? '' : '; secure')),
d6e8d8
	));
d6e8d8
d6e8d8
	// application/xhtml+xml not used because of IE
d6e8d8
	header('Content-type: text/html; charset=UTF-8');
d6e8d8
d6e8d8
	header('Cache-Control: private, no-cache="set-cookie"');
d6e8d8
	header('Expires: 0');
d6e8d8
	header('Pragma: no-cache');
d6e8d8
d6e8d8
	return;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Generate page footer
d6e8d8
*/
d6e8d8
function page_footer($run_cron = true)
d6e8d8
{
d6e8d8
	global $db, $config, $template, $user, $auth, $cache, $starttime, $phpbb_root_path, $phpEx;
d6e8d8
d6e8d8
	// Output page creation time
d6e8d8
	if (defined('DEBUG'))
d6e8d8
	{
d6e8d8
		$mtime = explode(' ', microtime());
d6e8d8
		$totaltime = $mtime[0] + $mtime[1] - $starttime;
d6e8d8
d6e8d8
		if (!empty($_REQUEST['explain']) && $auth->acl_get('a_') && defined('DEBUG_EXTRA') && method_exists($db, 'sql_report'))
d6e8d8
		{
d6e8d8
			$db->sql_report('display');
d6e8d8
		}
d6e8d8
d6e8d8
		$debug_output = sprintf('Time : %.3fs | ' . $db->sql_num_queries() . ' Queries | GZIP : ' . (($config['gzip_compress']) ? 'On' : 'Off') . (($user->load) ? ' | Load : ' . $user->load : ''), $totaltime);
d6e8d8
d6e8d8
		if ($auth->acl_get('a_') && defined('DEBUG_EXTRA'))
d6e8d8
		{
d6e8d8
			if (function_exists('memory_get_usage'))
d6e8d8
			{
d6e8d8
				if ($memory_usage = memory_get_usage())
d6e8d8
				{
d6e8d8
					global $base_memory_usage;
d6e8d8
					$memory_usage -= $base_memory_usage;
d6e8d8
					$memory_usage = get_formatted_filesize($memory_usage);
d6e8d8
d6e8d8
					$debug_output .= ' | Memory Usage: ' . $memory_usage;
d6e8d8
				}
d6e8d8
			}
d6e8d8
d6e8d8
			$debug_output .= ' | Explain';
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	$template->assign_vars(array(
d6e8d8
		'DEBUG_OUTPUT'			=> (defined('DEBUG')) ? $debug_output : '',
d6e8d8
		'TRANSLATION_INFO'		=> (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '',
d6e8d8
d6e8d8
		'U_ACP' => ($auth->acl_get('a_') && !empty($user->data['is_registered'])) ? append_sid("{$phpbb_root_path}adm/index.$phpEx", false, true, $user->session_id) : '')
d6e8d8
	);
d6e8d8
d6e8d8
	// Call cron-type script
d6e8d8
	if (!defined('IN_CRON') && $run_cron && !$config['board_disable'])
d6e8d8
	{
d6e8d8
		$cron_type = '';
d6e8d8
d6e8d8
		if (time() - $config['queue_interval'] > $config['last_queue_run'] && !defined('IN_ADMIN') && file_exists($phpbb_root_path . 'cache/queue.' . $phpEx))
d6e8d8
		{
d6e8d8
			// Process email queue
d6e8d8
			$cron_type = 'queue';
d6e8d8
		}
d6e8d8
		else if (method_exists($cache, 'tidy') && time() - $config['cache_gc'] > $config['cache_last_gc'])
d6e8d8
		{
d6e8d8
			// Tidy the cache
d6e8d8
			$cron_type = 'tidy_cache';
d6e8d8
		}
d6e8d8
		else if (time() - $config['warnings_gc'] > $config['warnings_last_gc'])
d6e8d8
		{
d6e8d8
			$cron_type = 'tidy_warnings';
d6e8d8
		}
d6e8d8
		else if (time() - $config['database_gc'] > $config['database_last_gc'])
d6e8d8
		{
d6e8d8
			// Tidy the database
d6e8d8
			$cron_type = 'tidy_database';
d6e8d8
		}
d6e8d8
		else if (time() - $config['search_gc'] > $config['search_last_gc'])
d6e8d8
		{
d6e8d8
			// Tidy the search
d6e8d8
			$cron_type = 'tidy_search';
d6e8d8
		}
d6e8d8
		else if (time() - $config['session_gc'] > $config['session_last_gc'])
d6e8d8
		{
d6e8d8
			$cron_type = 'tidy_sessions';
d6e8d8
		}
d6e8d8
d6e8d8
		if ($cron_type)
d6e8d8
		{
d6e8d8
			$template->assign_var('RUN_CRON_TASK', 'cron');
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	$template->display('body');
d6e8d8
d6e8d8
	garbage_collection();
d6e8d8
	exit_handler();
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Closing the cache object and the database
d6e8d8
* Cool function name, eh? We might want to add operations to it later
d6e8d8
*/
d6e8d8
function garbage_collection()
d6e8d8
{
d6e8d8
	global $cache, $db;
d6e8d8
d6e8d8
	// Unload cache, must be done before the DB connection if closed
d6e8d8
	if (!empty($cache))
d6e8d8
	{
d6e8d8
		$cache->unload();
d6e8d8
	}
d6e8d8
d6e8d8
	// Close our DB connection.
d6e8d8
	if (!empty($db))
d6e8d8
	{
d6e8d8
		$db->sql_close();
d6e8d8
	}
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Handler for exit calls in phpBB.
d6e8d8
* This function supports hooks.
d6e8d8
*
d6e8d8
* Note: This function is called after the template has been outputted.
d6e8d8
*/
d6e8d8
function exit_handler()
d6e8d8
{
d6e8d8
	global $phpbb_hook, $config;
d6e8d8
d6e8d8
	if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__))
d6e8d8
	{
d6e8d8
		if ($phpbb_hook->hook_return(__FUNCTION__))
d6e8d8
		{
d6e8d8
			return $phpbb_hook->hook_return_result(__FUNCTION__);
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	// As a pre-caution... some setups display a blank page if the flush() is not there.
d6e8d8
	(empty($config['gzip_compress'])) ? @flush() : @ob_flush();
d6e8d8
d6e8d8
	exit;
d6e8d8
}
d6e8d8
d6e8d8
/**
d6e8d8
* Handler for init calls in phpBB. This function is called in user::setup();
d6e8d8
* This function supports hooks.
d6e8d8
*/
d6e8d8
function phpbb_user_session_handler()
d6e8d8
{
d6e8d8
	global $phpbb_hook;
d6e8d8
d6e8d8
	if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__))
d6e8d8
	{
d6e8d8
		if ($phpbb_hook->hook_return(__FUNCTION__))
d6e8d8
		{
d6e8d8
			return $phpbb_hook->hook_return_result(__FUNCTION__);
d6e8d8
		}
d6e8d8
	}
d6e8d8
d6e8d8
	return;
d6e8d8
}
d6e8d8
d6e8d8
?>