diff options
Diffstat (limited to 'phpBB/includes')
53 files changed, 1509 insertions, 439 deletions
diff --git a/phpBB/includes/acm/acm_apc.php b/phpBB/includes/acm/acm_apc.php index 1a487f94ad..205353d3a5 100644 --- a/phpBB/includes/acm/acm_apc.php +++ b/phpBB/includes/acm/acm_apc.php @@ -33,7 +33,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { diff --git a/phpBB/includes/acm/acm_eaccelerator.php b/phpBB/includes/acm/acm_eaccelerator.php index 645067c199..ecec3ac9a5 100644 --- a/phpBB/includes/acm/acm_eaccelerator.php +++ b/phpBB/includes/acm/acm_eaccelerator.php @@ -37,7 +37,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { @@ -54,7 +54,7 @@ class acm extends acm_memory /** * Perform cache garbage collection * - * @return void + * @return null */ function tidy() { diff --git a/phpBB/includes/acm/acm_memcache.php b/phpBB/includes/acm/acm_memcache.php index e54fa36c38..70bc219952 100644 --- a/phpBB/includes/acm/acm_memcache.php +++ b/phpBB/includes/acm/acm_memcache.php @@ -71,7 +71,7 @@ class acm extends acm_memory /** * Unload the cache resources * - * @return void + * @return null */ function unload() { @@ -83,7 +83,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { diff --git a/phpBB/includes/acm/acm_redis.php b/phpBB/includes/acm/acm_redis.php index 41533eaacb..dc11ca7768 100644 --- a/phpBB/includes/acm/acm_redis.php +++ b/phpBB/includes/acm/acm_redis.php @@ -80,7 +80,7 @@ class acm extends acm_memory /** * Unload the cache resources * - * @return void + * @return null */ function unload() { @@ -92,7 +92,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { diff --git a/phpBB/includes/acm/acm_wincache.php b/phpBB/includes/acm/acm_wincache.php index 0501ab74c5..7faba4f5b6 100644 --- a/phpBB/includes/acm/acm_wincache.php +++ b/phpBB/includes/acm/acm_wincache.php @@ -32,7 +32,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { diff --git a/phpBB/includes/acm/acm_xcache.php b/phpBB/includes/acm/acm_xcache.php index d0a614660c..e3d83f8bfa 100644 --- a/phpBB/includes/acm/acm_xcache.php +++ b/phpBB/includes/acm/acm_xcache.php @@ -48,7 +48,7 @@ class acm extends acm_memory /** * Purge cache data * - * @return void + * @return null */ function purge() { diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index f437dca8f9..ebbf66657e 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -408,8 +408,8 @@ class acp_board 'board_email_form' => array('lang' => 'BOARD_EMAIL_FORM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), 'email_function_name' => array('lang' => 'EMAIL_FUNCTION_NAME', 'validate' => 'string', 'type' => 'text:20:50', 'explain' => true), 'email_package_size' => array('lang' => 'EMAIL_PACKAGE_SIZE', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true), - 'board_contact' => array('lang' => 'CONTACT_EMAIL', 'validate' => 'string', 'type' => 'text:25:100', 'explain' => true), - 'board_email' => array('lang' => 'ADMIN_EMAIL', 'validate' => 'string', 'type' => 'text:25:100', 'explain' => true), + 'board_contact' => array('lang' => 'CONTACT_EMAIL', 'validate' => 'email', 'type' => 'text:25:100', 'explain' => true), + 'board_email' => array('lang' => 'ADMIN_EMAIL', 'validate' => 'email', 'type' => 'text:25:100', 'explain' => true), 'board_email_sig' => array('lang' => 'EMAIL_SIG', 'validate' => 'string', 'type' => 'textarea:5:30', 'explain' => true), 'board_hide_emails' => array('lang' => 'BOARD_HIDE_EMAILS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php index 62bcd43a47..758cd10434 100644 --- a/phpBB/includes/acp/acp_database.php +++ b/phpBB/includes/acp/acp_database.php @@ -21,6 +21,7 @@ if (!defined('IN_PHPBB')) */ class acp_database { + var $db_tools; var $u_action; function main($id, $mode) @@ -28,6 +29,12 @@ class acp_database global $cache, $db, $user, $auth, $template, $table_prefix; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + if (!class_exists('phpbb_db_tools')) + { + require($phpbb_root_path . 'includes/db/db_tools.' . $phpEx); + } + $this->db_tools = new phpbb_db_tools($db); + $user->add_lang('acp/database'); $this->tpl_name = 'acp_database'; @@ -50,7 +57,7 @@ class acp_database { case 'download': $type = request_var('type', ''); - $table = request_var('table', array('')); + $table = array_intersect($this->db_tools->sql_list_tables(), request_var('table', array(''))); $format = request_var('method', ''); $where = request_var('where', ''); @@ -173,8 +180,7 @@ class acp_database break; default: - include($phpbb_root_path . 'includes/functions_install.' . $phpEx); - $tables = get_tables($db); + $tables = $this->db_tools->sql_list_tables(); asort($tables); foreach ($tables as $table_name) { diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php index 486616c33d..9b9ea38e07 100644 --- a/phpBB/includes/acp/acp_groups.php +++ b/phpBB/includes/acp/acp_groups.php @@ -80,6 +80,11 @@ class acp_groups case 'approve': case 'demote': case 'promote': + if (!check_form_key($form_key)) + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); + } + if (!$group_id) { trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING); @@ -120,48 +125,64 @@ class acp_groups { trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING); } + else if (empty($mark_ary)) + { + trigger_error($user->lang['NO_USERS'] . adm_back_link($this->u_action . '&action=list&g=' . $group_id), E_USER_WARNING); + } if (confirm_box(true)) { $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name']; + group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row); + trigger_error($user->lang['GROUP_DEFS_UPDATED'] . adm_back_link($this->u_action . '&action=list&g=' . $group_id)); + } + else + { + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( + 'mark' => $mark_ary, + 'g' => $group_id, + 'i' => $id, + 'mode' => $mode, + 'action' => $action)) + ); + } + break; - if (!sizeof($mark_ary)) - { - $start = 0; + case 'set_default_on_all': + if (confirm_box(true)) + { + $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name']; + + $start = 0; - do + do + { + $sql = 'SELECT user_id + FROM ' . USER_GROUP_TABLE . " + WHERE group_id = $group_id + ORDER BY user_id"; + $result = $db->sql_query_limit($sql, 200, $start); + + $mark_ary = array(); + if ($row = $db->sql_fetchrow($result)) { - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . " - WHERE group_id = $group_id - ORDER BY user_id"; - $result = $db->sql_query_limit($sql, 200, $start); - - $mark_ary = array(); - if ($row = $db->sql_fetchrow($result)) + do { - do - { - $mark_ary[] = $row['user_id']; - } - while ($row = $db->sql_fetchrow($result)); + $mark_ary[] = $row['user_id']; + } + while ($row = $db->sql_fetchrow($result)); - group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row); + group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row); - $start = (sizeof($mark_ary) < 200) ? 0 : $start + 200; - } - else - { - $start = 0; - } - $db->sql_freeresult($result); + $start = (sizeof($mark_ary) < 200) ? 0 : $start + 200; } - while ($start); - } - else - { - group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row); + else + { + $start = 0; + } + $db->sql_freeresult($result); } + while ($start); trigger_error($user->lang['GROUP_DEFS_UPDATED'] . adm_back_link($this->u_action . '&action=list&g=' . $group_id)); } @@ -175,10 +196,13 @@ class acp_groups 'action' => $action)) ); } - break; case 'deleteusers': + if (empty($mark_ary)) + { + trigger_error($user->lang['NO_USERS'] . adm_back_link($this->u_action . '&action=list&g=' . $group_id), E_USER_WARNING); + } case 'delete': if (!$group_id) { @@ -233,6 +257,11 @@ class acp_groups break; case 'addusers': + if (!check_form_key($form_key)) + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); + } + if (!$group_id) { trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING); @@ -394,13 +423,21 @@ class acp_groups } } - // Validate the length of "Maximum number of allowed recipients per private message" setting. - // We use 16777215 as a maximum because it matches MySQL unsigned mediumint maximum value - // which is the lowest amongst DBMSes supported by phpBB3 - if ($max_recipients_error = validate_data($submit_ary, array('max_recipients' => array('num', false, 0, 16777215)))) + /* + * Validate the length of "Maximum number of allowed recipients per + * private message" setting. We use 16777215 as a maximum because it matches + * MySQL unsigned mediumint maximum value which is the lowest amongst DBMSes + * supported by phpBB3. Also validate the submitted colour value. + */ + $validation_checks = array( + 'max_recipients' => array('num', false, 0, 16777215), + 'colour' => array('hex_colour', true), + ); + + if ($validation_error = validate_data($submit_ary, $validation_checks)) { // Replace "error" string with its real, localised form - $error = array_merge($error, array_map(array(&$user, 'lang'), $max_recipients_error)); + $error = array_merge($error, array_map(array(&$user, 'lang'), $validation_error)); } if (!sizeof($error)) @@ -683,7 +720,7 @@ class acp_groups 'U_ACTION' => $this->u_action . "&g=$group_id", 'U_BACK' => $this->u_action, 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=list&field=usernames'), - 'U_DEFAULT_ALL' => "{$this->u_action}&action=default&g=$group_id", + 'U_DEFAULT_ALL' => "{$this->u_action}&action=set_default_on_all&g=$group_id", )); // Grab the members @@ -795,4 +832,4 @@ class acp_groups } } -?>
\ No newline at end of file +?> diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php index c8df21f5a9..ee7bd4dc45 100644 --- a/phpBB/includes/acp/acp_main.php +++ b/phpBB/includes/acp/acp_main.php @@ -201,7 +201,7 @@ class acp_main // No maximum post id? :o if (!$max_post_id) { - $sql = 'SELECT MAX(post_id) + $sql = 'SELECT MAX(post_id) as max_post_id FROM ' . POSTS_TABLE; $result = $db->sql_query($sql); $max_post_id = (int) $db->sql_fetchfield('max_post_id'); @@ -398,11 +398,11 @@ class acp_main // Version check $user->add_lang('install'); - if ($auth->acl_get('a_server') && version_compare(PHP_VERSION, '5.2.0', '<')) + if ($auth->acl_get('a_server') && version_compare(PHP_VERSION, '5.3.3', '<')) { $template->assign_vars(array( 'S_PHP_VERSION_OLD' => true, - 'L_PHP_VERSION_OLD' => sprintf($user->lang['PHP_VERSION_OLD'], '<a href="http://www.phpbb.com/community/viewtopic.php?f=14&t=1958605">', '</a>'), + 'L_PHP_VERSION_OLD' => sprintf($user->lang['PHP_VERSION_OLD'], '<a href="http://www.phpbb.com/community/viewtopic.php?f=14&t=2152375">', '</a>'), )); } diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index a591474fce..19223847f0 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -365,6 +365,7 @@ class acp_profile $field_row = array_merge($default_values[$field_type], array( 'field_ident' => str_replace(' ', '_', utf8_clean_string(request_var('field_ident', '', true))), 'field_required' => 0, + 'field_show_novalue'=> 0, 'field_hide' => 0, 'field_show_profile'=> 0, 'field_no_view' => 0, @@ -380,7 +381,7 @@ class acp_profile // $exclude contains the data we gather in each step $exclude = array( - 1 => array('field_ident', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_show_on_vt', 'field_required', 'field_hide', 'field_show_profile', 'field_no_view'), + 1 => array('field_ident', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_show_on_vt', 'field_required', 'field_show_novalue', 'field_hide', 'field_show_profile', 'field_no_view'), 2 => array('field_length', 'field_maxlen', 'field_minlen', 'field_validation', 'field_novalue', 'field_default_value'), 3 => array('l_lang_name', 'l_lang_explain', 'l_lang_default_value', 'l_lang_options') ); @@ -405,6 +406,7 @@ class acp_profile // Visibility Options... $visibility_ary = array( 'field_required', + 'field_show_novalue', 'field_show_on_reg', 'field_show_on_vt', 'field_show_profile', @@ -757,6 +759,7 @@ class acp_profile $template->assign_vars(array( 'S_STEP_ONE' => true, 'S_FIELD_REQUIRED' => ($cp->vars['field_required']) ? true : false, + 'S_FIELD_SHOW_NOVALUE'=> ($cp->vars['field_show_novalue']) ? true : false, 'S_SHOW_ON_REG' => ($cp->vars['field_show_on_reg']) ? true : false, 'S_SHOW_ON_VT' => ($cp->vars['field_show_on_vt']) ? true : false, 'S_FIELD_HIDE' => ($cp->vars['field_hide']) ? true : false, @@ -1073,6 +1076,7 @@ class acp_profile 'field_default_value' => $cp->vars['field_default_value'], 'field_validation' => $cp->vars['field_validation'], 'field_required' => $cp->vars['field_required'], + 'field_show_novalue' => $cp->vars['field_show_novalue'], 'field_show_on_reg' => $cp->vars['field_show_on_reg'], 'field_show_on_vt' => $cp->vars['field_show_on_vt'], 'field_hide' => $cp->vars['field_hide'], diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php index d7b0484af8..47cd02bca7 100644 --- a/phpBB/includes/acp/acp_styles.php +++ b/phpBB/includes/acp/acp_styles.php @@ -667,7 +667,9 @@ inherit_from = {INHERIT_FROM} if ($name && !in_array($name, $installed)) { - $new_ary[] = array( + // The array key is used for sorting later on. + // $file is appended because $name doesn't have to be unique. + $new_ary[$name . $file] = array( 'path' => $file, 'name' => $name, 'copyright' => $items['copyright'], @@ -683,6 +685,8 @@ inherit_from = {INHERIT_FROM} if (sizeof($new_ary)) { + ksort($new_ary); + foreach ($new_ary as $cfg) { $template->assign_block_vars('uninstalled', array( diff --git a/phpBB/includes/acp/acp_update.php b/phpBB/includes/acp/acp_update.php index 7e3d1a1024..5d3e9abcea 100644 --- a/phpBB/includes/acp/acp_update.php +++ b/phpBB/includes/acp/acp_update.php @@ -39,7 +39,7 @@ class acp_update $info = obtain_latest_version_info(request_var('versioncheck_force', false)); - if ($info === false) + if (empty($info)) { trigger_error('VERSIONCHECK_FAIL', E_USER_WARNING); } diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index 363c900edc..70e08f79f2 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -1009,6 +1009,13 @@ class acp_users $user_row['posts_in_queue'] = (int) $db->sql_fetchfield('posts_in_queue'); $db->sql_freeresult($result); + $sql = 'SELECT post_id + FROM ' . POSTS_TABLE . ' + WHERE poster_id = '. $user_id; + $result = $db->sql_query_limit($sql, 1); + $user_row['user_has_posts'] = (bool) $db->sql_fetchfield('post_id'); + $db->sql_freeresult($result); + $template->assign_vars(array( 'L_NAME_CHARS_EXPLAIN' => sprintf($user->lang[$config['allow_name_chars'] . '_EXPLAIN'], $config['min_name_chars'], $config['max_name_chars']), 'L_CHANGE_PASSWORD_EXPLAIN' => sprintf($user->lang[$config['pass_complex'] . '_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), @@ -1036,6 +1043,7 @@ class acp_users 'USER_EMAIL' => $user_row['user_email'], 'USER_WARNINGS' => $user_row['user_warnings'], 'USER_POSTS' => $user_row['user_posts'], + 'USER_HAS_POSTS' => $user_row['user_has_posts'], 'USER_INACTIVE_REASON' => $inactive_reason, )); diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php index c20196d019..1c6cdf7832 100644 --- a/phpBB/includes/auth/auth_db.php +++ b/phpBB/includes/auth/auth_db.php @@ -163,7 +163,7 @@ function login_db($username, $password, $ip = '', $browser = '', $forwarded_for $password_old_format = (!STRIP) ? addslashes($password_old_format) : $password_old_format; $password_new_format = ''; - set_var($password_new_format, stripslashes($password_old_format), 'string'); + set_var($password_new_format, stripslashes($password_old_format), 'string', true); if ($password == $password_new_format) { diff --git a/phpBB/includes/auth/auth_ldap.php b/phpBB/includes/auth/auth_ldap.php index 5dfa74ddab..eebf147d48 100644 --- a/phpBB/includes/auth/auth_ldap.php +++ b/phpBB/includes/auth/auth_ldap.php @@ -156,7 +156,11 @@ function login_ldap(&$username, &$password) { if (!@ldap_bind($ldap, htmlspecialchars_decode($config['ldap_user']), htmlspecialchars_decode($config['ldap_password']))) { - return $user->lang['LDAP_NO_SERVER_CONNECTION']; + return array( + 'status' => LOGIN_ERROR_EXTERNAL_AUTH, + 'error_msg' => 'LDAP_NO_SERVER_CONNECTION', + 'user_row' => array('user_id' => ANONYMOUS), + ); } } diff --git a/phpBB/includes/captcha/captcha_non_gd.php b/phpBB/includes/captcha/captcha_non_gd.php index f82896f628..2adf909b96 100644 --- a/phpBB/includes/captcha/captcha_non_gd.php +++ b/phpBB/includes/captcha/captcha_non_gd.php @@ -119,7 +119,7 @@ class captcha $new_line = ''; $end = strlen($scanline) - ceil($width/2); - for ($i = floor($width/2); $i < $end; $i++) + for ($i = (int) floor($width / 2); $i < $end; $i++) { $pixel = ord($scanline{$i}); diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index a0444ea594..17c25ee3c6 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.11-dev'); +define('PHPBB_VERSION', '3.0.12-dev'); // QA-related // define('PHPBB_QA', 1); diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index 2cba11133a..f63ff18cbe 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -1819,6 +1819,22 @@ class phpbb_db_tools case 'mssql': case 'mssqlnative': + // remove default cosntraints first + // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx + $statements[] = "DECLARE @drop_default_name VARCHAR(100), @cmd VARCHAR(1000) + SET @drop_default_name = + (SELECT so.name FROM sysobjects so + JOIN sysconstraints sc ON so.id = sc.constid + WHERE object_name(so.parent_obj) = '{$table_name}' + AND so.xtype = 'D' + AND sc.colid = (SELECT colid FROM syscolumns + WHERE id = object_id('{$table_name}') + AND name = '{$column_name}')) + IF @drop_default_name <> '' + BEGIN + SET @cmd = 'ALTER TABLE [{$table_name}] DROP CONSTRAINT [' + @drop_default_name + ']' + EXEC(@cmd) + END"; $statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']'; break; @@ -2115,7 +2131,7 @@ class phpbb_db_tools case 'mysql_40': case 'mysql_41': - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD UNIQUE INDEX (' . implode(', ', $column) . ')'; + $statements[] = 'ALTER TABLE ' . $table_name . ' ADD UNIQUE INDEX ' . $index_name . '(' . implode(', ', $column) . ')'; break; case 'mssql': diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php index 5d456c2ff0..9cc337955b 100644 --- a/phpBB/includes/db/dbal.php +++ b/phpBB/includes/db/dbal.php @@ -195,6 +195,49 @@ class dbal } /** + * Seek to given row number + * rownum is zero-based + */ + function sql_rowseek($rownum, &$query_id) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if (isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_rowseek($rownum, $query_id); + } + + if ($query_id === false) + { + return false; + } + + $this->sql_freeresult($query_id); + $query_id = $this->sql_query($this->last_query_text); + + if ($query_id === false) + { + return false; + } + + // We do not fetch the row for rownum == 0 because then the next resultset would be the second row + for ($i = 0; $i < $rownum; $i++) + { + if (!$this->sql_fetchrow($query_id)) + { + return false; + } + } + + return true; + } + + /** * Fetch field * if rownum is false, the current row is used, else it is pointing to the row (zero-based) */ @@ -458,6 +501,18 @@ class dbal } /** + * Run LOWER() on DB column of type text (i.e. neither varchar nor char). + * + * @param string $column_name The column name to use + * + * @return string A SQL statement like "LOWER($column_name)" + */ + function sql_lower_text($column_name) + { + return "LOWER($column_name)"; + } + + /** * Run more than one insert statement. * * @param string $table table name to run the statements on diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/firebird.php index 7e3f15ed1d..7072c58ac0 100644 --- a/phpBB/includes/db/firebird.php +++ b/phpBB/includes/db/firebird.php @@ -360,49 +360,6 @@ class dbal_firebird extends dbal } /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - if ($query_id === false) - { - return; - } - - $this->sql_freeresult($query_id); - $query_id = $this->sql_query($this->last_query_text); - - if ($query_id === false) - { - return false; - } - - // We do not fetch the row for rownum == 0 because then the next resultset would be the second row - for ($i = 0; $i < $rownum; $i++) - { - if (!$this->sql_fetchrow($query_id)) - { - return false; - } - } - - return true; - } - - /** * Get last inserted id after insert statement */ function sql_nextid() diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/mssql.php index 6899a73902..2dd95c2508 100644 --- a/phpBB/includes/db/mssql.php +++ b/phpBB/includes/db/mssql.php @@ -25,11 +25,19 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); */ class dbal_mssql extends dbal { + var $connect_error = ''; + /** * Connect to server */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { + if (!function_exists('mssql_connect')) + { + $this->connect_error = 'mssql_connect function does not exist, is mssql extension installed?'; + return $this->sql_error(''); + } + $this->persistency = $persistency; $this->user = $sqluser; $this->dbname = $database; @@ -333,6 +341,14 @@ class dbal_mssql extends dbal } /** + * {@inheritDoc} + */ + function sql_lower_text($column_name) + { + return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))"; + } + + /** * Build LIKE expression * @access private */ @@ -347,34 +363,44 @@ class dbal_mssql extends dbal */ function _sql_error() { - $error = array( - 'message' => @mssql_get_last_message(), - 'code' => '' - ); - - // Get error code number - $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id); - if ($result_id) + if (function_exists('mssql_get_last_message')) { - $row = @mssql_fetch_assoc($result_id); - $error['code'] = $row['code']; - @mssql_free_result($result_id); - } + $error = array( + 'message' => @mssql_get_last_message(), + 'code' => '', + ); - // Get full error message if possible - $sql = 'SELECT CAST(description as varchar(255)) as message - FROM master.dbo.sysmessages - WHERE error = ' . $error['code']; - $result_id = @mssql_query($sql); - - if ($result_id) - { - $row = @mssql_fetch_assoc($result_id); - if (!empty($row['message'])) + // Get error code number + $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id); + if ($result_id) { - $error['message'] .= '<br />' . $row['message']; + $row = @mssql_fetch_assoc($result_id); + $error['code'] = $row['code']; + @mssql_free_result($result_id); } - @mssql_free_result($result_id); + + // Get full error message if possible + $sql = 'SELECT CAST(description as varchar(255)) as message + FROM master.dbo.sysmessages + WHERE error = ' . $error['code']; + $result_id = @mssql_query($sql); + + if ($result_id) + { + $row = @mssql_fetch_assoc($result_id); + if (!empty($row['message'])) + { + $error['message'] .= '<br />' . $row['message']; + } + @mssql_free_result($result_id); + } + } + else + { + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); } return $error; diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php index 75a080b1b7..04501cce8b 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/mssql_odbc.php @@ -32,6 +32,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_mssql_odbc extends dbal { var $last_query_text = ''; + var $connect_error = ''; /** * Connect to server @@ -68,7 +69,24 @@ class dbal_mssql_odbc extends dbal @ini_set('odbc.defaultlrl', $max_size); } - $this->db_connect_id = ($this->persistency) ? @odbc_pconnect($this->server, $this->user, $sqlpassword) : @odbc_connect($this->server, $this->user, $sqlpassword); + if ($this->persistency) + { + if (!function_exists('odbc_pconnect')) + { + $this->connect_error = 'odbc_pconnect function does not exist, is odbc extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @odbc_pconnect($this->server, $this->user, $sqlpassword); + } + else + { + if (!function_exists('odbc_connect')) + { + $this->connect_error = 'odbc_connect function does not exist, is odbc extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @odbc_connect($this->server, $this->user, $sqlpassword); + } return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } @@ -256,49 +274,6 @@ class dbal_mssql_odbc extends dbal } /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - if ($query_id === false) - { - return false; - } - - $this->sql_freeresult($query_id); - $query_id = $this->sql_query($this->last_query_text); - - if ($query_id === false) - { - return false; - } - - // We do not fetch the row for rownum == 0 because then the next resultset would be the second row - for ($i = 0; $i < $rownum; $i++) - { - if (!$this->sql_fetchrow($query_id)) - { - return false; - } - } - - return true; - } - - /** * Get last inserted id after insert statement */ function sql_nextid() @@ -354,6 +329,14 @@ class dbal_mssql_odbc extends dbal } /** + * {@inheritDoc} + */ + function sql_lower_text($column_name) + { + return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))"; + } + + /** * Build LIKE expression * @access private */ @@ -377,10 +360,22 @@ class dbal_mssql_odbc extends dbal */ function _sql_error() { - return array( - 'message' => @odbc_errormsg(), - 'code' => @odbc_error() - ); + if (function_exists('odbc_errormsg')) + { + $error = array( + 'message' => @odbc_errormsg(), + 'code' => @odbc_error(), + ); + } + else + { + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); + } + + return $error; } /** diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index 7fbc374e77..b91372ac61 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -199,16 +199,18 @@ class dbal_mssqlnative extends dbal var $m_insert_id = NULL; var $last_query_text = ''; var $query_options = array(); + var $connect_error = ''; /** * Connect to server */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) { - # Test for driver support, to avoid suppressed fatal error + // Test for driver support, to avoid suppressed fatal error if (!function_exists('sqlsrv_connect')) { - trigger_error('Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx\n', E_USER_ERROR); + $this->connect_error = 'Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx'; + return $this->sql_error(''); } //set up connection variables @@ -219,7 +221,6 @@ class dbal_mssqlnative extends dbal $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); //connect to database - error_reporting(E_ALL); $this->db_connect_id = sqlsrv_connect($this->server, array( 'Database' => $this->dbname, 'UID' => $this->user, @@ -436,25 +437,7 @@ class dbal_mssqlnative extends dbal unset($row['line2'], $row['line3']); } } - return $row; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - $seek = new result_mssqlnative($query_id); - $row = $seek->seek($rownum); - return ($row = $seek->fetch()) ? $row : false; + return (sizeof($row)) ? $row : false; } /** @@ -511,6 +494,14 @@ class dbal_mssqlnative extends dbal } /** + * {@inheritDoc} + */ + function sql_lower_text($column_name) + { + return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))"; + } + + /** * Build LIKE expression * @access private */ @@ -525,31 +516,43 @@ class dbal_mssqlnative extends dbal */ function _sql_error() { - $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS); - $error_message = ''; - $code = 0; - - if ($errors != null) + if (function_exists('sqlsrv_errors')) { - foreach ($errors as $error) + $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS); + $error_message = ''; + $code = 0; + + if ($errors != null) { - $error_message .= "SQLSTATE: ".$error[ 'SQLSTATE']."\n"; - $error_message .= "code: ".$error[ 'code']."\n"; - $code = $error['code']; - $error_message .= "message: ".$error[ 'message']."\n"; + foreach ($errors as $error) + { + $error_message .= "SQLSTATE: " . $error[ 'SQLSTATE'] . "\n"; + $error_message .= "code: " . $error[ 'code'] . "\n"; + $code = $error['code']; + $error_message .= "message: " . $error[ 'message'] . "\n"; + } + $this->last_error_result = $error_message; + $error = $this->last_error_result; + } + else + { + $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); } - $this->last_error_result = $error_message; - $error = $this->last_error_result; + + $error = array( + 'message' => $error, + 'code' => $code, + ); } else { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); } - return array( - 'message' => $error, - 'code' => $code, - ); + return $error; } /** diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index 1ccb785150..252cb20bd4 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -30,6 +30,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_mysql extends dbal { var $multi_insert = true; + var $connect_error = ''; /** * Connect to server @@ -44,7 +45,24 @@ class dbal_mysql extends dbal $this->sql_layer = 'mysql4'; - $this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $sqlpassword) : @mysql_connect($this->server, $this->user, $sqlpassword, $new_link); + if ($this->persistency) + { + if (!function_exists('mysql_pconnect')) + { + $this->connect_error = 'mysql_pconnect function does not exist, is mysql extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @mysql_pconnect($this->server, $this->user, $sqlpassword); + } + else + { + if (!function_exists('mysql_connect')) + { + $this->connect_error = 'mysql_connect function does not exist, is mysql extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @mysql_connect($this->server, $this->user, $sqlpassword, $new_link); + } if ($this->db_connect_id && $this->dbname != '') { @@ -419,18 +437,29 @@ class dbal_mysql extends dbal */ function _sql_error() { - if (!$this->db_connect_id) + if ($this->db_connect_id) + { + $error = array( + 'message' => @mysql_error($this->db_connect_id), + 'code' => @mysql_errno($this->db_connect_id), + ); + } + else if (function_exists('mysql_error')) { - return array( + $error = array( 'message' => @mysql_error(), - 'code' => @mysql_errno() + 'code' => @mysql_errno(), + ); + } + else + { + $error = array( + 'message' => $this->connect_error, + 'code' => '', ); } - return array( - 'message' => @mysql_error($this->db_connect_id), - 'code' => @mysql_errno($this->db_connect_id) - ); + return $error; } /** diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index a311b8cda6..69f1d26a40 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -27,12 +27,19 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_mysqli extends dbal { var $multi_insert = true; + var $connect_error = ''; /** * Connect to server */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false , $new_link = false) { + if (!function_exists('mysqli_connect')) + { + $this->connect_error = 'mysqli_connect function does not exist, is mysqli extension installed?'; + return $this->sql_error(''); + } + // Mysqli extension supports persistent connection since PHP 5.3.0 $this->persistency = (version_compare(PHP_VERSION, '5.3.0', '>=')) ? $persistency : false; $this->user = $sqluser; @@ -416,18 +423,29 @@ class dbal_mysqli extends dbal */ function _sql_error() { - if (!$this->db_connect_id) + if ($this->db_connect_id) + { + $error = array( + 'message' => @mysqli_error($this->db_connect_id), + 'code' => @mysqli_errno($this->db_connect_id) + ); + } + else if (function_exists('mysqli_connect_error')) { - return array( + $error = array( 'message' => @mysqli_connect_error(), - 'code' => @mysqli_connect_errno() + 'code' => @mysqli_connect_errno(), + ); + } + else + { + $error = array( + 'message' => $this->connect_error, + 'code' => '', ); } - return array( - 'message' => @mysqli_error($this->db_connect_id), - 'code' => @mysqli_errno($this->db_connect_id) - ); + return $error; } /** diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php index 62b36aa8bf..4a7a4ecc8c 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/oracle.php @@ -25,6 +25,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); class dbal_oracle extends dbal { var $last_query_text = ''; + var $connect_error = ''; /** * Connect to server @@ -48,7 +49,33 @@ class dbal_oracle extends dbal $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database; } - $this->db_connect_id = ($new_link) ? @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8') : (($this->persistency) ? @ociplogon($this->user, $sqlpassword, $connect, 'UTF8') : @ocilogon($this->user, $sqlpassword, $connect, 'UTF8')); + if ($new_link) + { + if (!function_exists('ocinlogon')) + { + $this->connect_error = 'ocinlogon function does not exist, is oci extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8'); + } + else if ($this->persistency) + { + if (!function_exists('ociplogon')) + { + $this->connect_error = 'ociplogon function does not exist, is oci extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @ociplogon($this->user, $sqlpassword, $connect, 'UTF8'); + } + else + { + if (!function_exists('ocilogon')) + { + $this->connect_error = 'ocilogon function does not exist, is oci extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8'); + } return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } @@ -647,17 +674,27 @@ class dbal_oracle extends dbal */ function _sql_error() { - $error = @ocierror(); - $error = (!$error) ? @ocierror($this->query_result) : $error; - $error = (!$error) ? @ocierror($this->db_connect_id) : $error; - - if ($error) + if (function_exists('ocierror')) { - $this->last_error_result = $error; + $error = @ocierror(); + $error = (!$error) ? @ocierror($this->query_result) : $error; + $error = (!$error) ? @ocierror($this->db_connect_id) : $error; + + if ($error) + { + $this->last_error_result = $error; + } + else + { + $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + } } else { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); } return $error; diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php index 8de72fd394..557b057cce 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/sqlite.php @@ -25,6 +25,8 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); */ class dbal_sqlite extends dbal { + var $connect_error = ''; + /** * Connect to server */ @@ -36,7 +38,24 @@ class dbal_sqlite extends dbal $this->dbname = $database; $error = ''; - $this->db_connect_id = ($this->persistency) ? @sqlite_popen($this->server, 0666, $error) : @sqlite_open($this->server, 0666, $error); + if ($this->persistency) + { + if (!function_exists('sqlite_popen')) + { + $this->connect_error = 'sqlite_popen function does not exist, is sqlite extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @sqlite_popen($this->server, 0666, $error); + } + else + { + if (!function_exists('sqlite_open')) + { + $this->connect_error = 'sqlite_open function does not exist, is sqlite extension installed?'; + return $this->sql_error(''); + } + $this->db_connect_id = @sqlite_open($this->server, 0666, $error); + } if ($this->db_connect_id) { @@ -281,10 +300,22 @@ class dbal_sqlite extends dbal */ function _sql_error() { - return array( - 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), - 'code' => @sqlite_last_error($this->db_connect_id) - ); + if (function_exists('sqlite_error_string')) + { + $error = array( + 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), + 'code' => @sqlite_last_error($this->db_connect_id), + ); + } + else + { + $error = array( + 'message' => $this->connect_error, + 'code' => '', + ); + } + + return $error; } /** diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 0320230a7d..b2b12c1445 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -137,7 +137,18 @@ function request_var($var_name, $default, $multibyte = false, $cookie = false) } /** -* Set config value. Creates missing config entry. +* Sets a configuration option's value. +* +* Please note that this function does not update the is_dynamic value for +* an already existing config option. +* +* @param string $config_name The configuration option's name +* @param string $config_value New configuration value +* @param bool $is_dynamic Whether this variable should be cached (false) or +* if it changes too frequently (true) to be +* efficiently cached. +* +* @return null */ function set_config($config_name, $config_value, $is_dynamic = false) { @@ -166,7 +177,15 @@ function set_config($config_name, $config_value, $is_dynamic = false) } /** -* Set dynamic config value with arithmetic operation. +* Increments an integer config value directly in the database. +* +* @param string $config_name The configuration option's name +* @param int $increment Amount to increment by +* @param bool $is_dynamic Whether this variable should be cached (false) or +* if it changes too frequently (true) to be +* efficiently cached. +* +* @return null */ function set_config_count($config_name, $increment, $is_dynamic = false) { @@ -289,7 +308,8 @@ function phpbb_gmgetdate($time = false) /** * Return formatted string for filesizes * -* @param int $value filesize in bytes +* @param mixed $value filesize in bytes +* (non-negative number; int, float or string) * @param bool $string_only true if language string should be returned * @param array $allowed_units only allow these units (data array indexes) * @@ -301,6 +321,12 @@ function get_formatted_filesize($value, $string_only = true, $allowed_units = fa global $user; $available_units = array( + 'tb' => array( + 'min' => 1099511627776, // pow(2, 40) + 'index' => 4, + 'si_unit' => 'TB', + 'iec_unit' => 'TIB', + ), 'gb' => array( 'min' => 1073741824, // pow(2, 30) 'index' => 3, @@ -979,7 +1005,7 @@ if (!function_exists('stripos')) */ function is_absolute($path) { - return ($path[0] == '/' || (DIRECTORY_SEPARATOR == '\\' && preg_match('#^[a-z]:[/\\\]#i', $path))) ? true : false; + return (isset($path[0]) && $path[0] == '/' || preg_match('#^[a-z]:[/\\\]#i', $path)) ? true : false; } /** @@ -1176,6 +1202,36 @@ else } } +/** +* Eliminates useless . and .. components from specified path. +* +* @param string $path Path to clean +* @return string Cleaned path +*/ +function phpbb_clean_path($path) +{ + $exploded = explode('/', $path); + $filtered = array(); + foreach ($exploded as $part) + { + if ($part === '.' && !empty($filtered)) + { + continue; + } + + if ($part === '..' && !empty($filtered) && $filtered[sizeof($filtered) - 1] !== '..') + { + array_pop($filtered); + } + else + { + $filtered[] = $part; + } + } + $path = implode('/', $filtered); + return $path; +} + if (!function_exists('htmlspecialchars_decode')) { /** @@ -1918,14 +1974,17 @@ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_ti } else { - $sql = 'SELECT t.forum_id FROM ' . TOPICS_TABLE . ' t - LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (tt.topic_id = t.topic_id AND tt.user_id = ' . $user->data['user_id'] . ') + $sql = 'SELECT t.forum_id + FROM ' . TOPICS_TABLE . ' t + LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt + ON (tt.topic_id = t.topic_id + AND tt.user_id = ' . $user->data['user_id'] . ') WHERE t.forum_id = ' . $forum_id . ' AND t.topic_last_post_time > ' . $mark_time_forum . ' AND t.topic_moved_id = 0 ' . $sql_update_unapproved . ' - AND (tt.topic_id IS NULL OR tt.mark_time < t.topic_last_post_time) - GROUP BY t.forum_id'; + AND (tt.topic_id IS NULL + OR tt.mark_time < t.topic_last_post_time)'; $result = $db->sql_query_limit($sql, 1); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -2681,7 +2740,7 @@ function meta_refresh($time, $url, $disable_cd_check = false) // For XHTML compatibility we change back & to & $template->assign_vars(array( - 'META' => '<meta http-equiv="refresh" content="' . $time . ';url=' . $url . '" />') + 'META' => '<meta http-equiv="refresh" content="' . $time . '; url=' . $url . '" />') ); return $url; @@ -2705,7 +2764,7 @@ function meta_refresh($time, $url, $disable_cd_check = false) * * @param int $code HTTP status code * @param string $message Message for the status code -* @return void +* @return null */ function send_status_line($code, $message) { @@ -2808,7 +2867,7 @@ function check_form_key($form_name, $timespan = false, $return_page = '', $trigg $diff = time() - $creation_time; // If creation_time and the time() now is zero we can assume it was not a human doing this (the check for if ($diff)... - if ($diff && ($diff <= $timespan || $timespan === -1)) + if (defined('DEBUG_TEST') || $diff && ($diff <= $timespan || $timespan === -1)) { $token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : ''; $key = sha1($creation_time . $user->data['user_form_salt'] . $form_name . $token_sid); @@ -3213,6 +3272,7 @@ function login_forum_box($forum_data) page_header($user->lang['LOGIN'], false); $template->assign_vars(array( + 'FORUM_NAME' => isset($forum_data['forum_name']) ? $forum_data['forum_name'] : '', 'S_LOGIN_ACTION' => build_url(array('f')), 'S_HIDDEN_FIELDS' => build_hidden_fields(array('f' => $forum_data['forum_id']))) ); @@ -3453,7 +3513,7 @@ function get_preg_expression($mode) case 'email': // Regex written by James Watts and Francisco Jose Martin Moreno // http://fightingforalostcause.net/misc/2006/compare-email-regex.php - return '([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&)+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)'; + return '([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&)+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)'; break; case 'bbcode_htm': @@ -3918,7 +3978,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) echo ' </div>'; echo ' </div>'; echo ' <div id="page-footer">'; - echo ' Powered by <a href="http://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Group'; + echo ' Powered by <a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Group'; echo ' </div>'; echo '</div>'; echo '</body>'; @@ -4292,7 +4352,7 @@ function phpbb_optionset($bit, $set, $data) * * @param array $param Parameter array, see $param_defaults array. * -* @return void +* @return null */ function phpbb_http_login($param) { @@ -4738,6 +4798,7 @@ function page_footer($run_cron = true) $template->assign_vars(array( 'DEBUG_OUTPUT' => (defined('DEBUG')) ? $debug_output : '', 'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '', + 'CREDIT_LINE' => $user->lang('POWERED_BY', '<a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Group'), 'U_ACP' => ($auth->acl_get('a_') && !empty($user->data['is_registered'])) ? append_sid("{$phpbb_root_path}adm/index.$phpEx", false, true, $user->session_id) : '') ); diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index 0e1a11b4aa..a9d1db24a5 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -2294,6 +2294,21 @@ function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_fr } /** +* remove_comments will strip the sql comment lines out of an uploaded sql file +* specifically for mssql and postgres type files in the install.... +* +* @deprecated Use phpbb_remove_comments() instead. +*/ +function remove_comments(&$output) +{ + // Remove /* */ comments (http://ostermiller.org/findcomment.html) + $output = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $output); + + // Return by reference and value. + return $output; +} + +/** * Cache moderators, called whenever permissions are changed via admin_permissions. Changes of username * and group names must be carried through for the moderators table */ @@ -2557,7 +2572,8 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id { $sql_keywords .= $db->sql_in_set('l.log_operation', $operations) . ' OR '; } - $sql_keywords .= 'LOWER(l.log_data) ' . implode(' OR LOWER(l.log_data) ', $keywords) . ')'; + $sql_lower = $db->sql_lower_text('l.log_data'); + $sql_keywords .= "$sql_lower " . implode(" OR $sql_lower ", $keywords) . ')'; } if ($log_count !== false) @@ -3303,7 +3319,7 @@ function obtain_latest_version_info($force_update = false, $warn_fail = false, $ $info = get_remote_file('version.phpbb.com', '/phpbb', ((defined('PHPBB_QA')) ? '30x_qa.txt' : '30x.txt'), $errstr, $errno); - if ($info === false) + if (empty($info)) { $cache->destroy('versioncheck'); if ($warn_fail) @@ -3327,7 +3343,7 @@ function obtain_latest_version_info($force_update = false, $warn_fail = false, $ * @param int $flag The binary flag which is OR-ed with the current column value * @param string $sql_more This string is attached to the sql query generated to update the table. * - * @return void + * @return null */ function enable_bitfield_column_flag($table_name, $column_name, $flag, $sql_more = '') { diff --git a/phpBB/includes/functions_database_helper.php b/phpBB/includes/functions_database_helper.php new file mode 100644 index 0000000000..664c246888 --- /dev/null +++ b/phpBB/includes/functions_database_helper.php @@ -0,0 +1,206 @@ +<?php +/** +* +* @package phpBB3 +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* Updates rows in given table from a set of values to a new value. +* If this results in rows violating uniqueness constraints, the duplicate +* rows are eliminated. +* +* The only supported table is bookmarks. +* +* @param dbal $db Database object +* @param string $table Table on which to perform the update +* @param string $column Column whose values to change +* @param array $from_values An array of values that should be changed +* @param int $to_value The new value +* @return null +*/ +function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_values, $to_value) +{ + $sql = "SELECT $column, user_id + FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $result = $db->sql_query($sql); + + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[$row[$column]][] = (int) $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = " . (int) $to_value; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = (int) $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + foreach ($from_values as $from_value) + { + if (!isset($old_user_ids[$from_value])) + { + continue; + } + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + } + } + + if (!empty($queries)) + { + $db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + $db->sql_transaction('commit'); + } +} + +/** +* Updates rows in given table from a set of values to a new value. +* If this results in rows violating uniqueness constraints, the duplicate +* rows are merged respecting notify_status (0 takes precedence over 1). +* +* The only supported table is topics_watch. +* +* @param dbal $db Database object +* @param string $table Table on which to perform the update +* @param string $column Column whose values to change +* @param array $from_values An array of values that should be changed +* @param int $to_value The new value +* @return null +*/ +function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $column, $from_values, $to_value) +{ + $sql = "SELECT $column, user_id, notify_status + FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $result = $db->sql_query($sql); + + $old_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $old_user_ids[(int) $row['notify_status']][$row[$column]][] = (int) $row['user_id']; + } + $db->sql_freeresult($result); + + $sql = "SELECT $column, user_id + FROM $table + WHERE $column = " . (int) $to_value; + $result = $db->sql_query($sql); + + $new_user_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $new_user_ids[$row[$column]][] = (int) $row['user_id']; + } + $db->sql_freeresult($result); + + $queries = array(); + $extra_updates = array( + 0 => 'notify_status = 0', + 1 => '', + ); + foreach ($from_values as $from_value) + { + foreach ($extra_updates as $notify_status => $extra_update) + { + if (!isset($old_user_ids[$notify_status][$from_value])) + { + continue; + } + if (empty($new_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "'"; + $queries[] = $sql; + } + else + { + $different_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $new_user_ids[$to_value]); + if (!empty($different_user_ids)) + { + $sql = "UPDATE $table + SET $column = " . (int) $to_value . " + WHERE $column = '" . $db->sql_escape($from_value) . "' + AND " . $db->sql_in_set('user_id', $different_user_ids); + $queries[] = $sql; + } + + if ($extra_update) + { + $same_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $different_user_ids); + if (!empty($same_user_ids)) + { + $sql = "UPDATE $table + SET $extra_update + WHERE $column = '" . (int) $to_value . "' + AND " . $db->sql_in_set('user_id', $same_user_ids); + $queries[] = $sql; + } + } + } + } + } + + if (!empty($queries)) + { + $db->sql_transaction('begin'); + + foreach ($queries as $sql) + { + $db->sql_query($sql); + } + + $sql = "DELETE FROM $table + WHERE " . $db->sql_in_set($column, $from_values); + $db->sql_query($sql); + + $db->sql_transaction('commit'); + } +} diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index 6caa5c943f..47f4eac627 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -50,15 +50,19 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'firebird', 'MODULE' => 'interbase', 'DELIM' => ';;', + 'COMMENTS' => 'remove_remarks', 'DRIVER' => 'firebird', 'AVAILABLE' => true, '2.0.x' => false, ), + // Note: php 5.5 alpha 2 deprecated mysql. + // Keep mysqli before mysql in this list. 'mysqli' => array( 'LABEL' => 'MySQL with MySQLi Extension', 'SCHEMA' => 'mysql_41', 'MODULE' => 'mysqli', 'DELIM' => ';', + 'COMMENTS' => 'remove_remarks', 'DRIVER' => 'mysqli', 'AVAILABLE' => true, '2.0.x' => true, @@ -68,6 +72,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mysql', 'MODULE' => 'mysql', 'DELIM' => ';', + 'COMMENTS' => 'remove_remarks', 'DRIVER' => 'mysql', 'AVAILABLE' => true, '2.0.x' => true, @@ -77,6 +82,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mssql', 'MODULE' => 'mssql', 'DELIM' => 'GO', + 'COMMENTS' => 'remove_comments', 'DRIVER' => 'mssql', 'AVAILABLE' => true, '2.0.x' => true, @@ -86,6 +92,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mssql', 'MODULE' => 'odbc', 'DELIM' => 'GO', + 'COMMENTS' => 'remove_comments', 'DRIVER' => 'mssql_odbc', 'AVAILABLE' => true, '2.0.x' => true, @@ -95,6 +102,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mssql', 'MODULE' => 'sqlsrv', 'DELIM' => 'GO', + 'COMMENTS' => 'remove_comments', 'DRIVER' => 'mssqlnative', 'AVAILABLE' => true, '2.0.x' => false, @@ -104,6 +112,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'oracle', 'MODULE' => 'oci8', 'DELIM' => '/', + 'COMMENTS' => 'remove_comments', 'DRIVER' => 'oracle', 'AVAILABLE' => true, '2.0.x' => false, @@ -113,6 +122,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'postgres', 'MODULE' => 'pgsql', 'DELIM' => ';', + 'COMMENTS' => 'remove_comments', 'DRIVER' => 'postgres', 'AVAILABLE' => true, '2.0.x' => true, @@ -122,6 +132,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'sqlite', 'MODULE' => 'sqlite', 'DELIM' => ';', + 'COMMENTS' => 'remove_remarks', 'DRIVER' => 'sqlite', 'AVAILABLE' => true, '2.0.x' => false, @@ -465,16 +476,39 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, /** * Removes comments from schema files +* +* @deprecated Use phpbb_remove_comments() instead. */ -function remove_comments($sql) +function remove_remarks(&$sql) { - // Remove /* */ comments (http://ostermiller.org/findcomment.html) - $sql = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $sql); - // Remove # style comments $sql = preg_replace('/\n{2,}/', "\n", preg_replace('/^#.*$/m', "\n", $sql)); - return $sql; + // Return by reference +} + +/** +* Removes "/* style" as well as "# style" comments from $input. +* +* @param string $input Input string +* +* @return string Input string with comments removed +*/ +function phpbb_remove_comments($input) +{ + if (!function_exists('remove_comments')) + { + global $phpbb_root_path, $phpEx; + require($phpbb_root_path . 'includes/functions_admin.' . $phpEx); + } + + // Remove /* */ comments + remove_comments($input); + + // Remove # style comments + remove_remarks($input); + + return $input; } /** @@ -512,4 +546,61 @@ function adjust_language_keys_callback($matches) } } +/** +* Creates the output to be stored in a phpBB config.php file +* +* @param array $data Array containing the database connection information +* @param string $dbms The name of the DBAL class to use +* @param array $load_extensions Array of additional extensions that should be loaded +* @param bool $debug If the debug constants should be enabled by default or not +* @param bool $debug_test If the DEBUG_TEST constant should be added +* NOTE: Only for use within the testing framework +* +* @return string The output to write to the file +*/ +function phpbb_create_config_file_data($data, $dbms, $load_extensions, $debug = false, $debug_test = false) +{ + $load_extensions = implode(',', $load_extensions); + + $config_data = "<?php\n"; + $config_data .= "// phpBB 3.0.x auto-generated configuration file\n// Do not change anything in this file!\n"; + + $config_data_array = array( + 'dbms' => $dbms, + 'dbhost' => $data['dbhost'], + 'dbport' => $data['dbport'], + 'dbname' => $data['dbname'], + 'dbuser' => $data['dbuser'], + 'dbpasswd' => htmlspecialchars_decode($data['dbpasswd']), + 'table_prefix' => $data['table_prefix'], + 'acm_type' => 'file', + 'load_extensions' => $load_extensions, + ); + + foreach ($config_data_array as $key => $value) + { + $config_data .= "\${$key} = '" . str_replace("'", "\\'", str_replace('\\', '\\\\', $value)) . "';\n"; + } + + $config_data .= "\n@define('PHPBB_INSTALLED', true);\n"; + + if ($debug) + { + $config_data .= "@define('DEBUG', true);\n"; + $config_data .= "@define('DEBUG_EXTRA', true);\n"; + } + else + { + $config_data .= "// @define('DEBUG', true);\n"; + $config_data .= "// @define('DEBUG_EXTRA', true);\n"; + } + + if ($debug_test) + { + $config_data .= "@define('DEBUG_TEST', true);\n"; + } + + return $config_data; +} + ?>
\ No newline at end of file diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index 6549693333..db2dea33e8 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -390,6 +390,28 @@ class messenger } /** + * Generates a valid message id to be used in emails + * + * @return string message id + */ + function generate_message_id() + { + global $config; + + $domain = 'phpbb.generated'; + if ($config['server_name']) + { + $domain = $config['server_name']; + } + else if (!empty($_SERVER['SERVER_NAME'])) + { + $domain = $_SERVER['SERVER_NAME']; + } + + return md5(unique_id(time())) . '@' . $domain; + } + + /** * Return email header */ function build_header($to, $cc, $bcc) @@ -415,7 +437,7 @@ class messenger $headers[] = 'Return-Path: <' . $config['board_email'] . '>'; $headers[] = 'Sender: <' . $config['board_email'] . '>'; $headers[] = 'MIME-Version: 1.0'; - $headers[] = 'Message-ID: <' . md5(unique_id(time())) . '@' . $config['server_name'] . '>'; + $headers[] = 'Message-ID: <' . $this->generate_message_id() . '>'; $headers[] = 'Date: ' . date('r', time()); $headers[] = 'Content-Type: text/plain; charset=UTF-8'; // format=flowed $headers[] = 'Content-Transfer-Encoding: 8bit'; // 7bit @@ -715,14 +737,21 @@ class queue $lock_fp = $this->lock(); - set_config('last_queue_run', time(), true); - - if (!file_exists($this->cache_file) || filemtime($this->cache_file) > time() - $config['queue_interval']) + // avoid races, check file existence once + $have_cache_file = file_exists($this->cache_file); + if (!$have_cache_file || $config['last_queue_run'] > time() - $config['queue_interval']) { + if (!$have_cache_file) + { + set_config('last_queue_run', time(), true); + } + $this->unlock($lock_fp); return; } + set_config('last_queue_run', time(), true); + include($this->cache_file); foreach ($this->queue_data as $object => $data_ary) diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index f920be9c4b..2e5130c5b8 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -288,13 +288,15 @@ function posting_gen_topic_icons($mode, $icon_id) if (sizeof($icons)) { + $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; + foreach ($icons as $id => $data) { if ($data['display']) { $template->assign_block_vars('topic_icon', array( 'ICON_ID' => $id, - 'ICON_IMG' => $phpbb_root_path . $config['icons_path'] . '/' . $data['img'], + 'ICON_IMG' => $root_path . $config['icons_path'] . '/' . $data['img'], 'ICON_WIDTH' => $data['width'], 'ICON_HEIGHT' => $data['height'], @@ -421,16 +423,6 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage $cat_id = (isset($extensions[$file->get('extension')]['display_cat'])) ? $extensions[$file->get('extension')]['display_cat'] : ATTACHMENT_CATEGORY_NONE; - // Make sure the image category only holds valid images... - if ($cat_id == ATTACHMENT_CATEGORY_IMAGE && !$file->is_image()) - { - $file->remove(); - - // If this error occurs a user tried to exploit an IE Bug by renaming extensions - // Since the image category is displaying content inline we need to catch this. - trigger_error($user->lang['ATTACHED_IMAGE_NOT_IMAGE']); - } - // Do we have to create a thumbnail? $filedata['thumbnail'] = ($cat_id == ATTACHMENT_CATEGORY_IMAGE && $config['img_create_thumbnail']) ? 1 : 0; @@ -471,6 +463,16 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage return $filedata; } + // Make sure the image category only holds valid images... + if ($cat_id == ATTACHMENT_CATEGORY_IMAGE && !$file->is_image()) + { + $file->remove(); + + // If this error occurs a user tried to exploit an IE Bug by renaming extensions + // Since the image category is displaying content inline we need to catch this. + trigger_error($user->lang['ATTACHED_IMAGE_NOT_IMAGE']); + } + $filedata['filesize'] = $file->get('filesize'); $filedata['mimetype'] = $file->get('mimetype'); $filedata['extension'] = $file->get('extension'); @@ -497,7 +499,14 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage { if ($free_space <= $file->get('filesize')) { - $filedata['error'][] = $user->lang['ATTACH_QUOTA_REACHED']; + if ($auth->acl_get('a_')) + { + $filedata['error'][] = $user->lang['ATTACH_DISK_FULL']; + } + else + { + $filedata['error'][] = $user->lang['ATTACH_QUOTA_REACHED']; + } $filedata['post_attach'] = false; $file->remove(); @@ -1160,7 +1169,7 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id /** * User Notification */ -function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id, $topic_id, $post_id) +function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id, $topic_id, $post_id, $author_name = '') { global $db, $user, $config, $phpbb_root_path, $phpEx, $auth; @@ -1180,36 +1189,32 @@ function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id $topic_title = ($topic_notification) ? $topic_title : $subject; $topic_title = censor_text($topic_title); - // Get banned User ID's - $sql = 'SELECT ban_userid - FROM ' . BANLIST_TABLE . ' - WHERE ban_userid <> 0 - AND ban_exclude <> 1'; - $result = $db->sql_query($sql); - - $sql_ignore_users = ANONYMOUS . ', ' . $user->data['user_id']; - while ($row = $db->sql_fetchrow($result)) + // Exclude guests, current user and banned users from notifications + if (!function_exists('phpbb_get_banned_user_ids')) { - $sql_ignore_users .= ', ' . (int) $row['ban_userid']; + include($phpbb_root_path . 'includes/functions_user.' . $phpEx); } - $db->sql_freeresult($result); + $sql_ignore_users = phpbb_get_banned_user_ids(); + $sql_ignore_users[ANONYMOUS] = ANONYMOUS; + $sql_ignore_users[$user->data['user_id']] = $user->data['user_id']; $notify_rows = array(); // -- get forum_userids || topic_userids $sql = 'SELECT u.user_id, u.username, u.user_email, u.user_lang, u.user_notify_type, u.user_jabber FROM ' . (($topic_notification) ? TOPICS_WATCH_TABLE : FORUMS_WATCH_TABLE) . ' w, ' . USERS_TABLE . ' u - WHERE w.' . (($topic_notification) ? 'topic_id' : 'forum_id') . ' = ' . (($topic_notification) ? $topic_id : $forum_id) . " - AND w.user_id NOT IN ($sql_ignore_users) - AND w.notify_status = " . NOTIFY_YES . ' + WHERE w.' . (($topic_notification) ? 'topic_id' : 'forum_id') . ' = ' . (($topic_notification) ? $topic_id : $forum_id) . ' + AND ' . $db->sql_in_set('w.user_id', $sql_ignore_users, true) . ' + AND w.notify_status = ' . NOTIFY_YES . ' AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ') AND u.user_id = w.user_id'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { - $notify_rows[$row['user_id']] = array( - 'user_id' => $row['user_id'], + $notify_user_id = (int) $row['user_id']; + $notify_rows[$notify_user_id] = array( + 'user_id' => $notify_user_id, 'username' => $row['username'], 'user_email' => $row['user_email'], 'user_jabber' => $row['user_jabber'], @@ -1219,30 +1224,29 @@ function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id 'method' => $row['user_notify_type'], 'allowed' => false ); + + // Add users who have been already notified to ignore list + $sql_ignore_users[$notify_user_id] = $notify_user_id; } $db->sql_freeresult($result); // forum notification is sent to those not already receiving topic notifications if ($topic_notification) { - if (sizeof($notify_rows)) - { - $sql_ignore_users .= ', ' . implode(', ', array_keys($notify_rows)); - } - $sql = 'SELECT u.user_id, u.username, u.user_email, u.user_lang, u.user_notify_type, u.user_jabber FROM ' . FORUMS_WATCH_TABLE . ' fw, ' . USERS_TABLE . " u WHERE fw.forum_id = $forum_id - AND fw.user_id NOT IN ($sql_ignore_users) - AND fw.notify_status = " . NOTIFY_YES . ' + AND " . $db->sql_in_set('fw.user_id', $sql_ignore_users, true) . ' + AND fw.notify_status = ' . NOTIFY_YES . ' AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ') AND u.user_id = fw.user_id'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { - $notify_rows[$row['user_id']] = array( - 'user_id' => $row['user_id'], + $notify_user_id = (int) $row['user_id']; + $notify_rows[$notify_user_id] = array( + 'user_id' => $notify_user_id, 'username' => $row['username'], 'user_email' => $row['user_email'], 'user_jabber' => $row['user_jabber'], @@ -1273,7 +1277,6 @@ function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id } } - // Now, we have to do a little step before really sending, we need to distinguish our users a little bit. ;) $msg_users = $delete_ids = $update_notification = array(); foreach ($notify_rows as $user_id => $row) @@ -1337,6 +1340,7 @@ function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id 'USERNAME' => htmlspecialchars_decode($addr['name']), 'TOPIC_TITLE' => htmlspecialchars_decode($topic_title), 'FORUM_NAME' => htmlspecialchars_decode($forum_name), + 'AUTHOR_NAME' => htmlspecialchars_decode($author_name), 'U_FORUM' => generate_board_url() . "/viewforum.$phpEx?f=$forum_id", 'U_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&t=$topic_id", @@ -1694,8 +1698,9 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u // The variable name should be $post_approved, because it indicates if the post is approved or not $post_approval = 1; - // Check the permissions for post approval. Moderators are not affected. - if (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) + // Check the permissions for post approval. + // Moderators must go through post approval like ordinary users. + if (!$auth->acl_get('f_noapprove', $data['forum_id'])) { // Post not approved, but in queue $post_approval = 0; @@ -2599,7 +2604,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u // Send Notifications if (($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $post_approval) { - user_notification($mode, $subject, $data['topic_title'], $data['forum_name'], $data['forum_id'], $data['topic_id'], $data['post_id']); + $username = ($username) ? $username : $user->data['username']; + user_notification($mode, $subject, $data['topic_title'], $data['forum_name'], $data['forum_id'], $data['topic_id'], $data['post_id'], $username); } $params = $add_anchor = ''; @@ -2636,7 +2642,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u * - '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(). +* @param int $bump_time The time at which topic was bumped, usually it is a current time as obtained via time(). * @return string An URL to the bumped topic, example: ./viewtopic.php?forum_id=1&topic_id=2&p=3#p3 */ function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false) diff --git a/phpBB/includes/functions_privmsgs.php b/phpBB/includes/functions_privmsgs.php index c40ceb088f..b08d6e7f5c 100644 --- a/phpBB/includes/functions_privmsgs.php +++ b/phpBB/includes/functions_privmsgs.php @@ -1084,6 +1084,205 @@ function delete_pm($user_id, $msg_ids, $folder_id) } /** +* Delete all PM(s) for a given user and delete the ones without references +* +* @param int $user_id ID of the user whose private messages we want to delete +* +* @return boolean False if there were no pms found, true otherwise. +*/ +function phpbb_delete_user_pms($user_id) +{ + global $db, $user, $phpbb_root_path, $phpEx; + + $user_id = (int) $user_id; + + if (!$user_id) + { + return false; + } + + // Get PM Information for later deleting + // The two queries where split, so we can use our indexes + $undelivered_msg = $delete_ids = array(); + + // Part 1: get PMs the user received + $sql = 'SELECT msg_id + FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE user_id = ' . $user_id; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $msg_id = (int) $row['msg_id']; + $delete_ids[$msg_id] = $msg_id; + } + $db->sql_freeresult($result); + + // Part 2: get PMs the user sent, but have yet to be received + // We cannot simply delete them. First we have to check, + // whether another user already received and read the message. + $sql = 'SELECT msg_id + FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE author_id = ' . $user_id . ' + AND folder_id = ' . PRIVMSGS_NO_BOX; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $msg_id = (int) $row['msg_id']; + $undelivered_msg[$msg_id] = $msg_id; + } + $db->sql_freeresult($result); + + if (empty($delete_ids) && empty($undelivered_msg)) + { + return false; + } + + $db->sql_transaction('begin'); + + if (!empty($undelivered_msg)) + { + // A pm is delivered, if for any recipient the message was moved + // from their NO_BOX to another folder. We do not delete such + // messages, but only delete them for users, who have not yet + // received them. + $sql = 'SELECT msg_id + FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE author_id = ' . $user_id . ' + AND folder_id <> ' . PRIVMSGS_NO_BOX . ' + AND folder_id <> ' . PRIVMSGS_OUTBOX . ' + AND folder_id <> ' . PRIVMSGS_SENTBOX; + $result = $db->sql_query($sql); + + $delivered_msg = array(); + while ($row = $db->sql_fetchrow($result)) + { + $msg_id = (int) $row['msg_id']; + $delivered_msg[$msg_id] = $msg_id; + unset($undelivered_msg[$msg_id]); + } + $db->sql_freeresult($result); + + $undelivered_user = array(); + + // Count the messages we delete, so we can correct the user pm data + $sql = 'SELECT user_id, COUNT(msg_id) as num_undelivered_privmsgs + FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE author_id = ' . $user_id . ' + AND folder_id = ' . PRIVMSGS_NO_BOX . ' + AND ' . $db->sql_in_set('msg_id', array_merge($undelivered_msg, $delivered_msg)) . ' + GROUP BY user_id'; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $num_pms = (int) $row['num_undelivered_privmsgs']; + $undelivered_user[$num_pms][] = (int) $row['user_id']; + + if (sizeof($undelivered_user[$num_pms]) > 50) + { + // If there are too many users affected the query might get + // too long, so we update the value for the first bunch here. + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ', + user_unread_privmsg = user_unread_privmsg - ' . $num_pms . ' + WHERE ' . $db->sql_in_set('user_id', $undelivered_user[$num_pms]); + $db->sql_query($sql); + unset($undelivered_user[$num_pms]); + } + } + $db->sql_freeresult($result); + + foreach ($undelivered_user as $num_pms => $undelivered_user_set) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ', + user_unread_privmsg = user_unread_privmsg - ' . $num_pms . ' + WHERE ' . $db->sql_in_set('user_id', $undelivered_user_set); + $db->sql_query($sql); + } + + if (!empty($delivered_msg)) + { + $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE folder_id = ' . PRIVMSGS_NO_BOX . ' + AND ' . $db->sql_in_set('msg_id', $delivered_msg); + $db->sql_query($sql); + } + + if (!empty($undelivered_msg)) + { + $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg); + $db->sql_query($sql); + + $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . ' + WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg); + $db->sql_query($sql); + } + } + + // Reset the user's pm count to 0 + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_new_privmsg = 0, + user_unread_privmsg = 0 + WHERE user_id = ' . $user_id; + $db->sql_query($sql); + + // Delete private message data of the user + $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE user_id = ' . (int) $user_id; + $db->sql_query($sql); + + if (!empty($delete_ids)) + { + // Now we have to check which messages we can delete completely + $sql = 'SELECT msg_id + FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE ' . $db->sql_in_set('msg_id', $delete_ids); + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + unset($delete_ids[$row['msg_id']]); + } + $db->sql_freeresult($result); + + if (!empty($delete_ids)) + { + // Check if there are any attachments we need to remove + if (!function_exists('delete_attachments')) + { + include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); + } + + delete_attachments('message', $delete_ids, false); + + $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . ' + WHERE ' . $db->sql_in_set('msg_id', $delete_ids); + $db->sql_query($sql); + } + } + + // Set the remaining author id to anonymous + // This way users are still able to read messages from users being removed + $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' + SET author_id = ' . ANONYMOUS . ' + WHERE author_id = ' . $user_id; + $db->sql_query($sql); + + $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' + SET author_id = ' . ANONYMOUS . ' + WHERE author_id = ' . $user_id; + $db->sql_query($sql); + + $db->sql_transaction('commit'); + + return true; +} + +/** * Rebuild message header */ function rebuild_header($check_ary) @@ -1362,12 +1561,6 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true) while ($row = $db->sql_fetchrow($result)) { - // Additionally, do not include the sender if he is in the group he wants to send to. ;) - if ($row['user_id'] === $user->data['user_id']) - { - continue; - } - $field = ($data['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc'; $recipients[$row['user_id']] = $field; } @@ -1622,6 +1815,7 @@ function pm_notification($mode, $author, $recipients, $subject, $message, $msg_i $subject = censor_text($subject); + // Exclude guests, current user and banned users from notifications unset($recipients[ANONYMOUS], $recipients[$user->data['user_id']]); if (!sizeof($recipients)) @@ -1629,18 +1823,12 @@ function pm_notification($mode, $author, $recipients, $subject, $message, $msg_i return; } - // Get banned User ID's - $sql = 'SELECT ban_userid - FROM ' . BANLIST_TABLE . ' - WHERE ' . $db->sql_in_set('ban_userid', array_map('intval', array_keys($recipients))) . ' - AND ban_exclude = 0'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) + if (!function_exists('phpbb_get_banned_user_ids')) { - unset($recipients[$row['ban_userid']]); + include($phpbb_root_path . 'includes/functions_user.' . $phpEx); } - $db->sql_freeresult($result); + $banned_users = phpbb_get_banned_user_ids(array_keys($recipients)); + $recipients = array_diff(array_keys($recipients), $banned_users); if (!sizeof($recipients)) { @@ -1649,7 +1837,7 @@ function pm_notification($mode, $author, $recipients, $subject, $message, $msg_i $sql = 'SELECT user_id, username, user_email, user_lang, user_notify_pm, user_notify_type, user_jabber FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', array_map('intval', array_keys($recipients))); + WHERE ' . $db->sql_in_set('user_id', $recipients); $result = $db->sql_query($sql); $msg_list_ary = array(); diff --git a/phpBB/includes/functions_profile_fields.php b/phpBB/includes/functions_profile_fields.php index 16c193c15a..8573533c2c 100644 --- a/phpBB/includes/functions_profile_fields.php +++ b/phpBB/includes/functions_profile_fields.php @@ -122,7 +122,7 @@ class custom_profile case FIELD_BOOL: $field_value = (bool) $field_value; - + if (!$field_value && $field_data['field_required']) { return 'FIELD_REQUIRED'; @@ -134,7 +134,7 @@ class custom_profile { return false; } - + $field_value = (int) $field_value; if ($field_value < $field_data['field_minlen']) @@ -456,6 +456,8 @@ class custom_profile $user_fields = array(); + $user_ids = $user_id; + // Go through the fields in correct order foreach (array_keys($this->profile_cache) as $used_ident) { @@ -464,6 +466,15 @@ class custom_profile $user_fields[$user_id][$used_ident]['value'] = $row['pf_' . $used_ident]; $user_fields[$user_id][$used_ident]['data'] = $this->profile_cache[$used_ident]; } + + foreach ($user_ids as $user_id) + { + if (!isset($user_fields[$user_id][$used_ident]) && $this->profile_cache[$used_ident]['field_show_novalue']) + { + $user_fields[$user_id][$used_ident]['value'] = ''; + $user_fields[$user_id][$used_ident]['data'] = $this->profile_cache[$used_ident]; + } + } } return $user_fields; @@ -521,7 +532,7 @@ class custom_profile switch ($this->profile_types[$field_type]) { case 'int': - if ($value === '') + if ($value === '' && !$ident_ary['data']['field_show_novalue']) { return NULL; } @@ -530,7 +541,7 @@ class custom_profile case 'string': case 'text': - if (!$value) + if (!$value && !$ident_ary['data']['field_show_novalue']) { return NULL; } @@ -548,7 +559,7 @@ class custom_profile $month = (isset($date[1])) ? (int) $date[1] : 0; $year = (isset($date[2])) ? (int) $date[2] : 0; - if (!$day && !$month && !$year) + if (!$day && !$month && !$year && !$ident_ary['data']['field_show_novalue']) { return NULL; } @@ -571,12 +582,7 @@ class custom_profile $this->get_option_lang($field_id, $lang_id, FIELD_DROPDOWN, false); } - // If a dropdown field is required, users - // cannot choose the "no value" option. - // They must choose one of the other options. - // Therefore, here we treat a value equal to - // the "no value" as a lack of value, i.e. NULL. - if ($value == $ident_ary['data']['field_novalue'] && $ident_ary['data']['field_required']) + if ($value == $ident_ary['data']['field_novalue'] && !$ident_ary['data']['field_show_novalue']) { return NULL; } @@ -586,7 +592,14 @@ class custom_profile // User not having a value assigned if (!isset($this->options_lang[$field_id][$lang_id][$value])) { - return NULL; + if ($ident_ary['data']['field_show_novalue']) + { + $value = $ident_ary['data']['field_novalue']; + } + else + { + return NULL; + } } return $this->options_lang[$field_id][$lang_id][$value]; @@ -600,6 +613,11 @@ class custom_profile $this->get_option_lang($field_id, $lang_id, FIELD_BOOL, false); } + if (!$value && $ident_ary['data']['field_show_novalue']) + { + $value = $ident_ary['data']['field_default_value']; + } + if ($ident_ary['data']['field_length'] == 1) { return (isset($this->options_lang[$field_id][$lang_id][(int) $value])) ? $this->options_lang[$field_id][$lang_id][(int) $value] : NULL; diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index d5bbd80242..73ac1df2d2 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -751,6 +751,31 @@ class fileupload $filename = $url['path']; $filesize = 0; + $remote_max_filesize = $this->max_filesize; + if (!$remote_max_filesize) + { + $max_filesize = @ini_get('upload_max_filesize'); + + if (!empty($max_filesize)) + { + $unit = strtolower(substr($max_filesize, -1, 1)); + $remote_max_filesize = (int) $max_filesize; + + switch ($unit) + { + case 'g': + $remote_max_filesize *= 1024; + // no break + case 'm': + $remote_max_filesize *= 1024; + // no break + case 'k': + $remote_max_filesize *= 1024; + // no break + } + } + } + $errno = 0; $errstr = ''; @@ -779,9 +804,9 @@ class fileupload $block = @fread($fsock, 1024); $filesize += strlen($block); - if ($this->max_filesize && $filesize > $this->max_filesize) + if ($remote_max_filesize && $filesize > $remote_max_filesize) { - $max_filesize = get_formatted_filesize($this->max_filesize, false); + $max_filesize = get_formatted_filesize($remote_max_filesize, false); $file = new fileerror(sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit'])); return $file; @@ -807,9 +832,9 @@ class fileupload { $length = (int) str_replace('content-length: ', '', strtolower($line)); - if ($length && $length > $this->max_filesize) + if ($remote_max_filesize && $length && $length > $remote_max_filesize) { - $max_filesize = get_formatted_filesize($this->max_filesize, false); + $max_filesize = get_formatted_filesize($remote_max_filesize, false); $file = new fileerror(sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit'])); return $file; diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php index 6b5cca8abb..ea8b0a4640 100644 --- a/phpBB/includes/functions_user.php +++ b/phpBB/includes/functions_user.php @@ -528,62 +528,12 @@ function user_delete($mode, $user_id, $post_username = false) WHERE session_user_id = ' . $user_id; $db->sql_query($sql); - // Remove any undelivered mails... - $sql = 'SELECT msg_id, user_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE author_id = ' . $user_id . ' - AND folder_id = ' . PRIVMSGS_NO_BOX; - $result = $db->sql_query($sql); - - $undelivered_msg = $undelivered_user = array(); - while ($row = $db->sql_fetchrow($result)) - { - $undelivered_msg[] = $row['msg_id']; - $undelivered_user[$row['user_id']][] = true; - } - $db->sql_freeresult($result); - - if (sizeof($undelivered_msg)) - { - $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . ' - WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg); - $db->sql_query($sql); - } - - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE author_id = ' . $user_id . ' - AND folder_id = ' . PRIVMSGS_NO_BOX; - $db->sql_query($sql); - - // Delete all to-information - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE user_id = ' . $user_id; - $db->sql_query($sql); - - // Set the remaining author id to anonymous - this way users are still able to read messages from users being removed - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET author_id = ' . ANONYMOUS . ' - WHERE author_id = ' . $user_id; - $db->sql_query($sql); - - $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' - SET author_id = ' . ANONYMOUS . ' - WHERE author_id = ' . $user_id; - $db->sql_query($sql); - - foreach ($undelivered_user as $_user_id => $ary) + // Clean the private messages tables from the user + if (!function_exists('phpbb_delete_user_pms')) { - if ($_user_id == $user_id) - { - continue; - } - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_new_privmsg = user_new_privmsg - ' . sizeof($ary) . ', - user_unread_privmsg = user_unread_privmsg - ' . sizeof($ary) . ' - WHERE user_id = ' . $_user_id; - $db->sql_query($sql); + include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); } + phpbb_delete_user_pms($user_id); $db->sql_transaction('commit'); @@ -1297,8 +1247,9 @@ function validate_data($data, $val_ary) { $function = array_shift($validate); array_unshift($validate, $data[$var]); + $function_prefix = (function_exists('phpbb_validate_' . $function)) ? 'phpbb_validate_' : 'validate_'; - if ($result = call_user_func_array('validate_' . $function, $validate)) + if ($result = call_user_func_array($function_prefix . $function, $validate)) { // Since errors are checked later for their language file existence, we need to make sure custom errors are not adjusted. $error[] = (empty($user->lang[$result . '_' . strtoupper($var)])) ? $result : $result . '_' . strtoupper($var); @@ -1603,7 +1554,7 @@ function validate_username($username, $allowed_username = false) */ function validate_password($password) { - global $config, $db, $user; + global $config; if ($password === '' || $config['pass_complex'] === 'PASS_TYPE_ANY') { @@ -1949,6 +1900,51 @@ function validate_jabber($jid) } /** +* Validate hex colour value +* +* @param string $colour The hex colour value +* @param bool $optional Whether the colour value is optional. True if an empty +* string will be accepted as correct input, false if not. +* @return bool|string Error message if colour value is incorrect, false if it +* fits the hex colour code +*/ +function phpbb_validate_hex_colour($colour, $optional = false) +{ + if ($colour === '') + { + return (($optional) ? false : 'WRONG_DATA'); + } + + if (!preg_match('/^([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/', $colour)) + { + return 'WRONG_DATA'; + } + + return false; +} + +/** +* Verifies whether a style ID corresponds to an active style. +* +* @param int $style_id The style_id of a style which should be checked if activated or not. +* @return boolean +*/ +function phpbb_style_is_active($style_id) +{ + global $db; + + $sql = 'SELECT style_active + FROM ' . STYLES_TABLE . ' + WHERE style_id = '. (int) $style_id; + $result = $db->sql_query($sql); + + $style_is_active = (bool) $db->sql_fetchfield('style_active'); + $db->sql_freeresult($result); + + return $style_is_active; +} + +/** * Remove avatar */ function avatar_delete($mode, $row, $clean_db = false) @@ -3587,4 +3583,37 @@ function remove_newly_registered($user_id, $user_data = false) return $user_data['group_id']; } +/** +* Gets user ids of currently banned registered users. +* +* @param array $user_ids Array of users' ids to check for banning, +* leave empty to get complete list of banned ids +* @return array Array of banned users' ids if any, empty array otherwise +*/ +function phpbb_get_banned_user_ids($user_ids = array()) +{ + global $db; + + $sql_user_ids = (!empty($user_ids)) ? $db->sql_in_set('ban_userid', $user_ids) : 'ban_userid <> 0'; + + // Get banned User ID's + // Ignore stale bans which were not wiped yet + $banned_ids_list = array(); + $sql = 'SELECT ban_userid + FROM ' . BANLIST_TABLE . " + WHERE $sql_user_ids + AND ban_exclude <> 1 + AND (ban_end > " . time() . ' + OR ban_end = 0)'; + $result = $db->sql_query($sql); + while ($row = $db->sql_fetchrow($result)) + { + $user_id = (int) $row['ban_userid']; + $banned_ids_list[$user_id] = $user_id; + } + $db->sql_freeresult($result); + + return $banned_ids_list; +} + ?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index b70601b479..04e0e70f1d 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -414,13 +414,16 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) // Message and return links $success_msg = 'POSTS_MERGED_SUCCESS'; - // If the topic no longer exist, we will update the topic watch table. - // To not let it error out on users watching both topics, we just return on an error... - $db->sql_return_on_error(true); - $db->sql_query('UPDATE ' . TOPICS_WATCH_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); - $db->sql_return_on_error(false); + if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status')) + { + include($phpbb_root_path . 'includes/functions_database_helper.' . $phpEx); + } + + // Update the topic watch table. + phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); - $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); + // Update the bookmarks table. + phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', $topic_ids, $to_topic_id); // Link to the new topic $return_link .= (($return_link) ? '<br /><br />' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $to_forum_id . '&t=' . $to_topic_id) . '">', '</a>'); diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index ffede11d37..0cef8933fc 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -1231,6 +1231,7 @@ function mcp_fork_topic($topic_ids) } } + // Copy topic subscriptions to new topic $sql = 'SELECT user_id, notify_status FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . $topic_id; @@ -1251,6 +1252,27 @@ function mcp_fork_topic($topic_ids) { $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary); } + + // Copy bookmarks to new topic + $sql = 'SELECT user_id + FROM ' . BOOKMARKS_TABLE . ' + WHERE topic_id = ' . $topic_id; + $result = $db->sql_query($sql); + + $sql_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $sql_ary[] = array( + 'topic_id' => (int) $new_topic_id, + 'user_id' => (int) $row['user_id'], + ); + } + $db->sql_freeresult($result); + + if (sizeof($sql_ary)) + { + $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary); + } } // Sync new topics, parent forums and board stats diff --git a/phpBB/includes/mcp/mcp_pm_reports.php b/phpBB/includes/mcp/mcp_pm_reports.php index 72f77fae7c..77bc7680e6 100644 --- a/phpBB/includes/mcp/mcp_pm_reports.php +++ b/phpBB/includes/mcp/mcp_pm_reports.php @@ -123,6 +123,7 @@ class mcp_pm_reports $message = bbcode_nl2br($message); $message = smiley_text($message); + $report['report_text'] = make_clickable(bbcode_nl2br($report['report_text'])); if ($pm_info['message_attachment'] && $auth->acl_get('u_pm_download')) { diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index d7cc1e795a..76985488b7 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -50,6 +50,16 @@ function mcp_topic_view($id, $mode, $action) $submitted_id_list = request_var('post_ids', array(0)); $checked_ids = $post_id_list = request_var('post_id_list', array(0)); + // Resync Topic? + if ($action == 'resync') + { + if (!function_exists('mcp_resync_topics')) + { + include($phpbb_root_path . 'includes/mcp/mcp_forum.' . $phpEx); + } + mcp_resync_topics(array($topic_id)); + } + // Split Topic? if ($action == 'split_all' || $action == 'split_beyond') { @@ -320,6 +330,7 @@ function mcp_topic_view($id, $mode, $action) 'S_CAN_APPROVE' => ($has_unapproved_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false, 'S_CAN_LOCK' => ($auth->acl_get('m_lock', $topic_info['forum_id'])) ? true : false, 'S_CAN_REPORT' => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? true : false, + 'S_CAN_SYNC' => $auth->acl_get('m_', $topic_info['forum_id']), 'S_REPORT_VIEW' => ($action == 'reports') ? true : false, 'S_MERGE_VIEW' => ($action == 'merge') ? true : false, 'S_SPLIT_VIEW' => ($action == 'split') ? true : false, @@ -506,6 +517,49 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) WHERE post_id = {$post_id_list[0]}"; $db->sql_query($sql); + // Copy topic subscriptions to new topic + $sql = 'SELECT user_id, notify_status + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . $topic_id; + $result = $db->sql_query($sql); + + $sql_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $sql_ary[] = array( + 'topic_id' => (int) $to_topic_id, + 'user_id' => (int) $row['user_id'], + 'notify_status' => (int) $row['notify_status'], + ); + } + $db->sql_freeresult($result); + + if (sizeof($sql_ary)) + { + $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary); + } + + // Copy bookmarks to new topic + $sql = 'SELECT user_id + FROM ' . BOOKMARKS_TABLE . ' + WHERE topic_id = ' . $topic_id; + $result = $db->sql_query($sql); + + $sql_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $sql_ary[] = array( + 'topic_id' => (int) $to_topic_id, + 'user_id' => (int) $row['user_id'], + ); + } + $db->sql_freeresult($result); + + if (sizeof($sql_ary)) + { + $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary); + } + $success_msg = 'TOPIC_SPLIT_SUCCESS'; // Update forum statistics @@ -608,13 +662,16 @@ function merge_posts($topic_id, $to_topic_id) } else { + if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status')) + { + include($phpbb_root_path . 'includes/functions_database_helper.' . $phpEx); + } + // If the topic no longer exist, we will update the topic watch table. - // To not let it error out on users watching both topics, we just return on an error... - $db->sql_return_on_error(true); - $db->sql_query('UPDATE ' . TOPICS_WATCH_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE topic_id = ' . (int) $topic_id); - $db->sql_return_on_error(false); + phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id); - $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $topic_id); + // If the topic no longer exist, we will update the bookmarks table. + phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', $topic_id, $to_topic_id); } // Link to the new topic diff --git a/phpBB/includes/mcp/mcp_warn.php b/phpBB/includes/mcp/mcp_warn.php index 63e5b19155..1016204ff8 100644 --- a/phpBB/includes/mcp/mcp_warn.php +++ b/phpBB/includes/mcp/mcp_warn.php @@ -308,7 +308,7 @@ class mcp_warn include($phpbb_root_path . 'includes/functions_display.' . $phpEx); } - $rank_title = $rank_img = ''; + get_user_rank($user_row['user_rank'], $user_row['user_posts'], $rank_title, $rank_img, $rank_img_src); $avatar_img = get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']); $template->assign_vars(array( @@ -413,7 +413,7 @@ class mcp_warn include($phpbb_root_path . 'includes/functions_display.' . $phpEx); } - $rank_title = $rank_img = ''; + get_user_rank($user_row['user_rank'], $user_row['user_posts'], $rank_title, $rank_img, $rank_img_src); $avatar_img = get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']); // OK, they didn't submit a warning so lets build the page for them to do so diff --git a/phpBB/includes/questionnaire/questionnaire.php b/phpBB/includes/questionnaire/questionnaire.php index cbd7638809..3268775cb6 100644 --- a/phpBB/includes/questionnaire/questionnaire.php +++ b/phpBB/includes/questionnaire/questionnaire.php @@ -71,7 +71,7 @@ class phpbb_questionnaire_data_collector /** * Collect info into the data property. * - * @return void + * @return null */ function collect() { diff --git a/phpBB/includes/search/fulltext_mysql.php b/phpBB/includes/search/fulltext_mysql.php index 779ec1d216..f28b8885e7 100644 --- a/phpBB/includes/search/fulltext_mysql.php +++ b/phpBB/includes/search/fulltext_mysql.php @@ -86,9 +86,16 @@ class fulltext_mysql extends search_backend $engine = $info['Type']; } - if ($engine != 'MyISAM') + $fulltext_supported = + $engine === 'MyISAM' || + // FULLTEXT is supported on InnoDB since MySQL 5.6.4 according to + // http://dev.mysql.com/doc/refman/5.6/en/innodb-storage-engine.html + $engine === 'InnoDB' && + phpbb_version_compare($db->sql_server_info(true), '5.6.4', '>='); + + if (!$fulltext_supported) { - return $user->lang['FULLTEXT_MYSQL_NOT_MYISAM']; + return $user->lang['FULLTEXT_MYSQL_NOT_SUPPORTED']; } $sql = 'SHOW VARIABLES @@ -747,7 +754,7 @@ class fulltext_mysql extends search_backend { if ($db->sql_layer == 'mysqli' || version_compare($db->sql_server_info(true), '4.1.3', '>=')) { - //$alter[] = 'MODIFY post_subject varchar(100) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; + $alter[] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; } else { diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index a894242a39..fe5357f32e 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -322,8 +322,15 @@ class session } } - // Is session_id is set or session_id is set and matches the url param if required - if (!empty($this->session_id) && (!defined('NEED_SID') || (isset($_GET['sid']) && $this->session_id === $_GET['sid']))) + // if no session id is set, redirect to index.php + if (defined('NEED_SID') && (!isset($_GET['sid']) || $this->session_id !== $_GET['sid'])) + { + send_status_line(401, 'Unauthorized'); + redirect(append_sid("{$phpbb_root_path}index.$phpEx")); + } + + // if session id is set + if (!empty($this->session_id)) { $sql = 'SELECT u.*, s.* FROM ' . SESSIONS_TABLE . ' s, ' . USERS_TABLE . " u @@ -1654,7 +1661,7 @@ class user extends session if (!$this->theme) { - trigger_error('Could not get style data', E_USER_ERROR); + trigger_error('NO_STYLE_DATA', E_USER_ERROR); } // Now parse the cfg file and cache it @@ -2149,7 +2156,8 @@ class user extends session 'is_short' => strpos($format, '|'), 'format_short' => substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1), 'format_long' => str_replace('|', '', $format), - 'lang' => $this->lang['datetime'], + // Filter out values that are not strings (e.g. arrays) for strtr(). + 'lang' => array_filter($this->lang['datetime'], 'is_string'), ); // Short representation of month in format? Some languages use different terms for the long and short format of May diff --git a/phpBB/includes/startup.php b/phpBB/includes/startup.php index bbe2f127f1..cf216a65db 100644 --- a/phpBB/includes/startup.php +++ b/phpBB/includes/startup.php @@ -19,7 +19,23 @@ if (!defined('E_DEPRECATED')) { define('E_DEPRECATED', 8192); } -error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED); +$level = E_ALL & ~E_NOTICE & ~E_DEPRECATED; +if (version_compare(PHP_VERSION, '5.4.0-dev', '>=')) +{ + // PHP 5.4 adds E_STRICT to E_ALL. + // Our utf8 normalizer triggers E_STRICT output on PHP 5.4. + // Unfortunately it cannot be made E_STRICT-clean while + // continuing to work on PHP 4. + // Therefore, in phpBB 3.0.x we disable E_STRICT on PHP 5.4+, + // while phpBB 3.1 will fix utf8 normalizer. + // E_STRICT is defined starting with PHP 5 + if (!defined('E_STRICT')) + { + define('E_STRICT', 2048); + } + $level &= ~E_STRICT; +} +error_reporting($level); /* * Remove variables created by register_globals from the global scope diff --git a/phpBB/includes/ucp/info/ucp_profile.php b/phpBB/includes/ucp/info/ucp_profile.php index d19b80f4c0..4591776768 100644 --- a/phpBB/includes/ucp/info/ucp_profile.php +++ b/phpBB/includes/ucp/info/ucp_profile.php @@ -21,7 +21,7 @@ class ucp_profile_info 'version' => '1.0.0', 'modes' => array( 'profile_info' => array('title' => 'UCP_PROFILE_PROFILE_INFO', 'auth' => '', 'cat' => array('UCP_PROFILE')), - 'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => '', 'cat' => array('UCP_PROFILE')), + 'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => 'acl_u_sig', 'cat' => array('UCP_PROFILE')), 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar && (cfg_allow_avatar_local || cfg_allow_avatar_remote || cfg_allow_avatar_upload || cfg_allow_avatar_remote_upload)', 'cat' => array('UCP_PROFILE')), 'reg_details' => array('title' => 'UCP_PROFILE_REG_DETAILS', 'auth' => '', 'cat' => array('UCP_PROFILE')), ), diff --git a/phpBB/includes/ucp/ucp_activate.php b/phpBB/includes/ucp/ucp_activate.php index 82c1937919..b262dc5c1c 100644 --- a/phpBB/includes/ucp/ucp_activate.php +++ b/phpBB/includes/ucp/ucp_activate.php @@ -51,7 +51,7 @@ class ucp_activate trigger_error('ALREADY_ACTIVATED'); } - if (($user_row['user_inactive_reason'] == INACTIVE_MANUAL) || $user_row['user_actkey'] != $key) + if ($user_row['user_inactive_reason'] == INACTIVE_MANUAL || $user_row['user_actkey'] !== $key) { trigger_error('WRONG_ACTIVATION'); } diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php index d62dbb1866..9365913541 100644 --- a/phpBB/includes/ucp/ucp_groups.php +++ b/phpBB/includes/ucp/ucp_groups.php @@ -595,6 +595,13 @@ class ucp_groups $error[] = $user->lang['FORM_INVALID']; } + // Validate submitted colour value + if ($colour_error = validate_data($submit_ary, array('colour' => array('hex_colour', true)))) + { + // Replace "error" string with its real, localised form + $error = array_merge($error, array_map(array(&$user, 'lang'), $colour_error)); + } + if (!sizeof($error)) { // Only set the rank, colour, etc. if it's changed or if we're adding a new diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index 05243e3d7a..d7509a1072 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -271,19 +271,16 @@ function compose_pm($id, $mode, $action, $user_folders = array()) // Passworded forum? if ($post['forum_id']) { - $sql = 'SELECT forum_password + $sql = 'SELECT forum_id, forum_name, forum_password FROM ' . FORUMS_TABLE . ' WHERE forum_id = ' . (int) $post['forum_id']; $result = $db->sql_query($sql); - $forum_password = (string) $db->sql_fetchfield('forum_password'); + $forum_data = $db->sql_fetchrow($result); $db->sql_freeresult($result); - if ($forum_password) + if (!empty($forum_data['forum_password'])) { - login_forum_box(array( - 'forum_id' => $post['forum_id'], - 'forum_password' => $forum_password, - )); + login_forum_box($forum_data); } } } @@ -359,7 +356,7 @@ function compose_pm($id, $mode, $action, $user_folders = array()) $message_attachment = 0; $message_text = $message_subject = ''; - if ($to_user_id && $action == 'post') + if ($to_user_id && $to_user_id != ANONYMOUS && $action == 'post') { $address_list['u'][$to_user_id] = 'to'; } @@ -755,7 +752,8 @@ function compose_pm($id, $mode, $action, $user_folders = array()) $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>'); + $save_message = ($action === 'edit') ? $user->lang['MESSAGE_EDITED'] : $user->lang['MESSAGE_STORED']; + $message = $save_message . '<br /><br />' . $user->lang('VIEW_PRIVATE_MESSAGE', '<a href="' . $return_message_url . '">', '</a>'); $last_click_type = 'CLICK_RETURN_FOLDER'; if ($folder_url) diff --git a/phpBB/includes/ucp/ucp_pm_options.php b/phpBB/includes/ucp/ucp_pm_options.php index 58c2d087c8..efa390ed87 100644 --- a/phpBB/includes/ucp/ucp_pm_options.php +++ b/phpBB/includes/ucp/ucp_pm_options.php @@ -328,10 +328,23 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit trigger_error('RULE_ALREADY_DEFINED'); } + // Prevent users from flooding the rules table + $sql = 'SELECT COUNT(rule_id) AS num_rules + FROM ' . PRIVMSGS_RULES_TABLE . ' + WHERE user_id = ' . (int) $user->data['user_id']; + $result = $db->sql_query($sql); + $num_rules = (int) $db->sql_fetchfield('num_rules'); + $db->sql_freeresult($result); + + if ($num_rules >= 5000) + { + trigger_error('RULE_LIMIT_REACHED'); + } + $sql = 'INSERT INTO ' . PRIVMSGS_RULES_TABLE . ' ' . $db->sql_build_array('INSERT', $rule_ary); $db->sql_query($sql); - // Update users message rules + // Set the user_message_rules bit $sql = 'UPDATE ' . USERS_TABLE . ' SET user_message_rules = 1 WHERE user_id = ' . $user->data['user_id']; @@ -378,7 +391,7 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - // Update users message rules + // Unset the user_message_rules bit if (!$row) { $sql = 'UPDATE ' . USERS_TABLE . ' diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php index 13167b2b3d..c6e43b831c 100644 --- a/phpBB/includes/ucp/ucp_prefs.php +++ b/phpBB/includes/ucp/ucp_prefs.php @@ -61,7 +61,14 @@ class ucp_prefs if ($submit) { - $data['style'] = ($config['override_user_style']) ? $config['default_style'] : $data['style']; + if ($config['override_user_style']) + { + $data['style'] = (int) $config['default_style']; + } + else if (!phpbb_style_is_active($data['style'])) + { + $data['style'] = (int) $user->data['user_style']; + } $error = validate_data($data, array( 'dateformat' => array('string', false, 1, 30), @@ -127,6 +134,35 @@ class ucp_prefs } $dateformat_options .= '>' . $user->lang['CUSTOM_DATEFORMAT'] . '</option>'; + // check if there are any user-selectable languages + $sql = 'SELECT COUNT(lang_id) as languages_count + FROM ' . LANG_TABLE; + $result = $db->sql_query($sql); + if ($db->sql_fetchfield('languages_count') > 1) + { + $s_more_languages = true; + } + else + { + $s_more_languages = false; + } + $db->sql_freeresult($result); + + // check if there are any user-selectable styles + $sql = 'SELECT COUNT(style_id) as styles_count + FROM ' . STYLES_TABLE . ' + WHERE style_active = 1'; + $result = $db->sql_query($sql); + if ($db->sql_fetchfield('styles_count') > 1) + { + $s_more_styles = true; + } + else + { + $s_more_styles = false; + } + $db->sql_freeresult($result); + $template->assign_vars(array( 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '', @@ -148,6 +184,9 @@ class ucp_prefs 'DEFAULT_DATEFORMAT' => $config['default_dateformat'], 'A_DEFAULT_DATEFORMAT' => addslashes($config['default_dateformat']), + 'S_MORE_LANGUAGES' => $s_more_languages, + 'S_MORE_STYLES' => $s_more_styles, + 'S_LANG_OPTIONS' => language_select($data['lang']), 'S_STYLE_OPTIONS' => ($config['override_user_style']) ? '' : style_select($data['style']), 'S_TZ_OPTIONS' => tz_select($data['tz'], true), |
