diff options
Diffstat (limited to 'phpBB/includes')
45 files changed, 1153 insertions, 260 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..8954b9d0e7 --- /dev/null +++ b/phpBB/includes/acm/acm_redis.php @@ -0,0 +1,155 @@ +<?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'); +} + +if (!defined('PHPBB_ACM_REDIS')) +{ + //can define multiple servers with host1/port1,host2/port2 format + define('PHPBB_ACM_REDIS', PHPBB_ACM_REDIS_HOST . '/' . PHPBB_ACM_REDIS_PORT); +} + +/** +* 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(); + foreach (explode(',', PHPBB_ACM_REDIS) as $server) + { + $parts = explode('/', $server); + $this->redis->connect(trim($parts[0]), trim($parts[1])); + } + + 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/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..d38c4d58ba 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -769,13 +769,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..37cf8d1f72 100644 --- a/phpBB/includes/acp/acp_styles.php +++ b/phpBB/includes/acp/acp_styles.php @@ -716,7 +716,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 +1587,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 +1633,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 +1655,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 +1677,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 +1696,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/auth.php b/phpBB/includes/auth.php index 02819f9e78..8324cb4977 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; } } 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/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_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 90440f74b8..ea34eb8e81 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -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); diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index f4b181c6ad..483ceee043 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -681,10 +681,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 +697,8 @@ class phpbb_db_tools { if ($column_exists) { - $sqlite_data[$table]['change_columns'][] = $result; + continue; +// $sqlite_data[$table]['change_columns'][] = $result; } else { @@ -717,6 +720,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 +785,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 +807,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 +1121,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 */ @@ -1371,24 +1619,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']; @@ -1957,6 +2210,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 5d8d5fbd47..2f9619c8ea 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 */ 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 ded69d7150..b8d9e0b92e 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; } @@ -2249,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) { @@ -2631,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 @@ -3729,7 +3759,7 @@ 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') + if (ob_get_level() > 0) { @ob_flush(); } @@ -4251,7 +4281,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)) { @@ -4523,7 +4553,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 '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']}/", @@ -4531,7 +4561,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'T_ICONS_PATH' => "{$web_path}{$config['icons_path']}/", 'T_RANKS_PATH' => "{$web_path}{$config['ranks_path']}/", 'T_UPLOAD_PATH' => "{$web_path}{$config['upload_path']}/", - 'T_STYLESHEET_LINK' => (!$user->theme['theme_storedb']) ? "{$web_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : append_sid("{$phpbb_root_path}style.$phpEx", 'id=' . $user->theme['style_id'] . '&lang=' . $user->data['user_lang']), + 'T_STYLESHEET_LINK' => (!$user->theme['theme_storedb']) ? "{$web_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : append_sid("{$phpbb_root_path}style.$phpEx", 'id=' . $user->theme['style_id'] . '&lang=' . $user->lang_name), 'T_STYLESHEET_NAME' => $user->theme['theme_name'], 'T_THEME_NAME' => $user->theme['theme_path'], @@ -4609,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(); @@ -4713,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_display.php b/phpBB/includes/functions_display.php index acaef49fe8..d7422aa2c9 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -477,7 +477,6 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'SUBFORUMS' => $s_subforums_list, 'L_SUBFORUM_STR' => $l_subforums, - 'L_FORUM_FOLDER_ALT' => $folder_alt, 'L_MODERATOR_STR' => $l_moderator, 'U_UNAPPROVED_TOPICS' => ($row['forum_id_unapproved_topics']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=unapproved_topics&f=' . $row['forum_id_unapproved_topics']) : '', diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 72331a73c6..271039f415 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -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' : ''); 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_user.php b/phpBB/includes/functions_user.php index 90341cd926..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) 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..6951dcf820 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -110,19 +110,19 @@ class bbcode_firstpass extends bbcode // order, so it is important to keep [code] in first position and // [quote] in second position. $this->bbcodes = array( - 'code' => array('bbcode_id' => 8, 'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#ise' => "\$this->bbcode_code('\$1', '\$2')")), - 'quote' => array('bbcode_id' => 0, 'regexp' => array('#\[quote(?:="(.*?)")?\](.+)\[/quote\]#ise' => "\$this->bbcode_quote('\$0')")), - 'attachment' => array('bbcode_id' => 12, 'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#ise' => "\$this->bbcode_attachment('\$1', '\$2')")), - 'b' => array('bbcode_id' => 1, 'regexp' => array('#\[b\](.*?)\[/b\]#ise' => "\$this->bbcode_strong('\$1')")), - 'i' => array('bbcode_id' => 2, 'regexp' => array('#\[i\](.*?)\[/i\]#ise' => "\$this->bbcode_italic('\$1')")), - 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](.*)\[/url\]#iUe' => "\$this->validate_url('\$2', '\$3')")), - 'img' => array('bbcode_id' => 4, 'regexp' => array('#\[img\](.*)\[/img\]#iUe' => "\$this->bbcode_img('\$1')")), - 'size' => array('bbcode_id' => 5, 'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#ise' => "\$this->bbcode_size('\$1', '\$2')")), - 'color' => array('bbcode_id' => 6, 'regexp' => array('!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!ise' => "\$this->bbcode_color('\$1', '\$2')")), - 'u' => array('bbcode_id' => 7, 'regexp' => array('#\[u\](.*?)\[/u\]#ise' => "\$this->bbcode_underline('\$1')")), - 'list' => array('bbcode_id' => 9, 'regexp' => array('#\[list(?:=(?:[a-z0-9]|disc|circle|square))?].*\[/list]#ise' => "\$this->bbcode_parse_list('\$0')")), - 'email' => array('bbcode_id' => 10, 'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#ise' => "\$this->validate_email('\$1', '\$2')")), - 'flash' => array('bbcode_id' => 11, 'regexp' => array('#\[flash=([0-9]+),([0-9]+)\](.*?)\[/flash\]#ie' => "\$this->bbcode_flash('\$1', '\$2', '\$3')")) + 'code' => array('bbcode_id' => 8, 'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#uise' => "\$this->bbcode_code('\$1', '\$2')")), + 'quote' => array('bbcode_id' => 0, 'regexp' => array('#\[quote(?:="(.*?)")?\](.+)\[/quote\]#uise' => "\$this->bbcode_quote('\$0')")), + 'attachment' => array('bbcode_id' => 12, 'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#uise' => "\$this->bbcode_attachment('\$1', '\$2')")), + 'b' => array('bbcode_id' => 1, 'regexp' => array('#\[b\](.*?)\[/b\]#uise' => "\$this->bbcode_strong('\$1')")), + 'i' => array('bbcode_id' => 2, 'regexp' => array('#\[i\](.*?)\[/i\]#uise' => "\$this->bbcode_italic('\$1')")), + 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](.*)\[/url\]#uiUe' => "\$this->validate_url('\$2', '\$3')")), + '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 @@ -1332,7 +1332,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 +1345,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..2181375dc1 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -583,6 +583,13 @@ 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'])) + { + 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 +626,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; } @@ -1237,6 +1238,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 +1973,7 @@ class user extends session $key_found = $num; } + break; } } diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 6347633b14..9ac395344f 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -276,7 +276,7 @@ class template $this->files_template[$handle] = (isset($user->theme['template_id'])) ? $user->theme['template_id'] : 0; $recompile = false; - if (!file_exists($filename) || @filesize($filename) === 0) + if (!file_exists($filename) || @filesize($filename) === 0 || defined('DEBUG_EXTRA')) { $recompile = true; } diff --git a/phpBB/includes/ucp/ucp_activate.php b/phpBB/includes/ucp/ucp_activate.php index 8debaabf31..b00c1b9f52 100644 --- a/phpBB/includes/ucp/ucp_activate.php +++ b/phpBB/includes/ucp/ucp_activate.php @@ -98,6 +98,13 @@ class ucp_activate SET user_actkey = '' WHERE user_id = {$user_row['user_id']}"; $db->sql_query($sql); + + // Create the correct logs + add_log('user', $user_row['user_id'], 'LOG_USER_ACTIVE_USER'); + if ($auth->acl_get('a_user')) + { + add_log('admin', 'LOG_USER_ACTIVE', $user_row['username']); + } } if ($config['require_activation'] == USER_ACTIVATION_ADMIN && !$update_password) diff --git a/phpBB/includes/ucp/ucp_pm.php b/phpBB/includes/ucp/ucp_pm.php index e1c51170db..c675928a5b 100644 --- a/phpBB/includes/ucp/ucp_pm.php +++ b/phpBB/includes/ucp/ucp_pm.php @@ -115,7 +115,7 @@ class ucp_pm case 'compose': $action = request_var('action', 'post'); - get_folder($user->data['user_id']); + $user_folders = get_folder($user->data['user_id']); if (!$auth->acl_get('u_sendpm')) { @@ -130,7 +130,7 @@ class ucp_pm } include($phpbb_root_path . 'includes/ucp/ucp_pm_compose.' . $phpEx); - compose_pm($id, $mode, $action); + compose_pm($id, $mode, $action, $user_folders); $tpl_file = 'posting_body'; break; diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index b596e72c41..05243e3d7a 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -20,7 +20,7 @@ if (!defined('IN_PHPBB')) * Compose private message * Called from ucp_pm with mode == 'compose' */ -function compose_pm($id, $mode, $action) +function compose_pm($id, $mode, $action, $user_folders = array()) { global $template, $db, $auth, $user; global $phpbb_root_path, $phpEx, $config; @@ -135,6 +135,7 @@ function compose_pm($id, $mode, $action) } $sql = ''; + $folder_id = 0; // What is all this following SQL for? Well, we need to know // some basic information in all cases before we do anything. @@ -398,7 +399,7 @@ function compose_pm($id, $mode, $action) unset($message_text); $s_action = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=$mode&action=$action", true, $user->session_id); - $s_action .= ($msg_id) ? "&p=$msg_id" : ''; + $s_action .= (($folder_id) ? "&f=$folder_id" : '') . (($msg_id) ? "&p=$msg_id" : ''); // Delete triggered ? if ($action == 'delete') @@ -741,10 +742,30 @@ function compose_pm($id, $mode, $action) $msg_id = submit_pm($action, $subject, $pm_data); $return_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=view&p=' . $msg_id); - $return_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=outbox'); - meta_refresh(3, $return_message_url); + $inbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'); + $outbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=outbox'); + + $folder_url = ''; + if (($folder_id > 0) && isset($user_folders[$folder_id])) + { + $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $folder_id); + } + + $return_box_url = ($action === 'post' || $action === 'edit') ? $outbox_folder_url : $inbox_folder_url; + $return_box_lang = ($action === 'post' || $action === 'edit') ? 'PM_OUTBOX' : 'PM_INBOX'; + - $message = $user->lang['MESSAGE_STORED'] . '<br /><br />' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '<a href="' . $return_message_url . '">', '</a>') . '<br /><br />' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . $return_folder_url . '">', '</a>', $user->lang['PM_OUTBOX']); + $message = $user->lang['MESSAGE_STORED'] . '<br /><br />' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '<a href="' . $return_message_url . '">', '</a>'); + + $last_click_type = 'CLICK_RETURN_FOLDER'; + if ($folder_url) + { + $message .= '<br /><br />' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . $folder_url . '">', '</a>', $user_folders[$folder_id]['folder_name']); + $last_click_type = 'CLICK_GOTO_FOLDER'; + } + $message .= '<br /><br />' . sprintf($user->lang[$last_click_type], '<a href="' . $return_box_url . '">', '</a>', $user->lang[$return_box_lang]); + + meta_refresh(3, $return_message_url); trigger_error($message); } diff --git a/phpBB/includes/ucp/ucp_pm_viewfolder.php b/phpBB/includes/ucp/ucp_pm_viewfolder.php index 6b7172ca2b..bd7bf89854 100644 --- a/phpBB/includes/ucp/ucp_pm_viewfolder.php +++ b/phpBB/includes/ucp/ucp_pm_viewfolder.php @@ -169,6 +169,7 @@ function view_folder($id, $mode, $folder_id, $folder) 'PM_IMG' => ($row_indicator) ? $user->img('pm_' . $row_indicator, '') : '', 'ATTACH_ICON_IMG' => ($auth->acl_get('u_pm_download') && $row['message_attachment'] && $config['allow_pm_attach']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', + 'S_PM_UNREAD' => ($row['pm_unread']) ? true : false, 'S_PM_DELETED' => ($row['pm_deleted']) ? true : false, 'S_PM_REPORTED' => (isset($row['report_id'])) ? true : false, 'S_AUTHOR_DELETED' => ($row['author_id'] == ANONYMOUS) ? true : false, diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php index b91636a9c8..d0cfa1ffd2 100644 --- a/phpBB/includes/ucp/ucp_pm_viewmessage.php +++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php @@ -208,7 +208,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) 'U_PM' => ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && ($user_info['user_allow_pm'] || $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $author_id) : '', 'U_WWW' => (!empty($user_info['user_website'])) ? $user_info['user_website'] : '', - 'U_ICQ' => ($user_info['user_icq']) ? 'http://www.icq.com/people/webmsg.php?to=' . urlencode($user_info['user_icq']) : '', + 'U_ICQ' => ($user_info['user_icq']) ? 'http://www.icq.com/people' . urlencode($user_info['user_icq']) . '/' : '', 'U_AIM' => ($user_info['user_aim'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=aim&u=' . $author_id) : '', 'U_YIM' => ($user_info['user_yim']) ? 'http://edit.yahoo.com/config/send_webmesg?.target=' . urlencode($user_info['user_yim']) . '&.src=pg' : '', 'U_MSN' => ($user_info['user_msnm'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=msnm&u=' . $author_id) : '', 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')) |