diff options
Diffstat (limited to 'phpBB/includes')
53 files changed, 1758 insertions, 341 deletions
diff --git a/phpBB/includes/acm/acm_file.php b/phpBB/includes/acm/acm_file.php index 5c1876d006..524a28561e 100644 --- a/phpBB/includes/acm/acm_file.php +++ b/phpBB/includes/acm/acm_file.php @@ -88,11 +88,11 @@ class acm  			if (!phpbb_is_writable($this->cache_dir))  			{  				// We need to use die() here, because else we may encounter an infinite loop (the message handler calls $cache->unload()) -				die($this->cache_dir . ' is NOT writable.'); +				die('Fatal: ' . $this->cache_dir . ' is NOT writable.');  				exit;  			} -			die('Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx); +			die('Fatal: Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx);  			exit;  		} diff --git a/phpBB/includes/acm/acm_redis.php b/phpBB/includes/acm/acm_redis.php new file mode 100644 index 0000000000..41533eaacb --- /dev/null +++ b/phpBB/includes/acm/acm_redis.php @@ -0,0 +1,145 @@ +<?php +/** +* +* @package acm +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +// Include the abstract base +if (!class_exists('acm_memory')) +{ +	require("{$phpbb_root_path}includes/acm/acm_memory.$phpEx"); +} + +if (!defined('PHPBB_ACM_REDIS_PORT')) +{ +	define('PHPBB_ACM_REDIS_PORT', 6379); +} + +if (!defined('PHPBB_ACM_REDIS_HOST')) +{ +	define('PHPBB_ACM_REDIS_HOST', 'localhost'); +} + +/** +* ACM for Redis +* +* Compatible with the php extension phpredis available +* at https://github.com/nicolasff/phpredis +* +* @package acm +*/ +class acm extends acm_memory +{ +	var $extension = 'redis'; + +	var $redis; + +	function acm() +	{ +		// Call the parent constructor +		parent::acm_memory(); + +		$this->redis = new Redis(); +		$this->redis->connect(PHPBB_ACM_REDIS_HOST, PHPBB_ACM_REDIS_PORT); + +		if (defined('PHPBB_ACM_REDIS_PASSWORD')) +		{ +			if (!$this->redis->auth(PHPBB_ACM_REDIS_PASSWORD)) +			{ +				global $acm_type; + +				trigger_error("Incorrect password for the ACM module $acm_type.", E_USER_ERROR); +			} +		} + +		$this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); +		$this->redis->setOption(Redis::OPT_PREFIX, $this->key_prefix); + +		if (defined('PHPBB_ACM_REDIS_DB')) +		{ +			if (!$this->redis->select(PHPBB_ACM_REDIS_DB)) +			{ +				global $acm_type; + +				trigger_error("Incorrect database for the ACM module $acm_type.", E_USER_ERROR); +			} +		} +	} + +	/** +	* Unload the cache resources +	* +	* @return void +	*/ +	function unload() +	{ +		parent::unload(); + +		$this->redis->close(); +	} + +	/** +	* Purge cache data +	* +	* @return void +	*/ +	function purge() +	{ +		$this->redis->flushDB(); + +		parent::purge(); +	} + +	/** +	* Fetch an item from the cache +	* +	* @access protected +	* @param string $var Cache key +	* @return mixed Cached data +	*/ +	function _read($var) +	{ +		return $this->redis->get($var); +	} + +	/** +	* Store data in the cache +	* +	* @access protected +	* @param string $var Cache key +	* @param mixed $data Data to store +	* @param int $ttl Time-to-live of cached data +	* @return bool True if the operation succeeded +	*/ +	function _write($var, $data, $ttl = 2592000) +	{ +		return $this->redis->setex($var, $ttl, $data); +	} + +	/** +	* Remove an item from the cache +	* +	* @access protected +	* @param string $var Cache key +	* @return bool True if the operation succeeded +	*/ +	function _delete($var) +	{ +		if ($this->redis->delete($var) > 0) +		{ +			return true; +		} +		return false; +	} +} diff --git a/phpBB/includes/acm/acm_wincache.php b/phpBB/includes/acm/acm_wincache.php new file mode 100644 index 0000000000..0501ab74c5 --- /dev/null +++ b/phpBB/includes/acm/acm_wincache.php @@ -0,0 +1,84 @@ +<?php +/** +* +* @package acm +* @copyright (c) 2010 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +// Include the abstract base +if (!class_exists('acm_memory')) +{ +	require("{$phpbb_root_path}includes/acm/acm_memory.$phpEx"); +} + +/** +* ACM for WinCache +* @package acm +*/ +class acm extends acm_memory +{ +	var $extension = 'wincache'; + +	/** +	* Purge cache data +	* +	* @return void +	*/ +	function purge() +	{ +		wincache_ucache_clear(); + +		parent::purge(); +	} + +	/** +	* Fetch an item from the cache +	* +	* @access protected +	* @param string $var Cache key +	* @return mixed Cached data +	*/ +	function _read($var) +	{ +		$success = false; +		$result = wincache_ucache_get($this->key_prefix . $var, $success); + +		return ($success) ? $result : false; +	} + +	/** +	* Store data in the cache +	* +	* @access protected +	* @param string $var Cache key +	* @param mixed $data Data to store +	* @param int $ttl Time-to-live of cached data +	* @return bool True if the operation succeeded +	*/ +	function _write($var, $data, $ttl = 2592000) +	{ +		return wincache_ucache_set($this->key_prefix . $var, $data, $ttl); +	} + +	/** +	* Remove an item from the cache +	* +	* @access protected +	* @param string $var Cache key +	* @return bool True if the operation succeeded +	*/ +	function _delete($var) +	{ +		return wincache_ucache_delete($this->key_prefix . $var); +	} +} diff --git a/phpBB/includes/acp/acp_bbcodes.php b/phpBB/includes/acp/acp_bbcodes.php index 2b706394c4..0644b38eb1 100644 --- a/phpBB/includes/acp/acp_bbcodes.php +++ b/phpBB/includes/acp/acp_bbcodes.php @@ -213,7 +213,7 @@ class acp_bbcodes  							$bbcode_id = NUM_CORE_BBCODES + 1;  						} -						if ($bbcode_id > 1511) +						if ($bbcode_id > BBCODE_LIMIT)  						{  							trigger_error($user->lang['TOO_MANY_BBCODES'] . adm_back_link($this->u_action), E_USER_WARNING);  						} diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index a5e80e1f6d..d8ab42ed2d 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -386,6 +386,9 @@ class acp_board  						'pass_complex'			=> array('lang' => 'PASSWORD_TYPE',			'validate' => 'string',	'type' => 'select', 'method' => 'select_password_chars', 'explain' => true),  						'chg_passforce'			=> array('lang' => 'FORCE_PASS_CHANGE',		'validate' => 'int:0',	'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),  						'max_login_attempts'	=> array('lang' => 'MAX_LOGIN_ATTEMPTS',	'validate' => 'int:0',	'type' => 'text:3:3', 'explain' => true), +						'ip_login_limit_max'	=> array('lang' => 'IP_LOGIN_LIMIT_MAX',	'validate' => 'int:0',	'type' => 'text:3:3', 'explain' => true), +						'ip_login_limit_time'	=> array('lang' => 'IP_LOGIN_LIMIT_TIME',	'validate' => 'int:0',	'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), +						'ip_login_limit_use_forwarded'	=> array('lang' => 'IP_LOGIN_LIMIT_USE_FORWARDED',	'validate' => 'bool',	'type' => 'radio:yes_no', 'explain' => true),  						'tpl_allow_php'			=> array('lang' => 'TPL_ALLOW_PHP',			'validate' => 'bool',	'type' => 'radio:yes_no', 'explain' => true),  						'form_token_lifetime'	=> array('lang' => 'FORM_TIME_MAX',			'validate' => 'int:-1',	'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),  						'form_token_sid_guests'	=> array('lang' => 'FORM_SID_GUESTS',		'validate' => 'bool',	'type' => 'radio:yes_no', 'explain' => true), @@ -769,13 +772,20 @@ class acp_board  	{  		global $user, $config; -		$radio_ary = array(USER_ACTIVATION_DISABLE => 'ACC_DISABLE', USER_ACTIVATION_NONE => 'ACC_NONE'); +		$radio_ary = array( +			USER_ACTIVATION_DISABLE => 'ACC_DISABLE', +			USER_ACTIVATION_NONE => 'ACC_NONE', +		); +  		if ($config['email_enable'])  		{ -			$radio_ary += array(USER_ACTIVATION_SELF => 'ACC_USER', USER_ACTIVATION_ADMIN => 'ACC_ADMIN'); +			$radio_ary[USER_ACTIVATION_SELF] = 'ACC_USER'; +			$radio_ary[USER_ACTIVATION_ADMIN] = 'ACC_ADMIN';  		} -		return h_radio('config[require_activation]', $radio_ary, $value, $key); +		$radio_text = h_radio('config[require_activation]', $radio_ary, $value, 'require_activation', $key, '<br />'); + +		return $radio_text;  	}  	/** diff --git a/phpBB/includes/acp/acp_disallow.php b/phpBB/includes/acp/acp_disallow.php index 9549955cc8..e2176b7bcd 100644 --- a/phpBB/includes/acp/acp_disallow.php +++ b/phpBB/includes/acp/acp_disallow.php @@ -56,6 +56,18 @@ class acp_disallow  				trigger_error($user->lang['NO_USERNAME_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING);  			} +			$sql = 'SELECT disallow_id +				FROM ' . DISALLOW_TABLE . " +				WHERE disallow_username = '" . $db->sql_escape($disallowed_user) . "'"; +			$result = $db->sql_query($sql); +			$row = $db->sql_fetchrow($result); +			$db->sql_freeresult($result); + +			if ($row) +			{ +				trigger_error($user->lang['DISALLOWED_ALREADY'] . adm_back_link($this->u_action), E_USER_WARNING); +			} +  			$sql = 'INSERT INTO ' . DISALLOW_TABLE . ' ' . $db->sql_build_array('INSERT', array('disallow_username' => $disallowed_user));  			$db->sql_query($sql); diff --git a/phpBB/includes/acp/acp_email.php b/phpBB/includes/acp/acp_email.php index 350693a630..133fe47e09 100644 --- a/phpBB/includes/acp/acp_email.php +++ b/phpBB/includes/acp/acp_email.php @@ -82,23 +82,48 @@ class acp_email  				{  					if ($group_id)  					{ -						$sql = 'SELECT u.user_email, u.username, u.username_clean, u.user_lang, u.user_jabber, u.user_notify_type -							FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug -							WHERE ug.group_id = ' . $group_id . ' +						$sql_ary = array( +							'SELECT'	=> 'u.user_email, u.username, u.username_clean, u.user_lang, u.user_jabber, u.user_notify_type', +							'FROM'		=> array( +								USERS_TABLE			=> 'u', +								USER_GROUP_TABLE	=> 'ug', +							), +							'WHERE'		=> 'ug.group_id = ' . $group_id . '  								AND ug.user_pending = 0  								AND u.user_id = ug.user_id  								AND u.user_allow_massemail = 1 -								AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ') -							ORDER BY u.user_lang, u.user_notify_type'; +								AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')', +							'ORDER_BY'	=> 'u.user_lang, u.user_notify_type', +						);  					}  					else  					{ -						$sql = 'SELECT username, username_clean, user_email, user_jabber, user_notify_type, user_lang -							FROM ' . USERS_TABLE . ' -							WHERE user_allow_massemail = 1 -								AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ') -							ORDER BY user_lang, user_notify_type'; +						$sql_ary = array( +							'SELECT'	=> 'u.username, u.username_clean, u.user_email, u.user_jabber, u.user_lang, u.user_notify_type', +							'FROM'		=> array( +								USERS_TABLE	=> 'u', +							), +							'WHERE'		=> 'u.user_allow_massemail = 1 +								AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')', +							'ORDER_BY'	=> 'u.user_lang, u.user_notify_type', +						);  					} + +					// Mail banned or not +					if (!isset($_REQUEST['mail_banned_flag'])) +					{ +						$sql_ary['WHERE'] .= ' AND (b.ban_id IS NULL +						        OR b.ban_exclude = 1)'; +						$sql_ary['LEFT_JOIN'] = array( +							array( +								'FROM'	=> array( +									BANLIST_TABLE	=> 'b', +								), +								'ON'	=> 'u.user_id = b.ban_userid', +							), +						); +					} +					$sql = $db->sql_build_query('SELECT', $sql_ary);  				}  				$result = $db->sql_query($sql);  				$row = $db->sql_fetchrow($result); diff --git a/phpBB/includes/acp/acp_icons.php b/phpBB/includes/acp/acp_icons.php index 3d64a2acda..24f6cbbcbf 100644 --- a/phpBB/includes/acp/acp_icons.php +++ b/phpBB/includes/acp/acp_icons.php @@ -394,6 +394,10 @@ class acp_icons  					{  						// skip images where add wasn't checked  					} +					else if (!file_exists($phpbb_root_path . $img_path . '/' . $image)) +					{ +						$errors[$image] = 'SMILIE_NO_FILE'; +					}  					else  					{  						if ($image_width[$image] == 0 || $image_height[$image] == 0) diff --git a/phpBB/includes/acp/acp_language.php b/phpBB/includes/acp/acp_language.php index c2cb2f9c11..598b390302 100644 --- a/phpBB/includes/acp/acp_language.php +++ b/phpBB/includes/acp/acp_language.php @@ -1055,14 +1055,14 @@ class acp_language  				$iso_src .= htmlspecialchars_decode($row['lang_author']);  				$compress->add_data($iso_src, 'language/' . $row['lang_iso'] . '/iso.txt'); -				// index.html files -				$compress->add_data('', 'language/' . $row['lang_iso'] . '/index.html'); -				$compress->add_data('', 'language/' . $row['lang_iso'] . '/email/index.html'); -				$compress->add_data('', 'language/' . $row['lang_iso'] . '/acp/index.html'); +				// index.htm files +				$compress->add_data('', 'language/' . $row['lang_iso'] . '/index.htm'); +				$compress->add_data('', 'language/' . $row['lang_iso'] . '/email/index.htm'); +				$compress->add_data('', 'language/' . $row['lang_iso'] . '/acp/index.htm');  				if (sizeof($mod_files))  				{ -					$compress->add_data('', 'language/' . $row['lang_iso'] . '/mods/index.html'); +					$compress->add_data('', 'language/' . $row['lang_iso'] . '/mods/index.htm');  				}  				$compress->close(); @@ -1217,7 +1217,7 @@ $lang = array_merge($lang, array(  ';  		// Language files in language root directory -		$this->main_files = array("common.$phpEx", "groups.$phpEx", "install.$phpEx", "mcp.$phpEx", "memberlist.$phpEx", "posting.$phpEx", "search.$phpEx", "ucp.$phpEx", "viewforum.$phpEx", "viewtopic.$phpEx", "help_bbcode.$phpEx", "help_faq.$phpEx"); +		$this->main_files = array("captcha_qa.$phpEx", "captcha_recaptcha.$phpEx", "common.$phpEx", "groups.$phpEx", "install.$phpEx", "mcp.$phpEx", "memberlist.$phpEx", "posting.$phpEx", "search.$phpEx", "ucp.$phpEx", "viewforum.$phpEx", "viewtopic.$phpEx", "help_bbcode.$phpEx", "help_faq.$phpEx");  	}  	/** diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php index b8712b2a3d..60cebe3c08 100644 --- a/phpBB/includes/acp/acp_main.php +++ b/phpBB/includes/acp/acp_main.php @@ -529,7 +529,7 @@ class acp_main  		);  		$log_data = array(); -		$log_count = 0; +		$log_count = false;  		if ($auth->acl_get('a_viewlogs'))  		{ diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index 2288a0728b..2e43b0545a 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -512,7 +512,7 @@ class acp_profile  					else if ($field_type == FIELD_INT && $key == 'field_default_value')  					{  						// Permit an empty string -						if (request_var('field_default_value', '') === '') +						if ($action == 'create' && request_var('field_default_value', '') === '')  						{  							$var = '';  						} diff --git a/phpBB/includes/acp/acp_search.php b/phpBB/includes/acp/acp_search.php index 930c8d2a26..0cd67b1c34 100644 --- a/phpBB/includes/acp/acp_search.php +++ b/phpBB/includes/acp/acp_search.php @@ -392,7 +392,18 @@ class acp_search  									AND post_id <= ' . (int) ($post_counter + $this->batch_size);  							$result = $db->sql_query($sql); -							while ($row = $db->sql_fetchrow($result)) +							$buffer = $db->sql_buffer_nested_transactions(); + +							if ($buffer) +							{ +								$rows = $db->sql_fetchrowset($result); +								$rows[] = false; // indicate end of array for while loop below + +								$db->sql_freeresult($result); +							} + +							$i = 0; +							while ($row = ($buffer ? $rows[$i++] : $db->sql_fetchrow($result)))  							{  								// Indexing enabled for this forum or global announcement?  								// Global announcements get indexed by default. @@ -402,7 +413,10 @@ class acp_search  								}  								$row_count++;  							} -							$db->sql_freeresult($result); +							if (!$buffer) +							{ +								$db->sql_freeresult($result); +							}  							$post_counter += $this->batch_size;  						} diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php index 2ccc728031..3bc8c86500 100644 --- a/phpBB/includes/acp/acp_styles.php +++ b/phpBB/includes/acp/acp_styles.php @@ -510,6 +510,7 @@ parse_css_file = {PARSE_CSS_FILE}  							$db->sql_transaction('commit');  							$cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE); +							$cache->destroy('imageset_site_logo_md5');  							add_log('admin', 'LOG_IMAGESET_REFRESHED', $imageset_row['imageset_name']);  							trigger_error($user->lang['IMAGESET_REFRESHED'] . adm_back_link($this->u_action)); @@ -716,7 +717,7 @@ parse_css_file = {PARSE_CSS_FILE}  		$save_changes	= (isset($_POST['save'])) ? true : false;  		// make sure template_file path doesn't go upwards -		$template_file = str_replace('..', '.', $template_file); +		$template_file = preg_replace('#\.{2,}#', '.', $template_file);  		// Retrieve some information about the template  		$sql = 'SELECT template_storedb, template_path, template_name @@ -1587,23 +1588,23 @@ parse_css_file = {PARSE_CSS_FILE}  		{  			case 'style':  				$sql_from = STYLES_TABLE; -				$sql_select = 'style_name'; +				$sql_select = 'style_id, style_name, template_id, theme_id, imageset_id';  				$sql_where = 'AND style_active = 1';  			break;  			case 'template':  				$sql_from = STYLES_TEMPLATE_TABLE; -				$sql_select = 'template_name, template_path, template_storedb'; +				$sql_select = 'template_id, template_name, template_path, template_storedb';  			break;  			case 'theme':  				$sql_from = STYLES_THEME_TABLE; -				$sql_select = 'theme_name, theme_path, theme_storedb'; +				$sql_select = 'theme_id, theme_name, theme_path, theme_storedb';  			break;  			case 'imageset':  				$sql_from = STYLES_IMAGESET_TABLE; -				$sql_select = 'imageset_name, imageset_path'; +				$sql_select = 'imageset_id, imageset_name, imageset_path';  			break;  		} @@ -1633,37 +1634,14 @@ parse_css_file = {PARSE_CSS_FILE}  			trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING);  		} -		$sql = "SELECT {$mode}_id, {$mode}_name -			FROM $sql_from -			WHERE {$mode}_id <> $style_id -			$sql_where -			ORDER BY {$mode}_name ASC"; -		$result = $db->sql_query($sql); - -		$s_options = ''; - -		if ($row = $db->sql_fetchrow($result)) -		{ -			do -			{ -				$s_options .= '<option value="' . $row[$mode . '_id'] . '">' . $row[$mode . '_name'] . '</option>'; -			} -			while ($row = $db->sql_fetchrow($result)); -		} -		else -		{ -			trigger_error($user->lang['ONLY_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING); -		} -		$db->sql_freeresult($result); -  		if ($update)  		{ -			$sql = "DELETE FROM $sql_from -				WHERE {$mode}_id = $style_id"; -			$db->sql_query($sql); -  			if ($mode == 'style')  			{ +				$sql = "DELETE FROM $sql_from +					WHERE {$mode}_id = $style_id"; +				$db->sql_query($sql); +  				$sql = 'UPDATE ' . USERS_TABLE . "  					SET user_style = $new_id  					WHERE user_style = $style_id"; @@ -1678,19 +1656,19 @@ parse_css_file = {PARSE_CSS_FILE}  				{  					set_config('default_style', $new_id);  				} + +				// Remove the components +				$components = array('template', 'theme', 'imageset'); +				foreach ($components as $component) +				{ +					$new_id = request_var('new_' . $component . '_id', 0); +					$component_id = $style_row[$component . '_id']; +					$this->remove_component($component, $component_id, $new_id, $style_id); +				}  			}  			else  			{ -				if ($mode == 'imageset') -				{ -					$sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . " -						WHERE imageset_id = $style_id"; -					$db->sql_query($sql); -				} -				$sql = 'UPDATE ' . STYLES_TABLE . " -					SET {$mode}_id = $new_id -					WHERE {$mode}_id = $style_id"; -				$db->sql_query($sql); +				$this->remove_component($mode, $style_id, $new_id);  			}  			$cache->destroy('sql', STYLES_TABLE); @@ -1700,11 +1678,12 @@ parse_css_file = {PARSE_CSS_FILE}  			trigger_error($user->lang[$message] . adm_back_link($this->u_action));  		} +		$this->display_component_options($mode, $style_row[$mode . '_id'], $style_row); +  		$this->page_title = 'DELETE_' . $l_prefix;  		$template->assign_vars(array(  			'S_DELETE'			=> true, -			'S_REPLACE_OPTIONS'	=> $s_options,  			'L_TITLE'			=> $user->lang[$this->page_title],  			'L_EXPLAIN'			=> $user->lang[$this->page_title . '_EXPLAIN'], @@ -1718,6 +1697,202 @@ parse_css_file = {PARSE_CSS_FILE}  			'NAME'			=> $style_row[$mode . '_name'],  			)  		); + +		if ($mode == 'style') +		{ +			$template->assign_vars(array( +				'S_DELETE_STYLE'		=> true, +			)); +		} +	} + +	/** +	* Remove template/theme/imageset entry from the database +	*/ +	function remove_component($component, $component_id, $new_id, $style_id = false) +	{ +		global $db; + +		if (($new_id == 0) || ($component === 'template' && ($conflicts = $this->check_inheritance($component, $component_id)))) +		{ +			// We can not delete the template, as the user wants to keep the component or an other template is inheriting from this one. +			return; +		} + +		$component_in_use = array(); +		if ($component != 'style') +		{ +			$component_in_use = $this->component_in_use($component, $component_id, $style_id); +		} + +		if (($new_id == -1) && !empty($component_in_use)) +		{ +			// We can not delete the component, as it is still in use +			return; +		} + +		if ($component == 'imageset') +		{ +			$sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . " +				WHERE imageset_id = $component_id"; +			$db->sql_query($sql); +		} + +		switch ($component) +		{ +			case 'template': +				$sql_from = STYLES_TEMPLATE_TABLE; +			break; + +			case 'theme': +				$sql_from = STYLES_THEME_TABLE; +			break; + +			case 'imageset': +				$sql_from = STYLES_IMAGESET_TABLE;; +			break; +		} + +		$sql = "DELETE FROM $sql_from +			WHERE {$component}_id = $component_id"; +		$db->sql_query($sql); + +		$sql = 'UPDATE ' . STYLES_TABLE . " +			SET {$component}_id = $new_id +			WHERE {$component}_id = $component_id"; +		$db->sql_query($sql); +	} + +	/** +	* Display the options which can be used to replace a style/template/theme/imageset +	*/ +	function display_component_options($component, $component_id, $style_row = false, $style_id = false) +	{ +		global $db, $template, $user; + +		$component_in_use = array(); +		if ($component != 'style') +		{ +			$component_in_use = $this->component_in_use($component, $component_id, $style_id); +		} + +		$sql_where = ''; +		switch ($component) +		{ +			case 'style': +				$sql_from = STYLES_TABLE; +				$sql_where = 'WHERE style_active = 1'; +			break; + +			case 'template': +				$sql_from = STYLES_TEMPLATE_TABLE; +				$sql_where = 'WHERE template_inherits_id <> ' . $component_id; +			break; + +			case 'theme': +				$sql_from = STYLES_THEME_TABLE; +			break; + +			case 'imageset': +				$sql_from = STYLES_IMAGESET_TABLE; +			break; +		} + +		$s_options = ''; +		if (($component != 'style') && empty($component_in_use)) +		{ +			$sql = "SELECT {$component}_id, {$component}_name +				FROM $sql_from +				WHERE {$component}_id = {$component_id}"; +			$result = $db->sql_query($sql); +			$row = $db->sql_fetchrow($result); +			$db->sql_freeresult($result); + +			$s_options .= '<option value="-1" selected="selected">' . $user->lang['DELETE_' . strtoupper($component)] . '</option>'; +			$s_options .= '<option value="0">' . sprintf($user->lang['KEEP_' . strtoupper($component)], $row[$component . '_name']) . '</option>'; +		} +		else +		{ +			$sql = "SELECT {$component}_id, {$component}_name +				FROM $sql_from +				$sql_where +				ORDER BY {$component}_name ASC"; +			$result = $db->sql_query($sql); + +			$s_keep_option = $s_options = ''; +			while ($row = $db->sql_fetchrow($result)) +			{ +				if ($row[$component . '_id'] != $component_id) +				{ +					$s_options .= '<option value="' . $row[$component . '_id'] . '">' . sprintf($user->lang['REPLACE_WITH_OPTION'], $row[$component . '_name']) . '</option>'; +				} +				else if ($component != 'style') +				{ +					$s_keep_option = '<option value="0" selected="selected">' . sprintf($user->lang['KEEP_' . strtoupper($component)], $row[$component . '_name']) . '</option>'; +				} +			} +			$db->sql_freeresult($result); +			$s_options = $s_keep_option . $s_options; +		} + +		if (!$style_row) +		{ +			$template->assign_var('S_REPLACE_' . strtoupper($component) . '_OPTIONS', $s_options); +		} +		else +		{ +			$template->assign_var('S_REPLACE_OPTIONS', $s_options); +			if ($component == 'style') +			{ +				$components = array('template', 'theme', 'imageset'); +				foreach ($components as $component) +				{ +					$this->display_component_options($component, $style_row[$component . '_id'], false, $component_id, true); +				} +			} +		} +	} + +	/** +	* Check whether the component is still used by another style or component +	*/ +	function component_in_use($component, $component_id, $style_id = false) +	{ +		global $db; + +		$component_in_use = array(); + +		if ($style_id) +		{ +			$sql = 'SELECT style_id, style_name +				FROM ' . STYLES_TABLE . " +				WHERE {$component}_id = {$component_id} +					AND style_id <> {$style_id} +				ORDER BY style_name ASC"; +		} +		else +		{ +			$sql = 'SELECT style_id, style_name +				FROM ' . STYLES_TABLE . " +				WHERE {$component}_id = {$component_id} +				ORDER BY style_name ASC"; +		} +		$result = $db->sql_query($sql); +		while ($row = $db->sql_fetchrow($result)) +		{ +			$component_in_use[] = $row['style_name']; +		} +		$db->sql_freeresult($result); + +		if ($component === 'template' && ($conflicts = $this->check_inheritance($component, $component_id))) +		{ +			foreach ($conflicts as $temp_id => $conflict_data) +			{ +				$component_in_use[] = $conflict_data['template_name']; +			} +		} + +		return $component_in_use;  	}  	/** diff --git a/phpBB/includes/acp/acp_words.php b/phpBB/includes/acp/acp_words.php index 1cb9545967..88c5bbe592 100644 --- a/phpBB/includes/acp/acp_words.php +++ b/phpBB/includes/acp/acp_words.php @@ -95,6 +95,9 @@ class acp_words  					trigger_error($user->lang['ENTER_WORD'] . adm_back_link($this->u_action), E_USER_WARNING);  				} +				// Replace multiple consecutive asterisks with single one as those are not needed +				$word = preg_replace('#\*{2,}#', '*', $word); +  				$sql_ary = array(  					'word'			=> $word,  					'replacement'	=> $replacement diff --git a/phpBB/includes/auth.php b/phpBB/includes/auth.php index 02819f9e78..5564de2943 100644 --- a/phpBB/includes/auth.php +++ b/phpBB/includes/auth.php @@ -109,6 +109,7 @@ class auth  	*/  	function _fill_acl($user_permissions)  	{ +		$seq_cache = array();  		$this->acl = array();  		$user_permissions = explode("\n", $user_permissions); @@ -125,8 +126,17 @@ class auth  				while ($subseq = substr($seq, $i, 6))  				{ +					if (isset($seq_cache[$subseq])) +					{ +						$converted = $seq_cache[$subseq]; +					} +					else +					{ +						$converted = $seq_cache[$subseq] = str_pad(base_convert($subseq, 36, 2), 31, 0, STR_PAD_LEFT); +					} +  					// We put the original bitstring into the acl array -					$this->acl[$f] .= str_pad(base_convert($subseq, 36, 2), 31, 0, STR_PAD_LEFT); +					$this->acl[$f] .= $converted;  					$i += 6;  				}  			} @@ -898,7 +908,7 @@ class auth  		$method = 'login_' . $method;  		if (function_exists($method))  		{ -			$login = $method($username, $password); +			$login = $method($username, $password, $user->ip, $user->browser, $user->forwarded_for);  			// If the auth module wants us to create an empty profile do so and then treat the status as LOGIN_SUCCESS  			if ($login['status'] == LOGIN_SUCCESS_CREATE_PROFILE) diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php index e04a6307e9..6ca69d9174 100644 --- a/phpBB/includes/auth/auth_db.php +++ b/phpBB/includes/auth/auth_db.php @@ -23,8 +23,21 @@ if (!defined('IN_PHPBB'))  /**  * Login function +* +* @param string $username +* @param string $password +* @param string $ip			IP address the login is taking place from. Used to +*							limit the number of login attempts per IP address. +* @param string $browser	The user agent used to login +* @param string $forwarded_for X_FORWARDED_FOR header sent with login request +* @return array				A associative array of the format +*							array( +*								'status' => status constant +*								'error_msg' => string +*								'user_row' => array +*							)  */ -function login_db(&$username, &$password) +function login_db($username, $password, $ip = '', $browser = '', $forwarded_for = '')  {  	global $db, $config; @@ -47,13 +60,51 @@ function login_db(&$username, &$password)  		);  	} +	$username_clean = utf8_clean_string($username); +  	$sql = 'SELECT user_id, username, user_password, user_passchg, user_pass_convert, user_email, user_type, user_login_attempts  		FROM ' . USERS_TABLE . " -		WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; +		WHERE username_clean = '" . $db->sql_escape($username_clean) . "'";  	$result = $db->sql_query($sql);  	$row = $db->sql_fetchrow($result);  	$db->sql_freeresult($result); +	if (($ip && !$config['ip_login_limit_use_forwarded']) || +		($forwarded_for && $config['ip_login_limit_use_forwarded'])) +	{ +		$sql = 'SELECT COUNT(*) AS attempts +			FROM ' . LOGIN_ATTEMPT_TABLE . ' +			WHERE attempt_time > ' . (time() - (int) $config['ip_login_limit_time']); +		if ($config['ip_login_limit_use_forwarded']) +		{ +			$sql .= " AND attempt_forwarded_for = '" . $db->sql_escape($forwarded_for) . "'"; +		} +		else +		{ +			$sql .= " AND attempt_ip = '" . $db->sql_escape($ip) . "' "; +		} + +		$result = $db->sql_query($sql); +		$attempts = (int) $db->sql_fetchfield('attempts'); +		$db->sql_freeresult($result); + +		$attempt_data = array( +			'attempt_ip'			=> $ip, +			'attempt_browser'		=> trim(substr($browser, 0, 149)), +			'attempt_forwarded_for'	=> $forwarded_for, +			'attempt_time'			=> time(), +			'user_id'				=> ($row) ? (int) $row['user_id'] : 0, +			'username'				=> $username, +			'username_clean'		=> $username_clean, +		); +		$sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $db->sql_build_array('INSERT', $attempt_data); +		$result = $db->sql_query($sql); +	} +	else +	{ +		$attempts = 0; +	} +  	if (!$row)  	{  		return array( @@ -62,7 +113,9 @@ function login_db(&$username, &$password)  			'user_row'	=> array('user_id' => ANONYMOUS),  		);  	} -	$show_captcha = $config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts']; + +	$show_captcha = ($config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts']) || +		($config['ip_login_limit_max'] && $attempts >= $config['ip_login_limit_max']);  	// If there are too much login attempts, we need to check for an confirm image  	// Every auth module is able to define what to do by itself... @@ -90,7 +143,7 @@ function login_db(&$username, &$password)  		{  			$captcha->reset();  		} -		 +  	}  	// If the password convert flag is set we need to convert it @@ -165,6 +218,10 @@ function login_db(&$username, &$password)  			$row['user_password'] = $hash;  		} +		$sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' +			WHERE user_id = ' . $row['user_id']; +		$db->sql_query($sql); +  		if ($row['user_login_attempts'] != 0)  		{  			// Successful, reset login attempts (the user passed all stages) diff --git a/phpBB/includes/auth/auth_ldap.php b/phpBB/includes/auth/auth_ldap.php index e8c957aaa3..5dfa74ddab 100644 --- a/phpBB/includes/auth/auth_ldap.php +++ b/phpBB/includes/auth/auth_ldap.php @@ -335,7 +335,7 @@ function acp_ldap(&$new)  	</dl>  	<dl>  		<dt><label for="ldap_password">' . $user->lang['LDAP_PASSWORD'] . ':</label><br /><span>' . $user->lang['LDAP_PASSWORD_EXPLAIN'] . '</span></dt> -		<dd><input type="password" id="ldap_password" size="40" name="config[ldap_password]" value="' . $new['ldap_password'] . '" /></dd> +		<dd><input type="password" id="ldap_password" size="40" name="config[ldap_password]" value="' . $new['ldap_password'] . '" autocomplete="off" /></dd>  	</dl>  	'; diff --git a/phpBB/includes/cache.php b/phpBB/includes/cache.php index b50fab4ca2..612adcca4f 100644 --- a/phpBB/includes/cache.php +++ b/phpBB/includes/cache.php @@ -82,26 +82,9 @@ class cache extends acm  			$result = $db->sql_query($sql);  			$censors = array(); -			$unicode = ((version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>='))) && @preg_match('/\p{L}/u', 'a') !== false) ? true : false; -  			while ($row = $db->sql_fetchrow($result))  			{ -				if ($unicode) -				{ -					// Unescape the asterisk to simplify further conversions -					$row['word'] = str_replace('\*', '*', preg_quote($row['word'], '#')); -					 -					// Replace the asterisk inside the pattern, at the start and at the end of it with regexes -					$row['word'] = preg_replace(array('#(?<=[\p{Nd}\p{L}_])\*(?=[\p{Nd}\p{L}_])#iu', '#^\*#', '#\*$#'), array('([\x20]*?|[\p{Nd}\p{L}_-]*?)', '[\p{Nd}\p{L}_-]*?', '[\p{Nd}\p{L}_-]*?'), $row['word']); - -					// Generate the final substitution -					$censors['match'][] = '#(?<![\p{Nd}\p{L}_-])(' . $row['word'] . ')(?![\p{Nd}\p{L}_-])#iu'; -				} -				else -				{ -					$censors['match'][] = '#(?<!\S)(' . str_replace('\*', '\S*?', preg_quote($row['word'], '#')) . ')(?!\S)#iu'; -				} - +				$censors['match'][] = get_censor_preg_expression($row['word']);  				$censors['replace'][] = $row['replacement'];  			}  			$db->sql_freeresult($result); diff --git a/phpBB/includes/captcha/captcha_gd.php b/phpBB/includes/captcha/captcha_gd.php index 96e39af85b..ecdad43978 100644 --- a/phpBB/includes/captcha/captcha_gd.php +++ b/phpBB/includes/captcha/captcha_gd.php @@ -77,7 +77,7 @@ class captcha  		{  			$denom = ($code_len - $i);  			$denom = max(1.3, $denom); -			$offset[$i] = mt_rand(0, (1.5 * $width_avail) / $denom); +			$offset[$i] = phpbb_mt_rand(0, (int) round((1.5 * $width_avail) / $denom));  			$width_avail -= $offset[$i];  		} @@ -112,7 +112,7 @@ class captcha  			$noise_bitmaps = $this->captcha_noise_bg_bitmaps();  			for ($i = 0; $i < $code_len; ++$i)  			{ -				$noise[$i] = new char_cube3d($noise_bitmaps, mt_rand(1, count($noise_bitmaps['data']))); +				$noise[$i] = new char_cube3d($noise_bitmaps, mt_rand(1, sizeof($noise_bitmaps['data'])));  				list($min, $max) = $noise[$i]->range();  				//$box = $noise[$i]->dimensions($sizes[$i]); @@ -1669,32 +1669,32 @@ class captcha  			'height'	=> 15,  			'data'		=> array( -			'A' =>	$chars['A'][mt_rand(0, min(count($chars['A']), $config['captcha_gd_fonts']) -1)], -			'B' =>	$chars['B'][mt_rand(0, min(count($chars['B']), $config['captcha_gd_fonts']) -1)], -			'C' =>	$chars['C'][mt_rand(0, min(count($chars['C']), $config['captcha_gd_fonts']) -1)], -			'D' =>	$chars['D'][mt_rand(0, min(count($chars['D']), $config['captcha_gd_fonts']) -1)], -			'E' =>	$chars['E'][mt_rand(0, min(count($chars['E']), $config['captcha_gd_fonts']) -1)], -			'F' =>	$chars['F'][mt_rand(0, min(count($chars['F']), $config['captcha_gd_fonts']) -1)], -			'G' =>	$chars['G'][mt_rand(0, min(count($chars['G']), $config['captcha_gd_fonts']) -1)], -			'H' =>	$chars['H'][mt_rand(0, min(count($chars['H']), $config['captcha_gd_fonts']) -1)], -			'I' =>	$chars['I'][mt_rand(0, min(count($chars['I']), $config['captcha_gd_fonts']) -1)], -			'J' =>	$chars['J'][mt_rand(0, min(count($chars['J']), $config['captcha_gd_fonts']) -1)], -			'K' =>	$chars['K'][mt_rand(0, min(count($chars['K']), $config['captcha_gd_fonts']) -1)], -			'L' =>	$chars['L'][mt_rand(0, min(count($chars['L']), $config['captcha_gd_fonts']) -1)], -			'M' =>	$chars['M'][mt_rand(0, min(count($chars['M']), $config['captcha_gd_fonts']) -1)],   -			'N' =>	$chars['N'][mt_rand(0, min(count($chars['N']), $config['captcha_gd_fonts']) -1)], -			'O' =>	$chars['O'][mt_rand(0, min(count($chars['O']), $config['captcha_gd_fonts']) -1)], -			'P' =>	$chars['P'][mt_rand(0, min(count($chars['P']), $config['captcha_gd_fonts']) -1)], -			'Q' =>	$chars['Q'][mt_rand(0, min(count($chars['Q']), $config['captcha_gd_fonts']) -1)], -			'R' =>	$chars['R'][mt_rand(0, min(count($chars['R']), $config['captcha_gd_fonts']) -1)], -			'S' =>	$chars['S'][mt_rand(0, min(count($chars['S']), $config['captcha_gd_fonts']) -1)], -			'T' =>	$chars['T'][mt_rand(0, min(count($chars['T']), $config['captcha_gd_fonts']) -1)], -			'U' =>	$chars['U'][mt_rand(0, min(count($chars['U']), $config['captcha_gd_fonts']) -1)], -			'V' =>	$chars['V'][mt_rand(0, min(count($chars['V']), $config['captcha_gd_fonts']) -1)], -			'W' =>	$chars['W'][mt_rand(0, min(count($chars['W']), $config['captcha_gd_fonts']) -1)], -			'X' =>	$chars['X'][mt_rand(0, min(count($chars['X']), $config['captcha_gd_fonts']) -1)], -			'Y' =>	$chars['Y'][mt_rand(0, min(count($chars['Y']), $config['captcha_gd_fonts']) -1)], -			'Z' =>	$chars['Z'][mt_rand(0, min(count($chars['Z']), $config['captcha_gd_fonts']) -1)], +			'A' =>	$chars['A'][mt_rand(0, min(sizeof($chars['A']), $config['captcha_gd_fonts']) -1)], +			'B' =>	$chars['B'][mt_rand(0, min(sizeof($chars['B']), $config['captcha_gd_fonts']) -1)], +			'C' =>	$chars['C'][mt_rand(0, min(sizeof($chars['C']), $config['captcha_gd_fonts']) -1)], +			'D' =>	$chars['D'][mt_rand(0, min(sizeof($chars['D']), $config['captcha_gd_fonts']) -1)], +			'E' =>	$chars['E'][mt_rand(0, min(sizeof($chars['E']), $config['captcha_gd_fonts']) -1)], +			'F' =>	$chars['F'][mt_rand(0, min(sizeof($chars['F']), $config['captcha_gd_fonts']) -1)], +			'G' =>	$chars['G'][mt_rand(0, min(sizeof($chars['G']), $config['captcha_gd_fonts']) -1)], +			'H' =>	$chars['H'][mt_rand(0, min(sizeof($chars['H']), $config['captcha_gd_fonts']) -1)], +			'I' =>	$chars['I'][mt_rand(0, min(sizeof($chars['I']), $config['captcha_gd_fonts']) -1)], +			'J' =>	$chars['J'][mt_rand(0, min(sizeof($chars['J']), $config['captcha_gd_fonts']) -1)], +			'K' =>	$chars['K'][mt_rand(0, min(sizeof($chars['K']), $config['captcha_gd_fonts']) -1)], +			'L' =>	$chars['L'][mt_rand(0, min(sizeof($chars['L']), $config['captcha_gd_fonts']) -1)], +			'M' =>	$chars['M'][mt_rand(0, min(sizeof($chars['M']), $config['captcha_gd_fonts']) -1)],   +			'N' =>	$chars['N'][mt_rand(0, min(sizeof($chars['N']), $config['captcha_gd_fonts']) -1)], +			'O' =>	$chars['O'][mt_rand(0, min(sizeof($chars['O']), $config['captcha_gd_fonts']) -1)], +			'P' =>	$chars['P'][mt_rand(0, min(sizeof($chars['P']), $config['captcha_gd_fonts']) -1)], +			'Q' =>	$chars['Q'][mt_rand(0, min(sizeof($chars['Q']), $config['captcha_gd_fonts']) -1)], +			'R' =>	$chars['R'][mt_rand(0, min(sizeof($chars['R']), $config['captcha_gd_fonts']) -1)], +			'S' =>	$chars['S'][mt_rand(0, min(sizeof($chars['S']), $config['captcha_gd_fonts']) -1)], +			'T' =>	$chars['T'][mt_rand(0, min(sizeof($chars['T']), $config['captcha_gd_fonts']) -1)], +			'U' =>	$chars['U'][mt_rand(0, min(sizeof($chars['U']), $config['captcha_gd_fonts']) -1)], +			'V' =>	$chars['V'][mt_rand(0, min(sizeof($chars['V']), $config['captcha_gd_fonts']) -1)], +			'W' =>	$chars['W'][mt_rand(0, min(sizeof($chars['W']), $config['captcha_gd_fonts']) -1)], +			'X' =>	$chars['X'][mt_rand(0, min(sizeof($chars['X']), $config['captcha_gd_fonts']) -1)], +			'Y' =>	$chars['Y'][mt_rand(0, min(sizeof($chars['Y']), $config['captcha_gd_fonts']) -1)], +			'Z' =>	$chars['Z'][mt_rand(0, min(sizeof($chars['Z']), $config['captcha_gd_fonts']) -1)],  			'1' => array(  				array(0,0,0,1,1,0,0,0,0), diff --git a/phpBB/includes/captcha/captcha_gd_wave.php b/phpBB/includes/captcha/captcha_gd_wave.php index f706c98d43..27422513d9 100644 --- a/phpBB/includes/captcha/captcha_gd_wave.php +++ b/phpBB/includes/captcha/captcha_gd_wave.php @@ -62,8 +62,8 @@ class captcha  				'y' => mt_rand(10, 17)  			),  			'lower_left'	=> array( -				'x' => mt_rand($img_x - 5, $img_x - 45), -				'y' => mt_rand($img_y - 0, $img_y - 15) +				'x' => mt_rand($img_x - 45, $img_x - 5), +				'y' => mt_rand($img_y - 15, $img_y - 0),  			),  		); diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 49a64b9339..45f76bd676 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -319,7 +319,7 @@ class phpbb_captcha_qa  					),  					'PRIMARY_KEY'		=> 'question_id',  					'KEYS'				=> array( -						'lang_iso'			=> array('INDEX', 'lang_iso'), +						'lang'			=> array('INDEX', 'lang_iso'),  					),  				),  				CAPTCHA_ANSWERS_TABLE		=> array ( @@ -328,7 +328,7 @@ class phpbb_captcha_qa  						'answer_text'	=> array('STEXT_UNI', ''),  					),  					'KEYS'				=> array( -						'question_id'			=> array('INDEX', 'question_id'), +						'qid'			=> array('INDEX', 'question_id'),  					),  				),  				CAPTCHA_QA_CONFIRM_TABLE		=> array ( diff --git a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php index ea171dbe2c..0b0270f568 100644 --- a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php @@ -27,9 +27,14 @@ if (!class_exists('phpbb_default_captcha'))  */  class phpbb_recaptcha extends phpbb_default_captcha  { -	var $recaptcha_server = 'http://api.recaptcha.net'; -	var $recaptcha_server_secure = 'https://api-secure.recaptcha.net'; // class constants :( -	var $recaptcha_verify_server = 'api-verify.recaptcha.net'; +	var $recaptcha_server = 'http://www.google.com/recaptcha/api'; +	var $recaptcha_server_secure = 'https://www.google.com/recaptcha/api'; // class constants :( + +	// We are opening a socket to port 80 of this host and send +	// the POST request asking for verification to the path specified here. +	var $recaptcha_verify_server = 'www.google.com'; +	var $recaptcha_verify_path = '/recaptcha/api/verify'; +  	var $challenge;  	var $response; @@ -296,7 +301,7 @@ class phpbb_recaptcha extends phpbb_default_captcha  			return $user->lang['RECAPTCHA_INCORRECT'];  		} -		$response = $this->_recaptcha_http_post($this->recaptcha_verify_server, '/verify', +		$response = $this->_recaptcha_http_post($this->recaptcha_verify_server, $this->recaptcha_verify_path,  			array(  				'privatekey'	=> $config['recaptcha_privkey'],  				'remoteip'		=> $user->ip, diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index af2a6ebd24..3940888216 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -25,7 +25,7 @@ if (!defined('IN_PHPBB'))  */  // phpBB Version -define('PHPBB_VERSION', '3.0.8'); +define('PHPBB_VERSION', '3.0.9');  // QA-related  // define('PHPBB_QA', 1); @@ -173,6 +173,9 @@ define('BBCODE_UID_LEN', 8);  // Number of core BBCodes  define('NUM_CORE_BBCODES', 12); +// BBCode hard limit +define('BBCODE_LIMIT', 1511); +  // Smiley hard limit  define('SMILEY_LIMIT', 1000); @@ -233,6 +236,7 @@ define('GROUPS_TABLE',				$table_prefix . 'groups');  define('ICONS_TABLE',				$table_prefix . 'icons');  define('LANG_TABLE',				$table_prefix . 'lang');  define('LOG_TABLE',					$table_prefix . 'log'); +define('LOGIN_ATTEMPT_TABLE',		$table_prefix . 'login_attempts');  define('MODERATOR_CACHE_TABLE',		$table_prefix . 'moderator_cache');  define('MODULES_TABLE',				$table_prefix . 'modules');  define('POLL_OPTIONS_TABLE',		$table_prefix . 'poll_options'); @@ -275,4 +279,4 @@ define('ZEBRA_TABLE',				$table_prefix . 'zebra');  // Additional tables -?>
\ No newline at end of file +?> diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index f4b181c6ad..50e308dea2 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -417,6 +417,11 @@ class phpbb_db_tools  			// here lies an array, filled with information compiled on the column's data  			$prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data); +			if (isset($prepared_column['auto_increment']) && strlen($column_name) > 26) // "${column_name}_gen" +			{ +				trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR); +			} +  			// here we add the definition of the new column to the list of columns  			switch ($this->sql_layer)  			{ @@ -538,7 +543,7 @@ class phpbb_db_tools  			break;  			case 'oracle': -				$table_sql .= "\n);"; +				$table_sql .= "\n)";  				$statements[] = $table_sql;  				// do we need to add a sequence and a tigger for auto incrementing columns? @@ -556,7 +561,7 @@ class phpbb_db_tools  					$trigger .= "BEGIN\n";  					$trigger .= "\tSELECT {$table_name}_seq.nextval\n";  					$trigger .= "\tINTO :new.{$create_sequence}\n"; -					$trigger .= "\tFROM dual\n"; +					$trigger .= "\tFROM dual;\n";  					$trigger .= "END;";  					$statements[] = $trigger; @@ -566,7 +571,13 @@ class phpbb_db_tools  			case 'firebird':  				if ($create_sequence)  				{ -					$statements[] = "CREATE SEQUENCE {$table_name}_seq;"; +					$statements[] = "CREATE GENERATOR {$table_name}_gen;"; +					$statements[] = "SET GENERATOR {$table_name}_gen TO 0;"; + +					$trigger = "CREATE TRIGGER t_$table_name FOR $table_name\n"; +					$trigger .= "BEFORE INSERT\nAS\nBEGIN\n"; +					$trigger .= "\tNEW.{$create_sequence} = GEN_ID({$table_name}_gen, 1);\nEND;"; +					$statements[] = $trigger;  				}  			break;  		} @@ -638,6 +649,19 @@ class phpbb_db_tools  			$sqlite = true;  		} +		// Add tables? +		if (!empty($schema_changes['add_tables'])) +		{ +			foreach ($schema_changes['add_tables'] as $table => $table_data) +			{ +				$result = $this->sql_create_table($table, $table_data); +				if ($this->return_statements) +				{ +					$statements = array_merge($statements, $result); +				} +			} +		} +  		// Change columns?  		if (!empty($schema_changes['change_columns']))  		{ @@ -681,10 +705,12 @@ class phpbb_db_tools  			{  				foreach ($columns as $column_name => $column_data)  				{ -					// Only add the column if it does not exist yet, else change it (to be consistent) +					// Only add the column if it does not exist yet  					if ($column_exists = $this->sql_column_exists($table, $column_name))  					{ -						$result = $this->sql_column_change($table, $column_name, $column_data, true); +						continue; +						// This is commented out here because it can take tremendous time on updates +//						$result = $this->sql_column_change($table, $column_name, $column_data, true);  					}  					else  					{ @@ -695,7 +721,8 @@ class phpbb_db_tools  					{  						if ($column_exists)  						{ -							$sqlite_data[$table]['change_columns'][] = $result; +							continue; +//							$sqlite_data[$table]['change_columns'][] = $result;  						}  						else  						{ @@ -717,6 +744,11 @@ class phpbb_db_tools  			{  				foreach ($indexes as $index_name)  				{ +					if (!$this->sql_index_exists($table, $index_name)) +					{ +						continue; +					} +  					$result = $this->sql_index_drop($table, $index_name);  					if ($this->return_statements) @@ -777,6 +809,11 @@ class phpbb_db_tools  			{  				foreach ($index_array as $index_name => $column)  				{ +					if ($this->sql_unique_index_exists($table, $index_name)) +					{ +						continue; +					} +  					$result = $this->sql_create_unique_index($table, $index_name, $column);  					if ($this->return_statements) @@ -794,6 +831,11 @@ class phpbb_db_tools  			{  				foreach ($index_array as $index_name => $column)  				{ +					if ($this->sql_index_exists($table, $index_name)) +					{ +						continue; +					} +  					$result = $this->sql_create_index($table, $index_name, $column);  					if ($this->return_statements) @@ -1103,6 +1145,236 @@ class phpbb_db_tools  	}  	/** +	* Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes. +	* +	* @param string	$table_name		Table to check the index at +	* @param string	$index_name		The index name to check +	* +	* @return bool True if index exists, else false +	*/ +	function sql_index_exists($table_name, $index_name) +	{ +		if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') +		{ +			$sql = "EXEC sp_statistics '$table_name'"; +			$result = $this->db->sql_query($sql); + +			while ($row = $this->db->sql_fetchrow($result)) +			{ +				if ($row['TYPE'] == 3) +				{ +					if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) +					{ +						$this->db->sql_freeresult($result); +						return true; +					} +				} +			} +			$this->db->sql_freeresult($result); + +			return false; +		} + +		switch ($this->sql_layer) +		{ +			case 'firebird': +				$sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name +					FROM RDB\$INDICES +					WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "' +						AND RDB\$UNIQUE_FLAG IS NULL +						AND RDB\$FOREIGN_KEY IS NULL"; +				$col = 'index_name'; +			break; + +			case 'postgres': +				$sql = "SELECT ic.relname as index_name +					FROM pg_class bc, pg_class ic, pg_index i +					WHERE (bc.oid = i.indrelid) +						AND (ic.oid = i.indexrelid) +						AND (bc.relname = '" . $table_name . "') +						AND (i.indisunique != 't') +						AND (i.indisprimary != 't')"; +				$col = 'index_name'; +			break; + +			case 'mysql_40': +			case 'mysql_41': +				$sql = 'SHOW KEYS +					FROM ' . $table_name; +				$col = 'Key_name'; +			break; + +			case 'oracle': +				$sql = "SELECT index_name +					FROM user_indexes +					WHERE table_name = '" . strtoupper($table_name) . "' +						AND generated = 'N' +						AND uniqueness = 'NONUNIQUE'"; +				$col = 'index_name'; +			break; + +			case 'sqlite': +				$sql = "PRAGMA index_list('" . $table_name . "');"; +				$col = 'name'; +			break; +		} + +		$result = $this->db->sql_query($sql); +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique']) +			{ +				continue; +			} + +			// These DBMS prefix index name with the table name +			switch ($this->sql_layer) +			{ +				case 'firebird': +				case 'oracle': +				case 'postgres': +				case 'sqlite': +					$row[$col] = substr($row[$col], strlen($table_name) + 1); +				break; +			} + +			if (strtolower($row[$col]) == strtolower($index_name)) +			{ +				$this->db->sql_freeresult($result); +				return true; +			} +		} +		$this->db->sql_freeresult($result); + +		return false; +	} + +	/** +	* Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes. +	* +	* @param string	$table_name		Table to check the index at +	* @param string	$index_name		The index name to check +	* +	* @return bool True if index exists, else false +	*/ +	function sql_unique_index_exists($table_name, $index_name) +	{ +		if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') +		{ +			$sql = "EXEC sp_statistics '$table_name'"; +			$result = $this->db->sql_query($sql); + +			while ($row = $this->db->sql_fetchrow($result)) +			{ +				// Usually NON_UNIQUE is the column we want to check, but we allow for both +				if ($row['TYPE'] == 3) +				{ +					if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) +					{ +						$this->db->sql_freeresult($result); +						return true; +					} +				} +			} +			$this->db->sql_freeresult($result); +			return false; +		} + +		switch ($this->sql_layer) +		{ +			case 'firebird': +				$sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name +					FROM RDB\$INDICES +					WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "' +						AND RDB\$UNIQUE_FLAG IS NOT NULL +						AND RDB\$FOREIGN_KEY IS NULL"; +				$col = 'index_name'; +			break; + +			case 'postgres': +				$sql = "SELECT ic.relname as index_name, i.indisunique +					FROM pg_class bc, pg_class ic, pg_index i +					WHERE (bc.oid = i.indrelid) +						AND (ic.oid = i.indexrelid) +						AND (bc.relname = '" . $table_name . "') +						AND (i.indisprimary != 't')"; +				$col = 'index_name'; +			break; + +			case 'mysql_40': +			case 'mysql_41': +				$sql = 'SHOW KEYS +					FROM ' . $table_name; +				$col = 'Key_name'; +			break; + +			case 'oracle': +				$sql = "SELECT index_name, table_owner +					FROM user_indexes +					WHERE table_name = '" . strtoupper($table_name) . "' +						AND generated = 'N' +						AND uniqueness = 'UNIQUE'"; +				$col = 'index_name'; +			break; + +			case 'sqlite': +				$sql = "PRAGMA index_list('" . $table_name . "');"; +				$col = 'name'; +			break; +		} + +		$result = $this->db->sql_query($sql); +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && ($row['Non_unique'] || $row[$col] == 'PRIMARY')) +			{ +				continue; +			} + +			if ($this->sql_layer == 'sqlite' && !$row['unique']) +			{ +				continue; +			} + +			if ($this->sql_layer == 'postgres' && $row['indisunique'] != 't') +			{ +				continue; +			} + +			// These DBMS prefix index name with the table name +			switch ($this->sql_layer) +			{ +				case 'oracle': +					// Two cases here... prefixed with U_[table_owner] and not prefixed with table_name +					if (strpos($row[$col], 'U_') === 0) +					{ +						$row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1); +					} +					else if (strpos($row[$col], strtoupper($table_name)) === 0) +					{ +						$row[$col] = substr($row[$col], strlen($table_name) + 1); +					} +				break; + +				case 'firebird': +				case 'postgres': +				case 'sqlite': +					$row[$col] = substr($row[$col], strlen($table_name) + 1); +				break; +			} + +			if (strtolower($row[$col]) == strtolower($index_name)) +			{ +				$this->db->sql_freeresult($result); +				return true; +			} +		} +		$this->db->sql_freeresult($result); + +		return false; +	} + +	/**  	* Private method for performing sql statements (either execute them or return them)  	* @access private  	*/ @@ -1139,6 +1411,11 @@ class phpbb_db_tools  	*/  	function sql_prepare_column_data($table_name, $column_name, $column_data)  	{ +		if (strlen($column_name) > 30) +		{ +			trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); +		} +  		// Get type  		if (strpos($column_data[0], ':') !== false)  		{ @@ -1371,24 +1648,29 @@ class phpbb_db_tools  		switch ($this->sql_layer)  		{  			case 'firebird': +				// Does not support AFTER statement, only POSITION (and there you need the column position)  				$statements[] = 'ALTER TABLE ' . $table_name . ' ADD "' . strtoupper($column_name) . '" ' . $column_data['column_type_sql'];  			break;  			case 'mssql':  			case 'mssqlnative': +				// Does not support AFTER, only through temporary table  				$statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default'];  			break;  			case 'mysql_40':  			case 'mysql_41': -				$statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql']; +				$after = (!empty($column_data['after'])) ? ' AFTER ' . $column_data['after'] : ''; +				$statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'] . $after;  			break;  			case 'oracle': +				// Does not support AFTER, only through temporary table  				$statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql'];  			break;  			case 'postgres': +				// Does not support AFTER, only through temporary table  				if (version_compare($this->db->sql_server_info(true), '8.0', '>='))  				{  					$statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql']; @@ -1774,6 +2056,13 @@ class phpbb_db_tools  	{  		$statements = array(); +		$table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) +		if (strlen($table_name . $index_name) - strlen($table_prefix) > 24) +		{ +			$max_length = $table_prefix + 24; +			trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR); +		} +  		switch ($this->sql_layer)  		{  			case 'firebird': @@ -1804,6 +2093,13 @@ class phpbb_db_tools  	{  		$statements = array(); +		$table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) +		if (strlen($table_name . $index_name) - strlen($table_prefix) > 24) +		{ +			$max_length = $table_prefix + 24; +			trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR); +		} +  		// remove index length unless MySQL4  		if ('mysql_40' != $this->sql_layer)  		{ @@ -1957,6 +2253,7 @@ class phpbb_db_tools  				}  				else  				{ +					// TODO: try to change pkey without removing trigger, generator or constraints. ATM this query may fail.  					$statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql_type'];  				}  			break; diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php index eeddf1f41b..9b45c085a2 100644 --- a/phpBB/includes/db/dbal.php +++ b/phpBB/includes/db/dbal.php @@ -242,6 +242,16 @@ class dbal  	}  	/** +	* Returns whether results of a query need to be buffered to run a transaction while iterating over them. +	* +	* @return bool Whether buffering is required. +	*/ +	function sql_buffer_nested_transactions() +	{ +		return false; +	} + +	/**  	* SQL Transaction  	* @access private  	*/ @@ -767,7 +777,7 @@ class dbal  							</div>  						</div>  						<div id="page-footer"> -							Powered by phpBB © 2000, 2002, 2005, 2007 <a href="http://www.phpbb.com/">phpBB Group</a> +							Powered by <a href="http://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Group  						</div>  					</div>  					</body> diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/firebird.php index 6f60dd5dad..7e3f15ed1d 100644 --- a/phpBB/includes/db/firebird.php +++ b/phpBB/includes/db/firebird.php @@ -28,6 +28,7 @@ class dbal_firebird extends dbal  	var $last_query_text = '';  	var $service_handle = false;  	var $affected_rows = 0; +	var $connect_error = '';  	/**  	* Connect to server @@ -53,9 +54,35 @@ class dbal_firebird extends dbal  			$use_database = $this->server . ':' . $this->dbname;  		} -		$this->db_connect_id = ($this->persistency) ? @ibase_pconnect($use_database, $this->user, $sqlpassword, false, false, 3) : @ibase_connect($use_database, $this->user, $sqlpassword, false, false, 3); +		if ($this->persistency) +		{ +			if (!function_exists('ibase_pconnect')) +			{ +				$this->connect_error = 'ibase_pconnect function does not exist, is interbase extension installed?'; +				return $this->sql_error(''); +			} +			$this->db_connect_id = @ibase_pconnect($use_database, $this->user, $sqlpassword, false, false, 3); +		} +		else +		{ +			if (!function_exists('ibase_connect')) +			{ +				$this->connect_error = 'ibase_connect function does not exist, is interbase extension installed?'; +				return $this->sql_error(''); +			} +			$this->db_connect_id = @ibase_connect($use_database, $this->user, $sqlpassword, false, false, 3); +		} -		$this->service_handle = (function_exists('ibase_service_attach') && $this->server) ? @ibase_service_attach($this->server, $this->user, $sqlpassword) : false; +		// Do not call ibase_service_attach if connection failed, +		// otherwise error message from ibase_(p)connect call will be clobbered. +		if ($this->db_connect_id && function_exists('ibase_service_attach') && $this->server) +		{ +			$this->service_handle = @ibase_service_attach($this->server, $this->user, $sqlpassword); +		} +		else +		{ +			$this->service_handle = false; +		}  		return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');  	} @@ -471,8 +498,24 @@ class dbal_firebird extends dbal  	*/  	function _sql_error()  	{ +		// Need special handling here because ibase_errmsg returns +		// connection errors, however if the interbase extension +		// is not installed then ibase_errmsg does not exist and +		// we cannot call it. +		if (function_exists('ibase_errmsg')) +		{ +			$msg = @ibase_errmsg(); +			if (!$msg) +			{ +				$msg = $this->connect_error; +			} +		} +		else +		{ +			$msg = $this->connect_error; +		}  		return array( -			'message'	=> @ibase_errmsg(), +			'message'	=> $msg,  			'code'		=> (@function_exists('ibase_errcode') ? @ibase_errcode() : '')  		);  	} diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index 7ed4146f27..6810562d17 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -50,7 +50,7 @@ class result_mssqlnative  			}  		} -		$this->m_row_count = count($this->m_rows); +		$this->m_row_count = sizeof($this->m_rows);  	}  	private function array_to_obj($array, &$obj) @@ -259,6 +259,14 @@ class dbal_mssqlnative extends dbal  	}  	/** +	* {@inheritDoc} +	*/ +	function sql_buffer_nested_transactions() +	{ +		return true; +	} + +	/**  	* SQL Transaction  	* @access private  	*/ @@ -628,7 +636,7 @@ class dbal_mssqlnative extends dbal  			return false;  		}  	} -	 +  	/**  	* Allows setting mssqlnative specific query options passed to sqlsrv_query as 4th parameter.  	*/ diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php index c8a9a5f604..62b36aa8bf 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/oracle.php @@ -269,11 +269,12 @@ class dbal_oracle extends dbal  						{  							$cols = explode(', ', $regs[2]); +							preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER); +  /*						The code inside this comment block breaks clob handling, but does allow the  						database restore script to work.  If you want to allow no posts longer than 4KB  						and/or need the db restore script, uncomment this. -							preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER);  							if (sizeof($cols) !== sizeof($vals))  							{ diff --git a/phpBB/includes/db/postgres.php b/phpBB/includes/db/postgres.php index 4360c790a1..bb116e0763 100644 --- a/phpBB/includes/db/postgres.php +++ b/phpBB/includes/db/postgres.php @@ -18,6 +18,11 @@ if (!defined('IN_PHPBB'))  include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); +if (!class_exists('phpbb_error_collector')) +{ +	include($phpbb_root_path . 'includes/error_collector.' . $phpEx); +} +  /**  * PostgreSQL Database Abstraction Layer  * Minimum Requirement is Version 7.3+ @@ -26,6 +31,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);  class dbal_postgres extends dbal  {  	var $last_query_text = ''; +	var $connect_error = '';  	/**  	* Connect to server @@ -81,13 +87,29 @@ class dbal_postgres extends dbal  		if ($this->persistency)  		{ +			if (!function_exists('pg_pconnect')) +			{ +				$this->connect_error = 'pg_pconnect function does not exist, is pgsql extension installed?'; +				return $this->sql_error(''); +			} +			$collector = new phpbb_error_collector; +			$collector->install();  			$this->db_connect_id = (!$new_link) ? @pg_pconnect($connect_string) : @pg_pconnect($connect_string, PGSQL_CONNECT_FORCE_NEW);  		}  		else  		{ +			if (!function_exists('pg_connect')) +			{ +				$this->connect_error = 'pg_connect function does not exist, is pgsql extension installed?'; +				return $this->sql_error(''); +			} +			$collector = new phpbb_error_collector; +			$collector->install();  			$this->db_connect_id = (!$new_link) ? @pg_connect($connect_string) : @pg_connect($connect_string, PGSQL_CONNECT_FORCE_NEW);  		} +		$collector->uninstall(); +  		if ($this->db_connect_id)  		{  			if (version_compare($this->sql_server_info(true), '8.2', '>=')) @@ -102,6 +124,7 @@ class dbal_postgres extends dbal  			return $this->db_connect_id;  		} +		$this->connect_error = $collector->format_errors();  		return $this->sql_error('');  	} @@ -371,8 +394,19 @@ class dbal_postgres extends dbal  	*/  	function _sql_error()  	{ +		// pg_last_error only works when there is an established connection. +		// Connection errors have to be tracked by us manually. +		if ($this->db_connect_id) +		{ +			$message = @pg_last_error($this->db_connect_id); +		} +		else +		{ +			$message = $this->connect_error; +		} +  		return array( -			'message'	=> (!$this->db_connect_id) ? @pg_last_error() : @pg_last_error($this->db_connect_id), +			'message'	=> $message,  			'code'		=> ''  		);  	} diff --git a/phpBB/includes/error_collector.php b/phpBB/includes/error_collector.php new file mode 100644 index 0000000000..55834f354c --- /dev/null +++ b/phpBB/includes/error_collector.php @@ -0,0 +1,61 @@ +<?php +/** +* +* @package phpBB +* @version $Id$ +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +class phpbb_error_collector +{ +	var $errors; + +	function phpbb_error_collector() +	{ +		$this->errors = array(); +	} + +	function install() +	{ +		set_error_handler(array(&$this, 'error_handler')); +	} + +	function uninstall() +	{ +		restore_error_handler(); +	} + +	function error_handler($errno, $msg_text, $errfile, $errline) +	{ +		$this->errors[] = array($errno, $msg_text, $errfile, $errline); +	} + +	function format_errors() +	{ +		$text = ''; +		foreach ($this->errors as $error) +		{ +			if (!empty($text)) +			{ +				$text .= "<br />\n"; +			} +			list($errno, $msg_text, $errfile, $errline) = $error; +			$text .= "Errno $errno: $msg_text"; +			if (defined('DEBUG_EXTRA') || defined('IN_INSTALL')) +			{ +				$text .= " at $errfile line $errline"; +			} +		} +		return $text; +	} +} diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 561a9906c4..b1c1c14d0c 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -175,8 +175,13 @@ function set_config_count($config_name, $increment, $is_dynamic = false)  	switch ($db->sql_layer)  	{  		case 'firebird': +			// Precision must be from 1 to 18 +			$sql_update = 'CAST(CAST(config_value as DECIMAL(18, 0)) + ' . (int) $increment . ' as VARCHAR(255))'; +		break; +  		case 'postgres': -			$sql_update = 'CAST(CAST(config_value as DECIMAL(255, 0)) + ' . (int) $increment . ' as VARCHAR(255))'; +			// Need to cast to text first for PostgreSQL 7.x +			$sql_update = 'CAST(CAST(config_value::text as DECIMAL(255, 0)) + ' . (int) $increment . ' as VARCHAR(255))';  		break;  		// MySQL, SQlite, mssql, mssql_odbc, oracle @@ -236,8 +241,8 @@ function unique_id($extra = 'c')  	if ($dss_seeded !== true && ($config['rand_seed_last_update'] < time() - rand(1,10)))  	{ -		set_config('rand_seed', $config['rand_seed'], true);  		set_config('rand_seed_last_update', time(), true); +		set_config('rand_seed', $config['rand_seed'], true);  		$dss_seeded = true;  	} @@ -245,6 +250,22 @@ function unique_id($extra = 'c')  }  /** +* Wrapper for mt_rand() which allows swapping $min and $max parameters. +* +* PHP does not allow us to swap the order of the arguments for mt_rand() anymore. +* (since PHP 5.3.4, see http://bugs.php.net/46587) +* +* @param int $min		Lowest value to be returned +* @param int $max		Highest value to be returned +* +* @return int			Random integer between $min and $max (or $max and $min) +*/ +function phpbb_mt_rand($min, $max) +{ +	return ($min > $max) ? mt_rand($max, $min) : mt_rand($min, $max); +} + +/**  * Return formatted string for filesizes  *  * @param int	$value			filesize in bytes @@ -512,7 +533,7 @@ function _hash_crypt_private($password, $setting, &$itoa64)  	$output = '*';  	// Check for correct hash -	if (substr($setting, 0, 3) != '$H$') +	if (substr($setting, 0, 3) != '$H$' && substr($setting, 0, 3) != '$P$')  	{  		return $output;  	} @@ -1698,7 +1719,7 @@ function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $s  	if ($config['load_db_lastread'] && $user->data['is_registered'])  	{  		// Get list of the unread topics -		$last_mark = $user->data['user_lastmark']; +		$last_mark = (int) $user->data['user_lastmark'];  		$sql_array = array(  			'SELECT'		=> 't.topic_id, t.topic_last_post_time, tt.mark_time as topic_mark_time, ft.mark_time as forum_mark_time', @@ -1717,10 +1738,11 @@ function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $s  			),  			'WHERE'			=> " +				 t.topic_last_post_time > $last_mark AND  				(  				(tt.mark_time IS NOT NULL AND t.topic_last_post_time > tt.mark_time) OR  				(tt.mark_time IS NULL AND ft.mark_time IS NOT NULL AND t.topic_last_post_time > ft.mark_time) OR -				(tt.mark_time IS NULL AND ft.mark_time IS NULL AND t.topic_last_post_time > $last_mark) +				(tt.mark_time IS NULL AND ft.mark_time IS NULL)  				)  				$sql_extra  				$sql_sort", @@ -2248,7 +2270,10 @@ function append_sid($url, $params = false, $is_amp = true, $session_id = false)  /**  * Generate board url (example: http://www.example.com/phpBB) +*  * @param bool $without_script_path if set to true the script path gets not appended (example: http://www.example.com) +* +* @return string the generated board url  */  function generate_board_url($without_script_path = false)  { @@ -2353,12 +2378,12 @@ function redirect($url, $return = false, $disable_cd_check = false)  		// Relative uri  		$pathinfo = pathinfo($url); -		if (!$disable_cd_check && !file_exists($pathinfo['dirname'])) +		if (!$disable_cd_check && !file_exists($pathinfo['dirname'] . '/'))  		{  			$url = str_replace('../', '', $url);  			$pathinfo = pathinfo($url); -			if (!file_exists($pathinfo['dirname'])) +			if (!file_exists($pathinfo['dirname'] . '/'))  			{  				// fallback to "last known user page"  				// at least this way we know the user does not leave the phpBB root @@ -2630,8 +2655,14 @@ function send_status_line($code, $message)  	}  	else  	{ -		if (isset($_SERVER['HTTP_VERSION'])) +		if (!empty($_SERVER['SERVER_PROTOCOL'])) +		{ +			$version = $_SERVER['SERVER_PROTOCOL']; +		} +		else if (!empty($_SERVER['HTTP_VERSION']))  		{ +			// I cannot remember where I got this from. +			// This code path may never be reachable in reality.  			$version = $_SERVER['HTTP_VERSION'];  		}  		else @@ -3429,6 +3460,48 @@ function get_preg_expression($mode)  }  /** +* Generate regexp for naughty words censoring +* Depends on whether installed PHP version supports unicode properties +* +* @param string	$word			word template to be replaced +* @param bool	$use_unicode	whether or not to take advantage of PCRE supporting unicode +* +* @return string $preg_expr		regex to use with word censor +*/ +function get_censor_preg_expression($word, $use_unicode = true) +{ +	static $unicode_support = null; + +	// Check whether PHP version supports unicode properties +	if (is_null($unicode_support)) +	{ +		$unicode_support = ((version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>='))) && @preg_match('/\p{L}/u', 'a') !== false) ? true : false; +	} + +	// Unescape the asterisk to simplify further conversions +	$word = str_replace('\*', '*', preg_quote($word, '#')); + +	if ($use_unicode && $unicode_support) +	{ +		// Replace asterisk(s) inside the pattern, at the start and at the end of it with regexes +		$word = preg_replace(array('#(?<=[\p{Nd}\p{L}_])\*+(?=[\p{Nd}\p{L}_])#iu', '#^\*+#', '#\*+$#'), array('([\x20]*?|[\p{Nd}\p{L}_-]*?)', '[\p{Nd}\p{L}_-]*?', '[\p{Nd}\p{L}_-]*?'), $word); + +		// Generate the final substitution +		$preg_expr = '#(?<![\p{Nd}\p{L}_-])(' . $word . ')(?![\p{Nd}\p{L}_-])#iu'; +	} +	else +	{ +		// Replace the asterisk inside the pattern, at the start and at the end of it with regexes +		$word = preg_replace(array('#(?<=\S)\*+(?=\S)#iu', '#^\*+#', '#\*+$#'), array('(\x20*?\S*?)', '\S*?', '\S*?'), $word); + +		// Generate the final substitution +		$preg_expr = '#(?<!\S)(' . $word . ')(?!\S)#iu'; +	} + +	return $preg_expr; +} + +/**  * Returns the first block of the specified IPv6 address and as many additional  * ones as specified in the length paramater.  * If length is zero, then an empty string is returned. @@ -3501,7 +3574,7 @@ function phpbb_checkdnsrr($host, $type = 'MX')  	// but until 5.3.3 it only works for MX records  	// See: http://bugs.php.net/bug.php?id=51844 -	// Call checkdnsrr() if  +	// Call checkdnsrr() if  	// we're looking for an MX record or  	// we're not on Windows or  	// we're running a PHP version where #51844 has been fixed @@ -3521,7 +3594,7 @@ function phpbb_checkdnsrr($host, $type = 'MX')  	// dns_get_record() is available since PHP 5; since PHP 5.3 also on Windows,  	// but on Windows it does not work reliable for AAAA records before PHP 5.3.1 -	// Call dns_get_record() if  +	// Call dns_get_record() if  	// we're not looking for an AAAA record or  	// we're not on Windows or  	// we're running a PHP version where AAAA lookups work reliable @@ -3551,7 +3624,7 @@ function phpbb_checkdnsrr($host, $type = 'MX')  		foreach ($resultset as $result)  		{  			if ( -				isset($result['host']) && $result['host'] == $host &&  +				isset($result['host']) && $result['host'] == $host &&  				isset($result['type']) && $result['type'] == $type  			)  			{ @@ -3685,25 +3758,11 @@ function msg_handler($errno, $msg_text, $errfile, $errline)  			if (strpos($errfile, 'cache') === false && strpos($errfile, 'template.') === false)  			{ -				// flush the content, else we get a white page if output buffering is on -				if ((int) @ini_get('output_buffering') === 1 || strtolower(@ini_get('output_buffering')) === 'on') -				{ -					@ob_flush(); -				} - -				// Another quick fix for those having gzip compression enabled, but do not flush if the coder wants to catch "something". ;) -				if (!empty($config['gzip_compress'])) -				{ -					if (@extension_loaded('zlib') && !headers_sent() && !ob_get_level()) -					{ -						@ob_flush(); -					} -				} -  				// remove complete path to installation, with the risk of changing backslashes meant to be there  				$errfile = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $errfile);  				$msg_text = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $msg_text); -				echo '<b>[phpBB Debug] PHP Notice</b>: in file <b>' . $errfile . '</b> on line <b>' . $errline . '</b>: <b>' . $msg_text . '</b><br />' . "\n"; +				$error_name = ($errno === E_WARNING) ? 'PHP Warning' : 'PHP Notice'; +				echo '<b>[phpBB Debug] ' . $error_name . '</b>: in file <b>' . $errfile . '</b> on line <b>' . $errline . '</b>: <b>' . $msg_text . '</b><br />' . "\n";  				// we are writing an image - the user won't see the debug, so let's place it in the log  				if (defined('IMAGE_OUTPUT') || defined('IN_CRON')) @@ -3792,7 +3851,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline)  			echo '	</div>';  			echo '	</div>';  			echo '	<div id="page-footer">'; -			echo '		Powered by phpBB © 2000, 2002, 2005, 2007 <a href="http://www.phpbb.com/">phpBB Group</a>'; +			echo '		Powered by <a href="http://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Group';  			echo '	</div>';  			echo '</div>';  			echo '</body>'; @@ -4208,7 +4267,7 @@ function phpbb_http_login($param)  	if (!is_null($username) && is_null($password) && strpos($username, 'Basic ') === 0)  	{  		list($username, $password) = explode(':', base64_decode(substr($username, 6)), 2); -    } +	}  	if (!is_null($username) && !is_null($password))  	{ @@ -4258,7 +4317,21 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0  	// gzip_compression  	if ($config['gzip_compress'])  	{ -		if (@extension_loaded('zlib') && !headers_sent()) +		// to avoid partially compressed output resulting in blank pages in +		// the browser or error messages, compression is disabled in a few cases: +		// +		// 1) if headers have already been sent, this indicates plaintext output +		//    has been started so further content must not be compressed +		// 2) the length of the current output buffer is non-zero. This means +		//    there is already some uncompressed content in this output buffer +		//    so further output must not be compressed +		// 3) if more than one level of output buffering is used because we +		//    cannot test all output buffer level content lengths. One level +		//    could be caused by php.ini output_buffering. Anything +		//    beyond that is manual, so the code wrapping phpBB in output buffering +		//    can easily compress the output itself. +		// +		if (@extension_loaded('zlib') && !headers_sent() && ob_get_level() <= 1 && ob_get_length() == 0)  		{  			ob_start('ob_gzhandler');  		} @@ -4379,6 +4452,12 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0  		$user_lang = substr($user_lang, 0, strpos($user_lang, '-x-'));  	} +	$s_search_hidden_fields = array(); +	if ($_SID) +	{ +		$s_search_hidden_fields['sid'] = $_SID; +	} +  	// The following assigns all _common_ variables that may be used at any point in a template.  	$template->assign_vars(array(  		'SITENAME'						=> $config['sitename'], @@ -4468,11 +4547,13 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0  		'S_LOAD_UNREADS'			=> ($config['load_unreads_search'] && ($config['load_anon_lastread'] || $user->data['is_registered'])) ? true : false, +		'S_SEARCH_HIDDEN_FIELDS'	=> build_hidden_fields($s_search_hidden_fields), +  		'T_THEME_PATH'			=> "{$web_path}styles/" . $user->theme['theme_path'] . '/theme',  		'T_TEMPLATE_PATH'		=> "{$web_path}styles/" . $user->theme['template_path'] . '/template',  		'T_SUPER_TEMPLATE_PATH'	=> (isset($user->theme['template_inherit_path']) && $user->theme['template_inherit_path']) ? "{$web_path}styles/" . $user->theme['template_inherit_path'] . '/template' : "{$web_path}styles/" . $user->theme['template_path'] . '/template',  		'T_IMAGESET_PATH'		=> "{$web_path}styles/" . $user->theme['imageset_path'] . '/imageset', -		'T_IMAGESET_LANG_PATH'	=> "{$web_path}styles/" . $user->theme['imageset_path'] . '/imageset/' . $user->data['user_lang'], +		'T_IMAGESET_LANG_PATH'	=> "{$web_path}styles/" . $user->theme['imageset_path'] . '/imageset/' . $user->lang_name,  		'T_IMAGES_PATH'			=> "{$web_path}images/",  		'T_SMILIES_PATH'		=> "{$web_path}{$config['smilies_path']}/",  		'T_AVATAR_PATH'			=> "{$web_path}{$config['avatar_path']}/", @@ -4480,7 +4561,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0  		'T_ICONS_PATH'			=> "{$web_path}{$config['icons_path']}/",  		'T_RANKS_PATH'			=> "{$web_path}{$config['ranks_path']}/",  		'T_UPLOAD_PATH'			=> "{$web_path}{$config['upload_path']}/", -		'T_STYLESHEET_LINK'		=> (!$user->theme['theme_storedb']) ? "{$web_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : append_sid("{$phpbb_root_path}style.$phpEx", 'id=' . $user->theme['style_id'] . '&lang=' . $user->data['user_lang']), +		'T_STYLESHEET_LINK'		=> (!$user->theme['theme_storedb']) ? "{$web_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : append_sid("{$phpbb_root_path}style.$phpEx", 'id=' . $user->theme['style_id'] . '&lang=' . $user->lang_name),  		'T_STYLESHEET_NAME'		=> $user->theme['theme_name'],  		'T_THEME_NAME'			=> $user->theme['theme_path'], @@ -4558,7 +4639,7 @@ function page_footer($run_cron = true)  	// Call cron-type script  	$call_cron = false; -	if (!defined('IN_CRON') && $run_cron && !$config['board_disable']) +	if (!defined('IN_CRON') && $run_cron && !$config['board_disable'] && !$user->data['is_bot'])  	{  		$call_cron = true;  		$time_now = (!empty($user->time_now) && is_int($user->time_now)) ? $user->time_now : time(); @@ -4662,7 +4743,7 @@ function exit_handler()  	}  	// As a pre-caution... some setups display a blank page if the flush() is not there. -	(empty($config['gzip_compress'])) ? @flush() : @ob_flush(); +	(ob_get_level() > 0) ? @ob_flush() : @flush();  	exit;  } diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index 2aa12adb2e..cb0cf34e69 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -2506,6 +2506,7 @@ function cache_moderators()  /**  * View log +* If $log_count is set to false, we will skip counting all entries in the database.  */  function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $limit_days = 0, $sort_by = 'l.log_time DESC', $keywords = '')  { @@ -2761,16 +2762,19 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id  		}  	} -	$sql = 'SELECT COUNT(l.log_id) AS total_entries -		FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . " u -		WHERE l.log_type = $log_type -			AND l.user_id = u.user_id -			AND l.log_time >= $limit_days -			$sql_keywords -			$sql_forum"; -	$result = $db->sql_query($sql); -	$log_count = (int) $db->sql_fetchfield('total_entries'); -	$db->sql_freeresult($result); +	if ($log_count !== false) +	{ +		$sql = 'SELECT COUNT(l.log_id) AS total_entries +			FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . " u +			WHERE l.log_type = $log_type +				AND l.user_id = u.user_id +				AND l.log_time >= $limit_days +				$sql_keywords +				$sql_forum"; +		$result = $db->sql_query($sql); +		$log_count = (int) $db->sql_fetchfield('total_entries'); +		$db->sql_freeresult($result); +	}  	return;  } diff --git a/phpBB/includes/functions_convert.php b/phpBB/includes/functions_convert.php index 9e26043b39..4a359dcade 100644 --- a/phpBB/includes/functions_convert.php +++ b/phpBB/includes/functions_convert.php @@ -1816,6 +1816,7 @@ function add_bots()  		'Alta Vista [Bot]'			=> array('Scooter/', ''),  		'Ask Jeeves [Bot]'			=> array('Ask Jeeves', ''),  		'Baidu [Spider]'			=> array('Baiduspider+(', ''), +		'Bing [Bot]'				=> array('bingbot/', ''),  		'Exabot [Bot]'				=> array('Exabot/', ''),  		'FAST Enterprise [Crawler]'	=> array('FAST Enterprise Crawler', ''),  		'FAST WebCrawler [Crawler]'	=> array('FAST-WebCrawler/', ''), diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php index 2de7e1b169..d7422aa2c9 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -456,7 +456,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod  			'S_LOCKED_FORUM'	=> ($row['forum_status'] == ITEM_LOCKED) ? true : false,  			'S_LIST_SUBFORUMS'	=> ($row['display_subforum_list']) ? true : false,  			'S_SUBFORUMS'		=> (sizeof($subforums_list)) ? true : false, -			'S_FEED_ENABLED'	=> ($config['feed_forum'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $row['forum_options'])) ? true : false, +			'S_FEED_ENABLED'	=> ($config['feed_forum'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $row['forum_options']) && $row['forum_type'] == FORUM_POST) ? true : false,  			'FORUM_ID'				=> $row['forum_id'],  			'FORUM_NAME'			=> $row['forum_name'], @@ -477,7 +477,6 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod  			'SUBFORUMS'				=> $s_subforums_list,  			'L_SUBFORUM_STR'		=> $l_subforums, -			'L_FORUM_FOLDER_ALT'	=> $folder_alt,  			'L_MODERATOR_STR'		=> $l_moderator,  			'U_UNAPPROVED_TOPICS'	=> ($row['forum_id_unapproved_topics']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=unapproved_topics&f=' . $row['forum_id_unapproved_topics']) : '', diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 6fd87db663..a641afbaed 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -388,7 +388,7 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage  	include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);  	$upload = new fileupload(); -	if ($config['check_attachment_content']) +	if ($config['check_attachment_content'] && isset($config['mime_triggers']))  	{  		$upload->set_disallowed_content(explode('|', $config['mime_triggers']));  	} @@ -1479,7 +1479,7 @@ function delete_post($forum_id, $topic_id, $post_id, &$data)  		break;  		case 'delete_first_post': -			$sql = 'SELECT p.post_id, p.poster_id, p.post_username, u.username, u.user_colour +			$sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour  				FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u  				WHERE p.topic_id = $topic_id  					AND p.poster_id = u.user_id @@ -1493,7 +1493,7 @@ function delete_post($forum_id, $topic_id, $post_id, &$data)  				$sql_data[FORUMS_TABLE] = ($data['post_approved']) ? 'forum_posts = forum_posts - 1' : '';  			} -			$sql_data[TOPICS_TABLE] = 'topic_poster = ' . intval($row['poster_id']) . ', topic_first_post_id = ' . intval($row['post_id']) . ", topic_first_poster_colour = '" . $db->sql_escape($row['user_colour']) . "', topic_first_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'"; +			$sql_data[TOPICS_TABLE] = 'topic_poster = ' . intval($row['poster_id']) . ', topic_first_post_id = ' . intval($row['post_id']) . ", topic_first_poster_colour = '" . $db->sql_escape($row['user_colour']) . "', topic_first_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "', topic_time = " . (int) $row['post_time'];  			// Decrementing topic_replies here is fine because this case only happens if there is more than one post within the topic - basically removing one "reply"  			$sql_data[TOPICS_TABLE] .= ', topic_replies_real = topic_replies_real - 1' . (($data['post_approved']) ? ', topic_replies = topic_replies - 1' : ''); @@ -2611,4 +2611,106 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u  	return $url;  } +/** +* Handle topic bumping +* @param int $forum_id The ID of the forum the topic is being bumped belongs to +* @param int $topic_id The ID of the topic is being bumping +* @param array $post_data Passes some topic parameters: +*				- 'topic_title' +*				- 'topic_last_post_id' +*				- 'topic_last_poster_id' +*				- 'topic_last_post_subject' +*				- 'topic_last_poster_name' +*				- 'topic_last_poster_colour' +* @param int $bump_time The time at which topic was bumped, usually it is a current time as obtained via time().  +* @return string An URL to the bumped topic, example: ./viewtopic.php?forum_id=1&topic_id=2&p=3#p3 +*/ +function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false) +{ +	global $config, $db, $user, $phpEx, $phpbb_root_path; + +	if ($bump_time === false) +	{ +		$bump_time = time(); +	} + +	// Begin bumping +	$db->sql_transaction('begin'); + +	// Update the topic's last post post_time +	$sql = 'UPDATE ' . POSTS_TABLE . " +		SET post_time = $bump_time +		WHERE post_id = {$post_data['topic_last_post_id']} +			AND topic_id = $topic_id"; +	$db->sql_query($sql); + +	// Sync the topic's last post time, the rest of the topic's last post data isn't changed +	$sql = 'UPDATE ' . TOPICS_TABLE . " +		SET topic_last_post_time = $bump_time, +			topic_bumped = 1, +			topic_bumper = " . $user->data['user_id'] . " +		WHERE topic_id = $topic_id"; +	$db->sql_query($sql); + +	// Update the forum's last post info +	$sql = 'UPDATE ' . FORUMS_TABLE . " +		SET forum_last_post_id = " . $post_data['topic_last_post_id'] . ", +			forum_last_poster_id = " . $post_data['topic_last_poster_id'] . ", +			forum_last_post_subject = '" . $db->sql_escape($post_data['topic_last_post_subject']) . "', +			forum_last_post_time = $bump_time, +			forum_last_poster_name = '" . $db->sql_escape($post_data['topic_last_poster_name']) . "', +			forum_last_poster_colour = '" . $db->sql_escape($post_data['topic_last_poster_colour']) . "' +		WHERE forum_id = $forum_id"; +	$db->sql_query($sql); + +	// Update bumper's time of the last posting to prevent flood +	$sql = 'UPDATE ' . USERS_TABLE . " +		SET user_lastpost_time = $bump_time +		WHERE user_id = " . $user->data['user_id']; +	$db->sql_query($sql); + +	$db->sql_transaction('commit'); + +	// Mark this topic as posted to +	markread('post', $forum_id, $topic_id, $bump_time); + +	// Mark this topic as read +	markread('topic', $forum_id, $topic_id, $bump_time); + +	// Update forum tracking info +	if ($config['load_db_lastread'] && $user->data['is_registered']) +	{ +		$sql = 'SELECT mark_time +			FROM ' . FORUMS_TRACK_TABLE . ' +			WHERE user_id = ' . $user->data['user_id'] . ' +				AND forum_id = ' . $forum_id; +		$result = $db->sql_query($sql); +		$f_mark_time = (int) $db->sql_fetchfield('mark_time'); +		$db->sql_freeresult($result); +	} +	else if ($config['load_anon_lastread'] || $user->data['is_registered']) +	{ +		$f_mark_time = false; +	} + +	if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered']) +	{ +		// Update forum info +		$sql = 'SELECT forum_last_post_time +			FROM ' . FORUMS_TABLE . ' +			WHERE forum_id = ' . $forum_id; +		$result = $db->sql_query($sql); +		$forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time'); +		$db->sql_freeresult($result); + +		update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time, false); +	} + +	add_log('mod', $forum_id, $topic_id, 'LOG_BUMP_TOPIC', $post_data['topic_title']); + +	$url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&p={$post_data['topic_last_post_id']}") . "#p{$post_data['topic_last_post_id']}"; + +	return $url; +} +  ?>
\ No newline at end of file diff --git a/phpBB/includes/functions_profile_fields.php b/phpBB/includes/functions_profile_fields.php index 78fe049f40..1eae2a9ad6 100644 --- a/phpBB/includes/functions_profile_fields.php +++ b/phpBB/includes/functions_profile_fields.php @@ -149,7 +149,18 @@ class custom_profile  			case FIELD_DROPDOWN:  				$field_value = (int) $field_value; -			 + +				// retrieve option lang data if necessary +				if (!isset($this->options_lang[$field_data['field_id']]) || !isset($this->options_lang[$field_data['field_id']][$field_data['lang_id']]) || !sizeof($this->options_lang[$file_data['field_id']][$field_data['lang_id']])) +				{ +					$this->get_option_lang($field_data['field_id'], $field_data['lang_id'], FIELD_DROPDOWN, false); +				} + +				if (!isset($this->options_lang[$field_data['field_id']][$field_data['lang_id']][$field_value])) +				{ +					return 'FIELD_INVALID_VALUE'; +				} +  				if ($field_value == $field_data['field_novalue'] && $field_data['field_required'])  				{  					return 'FIELD_REQUIRED'; @@ -302,6 +313,7 @@ class custom_profile  				switch ($cp_result)  				{  					case 'FIELD_INVALID_DATE': +					case 'FIELD_INVALID_VALUE':  					case 'FIELD_REQUIRED':  						$error = sprintf($user->lang[$cp_result], $row['lang_name']);  					break; diff --git a/phpBB/includes/functions_template.php b/phpBB/includes/functions_template.php index 1d3a4d74f8..8636dfe010 100644 --- a/phpBB/includes/functions_template.php +++ b/phpBB/includes/functions_template.php @@ -322,7 +322,7 @@ class template_compile  		// Is the designer wanting to call another loop in a loop?  		if (strpos($tag_args, '!') === 0)  		{ -			// Count the number if ! occurrences (not allowed in vars) +			// Count the number of ! occurrences (not allowed in vars)  			$no_nesting = substr_count($tag_args, '!');  			$tag_args = substr($tag_args, $no_nesting);  		} diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index 7f09cc1640..d5bbd80242 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -458,7 +458,7 @@ class fileerror extends filespec  class fileupload  {  	var $allowed_extensions = array(); -	var $disallowed_content = array(); +	var $disallowed_content = array('body', 'head', 'html', 'img', 'plaintext', 'a href', 'pre', 'script', 'table', 'title');   	var $max_filesize = 0;  	var $min_width = 0;  	var $min_height = 0; @@ -539,7 +539,7 @@ class fileupload  	{  		if ($disallowed_content !== false && is_array($disallowed_content))  		{ -			$this->disallowed_content = $disallowed_content; +			$this->disallowed_content = array_diff($disallowed_content, array(''));  		}  	} diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php index f2c80705ba..6b5cca8abb 100644 --- a/phpBB/includes/functions_user.php +++ b/phpBB/includes/functions_user.php @@ -482,44 +482,6 @@ function user_delete($mode, $user_id, $post_username = false)  				include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);  			} -			$sql = 'SELECT topic_id, COUNT(post_id) AS total_posts -				FROM ' . POSTS_TABLE . " -				WHERE poster_id = $user_id -				GROUP BY topic_id"; -			$result = $db->sql_query($sql); - -			$topic_id_ary = array(); -			while ($row = $db->sql_fetchrow($result)) -			{ -				$topic_id_ary[$row['topic_id']] = $row['total_posts']; -			} -			$db->sql_freeresult($result); - -			if (sizeof($topic_id_ary)) -			{ -				$sql = 'SELECT topic_id, topic_replies, topic_replies_real -					FROM ' . TOPICS_TABLE . ' -					WHERE ' . $db->sql_in_set('topic_id', array_keys($topic_id_ary)); -				$result = $db->sql_query($sql); - -				$del_topic_ary = array(); -				while ($row = $db->sql_fetchrow($result)) -				{ -					if (max($row['topic_replies'], $row['topic_replies_real']) + 1 == $topic_id_ary[$row['topic_id']]) -					{ -						$del_topic_ary[] = $row['topic_id']; -					} -				} -				$db->sql_freeresult($result); - -				if (sizeof($del_topic_ary)) -				{ -					$sql = 'DELETE FROM ' . TOPICS_TABLE . ' -						WHERE ' . $db->sql_in_set('topic_id', $del_topic_ary); -					$db->sql_query($sql); -				} -			} -  			// Delete posts, attachments, etc.  			delete_posts('poster_id', $user_id); @@ -771,7 +733,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas  			}  			else  			{ -				trigger_error('LENGTH_BAN_INVALID'); +				trigger_error('LENGTH_BAN_INVALID', E_USER_WARNING);  			}  		}  	} @@ -831,7 +793,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas  			// Make sure we have been given someone to ban  			if (!sizeof($sql_usernames))  			{ -				trigger_error('NO_USER_SPECIFIED'); +				trigger_error('NO_USER_SPECIFIED', E_USER_WARNING);  			}  			$sql = 'SELECT user_id @@ -862,7 +824,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas  			else  			{  				$db->sql_freeresult($result); -				trigger_error('NO_USERS'); +				trigger_error('NO_USERS', E_USER_WARNING);  			}  			$db->sql_freeresult($result);  		break; @@ -964,7 +926,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas  				if (empty($banlist_ary))  				{ -					trigger_error('NO_IPS_DEFINED'); +					trigger_error('NO_IPS_DEFINED', E_USER_WARNING);  				}  			}  		break; @@ -992,12 +954,12 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas  			if (sizeof($ban_list) == 0)  			{ -				trigger_error('NO_EMAILS_DEFINED'); +				trigger_error('NO_EMAILS_DEFINED', E_USER_WARNING);  			}  		break;  		default: -			trigger_error('NO_MODE'); +			trigger_error('NO_MODE', E_USER_WARNING);  		break;  	} @@ -1460,6 +1422,31 @@ function validate_match($string, $optional = false, $match = '')  }  /** +* Validate Language Pack ISO Name +* +* Tests whether a language name is valid and installed +* +* @param string $lang_iso	The language string to test +* +* @return bool|string		Either false if validation succeeded or +*							a string which will be used as the error message +*							(with the variable name appended) +*/ +function validate_language_iso_name($lang_iso) +{ +	global $db; + +	$sql = 'SELECT lang_id +		FROM ' . LANG_TABLE . " +		WHERE lang_iso = '" . $db->sql_escape($lang_iso) . "'"; +	$result = $db->sql_query($sql); +	$lang_id = (int) $db->sql_fetchfield('lang_id'); +	$db->sql_freeresult($result); + +	return ($lang_id) ? false : 'WRONG_DATA'; +} + +/**  * Check to see if the username has been taken, or if it is disallowed.  * Also checks if it includes the " character, which we don't allow in usernames.  * Used for registering, changing names, and posting anonymously with a username @@ -1618,8 +1605,9 @@ function validate_password($password)  {  	global $config, $db, $user; -	if (!$password) +	if ($password === '' || $config['pass_complex'] === 'PASS_TYPE_ANY')  	{ +		// Password empty or no password complexity required.  		return false;  	} @@ -1630,7 +1618,6 @@ function validate_password($password)  	{  		$upp = '\p{Lu}';  		$low = '\p{Ll}'; -		$let = '\p{L}';  		$num = '\p{N}';  		$sym = '[^\p{Lu}\p{Ll}\p{N}]';  		$pcre = true; @@ -1640,7 +1627,6 @@ function validate_password($password)  		mb_regex_encoding('UTF-8');  		$upp = '[[:upper:]]';  		$low = '[[:lower:]]'; -		$let = '[[:lower:][:upper:]]';  		$num = '[[:digit:]]';  		$sym = '[^[:upper:][:lower:][:digit:]]';  		$mbstring = true; @@ -1649,7 +1635,6 @@ function validate_password($password)  	{  		$upp = '[A-Z]';  		$low = '[a-z]'; -		$let = '[a-zA-Z]';  		$num = '[0-9]';  		$sym = '[^A-Za-z0-9]';  		$pcre = true; @@ -1659,22 +1644,22 @@ function validate_password($password)  	switch ($config['pass_complex'])  	{ -		case 'PASS_TYPE_CASE': -			$chars[] = $low; -			$chars[] = $upp; -		break; +		// No break statements below ... +		// We require strong passwords in case pass_complex is not set or is invalid +		default: + +		// Require mixed case letters, numbers and symbols +		case 'PASS_TYPE_SYMBOL': +			$chars[] = $sym; +		// Require mixed case letters and numbers  		case 'PASS_TYPE_ALPHA': -			$chars[] = $let;  			$chars[] = $num; -		break; -		case 'PASS_TYPE_SYMBOL': +		// Require mixed case letters +		case 'PASS_TYPE_CASE':  			$chars[] = $low;  			$chars[] = $upp; -			$chars[] = $num; -			$chars[] = $sym; -		break;  	}  	if ($pcre) @@ -2080,7 +2065,7 @@ function avatar_upload($data, &$error)  	// Init upload class  	include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx); -	$upload = new fileupload('AVATAR_', array('jpg', 'jpeg', 'gif', 'png'), $config['avatar_filesize'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], explode('|', $config['mime_triggers'])); +	$upload = new fileupload('AVATAR_', array('jpg', 'jpeg', 'gif', 'png'), $config['avatar_filesize'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], (isset($config['mime_triggers']) ? explode('|', $config['mime_triggers']) : false));  	if (!empty($_FILES['uploadfile']['name']))  	{ diff --git a/phpBB/includes/mcp/mcp_front.php b/phpBB/includes/mcp/mcp_front.php index 50e14b9336..af262baa29 100644 --- a/phpBB/includes/mcp/mcp_front.php +++ b/phpBB/includes/mcp/mcp_front.php @@ -350,7 +350,7 @@ function mcp_front_view($id, $mode, $action)  			// Add forum_id 0 for global announcements  			$forum_list[] = 0; -			$log_count = 0; +			$log_count = false;  			$log = array();  			view_log('mod', $log, $log_count, 5, 0, $forum_list); diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index d5551f5114..ad10a52705 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -1048,37 +1048,38 @@ function mcp_fork_topic($topic_ids)  		$total_posts = 0;  		$new_topic_id_list = array(); -		if ($topic_data['enable_indexing']) -		{ -			// Select the search method and do some additional checks to ensure it can actually be utilised -			$search_type = basename($config['search_type']); -			if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx)) +		foreach ($topic_data as $topic_id => $topic_row) +		{ +			if (!isset($search_type) && $topic_row['enable_indexing'])  			{ -				trigger_error('NO_SUCH_SEARCH_MODULE'); -			} +				// Select the search method and do some additional checks to ensure it can actually be utilised +				$search_type = basename($config['search_type']); -			if (!class_exists($search_type)) -			{ -				include("{$phpbb_root_path}includes/search/$search_type.$phpEx"); -			} +				if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx)) +				{ +					trigger_error('NO_SUCH_SEARCH_MODULE'); +				} + +				if (!class_exists($search_type)) +				{ +					include("{$phpbb_root_path}includes/search/$search_type.$phpEx"); +				} -			$error = false; -			$search = new $search_type($error); -			$search_mode = 'post'; +				$error = false; +				$search = new $search_type($error); +				$search_mode = 'post'; -			if ($error) +				if ($error) +				{ +					trigger_error($error); +				} +			} +			else if (!isset($search_type) && !$topic_row['enable_indexing'])  			{ -				trigger_error($error); +				$search_type = false;  			} -		} -		else -		{ -			$search_type = false; -		} -		foreach ($topic_data as $topic_id => $topic_row) -		{  			$sql_ary = array(  				'forum_id'					=> (int) $to_forum_id,  				'icon_id'					=> (int) $topic_row['icon_id'], @@ -1187,9 +1188,9 @@ function mcp_fork_topic($topic_ids)  				// Copy whether the topic is dotted  				markread('post', $to_forum_id, $new_topic_id, 0, $row['poster_id']); -				if ($search_type) +				if (!empty($search_type))  				{ -					$search->index($search_mode, $sql_ary['post_id'], $sql_ary['post_text'], $sql_ary['post_subject'], $sql_ary['poster_id'], ($topic_row['topic_type'] == POST_GLOBAL) ? 0 : $to_forum_id); +					$search->index($search_mode, $new_post_id, $sql_ary['post_text'], $sql_ary['post_subject'], $sql_ary['poster_id'], ($topic_row['topic_type'] == POST_GLOBAL) ? 0 : $to_forum_id);  					$search_mode = 'reply'; // After one we index replies  				} diff --git a/phpBB/includes/mcp/mcp_post.php b/phpBB/includes/mcp/mcp_post.php index 7098b4bbce..de7f3e63ee 100644 --- a/phpBB/includes/mcp/mcp_post.php +++ b/phpBB/includes/mcp/mcp_post.php @@ -227,10 +227,10 @@ function mcp_post_details($id, $mode, $action)  	// Get User Notes  	$log_data = array(); -	$log_count = 0; +	$log_count = false;  	view_log('user', $log_data, $log_count, $config['posts_per_page'], 0, 0, 0, $post_info['user_id']); -	if ($log_count) +	if (!empty($log_data))  	{  		$template->assign_var('S_USER_NOTES', true); diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index b2d0b6c566..a134fab5d3 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -102,27 +102,29 @@ class bbcode_firstpass extends bbcode  	/**  	* Init bbcode data for later parsing  	*/ -	function bbcode_init() +	function bbcode_init($allow_custom_bbcode = true)  	{  		static $rowset;  		// This array holds all bbcode data. BBCodes will be processed in this  		// order, so it is important to keep [code] in first position and  		// [quote] in second position. +		// To parse multiline URL we enable dotall option setting only for URL text +		// but not for link itself, thus [url][/url] is not affected.  		$this->bbcodes = array( -			'code'			=> array('bbcode_id' => 8,	'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#ise' => "\$this->bbcode_code('\$1', '\$2')")), -			'quote'			=> array('bbcode_id' => 0,	'regexp' => array('#\[quote(?:="(.*?)")?\](.+)\[/quote\]#ise' => "\$this->bbcode_quote('\$0')")), -			'attachment'	=> array('bbcode_id' => 12,	'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#ise' => "\$this->bbcode_attachment('\$1', '\$2')")), -			'b'				=> array('bbcode_id' => 1,	'regexp' => array('#\[b\](.*?)\[/b\]#ise' => "\$this->bbcode_strong('\$1')")), -			'i'				=> array('bbcode_id' => 2,	'regexp' => array('#\[i\](.*?)\[/i\]#ise' => "\$this->bbcode_italic('\$1')")), -			'url'			=> array('bbcode_id' => 3,	'regexp' => array('#\[url(=(.*))?\](.*)\[/url\]#iUe' => "\$this->validate_url('\$2', '\$3')")), -			'img'			=> array('bbcode_id' => 4,	'regexp' => array('#\[img\](.*)\[/img\]#iUe' => "\$this->bbcode_img('\$1')")), -			'size'			=> array('bbcode_id' => 5,	'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#ise' => "\$this->bbcode_size('\$1', '\$2')")), -			'color'			=> array('bbcode_id' => 6,	'regexp' => array('!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!ise' => "\$this->bbcode_color('\$1', '\$2')")), -			'u'				=> array('bbcode_id' => 7,	'regexp' => array('#\[u\](.*?)\[/u\]#ise' => "\$this->bbcode_underline('\$1')")), -			'list'			=> array('bbcode_id' => 9,	'regexp' => array('#\[list(?:=(?:[a-z0-9]|disc|circle|square))?].*\[/list]#ise' => "\$this->bbcode_parse_list('\$0')")), -			'email'			=> array('bbcode_id' => 10,	'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#ise' => "\$this->validate_email('\$1', '\$2')")), -			'flash'			=> array('bbcode_id' => 11,	'regexp' => array('#\[flash=([0-9]+),([0-9]+)\](.*?)\[/flash\]#ie' => "\$this->bbcode_flash('\$1', '\$2', '\$3')")) +			'code'			=> array('bbcode_id' => 8,	'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#uise' => "\$this->bbcode_code('\$1', '\$2')")), +			'quote'			=> array('bbcode_id' => 0,	'regexp' => array('#\[quote(?:="(.*?)")?\](.+)\[/quote\]#uise' => "\$this->bbcode_quote('\$0')")), +			'attachment'	=> array('bbcode_id' => 12,	'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#uise' => "\$this->bbcode_attachment('\$1', '\$2')")), +			'b'				=> array('bbcode_id' => 1,	'regexp' => array('#\[b\](.*?)\[/b\]#uise' => "\$this->bbcode_strong('\$1')")), +			'i'				=> array('bbcode_id' => 2,	'regexp' => array('#\[i\](.*?)\[/i\]#uise' => "\$this->bbcode_italic('\$1')")), +			'url'			=> array('bbcode_id' => 3,	'regexp' => array('#\[url(=(.*))?\](?(1)((?s).*(?-s))|(.*))\[/url\]#uiUe' => "\$this->validate_url('\$2', ('\$3') ? '\$3' : '\$4')")), +			'img'			=> array('bbcode_id' => 4,	'regexp' => array('#\[img\](.*)\[/img\]#uiUe' => "\$this->bbcode_img('\$1')")), +			'size'			=> array('bbcode_id' => 5,	'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#uise' => "\$this->bbcode_size('\$1', '\$2')")), +			'color'			=> array('bbcode_id' => 6,	'regexp' => array('!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!uise' => "\$this->bbcode_color('\$1', '\$2')")), +			'u'				=> array('bbcode_id' => 7,	'regexp' => array('#\[u\](.*?)\[/u\]#uise' => "\$this->bbcode_underline('\$1')")), +			'list'			=> array('bbcode_id' => 9,	'regexp' => array('#\[list(?:=(?:[a-z0-9]|disc|circle|square))?].*\[/list]#uise' => "\$this->bbcode_parse_list('\$0')")), +			'email'			=> array('bbcode_id' => 10,	'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#uise' => "\$this->validate_email('\$1', '\$2')")), +			'flash'			=> array('bbcode_id' => 11,	'regexp' => array('#\[flash=([0-9]+),([0-9]+)\](.*?)\[/flash\]#uie' => "\$this->bbcode_flash('\$1', '\$2', '\$3')"))  		);  		// Zero the parsed items array @@ -133,6 +135,11 @@ class bbcode_firstpass extends bbcode  			$this->parsed_items[$tag] = 0;  		} +		if (!$allow_custom_bbcode) +		{ +			return; +		} +  		if (!is_array($rowset))  		{  			global $db; @@ -1332,7 +1339,9 @@ class parse_message extends bbcode_firstpass  		{  			if ($max_smilies)  			{ -				$num_matches = preg_match_all('#(?<=^|[\n .])(?:' . implode('|', $match) . ')(?![^<>]*>)#', $this->message, $matches); +				// 'u' modifier has been added to correctly parse smilies within unicode strings +				// For details: http://tracker.phpbb.com/browse/PHPBB3-10117 +				$num_matches = preg_match_all('#(?<=^|[\n .])(?:' . implode('|', $match) . ')(?![^<>]*>)#u', $this->message, $matches);  				unset($matches);  				if ($num_matches !== false && $num_matches > $max_smilies) @@ -1343,7 +1352,10 @@ class parse_message extends bbcode_firstpass  			}  			// Make sure the delimiter # is added in front and at the end of every element within $match -			$this->message = trim(preg_replace(explode(chr(0), '#(?<=^|[\n .])' . implode('(?![^<>]*>)#' . chr(0) . '#(?<=^|[\n .])', $match) . '(?![^<>]*>)#'), $replace, $this->message)); +			// 'u' modifier has been added to correctly parse smilies within unicode strings +			// For details: http://tracker.phpbb.com/browse/PHPBB3-10117 + +			$this->message = trim(preg_replace(explode(chr(0), '#(?<=^|[\n .])' . implode('(?![^<>]*>)#u' . chr(0) . '#(?<=^|[\n .])', $match) . '(?![^<>]*>)#u'), $replace, $this->message));  		}  	} diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index 5f5b39fe27..e9e706e2b8 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -221,7 +221,7 @@ class session  		// if the forwarded for header shall be checked we have to validate its contents  		if ($config['forwarded_for_check'])  		{ -			$this->forwarded_for = preg_replace('#[ ]{2,}#', ' ', str_replace(array(',', ' '), ' ', $this->forwarded_for)); +			$this->forwarded_for = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->forwarded_for));  			// split the list of IPs  			$ips = explode(' ', $this->forwarded_for); @@ -267,37 +267,42 @@ class session  		// Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests  		// it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip. -		$this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars((string) $_SERVER['REMOTE_ADDR']) : ''; -		$this->ip = preg_replace('#[ ]{2,}#', ' ', str_replace(array(',', ' '), ' ', $this->ip)); +		$this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? (string) $_SERVER['REMOTE_ADDR'] : ''; +		$this->ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->ip));  		// split the list of IPs -		$ips = explode(' ', $this->ip); +		$ips = explode(' ', trim($this->ip));  		// Default IP if REMOTE_ADDR is invalid  		$this->ip = '127.0.0.1';  		foreach ($ips as $ip)  		{ -			// check IPv4 first, the IPv6 is hopefully only going to be used very seldomly -			if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip)) +			if (preg_match(get_preg_expression('ipv4'), $ip))  			{ -				// Just break -				break; +				$this->ip = $ip;  			} - -			// Quick check for IPv4-mapped address in IPv6 -			if (stripos($ip, '::ffff:') === 0) +			else if (preg_match(get_preg_expression('ipv6'), $ip))  			{ -				$ipv4 = substr($ip, 7); - -				if (preg_match(get_preg_expression('ipv4'), $ipv4)) +				// Quick check for IPv4-mapped address in IPv6 +				if (stripos($ip, '::ffff:') === 0)  				{ -					$ip = $ipv4; +					$ipv4 = substr($ip, 7); + +					if (preg_match(get_preg_expression('ipv4'), $ipv4)) +					{ +						$ip = $ipv4; +					}  				} -			} -			// Use the last in chain -			$this->ip = $ip; +				$this->ip = $ip; +			} +			else +			{ +				// We want to use the last valid address in the chain +				// Leave foreach loop when address is invalid +				break; +			}  		}  		$this->load = false; @@ -583,6 +588,14 @@ class session  			$bot = false;  		} +		// Bot user, if they have a SID in the Request URI we need to get rid of it +		// otherwise they'll index this page with the SID, duplicate content oh my! +		if ($bot && isset($_GET['sid'])) +		{ +			send_status_line(301, 'Moved Permanently'); +			redirect(build_url(array('sid'))); +		} +  		// If no data was returned one or more of the following occurred:  		// Key didn't match one in the DB  		// User does not exist @@ -619,12 +632,6 @@ class session  		}  		else  		{ -			// Bot user, if they have a SID in the Request URI we need to get rid of it -			// otherwise they'll index this page with the SID, duplicate content oh my! -			if (isset($_GET['sid'])) -			{ -				redirect(build_url(array('sid'))); -			}  			$this->data['session_last_visit'] = $this->time_now;  		} @@ -999,6 +1006,10 @@ class session  				include($phpbb_root_path . "includes/captcha/captcha_factory." . $phpEx);  			}  			phpbb_captcha_factory::garbage_collect($config['captcha_plugin']); + +			$sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' +				WHERE attempt_time < ' . (time() - (int) $config['ip_login_limit_time']); +			$db->sql_query($sql);  		}  		return; @@ -1237,6 +1248,12 @@ class session  			$ip = $this->ip;  		} +		// Neither Spamhaus nor Spamcop supports IPv6 addresses. +		if (strpos($ip, ':') !== false) +		{ +			return false; +		} +  		$dnsbl_check = array(  			'sbl.spamhaus.org'	=> 'http://www.spamhaus.org/query/bl?ip=',  		); @@ -1966,6 +1983,7 @@ class user extends session  					$key_found = $num;  				} +				break;  			}  		} @@ -2254,9 +2272,44 @@ class user extends session  			// Use URL if told so  			$root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; -			$img_data['src'] = $root_path . 'styles/' . rawurlencode($this->theme['imageset_path']) . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename']; +			$path = 'styles/' . rawurlencode($this->theme['imageset_path']) . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename']; + +			$img_data['src'] = $root_path . $path;  			$img_data['width'] = $this->img_array[$img]['image_width'];  			$img_data['height'] = $this->img_array[$img]['image_height']; + +			// We overwrite the width and height to the phpbb logo's width +			// and height here if the contents of the site_logo file are +			// really equal to the phpbb_logo +			// This allows us to change the dimensions of the phpbb_logo without +			// modifying the imageset.cfg and causing a conflict for everyone +			// who modified it for their custom logo on updating +			if ($img == 'site_logo' && file_exists($phpbb_root_path . $path)) +			{ +				global $cache; + +				$img_file_hashes = $cache->get('imageset_site_logo_md5'); + +				if ($img_file_hashes === false) +				{ +					$img_file_hashes = array(); +				} + +				$key = $this->theme['imageset_path'] . '::' . $this->img_array[$img]['image_lang']; +				if (!isset($img_file_hashes[$key])) +				{ +					$img_file_hashes[$key] = md5(file_get_contents($phpbb_root_path . $path)); +					$cache->put('imageset_site_logo_md5', $img_file_hashes); +				} + +				$phpbb_logo_hash = '0c461a32cd3621643105f0d02a772c10'; + +				if ($phpbb_logo_hash == $img_file_hashes[$key]) +				{ +					$img_data['width'] = '149'; +					$img_data['height'] = '52'; +				} +			}  		}  		$alt = (!empty($this->lang[$alt])) ? $this->lang[$alt] : $alt; diff --git a/phpBB/includes/startup.php b/phpBB/includes/startup.php new file mode 100644 index 0000000000..ca9665da29 --- /dev/null +++ b/phpBB/includes/startup.php @@ -0,0 +1,150 @@ +<?php +/** +* +* @package phpBB3 +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +// Report all errors, except notices and deprecation messages +if (!defined('E_DEPRECATED')) +{ +	define('E_DEPRECATED', 8192); +} +error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED); + +/* +* Remove variables created by register_globals from the global scope +* Thanks to Matt Kavanagh +*/ +function deregister_globals() +{ +	$not_unset = array( +		'GLOBALS'	=> true, +		'_GET'		=> true, +		'_POST'		=> true, +		'_COOKIE'	=> true, +		'_REQUEST'	=> true, +		'_SERVER'	=> true, +		'_SESSION'	=> true, +		'_ENV'		=> true, +		'_FILES'	=> true, +		'phpEx'		=> true, +		'phpbb_root_path'	=> true +	); + +	// Not only will array_merge and array_keys give a warning if +	// a parameter is not an array, array_merge will actually fail. +	// So we check if _SESSION has been initialised. +	if (!isset($_SESSION) || !is_array($_SESSION)) +	{ +		$_SESSION = array(); +	} + +	// Merge all into one extremely huge array; unset this later +	$input = array_merge( +		array_keys($_GET), +		array_keys($_POST), +		array_keys($_COOKIE), +		array_keys($_SERVER), +		array_keys($_SESSION), +		array_keys($_ENV), +		array_keys($_FILES) +	); + +	foreach ($input as $varname) +	{ +		if (isset($not_unset[$varname])) +		{ +			// Hacking attempt. No point in continuing unless it's a COOKIE (so a cookie called GLOBALS doesn't lock users out completely) +			if ($varname !== 'GLOBALS' || isset($_GET['GLOBALS']) || isset($_POST['GLOBALS']) || isset($_SERVER['GLOBALS']) || isset($_SESSION['GLOBALS']) || isset($_ENV['GLOBALS']) || isset($_FILES['GLOBALS'])) +			{ +				exit; +			} +			else +			{ +				$cookie = &$_COOKIE; +				while (isset($cookie['GLOBALS'])) +				{ +					if (!is_array($cookie['GLOBALS'])) +					{ +						break; +					} + +					foreach ($cookie['GLOBALS'] as $registered_var => $value) +					{ +						if (!isset($not_unset[$registered_var])) +						{ +							unset($GLOBALS[$registered_var]); +						} +					} +					$cookie = &$cookie['GLOBALS']; +				} +			} +		} + +		unset($GLOBALS[$varname]); +	} + +	unset($input); +} + +// If we are on PHP >= 6.0.0 we do not need some code +if (version_compare(PHP_VERSION, '6.0.0-dev', '>=')) +{ +	/** +	* @ignore +	*/ +	define('STRIP', false); +} +else +{ +	@set_magic_quotes_runtime(0); + +	// Be paranoid with passed vars +	if (@ini_get('register_globals') == '1' || strtolower(@ini_get('register_globals')) == 'on' || !function_exists('ini_get')) +	{ +		deregister_globals(); +	} + +	define('STRIP', (get_magic_quotes_gpc()) ? true : false); +} + +// Prevent date/time functions from throwing E_WARNING on PHP 5.3 by setting a default timezone +if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) +{ +	// For PHP 5.1.0 the date/time functions have been rewritten +	// and setting a timezone is required prior to calling any date/time function. + +	// Since PHP 5.2.0 calls to date/time functions without having a timezone set +	// result in E_STRICT errors being thrown. +	// Note: We already exclude E_STRICT errors +	// (to be exact: they are not included in E_ALL in PHP 5.2) + +	// In PHP 5.3.0 the error level has been raised to E_WARNING which causes problems +	// because we show E_WARNING errors and do not set a default timezone. +	// This is because we have our own timezone handling and work in UTC only anyway. + +	// So what we basically want to do is set our timezone to UTC, +	// but we don't know what other scripts (such as bridges) are involved, +	// so we check whether a timezone is already set by calling date_default_timezone_get(). + +	// Unfortunately, date_default_timezone_get() itself might throw E_WARNING +	// if no timezone has been set, so we have to keep it quiet with @. + +	// date_default_timezone_get() tries to guess the correct timezone first +	// and then falls back to UTC when everything fails. +	// We just set the timezone to whatever date_default_timezone_get() returns. +	date_default_timezone_set(@date_default_timezone_get()); +} + +$starttime = explode(' ', microtime()); +$starttime = $starttime[1] + $starttime[0]; diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index f1c8094a9b..9ac395344f 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -205,7 +205,7 @@ class template  	{  		global $user, $phpbb_hook; -		if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once)) +		if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once, $this))  		{  			if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__)))  			{ @@ -276,7 +276,7 @@ class template  		$this->files_template[$handle] = (isset($user->theme['template_id'])) ? $user->theme['template_id'] : 0;  		$recompile = false; -		if (!file_exists($filename) || @filesize($filename) === 0) +		if (!file_exists($filename) || @filesize($filename) === 0 || defined('DEBUG_EXTRA'))  		{  			$recompile = true;  		} diff --git a/phpBB/includes/ucp/ucp_activate.php b/phpBB/includes/ucp/ucp_activate.php index 8debaabf31..b00c1b9f52 100644 --- a/phpBB/includes/ucp/ucp_activate.php +++ b/phpBB/includes/ucp/ucp_activate.php @@ -98,6 +98,13 @@ class ucp_activate  				SET user_actkey = ''  				WHERE user_id = {$user_row['user_id']}";  			$db->sql_query($sql); + +			// Create the correct logs +			add_log('user', $user_row['user_id'], 'LOG_USER_ACTIVE_USER'); +			if ($auth->acl_get('a_user')) +			{ +				add_log('admin', 'LOG_USER_ACTIVE', $user_row['username']); +			}  		}  		if ($config['require_activation'] == USER_ACTIVATION_ADMIN && !$update_password) diff --git a/phpBB/includes/ucp/ucp_pm.php b/phpBB/includes/ucp/ucp_pm.php index e1c51170db..c675928a5b 100644 --- a/phpBB/includes/ucp/ucp_pm.php +++ b/phpBB/includes/ucp/ucp_pm.php @@ -115,7 +115,7 @@ class ucp_pm  			case 'compose':  				$action = request_var('action', 'post'); -				get_folder($user->data['user_id']); +				$user_folders = get_folder($user->data['user_id']);  				if (!$auth->acl_get('u_sendpm'))  				{ @@ -130,7 +130,7 @@ class ucp_pm  				}  				include($phpbb_root_path . 'includes/ucp/ucp_pm_compose.' . $phpEx); -				compose_pm($id, $mode, $action); +				compose_pm($id, $mode, $action, $user_folders);  				$tpl_file = 'posting_body';  			break; diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index b596e72c41..05243e3d7a 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -20,7 +20,7 @@ if (!defined('IN_PHPBB'))  * Compose private message  * Called from ucp_pm with mode == 'compose'  */ -function compose_pm($id, $mode, $action) +function compose_pm($id, $mode, $action, $user_folders = array())  {  	global $template, $db, $auth, $user;  	global $phpbb_root_path, $phpEx, $config; @@ -135,6 +135,7 @@ function compose_pm($id, $mode, $action)  	}  	$sql = ''; +	$folder_id = 0;  	// What is all this following SQL for? Well, we need to know  	// some basic information in all cases before we do anything. @@ -398,7 +399,7 @@ function compose_pm($id, $mode, $action)  	unset($message_text);  	$s_action = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=$mode&action=$action", true, $user->session_id); -	$s_action .= ($msg_id) ? "&p=$msg_id" : ''; +	$s_action .= (($folder_id) ? "&f=$folder_id" : '') . (($msg_id) ? "&p=$msg_id" : '');  	// Delete triggered ?  	if ($action == 'delete') @@ -741,10 +742,30 @@ function compose_pm($id, $mode, $action)  			$msg_id = submit_pm($action, $subject, $pm_data);  			$return_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=view&p=' . $msg_id); -			$return_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=outbox'); -			meta_refresh(3, $return_message_url); +			$inbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'); +			$outbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=outbox'); + +			$folder_url = ''; +			if (($folder_id > 0) && isset($user_folders[$folder_id])) +			{ +				$folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $folder_id); +			} + +			$return_box_url = ($action === 'post' || $action === 'edit') ? $outbox_folder_url : $inbox_folder_url; +			$return_box_lang = ($action === 'post' || $action === 'edit') ? 'PM_OUTBOX' : 'PM_INBOX'; + -			$message = $user->lang['MESSAGE_STORED'] . '<br /><br />' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '<a href="' . $return_message_url . '">', '</a>') . '<br /><br />' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . $return_folder_url . '">', '</a>', $user->lang['PM_OUTBOX']); +			$message = $user->lang['MESSAGE_STORED'] . '<br /><br />' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '<a href="' . $return_message_url . '">', '</a>'); + +			$last_click_type = 'CLICK_RETURN_FOLDER'; +			if ($folder_url) +			{ +				$message .= '<br /><br />' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . $folder_url . '">', '</a>', $user_folders[$folder_id]['folder_name']); +				$last_click_type = 'CLICK_GOTO_FOLDER'; +			} +			$message .= '<br /><br />' . sprintf($user->lang[$last_click_type], '<a href="' . $return_box_url . '">', '</a>', $user->lang[$return_box_lang]); + +			meta_refresh(3, $return_message_url);  			trigger_error($message);  		} diff --git a/phpBB/includes/ucp/ucp_pm_viewfolder.php b/phpBB/includes/ucp/ucp_pm_viewfolder.php index 6b7172ca2b..bd7bf89854 100644 --- a/phpBB/includes/ucp/ucp_pm_viewfolder.php +++ b/phpBB/includes/ucp/ucp_pm_viewfolder.php @@ -169,6 +169,7 @@ function view_folder($id, $mode, $folder_id, $folder)  					'PM_IMG'			=> ($row_indicator) ? $user->img('pm_' . $row_indicator, '') : '',  					'ATTACH_ICON_IMG'	=> ($auth->acl_get('u_pm_download') && $row['message_attachment'] && $config['allow_pm_attach']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', +					'S_PM_UNREAD'		=> ($row['pm_unread']) ? true : false,  					'S_PM_DELETED'		=> ($row['pm_deleted']) ? true : false,  					'S_PM_REPORTED'		=> (isset($row['report_id'])) ? true : false,  					'S_AUTHOR_DELETED'	=> ($row['author_id'] == ANONYMOUS) ? true : false, diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php index 16700c490c..d0cfa1ffd2 100644 --- a/phpBB/includes/ucp/ucp_pm_viewmessage.php +++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php @@ -172,6 +172,8 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)  	// Number of "to" recipients  	$num_recipients = (int) preg_match_all('/:?(u|g)_([0-9]+):?/', $message_row['to_address'], $match); +	$bbcode_status	= ($config['allow_bbcode'] && $config['auth_bbcode_pm'] && $auth->acl_get('u_pm_bbcode')) ? true : false; +  	$template->assign_vars(array(  		'MESSAGE_AUTHOR_FULL'		=> get_username_string('full', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']),  		'MESSAGE_AUTHOR_COLOUR'		=> get_username_string('colour', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']), @@ -206,7 +208,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)  		'U_PM'			=> ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && ($user_info['user_allow_pm'] || $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $author_id) : '',  		'U_WWW'			=> (!empty($user_info['user_website'])) ? $user_info['user_website'] : '', -		'U_ICQ'			=> ($user_info['user_icq']) ? 'http://www.icq.com/people/webmsg.php?to=' . urlencode($user_info['user_icq']) : '', +		'U_ICQ'			=> ($user_info['user_icq']) ? 'http://www.icq.com/people' . urlencode($user_info['user_icq']) . '/' : '',  		'U_AIM'			=> ($user_info['user_aim'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=aim&u=' . $author_id) : '',  		'U_YIM'			=> ($user_info['user_yim']) ? 'http://edit.yahoo.com/config/send_webmesg?.target=' . urlencode($user_info['user_yim']) . '&.src=pg' : '',  		'U_MSN'			=> ($user_info['user_msnm'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=msnm&u=' . $author_id) : '', @@ -229,6 +231,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)  		'S_AUTHOR_DELETED'	=> ($author_id == ANONYMOUS) ? true : false,  		'S_SPECIAL_FOLDER'	=> in_array($folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)),  		'S_PM_RECIPIENTS'	=> $num_recipients, +		'S_BBCODE_ALLOWED'	=> ($bbcode_status) ? 1 : 0,  		'U_PRINT_PM'		=> ($config['print_pm'] && $auth->acl_get('u_pm_printpm')) ? "$url&f=$folder_id&p=" . $message_row['msg_id'] . "&view=print" : '',  		'U_FORWARD_PM'		=> ($config['forward_pm'] && $auth->acl_get('u_sendpm') && $auth->acl_get('u_pm_forward')) ? "$url&mode=compose&action=forward&f=$folder_id&p=" . $message_row['msg_id'] : '') diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php index cc8565e69d..13167b2b3d 100644 --- a/phpBB/includes/ucp/ucp_prefs.php +++ b/phpBB/includes/ucp/ucp_prefs.php @@ -65,7 +65,7 @@ class ucp_prefs  					$error = validate_data($data, array(  						'dateformat'	=> array('string', false, 1, 30), -						'lang'			=> array('match', false, '#^[a-z0-9_\-]{2,}$#i'), +						'lang'			=> array('language_iso_name'),  						'tz'			=> array('num', false, -14, 14),  					)); diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index 7fd99da55a..13b9945851 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -56,7 +56,7 @@ class ucp_register  		{  			$use_lang = ($change_lang) ? basename($change_lang) : basename($user_lang); -			if (file_exists($user->lang_path . $use_lang . '/')) +			if (!validate_language_iso_name($use_lang))  			{  				if ($change_lang)  				{ @@ -210,7 +210,7 @@ class ucp_register  					array('email')),  				'email_confirm'		=> array('string', false, 6, 60),  				'tz'				=> array('num', false, -14, 14), -				'lang'				=> array('match', false, '#^[a-z_\-]{2,}$#i'), +				'lang'				=> array('language_iso_name'),  			));  			if (!check_form_key('ucp_register'))  | 
