aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/includes
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/includes')
-rw-r--r--phpBB/includes/acm/acm_file.php4
-rw-r--r--phpBB/includes/acm/acm_redis.php145
-rw-r--r--phpBB/includes/acm/acm_wincache.php84
-rw-r--r--phpBB/includes/acp/acp_bbcodes.php2
-rw-r--r--phpBB/includes/acp/acp_board.php16
-rw-r--r--phpBB/includes/acp/acp_disallow.php12
-rw-r--r--phpBB/includes/acp/acp_email.php45
-rw-r--r--phpBB/includes/acp/acp_icons.php4
-rw-r--r--phpBB/includes/acp/acp_language.php12
-rw-r--r--phpBB/includes/acp/acp_main.php2
-rw-r--r--phpBB/includes/acp/acp_profile.php2
-rw-r--r--phpBB/includes/acp/acp_search.php18
-rw-r--r--phpBB/includes/acp/acp_styles.php261
-rw-r--r--phpBB/includes/acp/acp_words.php3
-rw-r--r--phpBB/includes/auth.php14
-rw-r--r--phpBB/includes/auth/auth_db.php65
-rw-r--r--phpBB/includes/auth/auth_ldap.php2
-rw-r--r--phpBB/includes/cache.php19
-rw-r--r--phpBB/includes/captcha/captcha_gd.php56
-rw-r--r--phpBB/includes/captcha/captcha_gd_wave.php4
-rw-r--r--phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php4
-rw-r--r--phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php13
-rw-r--r--phpBB/includes/constants.php8
-rw-r--r--phpBB/includes/db/db_tools.php311
-rw-r--r--phpBB/includes/db/dbal.php12
-rw-r--r--phpBB/includes/db/firebird.php49
-rw-r--r--phpBB/includes/db/mssqlnative.php12
-rw-r--r--phpBB/includes/db/oracle.php3
-rw-r--r--phpBB/includes/db/postgres.php36
-rw-r--r--phpBB/includes/error_collector.php61
-rw-r--r--phpBB/includes/functions.php149
-rw-r--r--phpBB/includes/functions_admin.php24
-rw-r--r--phpBB/includes/functions_convert.php1
-rw-r--r--phpBB/includes/functions_display.php3
-rw-r--r--phpBB/includes/functions_posting.php108
-rw-r--r--phpBB/includes/functions_profile_fields.php14
-rw-r--r--phpBB/includes/functions_template.php2
-rw-r--r--phpBB/includes/functions_upload.php4
-rw-r--r--phpBB/includes/functions_user.php103
-rw-r--r--phpBB/includes/mcp/mcp_front.php2
-rw-r--r--phpBB/includes/mcp/mcp_main.php51
-rw-r--r--phpBB/includes/mcp/mcp_post.php4
-rw-r--r--phpBB/includes/message_parser.php44
-rw-r--r--phpBB/includes/session.php103
-rw-r--r--phpBB/includes/startup.php150
-rw-r--r--phpBB/includes/template.php4
-rw-r--r--phpBB/includes/ucp/ucp_activate.php7
-rw-r--r--phpBB/includes/ucp/ucp_pm.php4
-rw-r--r--phpBB/includes/ucp/ucp_pm_compose.php31
-rw-r--r--phpBB/includes/ucp/ucp_pm_viewfolder.php1
-rw-r--r--phpBB/includes/ucp/ucp_pm_viewmessage.php5
-rw-r--r--phpBB/includes/ucp/ucp_prefs.php2
-rw-r--r--phpBB/includes/ucp/ucp_register.php4
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 &copy; 2000, 2002, 2005, 2007 <a href="http://www.phpbb.com/">phpBB Group</a>
+ Powered by <a href="http://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; 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 &copy; 2000, 2002, 2005, 2007 <a href="http://www.phpbb.com/">phpBB Group</a>';
+ echo ' Powered by <a href="http://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; 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'] . '&amp;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'] . '&amp;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&amp;mode=unapproved_topics&amp;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&amptopic_id=2&ampp=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&amp;t=$topic_id&amp;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(?:=&quot;(.*?)&quot;)?\](.+)\[/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(?:=&quot;(.*?)&quot;)?\](.+)\[/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&amp;mode=$mode&amp;action=$action", true, $user->session_id);
- $s_action .= ($msg_id) ? "&amp;p=$msg_id" : '';
+ $s_action .= (($folder_id) ? "&amp;f=$folder_id" : '') . (($msg_id) ? "&amp;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&amp;mode=view&amp;p=' . $msg_id);
- $return_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=outbox');
- meta_refresh(3, $return_message_url);
+ $inbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=inbox');
+ $outbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=outbox');
+
+ $folder_url = '';
+ if (($folder_id > 0) && isset($user_folders[$folder_id]))
+ {
+ $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;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&amp;mode=compose&amp;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&amp;action=aim&amp;u=' . $author_id) : '',
'U_YIM' => ($user_info['user_yim']) ? 'http://edit.yahoo.com/config/send_webmesg?.target=' . urlencode($user_info['user_yim']) . '&amp;.src=pg' : '',
'U_MSN' => ($user_info['user_msnm'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&amp;action=msnm&amp;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&amp;f=$folder_id&amp;p=" . $message_row['msg_id'] . "&amp;view=print" : '',
'U_FORWARD_PM' => ($config['forward_pm'] && $auth->acl_get('u_sendpm') && $auth->acl_get('u_pm_forward')) ? "$url&amp;mode=compose&amp;action=forward&amp;f=$folder_id&amp;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'))