aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/includes
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/includes')
-rw-r--r--phpBB/includes/acp/acp_attachments.php228
-rw-r--r--phpBB/includes/acp/acp_board.php18
-rw-r--r--phpBB/includes/acp/acp_inactive.php2
-rw-r--r--phpBB/includes/acp/acp_logs.php4
-rw-r--r--phpBB/includes/acp/acp_main.php7
-rw-r--r--phpBB/includes/acp/acp_php_info.php8
-rw-r--r--phpBB/includes/acp/acp_profile.php6
-rw-r--r--phpBB/includes/acp/acp_send_statistics.php6
-rw-r--r--phpBB/includes/acp/acp_styles.php5
-rw-r--r--phpBB/includes/acp/acp_update.php7
-rw-r--r--phpBB/includes/acp/acp_users.php2
-rw-r--r--phpBB/includes/acp/info/acp_attachments.php3
-rw-r--r--phpBB/includes/auth.php10
-rw-r--r--phpBB/includes/auth/auth_db.php63
-rw-r--r--phpBB/includes/auth/auth_ldap.php2
-rw-r--r--phpBB/includes/bbcode.php7
-rwxr-xr-xphpBB/includes/cache/driver/redis.php14
-rw-r--r--phpBB/includes/cache/service.php1
-rw-r--r--phpBB/includes/captcha/captcha_gd.php2
-rw-r--r--phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php4
-rw-r--r--phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php13
-rw-r--r--phpBB/includes/constants.php1
-rw-r--r--phpBB/includes/cron/manager.php12
-rw-r--r--phpBB/includes/db/db_tools.php311
-rw-r--r--phpBB/includes/db/dbal.php12
-rw-r--r--phpBB/includes/db/firebird.php3
-rw-r--r--phpBB/includes/db/mssqlnative.php2
-rw-r--r--phpBB/includes/db/mysqli.php27
-rw-r--r--phpBB/includes/functions.php147
-rw-r--r--phpBB/includes/functions_acp.php10
-rw-r--r--phpBB/includes/functions_admin.php47
-rw-r--r--phpBB/includes/functions_content.php5
-rw-r--r--phpBB/includes/functions_display.php83
-rw-r--r--phpBB/includes/functions_download.php4
-rw-r--r--phpBB/includes/functions_posting.php106
-rw-r--r--phpBB/includes/functions_profile_fields.php14
-rw-r--r--phpBB/includes/mcp/mcp_logs.php4
-rw-r--r--phpBB/includes/mcp/mcp_notes.php2
-rw-r--r--phpBB/includes/message_parser.php11
-rw-r--r--phpBB/includes/session.php89
-rw-r--r--phpBB/includes/startup.php150
-rw-r--r--phpBB/includes/ucp/ucp_activate.php7
-rw-r--r--phpBB/includes/ucp/ucp_pm.php4
-rw-r--r--phpBB/includes/ucp/ucp_pm_compose.php31
-rw-r--r--phpBB/includes/ucp/ucp_pm_viewmessage.php43
45 files changed, 1351 insertions, 186 deletions
diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php
index 3179be7de7..c62fefae46 100644
--- a/phpBB/includes/acp/acp_attachments.php
+++ b/phpBB/includes/acp/acp_attachments.php
@@ -61,6 +61,10 @@ class acp_attachments
$l_title = 'ACP_ORPHAN_ATTACHMENTS';
break;
+ case 'manage':
+ $l_title = 'ACP_MANAGE_ATTACHMENTS';
+ break;
+
default:
trigger_error('NO_MODE', E_USER_ERROR);
break;
@@ -1043,6 +1047,230 @@ class acp_attachments
$db->sql_freeresult($result);
break;
+
+ case 'manage':
+
+ if ($submit)
+ {
+ $delete_files = (isset($_POST['delete'])) ? array_keys(request_var('delete', array('' => 0))) : array();
+
+ if (sizeof($delete_files))
+ {
+ // Select those attachments we want to delete...
+ $sql = 'SELECT real_filename
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE ' . $db->sql_in_set('attach_id', $delete_files) . '
+ AND is_orphan = 0';
+ $result = $db->sql_query($sql);
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $deleted_filenames[] = $row['real_filename'];
+ }
+ $db->sql_freeresult($result);
+
+ if ($num_deleted = delete_attachments('attach', $delete_files))
+ {
+ if (sizeof($delete_files) != $num_deleted)
+ {
+ $error[] = $user->lang['FILES_GONE'];
+ }
+ add_log('admin', 'LOG_ATTACHMENTS_DELETED', implode(', ', $deleted_filenames));
+ $notify[] = sprintf($user->lang['LOG_ATTACHMENTS_DELETED'], implode(', ', $deleted_filenames));
+ }
+ else
+ {
+ $error[] = $user->lang['NO_FILES_TO_DELETE'];
+ }
+ }
+ }
+
+ $template->assign_vars(array(
+ 'S_MANAGE' => true)
+ );
+
+ $start = request_var('start', 0);
+
+ // Sort keys
+ $sort_days = request_var('st', 0);
+ $sort_key = request_var('sk', 't');
+ $sort_dir = request_var('sd', 'd');
+
+ // Sorting
+ $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
+ $sort_by_text = array('f' => $user->lang['FILENAME'], 't' => $user->lang['FILEDATE'], 's' => $user->lang['FILESIZE'], 'x' => $user->lang['EXTENSION'], 'd' => $user->lang['DOWNLOADS'],'p' => $user->lang['ATTACH_POST_TYPE'], 'u' => $user->lang['AUTHOR']);
+ $sort_by_sql = array('f' => 'a.real_filename', 't' => 'a.filetime', 's' => 'a.filesize', 'x' => 'a.extension', 'd' => 'a.download_count', 'p' => 'a.in_message', 'u' => 'u.username');
+
+ $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
+ gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
+
+ $min_filetime = ($sort_days) ? (time() - ($sort_days * 86400)) : '';
+ $limit_filetime = ($min_filetime) ? " AND a.filetime >= $min_filetime " : '';
+ $start = ($sort_days && isset($_POST['sort'])) ? 0 : $start;
+
+ $attachments_per_page = (int) $config['topics_per_page'];
+
+ // Handle files stats resync
+ $action = request_var('action', '');
+ $resync_files_stats = false;
+ if ($action && $action = 'stats')
+ {
+ if (!confirm_box(true))
+ {
+ confirm_box(false, $user->lang['RESYNC_FILES_STATS_CONFIRM'], build_hidden_fields(array(
+ 'i' => $id,
+ 'mode' => $mode,
+ 'action' => $action,
+ )));
+ }
+ else
+ {
+ $resync_files_stats = true;
+ add_log('admin', 'LOG_RESYNC_FILES_STATS');
+ }
+ }
+
+ // Check if files stats are accurate
+ $sql = 'SELECT COUNT(attach_id) as num_files
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE is_orphan = 0';
+ $result = $db->sql_query($sql, 600);
+ $num_files_real = (int) $db->sql_fetchfield('num_files');
+ if ($resync_files_stats === true)
+ {
+ set_config('num_files', $num_files_real, true);
+ }
+ $db->sql_freeresult($result);
+
+ $sql = 'SELECT SUM(filesize) as upload_dir_size
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE is_orphan = 0';
+ $result = $db->sql_query($sql, 600);
+ $total_size_real = (float) $db->sql_fetchfield('upload_dir_size');
+ if ($resync_files_stats === true)
+ {
+ set_config('upload_dir_size', $total_size_real, true);
+ }
+ $db->sql_freeresult($result);
+
+ // Get current files stats
+ $num_files = (int) $config['num_files'];
+ $total_size = (float) $config['upload_dir_size'];
+
+ // Issue warning message if files stats are inaccurate
+ if (($num_files != $num_files_real) || ($total_size != $total_size_real))
+ {
+ $error[] = sprintf($user->lang['FILES_STATS_WRONG'], $num_files_real, get_formatted_filesize($total_size_real));
+
+ $template->assign_vars(array(
+ 'S_ACTION_OPTIONS' => ($auth->acl_get('a_board')) ? true : false,
+ 'U_ACTION' => $this->u_action,)
+ );
+ }
+
+ // Make sure $start is set to the last page if it exceeds the amount
+ if ($start < 0 || $start > $num_files)
+ {
+ $start = ($start < 0) ? 0 : floor(($num_files - 1) / $attachments_per_page) * $attachments_per_page;
+ }
+
+ // If the user is trying to reach the second half of the attachments list, fetch it starting from the end
+ $store_reverse = false;
+ $sql_limit = $attachments_per_page;
+
+ if ($start > $num_files / 2)
+ {
+ $store_reverse = true;
+
+ if ($start + $attachments_per_page > $num_files)
+ {
+ $sql_limit = min($attachments_per_page, max(1, $num_files - $start));
+ }
+
+ // Select the sort order. Add time sort anchor for non-time sorting cases
+ $sql_sort_anchor = ($sort_key != 't') ? ', a.filetime ' . (($sort_dir == 'd') ? 'ASC' : 'DESC') : '';
+ $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'ASC' : 'DESC') . $sql_sort_anchor;
+ $sql_start = max(0, $num_files - $sql_limit - $start);
+ }
+ else
+ {
+ // Select the sort order. Add time sort anchor for non-time sorting cases
+ $sql_sort_anchor = ($sort_key != 't') ? ', a.filetime ' . (($sort_dir == 'd') ? 'DESC' : 'ASC') : '';
+ $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC') . $sql_sort_anchor;
+ $sql_start = $start;
+
+ }
+
+ $attachments_list = array();
+
+ // Just get the files
+ $sql = 'SELECT a.*, u.username, u.user_colour, t.topic_title
+ FROM ' . ATTACHMENTS_TABLE . ' a
+ LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = a.poster_id)
+ LEFT JOIN ' . TOPICS_TABLE . " t ON (a.topic_id = t.topic_id)
+ WHERE a.is_orphan = 0
+ $limit_filetime
+ ORDER BY $sql_sort_order";
+ $result = $db->sql_query_limit($sql, $sql_limit, $sql_start);
+
+ $i = ($store_reverse) ? $sql_limit - 1 : 0;
+
+ // Store increment value in a variable to save some conditional calls
+ $i_increment = ($store_reverse) ? -1 : 1;
+ while ($attachment_row = $db->sql_fetchrow($result))
+ {
+ $attachments_list[$i] = $attachment_row;
+ $i = $i + $i_increment;
+ }
+ $db->sql_freeresult($result);
+
+ $template->assign_vars(array(
+ 'TOTAL_FILES' => $num_files,
+ 'TOTAL_SIZE' => get_formatted_filesize($total_size),
+ 'PAGINATION' => generate_pagination($this->u_action . "&amp;$u_sort_param", $num_files, $attachments_per_page, $start, true),
+
+ 'S_ON_PAGE' => on_page($num_files, $attachments_per_page, $start),
+ 'S_LIMIT_DAYS' => $s_limit_days,
+ 'S_SORT_KEY' => $s_sort_key,
+ 'S_SORT_DIR' => $s_sort_dir)
+ );
+
+ // Grab extensions
+ $extensions = $cache->obtain_attach_extensions(true);
+
+ for ($i = 0, $end = sizeof($attachments_list); $i < $end; ++$i)
+ {
+ $row = $attachments_list[$i];
+
+ $row['extension'] = strtolower(trim((string) $row['extension']));
+ $comment = ($row['attach_comment'] && !$row['in_message']) ? str_replace(array("\n", "\r"), array('<br />', "\n"), $row['attach_comment']) : '';
+ $display_cat = $extensions[$row['extension']]['display_cat'];
+ $l_downloaded_viewed = ($display_cat == ATTACHMENT_CATEGORY_NONE) ? 'DOWNLOAD_COUNT' : 'VIEWED_COUNT';
+ $l_download_count = (!isset($row['download_count']) || (int) $row['download_count'] == 0) ? $user->lang[$l_downloaded_viewed . '_NONE'] : (((int) $row['download_count'] == 1) ? sprintf($user->lang[$l_downloaded_viewed], $row['download_count']) : sprintf($user->lang[$l_downloaded_viewed . 'S'], $row['download_count']));
+
+ $template->assign_block_vars('attachments', array(
+ 'ATTACHMENT_POSTER' => get_username_string('full', (int) $row['poster_id'], (string) $row['username'], (string) $row['user_colour'], (string) $row['username']),
+ 'FILESIZE' => get_formatted_filesize((int) $row['filesize']),
+ 'FILETIME' => $user->format_date((int) $row['filetime']),
+ 'REAL_FILENAME' => (!$row['in_message']) ? utf8_wordwrap(utf8_basename((string) $row['real_filename']), 40, '<br />', true) : '',
+ 'PHYSICAL_FILENAME' => utf8_basename((string) $row['physical_filename']),
+ 'EXT_GROUP_NAME' => (!empty($extensions[$row['extension']]['group_name'])) ? $user->lang['EXT_GROUP_' . $extensions[$row['extension']]['group_name']] : '',
+ 'COMMENT' => $comment,
+ 'TOPIC_TITLE' => (!$row['in_message']) ? (string) $row['topic_title'] : '',
+ 'ATTACH_ID' => (int) $row['attach_id'],
+ 'POST_ID' => (int) $row['post_msg_id'],
+ 'TOPIC_ID' => (int) $row['topic_id'],
+ 'POST_IDS' => (!empty($post_ids[$row['attach_id']])) ? (int) $post_ids[$row['attach_id']] : '',
+
+ 'L_DOWNLOAD_COUNT' => $l_download_count,
+
+ 'S_IN_MESSAGE' => (bool) $row['in_message'],
+
+ 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row['topic_id']}&amp;p={$row['post_msg_id']}") . "#p{$row['post_msg_id']}",
+ 'U_FILE' => append_sid($phpbb_root_path . 'download/file.' . $phpEx, 'mode=view&amp;id=' . $row['attach_id']))
+ );
+ }
+
+ break;
}
if (sizeof($error))
diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php
index 6821073749..f27a133eb5 100644
--- a/phpBB/includes/acp/acp_board.php
+++ b/phpBB/includes/acp/acp_board.php
@@ -96,6 +96,7 @@ class acp_board
'load_moderators' => array('lang' => 'YES_MODERATORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'load_jumpbox' => array('lang' => 'YES_JUMPBOX', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
+ 'load_cpf_pm' => array('lang' => 'LOAD_CPF_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
@@ -327,6 +328,7 @@ class acp_board
'legend3' => 'CUSTOM_PROFILE_FIELDS',
'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
+ 'load_cpf_pm' => array('lang' => 'LOAD_CPF_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
@@ -387,6 +389,9 @@ class acp_board
'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true),
'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true),
+ 'ip_login_limit_max' => array('lang' => 'IP_LOGIN_LIMIT_MAX', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true),
+ 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
+ 'ip_login_limit_use_forwarded' => array('lang' => 'IP_LOGIN_LIMIT_USE_FORWARDED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'tpl_allow_php' => array('lang' => 'TPL_ALLOW_PHP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'form_token_lifetime' => array('lang' => 'FORM_TIME_MAX', 'validate' => 'int:-1', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
'form_token_sid_guests' => array('lang' => 'FORM_SID_GUESTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -770,13 +775,20 @@ class acp_board
{
global $user, $config;
- $radio_ary = array(USER_ACTIVATION_DISABLE => 'ACC_DISABLE', USER_ACTIVATION_NONE => 'ACC_NONE');
+ $radio_ary = array(
+ USER_ACTIVATION_DISABLE => 'ACC_DISABLE',
+ USER_ACTIVATION_NONE => 'ACC_NONE',
+ );
+
if ($config['email_enable'])
{
- $radio_ary += array(USER_ACTIVATION_SELF => 'ACC_USER', USER_ACTIVATION_ADMIN => 'ACC_ADMIN');
+ $radio_ary[USER_ACTIVATION_SELF] = 'ACC_USER';
+ $radio_ary[USER_ACTIVATION_ADMIN] = 'ACC_ADMIN';
}
- return h_radio('config[require_activation]', $radio_ary, $value, $key);
+ $radio_text = h_radio('config[require_activation]', $radio_ary, $value, 'require_activation', $key, '<br />');
+
+ return $radio_text;
}
/**
diff --git a/phpBB/includes/acp/acp_inactive.php b/phpBB/includes/acp/acp_inactive.php
index e4fb695a11..0e4801f630 100644
--- a/phpBB/includes/acp/acp_inactive.php
+++ b/phpBB/includes/acp/acp_inactive.php
@@ -301,7 +301,7 @@ class acp_inactive
'PAGINATION' => generate_pagination($this->u_action . "&amp;$u_sort_param&amp;users_per_page=$per_page", $inactive_count, $per_page, $start, true),
'USERS_PER_PAGE' => $per_page,
- 'U_ACTION' => $this->u_action . '&amp;start=' . $start,
+ 'U_ACTION' => $this->u_action . "&amp;$u_sort_param&amp;users_per_page=$per_page&amp;start=$start",
));
$this->tpl_name = 'acp_inactive';
diff --git a/phpBB/includes/acp/acp_logs.php b/phpBB/includes/acp/acp_logs.php
index 90c1a10649..065a6d1c22 100644
--- a/phpBB/includes/acp/acp_logs.php
+++ b/phpBB/includes/acp/acp_logs.php
@@ -128,12 +128,12 @@ class acp_logs
// Grab log data
$log_data = array();
$log_count = 0;
- view_log($mode, $log_data, $log_count, $config['topics_per_page'], $start, $forum_id, 0, 0, $sql_where, $sql_sort, $keywords);
+ $start = view_log($mode, $log_data, $log_count, $config['topics_per_page'], $start, $forum_id, 0, 0, $sql_where, $sql_sort, $keywords);
$template->assign_vars(array(
'L_TITLE' => $l_title,
'L_EXPLAIN' => $l_title_explain,
- 'U_ACTION' => $this->u_action,
+ 'U_ACTION' => $this->u_action . "&amp;$u_sort_param$keywords_param&amp;start=$start",
'S_ON_PAGE' => on_page($log_count, $config['topics_per_page'], $start),
'PAGINATION' => generate_pagination($this->u_action . "&amp;$u_sort_param$keywords_param", $log_count, $config['topics_per_page'], $start, true),
diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php
index ac375838fd..a922ef570c 100644
--- a/phpBB/includes/acp/acp_main.php
+++ b/phpBB/includes/acp/acp_main.php
@@ -415,11 +415,8 @@ class acp_main
{
$latest_version_info = explode("\n", $latest_version_info);
- $latest_version = str_replace('rc', 'RC', strtolower(trim($latest_version_info[0])));
- $current_version = str_replace('rc', 'RC', strtolower($config['version']));
-
$template->assign_vars(array(
- 'S_VERSION_UP_TO_DATE' => version_compare($current_version, $latest_version, '<') ? false : true,
+ 'S_VERSION_UP_TO_DATE' => phpbb_version_compare(trim($latest_version_info[0]), $config['version'], '<='),
));
}
@@ -521,7 +518,7 @@ class acp_main
'U_ADMIN_LOG' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=logs&amp;mode=admin'),
'U_INACTIVE_USERS' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=inactive&amp;mode=list'),
'U_VERSIONCHECK' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=update&amp;mode=version_check'),
- 'U_VERSIONCHECK_FORCE' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=1&amp;versioncheck_force=1'),
+ 'U_VERSIONCHECK_FORCE' => append_sid("{$phpbb_admin_path}index.$phpEx", 'versioncheck_force=1'),
'S_ACTION_OPTIONS' => ($auth->acl_get('a_board')) ? true : false,
'S_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false,
diff --git a/phpBB/includes/acp/acp_php_info.php b/phpBB/includes/acp/acp_php_info.php
index 03561f3e30..65150a40c5 100644
--- a/phpBB/includes/acp/acp_php_info.php
+++ b/phpBB/includes/acp/acp_php_info.php
@@ -67,6 +67,9 @@ class acp_php_info
$output = preg_replace('#<img border="0"#i', '<img', $output);
$output = str_replace(array('class="e"', 'class="v"', 'class="h"', '<hr />', '<font', '</font>'), array('class="row1"', 'class="row2"', '', '', '<span', '</span>'), $output);
+ // Fix invalid anchor names (eg "module_Zend Optimizer")
+ $output = preg_replace_callback('#<a name="([^"]+)">#', array($this, 'remove_spaces'), $output);
+
if (empty($output))
{
trigger_error('NO_PHPINFO_AVAILABLE', E_USER_WARNING);
@@ -79,4 +82,9 @@ class acp_php_info
$template->assign_var('PHPINFO', $output);
}
+
+ function remove_spaces($matches)
+ {
+ return '<a name="' . str_replace(' ', '_', $matches[1]) . '">';
+ }
}
diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php
index ca6a5f04d2..a18a01c44a 100644
--- a/phpBB/includes/acp/acp_profile.php
+++ b/phpBB/includes/acp/acp_profile.php
@@ -370,6 +370,7 @@ class acp_profile
'field_show_profile'=> 0,
'field_no_view' => 0,
'field_show_on_reg' => 0,
+ 'field_show_on_pm' => 0,
'field_show_on_vt' => 0,
'lang_name' => utf8_normalize_nfc(request_var('field_ident', '', true)),
'lang_explain' => '',
@@ -381,7 +382,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_pm', 'field_show_on_vt', 'field_required', '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')
);
@@ -407,6 +408,7 @@ class acp_profile
$visibility_ary = array(
'field_required',
'field_show_on_reg',
+ 'field_show_on_pm',
'field_show_on_vt',
'field_show_profile',
'field_hide',
@@ -734,6 +736,7 @@ class acp_profile
'S_STEP_ONE' => true,
'S_FIELD_REQUIRED' => ($cp->vars['field_required']) ? true : false,
'S_SHOW_ON_REG' => ($cp->vars['field_show_on_reg']) ? true : false,
+ 'S_SHOW_ON_PM' => ($cp->vars['field_show_on_pm']) ? true : false,
'S_SHOW_ON_VT' => ($cp->vars['field_show_on_vt']) ? true : false,
'S_FIELD_HIDE' => ($cp->vars['field_hide']) ? true : false,
'S_SHOW_PROFILE' => ($cp->vars['field_show_profile']) ? true : false,
@@ -1050,6 +1053,7 @@ class acp_profile
'field_validation' => $cp->vars['field_validation'],
'field_required' => $cp->vars['field_required'],
'field_show_on_reg' => $cp->vars['field_show_on_reg'],
+ 'field_show_on_pm' => $cp->vars['field_show_on_pm'],
'field_show_on_vt' => $cp->vars['field_show_on_vt'],
'field_hide' => $cp->vars['field_hide'],
'field_show_profile' => $cp->vars['field_show_profile'],
diff --git a/phpBB/includes/acp/acp_send_statistics.php b/phpBB/includes/acp/acp_send_statistics.php
index aef67a8b1a..eb7154d114 100644
--- a/phpBB/includes/acp/acp_send_statistics.php
+++ b/phpBB/includes/acp/acp_send_statistics.php
@@ -16,8 +16,6 @@ if (!defined('IN_PHPBB'))
exit;
}
-include($phpbb_root_path . 'includes/questionnaire/questionnaire.' . $phpEx);
-
/**
* @package acp
*/
@@ -27,7 +25,9 @@ class acp_send_statistics
function main($id, $mode)
{
- global $config, $template, $phpbb_admin_path, $phpEx;
+ global $config, $template, $phpbb_admin_path, $phpbb_root_path, $phpEx;
+
+ include($phpbb_root_path . 'includes/questionnaire/questionnaire.' . $phpEx);
$collect_url = "http://www.phpbb.com/stats/receive_stats.php";
diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php
index 6a0d4c4c98..18a90fb8e8 100644
--- a/phpBB/includes/acp/acp_styles.php
+++ b/phpBB/includes/acp/acp_styles.php
@@ -45,7 +45,7 @@ class acp_styles
$bitfield->set(9);
$bitfield->set(11);
$bitfield->set(12);
- define('TEMPLATE_BITFIELD', $bitfield->get_base64());
+ $this->template_bitfield = $bitfield->get_base64();
unset($bitfield);
$user->add_lang('acp/styles');
@@ -510,6 +510,7 @@ parse_css_file = {PARSE_CSS_FILE}
$db->sql_transaction('commit');
$cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE);
+ $cache->destroy('imageset_site_logo_md5');
add_log('admin', 'LOG_IMAGESET_REFRESHED', $imageset_row['imageset_name']);
trigger_error($user->lang['IMAGESET_REFRESHED'] . adm_back_link($this->u_action));
@@ -3496,7 +3497,7 @@ parse_css_file = {PARSE_CSS_FILE}
}
else
{
- $sql_ary['bbcode_bitfield'] = TEMPLATE_BITFIELD;
+ $sql_ary['bbcode_bitfield'] = $this->template_bitfield;
}
// We set a pre-defined bitfield here which we may use further in 3.2
diff --git a/phpBB/includes/acp/acp_update.php b/phpBB/includes/acp/acp_update.php
index 41fb0884b7..f0365e8e66 100644
--- a/phpBB/includes/acp/acp_update.php
+++ b/phpBB/includes/acp/acp_update.php
@@ -69,12 +69,9 @@ class acp_update
$current_version = (!empty($version_update_from)) ? $version_update_from : $config['version'];
- $up_to_date_automatic = (version_compare(str_replace('rc', 'RC', strtolower($current_version)), str_replace('rc', 'RC', strtolower($latest_version)), '<')) ? false : true;
- $up_to_date = (version_compare(str_replace('rc', 'RC', strtolower($config['version'])), str_replace('rc', 'RC', strtolower($latest_version)), '<')) ? false : true;
-
$template->assign_vars(array(
- 'S_UP_TO_DATE' => $up_to_date,
- 'S_UP_TO_DATE_AUTO' => $up_to_date_automatic,
+ 'S_UP_TO_DATE' => phpbb_version_compare($latest_version, $config['version'], '<='),
+ 'S_UP_TO_DATE_AUTO' => phpbb_version_compare($latest_version, $current_version, '<='),
'S_VERSION_CHECK' => true,
'U_ACTION' => $this->u_action,
'U_VERSIONCHECK_FORCE' => append_sid($this->u_action . '&amp;versioncheck_force=1'),
diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php
index 006c3617f7..9bcf1b20db 100644
--- a/phpBB/includes/acp/acp_users.php
+++ b/phpBB/includes/acp/acp_users.php
@@ -1124,7 +1124,7 @@ class acp_users
// Grab log data
$log_data = array();
$log_count = 0;
- view_log('user', $log_data, $log_count, $config['topics_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort);
+ $start = view_log('user', $log_data, $log_count, $config['topics_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort);
$template->assign_vars(array(
'S_FEEDBACK' => true,
diff --git a/phpBB/includes/acp/info/acp_attachments.php b/phpBB/includes/acp/info/acp_attachments.php
index d5f57ece4e..4bcd7e2ea5 100644
--- a/phpBB/includes/acp/info/acp_attachments.php
+++ b/phpBB/includes/acp/info/acp_attachments.php
@@ -23,7 +23,8 @@ class acp_attachments_info
'attach' => array('title' => 'ACP_ATTACHMENT_SETTINGS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_BOARD_CONFIGURATION', 'ACP_ATTACHMENTS')),
'extensions' => array('title' => 'ACP_MANAGE_EXTENSIONS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')),
'ext_groups' => array('title' => 'ACP_EXTENSION_GROUPS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')),
- 'orphan' => array('title' => 'ACP_ORPHAN_ATTACHMENTS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS'))
+ 'orphan' => array('title' => 'ACP_ORPHAN_ATTACHMENTS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')),
+ 'manage' => array('title' => 'ACP_MANAGE_ATTACHMENTS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')),
),
);
}
diff --git a/phpBB/includes/auth.php b/phpBB/includes/auth.php
index 22aca5faf9..25f26e5334 100644
--- a/phpBB/includes/auth.php
+++ b/phpBB/includes/auth.php
@@ -349,6 +349,14 @@ class auth
/**
* Get permission listing based on user_id/options/forum_ids
+ *
+ * Be careful when using this function with permissions a_, m_, u_ and f_ !
+ * It may not work correctly. When a user group grants an a_* permission,
+ * e.g. a_foo, but the user's a_foo permission is set to "Never", then
+ * the user does not in fact have the a_ permission.
+ * But the user will still be listed as having the a_ permission.
+ *
+ * For more information see: http://tracker.phpbb.com/browse/PHPBB3-10252
*/
function acl_get_list($user_id = false, $opts = false, $forum_id = false)
{
@@ -908,7 +916,7 @@ class auth
$method = 'login_' . $method;
if (function_exists($method))
{
- $login = $method($username, $password);
+ $login = $method($username, $password, $user->ip, $user->browser, $user->forwarded_for);
// If the auth module wants us to create an empty profile do so and then treat the status as LOGIN_SUCCESS
if ($login['status'] == LOGIN_SUCCESS_CREATE_PROFILE)
diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php
index 6304d6e49a..b4ae1911cf 100644
--- a/phpBB/includes/auth/auth_db.php
+++ b/phpBB/includes/auth/auth_db.php
@@ -23,8 +23,21 @@ if (!defined('IN_PHPBB'))
/**
* Login function
+*
+* @param string $username
+* @param string $password
+* @param string $ip IP address the login is taking place from. Used to
+* limit the number of login attempts per IP address.
+* @param string $browser The user agent used to login
+* @param string $forwarded_for X_FORWARDED_FOR header sent with login request
+* @return array A associative array of the format
+* array(
+* 'status' => status constant
+* 'error_msg' => string
+* 'user_row' => array
+* )
*/
-function login_db(&$username, &$password)
+function login_db($username, $password, $ip = '', $browser = '', $forwarded_for = '')
{
global $db, $config;
global $request;
@@ -48,13 +61,51 @@ function login_db(&$username, &$password)
);
}
+ $username_clean = utf8_clean_string($username);
+
$sql = 'SELECT user_id, username, user_password, user_passchg, user_pass_convert, user_email, user_type, user_login_attempts
FROM ' . USERS_TABLE . "
- WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'";
+ WHERE username_clean = '" . $db->sql_escape($username_clean) . "'";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
+ if (($ip && !$config['ip_login_limit_use_forwarded']) ||
+ ($forwarded_for && $config['ip_login_limit_use_forwarded']))
+ {
+ $sql = 'SELECT COUNT(*) AS attempts
+ FROM ' . LOGIN_ATTEMPT_TABLE . '
+ WHERE attempt_time > ' . (time() - (int) $config['ip_login_limit_time']);
+ if ($config['ip_login_limit_use_forwarded'])
+ {
+ $sql .= " AND attempt_forwarded_for = '" . $db->sql_escape($forwarded_for) . "'";
+ }
+ else
+ {
+ $sql .= " AND attempt_ip = '" . $db->sql_escape($ip) . "' ";
+ }
+
+ $result = $db->sql_query($sql);
+ $attempts = (int) $db->sql_fetchfield('attempts');
+ $db->sql_freeresult($result);
+
+ $attempt_data = array(
+ 'attempt_ip' => $ip,
+ 'attempt_browser' => trim(substr($browser, 0, 149)),
+ 'attempt_forwarded_for' => $forwarded_for,
+ 'attempt_time' => time(),
+ 'user_id' => ($row) ? (int) $row['user_id'] : 0,
+ 'username' => $username,
+ 'username_clean' => $username_clean,
+ );
+ $sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $db->sql_build_array('INSERT', $attempt_data);
+ $result = $db->sql_query($sql);
+ }
+ else
+ {
+ $attempts = 0;
+ }
+
if (!$row)
{
return array(
@@ -63,7 +114,9 @@ function login_db(&$username, &$password)
'user_row' => array('user_id' => ANONYMOUS),
);
}
- $show_captcha = $config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts'];
+
+ $show_captcha = ($config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts']) ||
+ ($config['ip_login_limit_max'] && $attempts >= $config['ip_login_limit_max']);
// If there are too much login attempts, we need to check for an confirm image
// Every auth module is able to define what to do by itself...
@@ -177,6 +230,10 @@ function login_db(&$username, &$password)
$row['user_password'] = $hash;
}
+ $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . '
+ WHERE user_id = ' . $row['user_id'];
+ $db->sql_query($sql);
+
if ($row['user_login_attempts'] != 0)
{
// Successful, reset login attempts (the user passed all stages)
diff --git a/phpBB/includes/auth/auth_ldap.php b/phpBB/includes/auth/auth_ldap.php
index 4f311797b2..66facd0faa 100644
--- a/phpBB/includes/auth/auth_ldap.php
+++ b/phpBB/includes/auth/auth_ldap.php
@@ -335,7 +335,7 @@ function acp_ldap(&$new)
</dl>
<dl>
<dt><label for="ldap_password">' . $user->lang['LDAP_PASSWORD'] . ':</label><br /><span>' . $user->lang['LDAP_PASSWORD_EXPLAIN'] . '</span></dt>
- <dd><input type="password" id="ldap_password" size="40" name="config[ldap_password]" value="' . $new['ldap_password'] . '" /></dd>
+ <dd><input type="password" id="ldap_password" size="40" name="config[ldap_password]" value="' . $new['ldap_password'] . '" autocomplete="off" /></dd>
</dl>
';
diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php
index eeac98d3f3..c3367fbd46 100644
--- a/phpBB/includes/bbcode.php
+++ b/phpBB/includes/bbcode.php
@@ -572,6 +572,13 @@ class bbcode
$code = str_replace("\t", '&nbsp; &nbsp;', $code);
$code = str_replace(' ', '&nbsp; ', $code);
$code = str_replace(' ', ' &nbsp;', $code);
+ $code = str_replace("\n ", "\n&nbsp;", $code);
+
+ // keep space at the beginning
+ if (!empty($code) && $code[0] == ' ')
+ {
+ $code = '&nbsp;' . substr($code, 1);
+ }
// remove newline at the beginning
if (!empty($code) && $code[0] == "\n")
diff --git a/phpBB/includes/cache/driver/redis.php b/phpBB/includes/cache/driver/redis.php
index f0997c3cad..6362938a9e 100755
--- a/phpBB/includes/cache/driver/redis.php
+++ b/phpBB/includes/cache/driver/redis.php
@@ -25,12 +25,6 @@ if (!defined('PHPBB_ACM_REDIS_HOST'))
define('PHPBB_ACM_REDIS_HOST', 'localhost');
}
-if (!defined('PHPBB_ACM_REDIS'))
-{
- //can define multiple servers with host1/port1,host2/port2 format
- define('PHPBB_ACM_REDIS', PHPBB_ACM_REDIS_HOST . '/' . PHPBB_ACM_REDIS_PORT);
-}
-
/**
* ACM for Redis
*
@@ -51,12 +45,8 @@ class phpbb_cache_driver_redis extends phpbb_cache_driver_memory
parent::__construct();
$this->redis = new Redis();
- foreach (explode(',', PHPBB_ACM_REDIS) as $server)
- {
- $parts = explode('/', $server);
- $this->redis->connect(trim($parts[0]), trim($parts[1]));
- }
-
+ $this->redis->connect(PHPBB_ACM_REDIS_HOST, PHPBB_ACM_REDIS_PORT);
+
if (defined('PHPBB_ACM_REDIS_PASSWORD'))
{
if (!$this->redis->auth(PHPBB_ACM_REDIS_PASSWORD))
diff --git a/phpBB/includes/cache/service.php b/phpBB/includes/cache/service.php
index 68026c8647..0c01953d55 100644
--- a/phpBB/includes/cache/service.php
+++ b/phpBB/includes/cache/service.php
@@ -194,6 +194,7 @@ class phpbb_cache_service
'max_filesize' => (int) $row['max_filesize'],
'allow_group' => $row['allow_group'],
'allow_in_pm' => $row['allow_in_pm'],
+ 'group_name' => $row['group_name'],
);
$allowed_forums = ($row['allowed_forums']) ? unserialize(trim($row['allowed_forums'])) : array();
diff --git a/phpBB/includes/captcha/captcha_gd.php b/phpBB/includes/captcha/captcha_gd.php
index 15f34aa58f..5e61d6a47b 100644
--- a/phpBB/includes/captcha/captcha_gd.php
+++ b/phpBB/includes/captcha/captcha_gd.php
@@ -77,7 +77,7 @@ class captcha
{
$denom = ($code_len - $i);
$denom = max(1.3, $denom);
- $offset[$i] = mt_rand(0, (1.5 * $width_avail) / $denom);
+ $offset[$i] = phpbb_mt_rand(0, (int) round((1.5 * $width_avail) / $denom));
$width_avail -= $offset[$i];
}
diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php
index 75fef25a9f..3bc727da41 100644
--- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php
+++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php
@@ -319,7 +319,7 @@ class phpbb_captcha_qa
),
'PRIMARY_KEY' => 'question_id',
'KEYS' => array(
- 'lang_iso' => array('INDEX', 'lang_iso'),
+ 'lang' => array('INDEX', 'lang_iso'),
),
),
CAPTCHA_ANSWERS_TABLE => array (
@@ -328,7 +328,7 @@ class phpbb_captcha_qa
'answer_text' => array('STEXT_UNI', ''),
),
'KEYS' => array(
- 'question_id' => array('INDEX', 'question_id'),
+ 'qid' => array('INDEX', 'question_id'),
),
),
CAPTCHA_QA_CONFIRM_TABLE => array (
diff --git a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php
index 12e3536893..c0db41d5a5 100644
--- a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php
+++ b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php
@@ -27,9 +27,14 @@ if (!class_exists('phpbb_default_captcha', false))
*/
class phpbb_recaptcha extends phpbb_default_captcha
{
- var $recaptcha_server = 'http://api.recaptcha.net';
- var $recaptcha_server_secure = 'https://api-secure.recaptcha.net'; // class constants :(
- var $recaptcha_verify_server = 'api-verify.recaptcha.net';
+ var $recaptcha_server = 'http://www.google.com/recaptcha/api';
+ var $recaptcha_server_secure = 'https://www.google.com/recaptcha/api'; // class constants :(
+
+ // We are opening a socket to port 80 of this host and send
+ // the POST request asking for verification to the path specified here.
+ var $recaptcha_verify_server = 'www.google.com';
+ var $recaptcha_verify_path = '/recaptcha/api/verify';
+
var $challenge;
var $response;
@@ -296,7 +301,7 @@ class phpbb_recaptcha extends phpbb_default_captcha
return $user->lang['RECAPTCHA_INCORRECT'];
}
- $response = $this->_recaptcha_http_post($this->recaptcha_verify_server, '/verify',
+ $response = $this->_recaptcha_http_post($this->recaptcha_verify_server, $this->recaptcha_verify_path,
array(
'privatekey' => $config['recaptcha_privkey'],
'remoteip' => $user->ip,
diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php
index 216aac7489..8ef1a4655d 100644
--- a/phpBB/includes/constants.php
+++ b/phpBB/includes/constants.php
@@ -236,6 +236,7 @@ define('GROUPS_TABLE', $table_prefix . 'groups');
define('ICONS_TABLE', $table_prefix . 'icons');
define('LANG_TABLE', $table_prefix . 'lang');
define('LOG_TABLE', $table_prefix . 'log');
+define('LOGIN_ATTEMPT_TABLE', $table_prefix . 'login_attempts');
define('MODERATOR_CACHE_TABLE', $table_prefix . 'moderator_cache');
define('MODULES_TABLE', $table_prefix . 'modules');
define('POLL_OPTIONS_TABLE', $table_prefix . 'poll_options');
diff --git a/phpBB/includes/cron/manager.php b/phpBB/includes/cron/manager.php
index 21dcb91695..31be1a69cb 100644
--- a/phpBB/includes/cron/manager.php
+++ b/phpBB/includes/cron/manager.php
@@ -73,6 +73,14 @@ class phpbb_cron_manager
*/
public function __construct($task_path, $phpEx, phpbb_cache_driver_interface $cache = null)
{
+ if (DIRECTORY_SEPARATOR != '/')
+ {
+ // Need this on some platforms since the code elsewhere uses /
+ // to separate directory components, but PHP iterators return
+ // paths with platform-specific directory separators.
+ $task_path = str_replace('/', DIRECTORY_SEPARATOR, $task_path);
+ }
+
$this->task_path = $task_path;
$this->phpEx = $phpEx;
$this->cache = $cache;
@@ -116,9 +124,9 @@ class phpbb_cron_manager
$file = preg_replace('#^' . preg_quote($this->task_path, '#') . '#', '', $fileinfo->getPathname());
// skip directories and files direclty in the task root path
- if ($fileinfo->isFile() && strpos($file, '/') !== false)
+ if ($fileinfo->isFile() && strpos($file, DIRECTORY_SEPARATOR) !== false)
{
- $task_name = str_replace('/', '_', substr($file, 0, -$ext_length));
+ $task_name = str_replace(DIRECTORY_SEPARATOR, '_', substr($file, 0, -$ext_length));
if (substr($file, -$ext_length) == $ext && $this->is_valid_name($task_name))
{
$task_names[] = 'phpbb_cron_task_' . $task_name;
diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php
index 88bbd614e6..7c96965a9b 100644
--- a/phpBB/includes/db/db_tools.php
+++ b/phpBB/includes/db/db_tools.php
@@ -417,6 +417,11 @@ class phpbb_db_tools
// here lies an array, filled with information compiled on the column's data
$prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
+ if (isset($prepared_column['auto_increment']) && strlen($column_name) > 26) // "${column_name}_gen"
+ {
+ trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR);
+ }
+
// here we add the definition of the new column to the list of columns
switch ($this->sql_layer)
{
@@ -538,7 +543,7 @@ class phpbb_db_tools
break;
case 'oracle':
- $table_sql .= "\n);";
+ $table_sql .= "\n)";
$statements[] = $table_sql;
// do we need to add a sequence and a tigger for auto incrementing columns?
@@ -556,7 +561,7 @@ class phpbb_db_tools
$trigger .= "BEGIN\n";
$trigger .= "\tSELECT {$table_name}_seq.nextval\n";
$trigger .= "\tINTO :new.{$create_sequence}\n";
- $trigger .= "\tFROM dual\n";
+ $trigger .= "\tFROM dual;\n";
$trigger .= "END;";
$statements[] = $trigger;
@@ -566,7 +571,13 @@ class phpbb_db_tools
case 'firebird':
if ($create_sequence)
{
- $statements[] = "CREATE SEQUENCE {$table_name}_seq;";
+ $statements[] = "CREATE GENERATOR {$table_name}_gen;";
+ $statements[] = "SET GENERATOR {$table_name}_gen TO 0;";
+
+ $trigger = "CREATE TRIGGER t_$table_name FOR $table_name\n";
+ $trigger .= "BEFORE INSERT\nAS\nBEGIN\n";
+ $trigger .= "\tNEW.{$create_sequence} = GEN_ID({$table_name}_gen, 1);\nEND;";
+ $statements[] = $trigger;
}
break;
}
@@ -638,6 +649,19 @@ class phpbb_db_tools
$sqlite = true;
}
+ // Add tables?
+ if (!empty($schema_changes['add_tables']))
+ {
+ foreach ($schema_changes['add_tables'] as $table => $table_data)
+ {
+ $result = $this->sql_create_table($table, $table_data);
+ if ($this->return_statements)
+ {
+ $statements = array_merge($statements, $result);
+ }
+ }
+ }
+
// Change columns?
if (!empty($schema_changes['change_columns']))
{
@@ -681,10 +705,12 @@ class phpbb_db_tools
{
foreach ($columns as $column_name => $column_data)
{
- // Only add the column if it does not exist yet, else change it (to be consistent)
+ // Only add the column if it does not exist yet
if ($column_exists = $this->sql_column_exists($table, $column_name))
{
- $result = $this->sql_column_change($table, $column_name, $column_data, true);
+ continue;
+ // This is commented out here because it can take tremendous time on updates
+// $result = $this->sql_column_change($table, $column_name, $column_data, true);
}
else
{
@@ -695,7 +721,8 @@ class phpbb_db_tools
{
if ($column_exists)
{
- $sqlite_data[$table]['change_columns'][] = $result;
+ continue;
+// $sqlite_data[$table]['change_columns'][] = $result;
}
else
{
@@ -717,6 +744,11 @@ class phpbb_db_tools
{
foreach ($indexes as $index_name)
{
+ if (!$this->sql_index_exists($table, $index_name))
+ {
+ continue;
+ }
+
$result = $this->sql_index_drop($table, $index_name);
if ($this->return_statements)
@@ -777,6 +809,11 @@ class phpbb_db_tools
{
foreach ($index_array as $index_name => $column)
{
+ if ($this->sql_unique_index_exists($table, $index_name))
+ {
+ continue;
+ }
+
$result = $this->sql_create_unique_index($table, $index_name, $column);
if ($this->return_statements)
@@ -794,6 +831,11 @@ class phpbb_db_tools
{
foreach ($index_array as $index_name => $column)
{
+ if ($this->sql_index_exists($table, $index_name))
+ {
+ continue;
+ }
+
$result = $this->sql_create_index($table, $index_name, $column);
if ($this->return_statements)
@@ -1103,6 +1145,236 @@ class phpbb_db_tools
}
/**
+ * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes.
+ *
+ * @param string $table_name Table to check the index at
+ * @param string $index_name The index name to check
+ *
+ * @return bool True if index exists, else false
+ */
+ function sql_index_exists($table_name, $index_name)
+ {
+ if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative')
+ {
+ $sql = "EXEC sp_statistics '$table_name'";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if ($row['TYPE'] == 3)
+ {
+ if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
+ {
+ $this->db->sql_freeresult($result);
+ return true;
+ }
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return false;
+ }
+
+ switch ($this->sql_layer)
+ {
+ case 'firebird':
+ $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name
+ FROM RDB\$INDICES
+ WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "'
+ AND RDB\$UNIQUE_FLAG IS NULL
+ AND RDB\$FOREIGN_KEY IS NULL";
+ $col = 'index_name';
+ break;
+
+ case 'postgres':
+ $sql = "SELECT ic.relname as index_name
+ FROM pg_class bc, pg_class ic, pg_index i
+ WHERE (bc.oid = i.indrelid)
+ AND (ic.oid = i.indexrelid)
+ AND (bc.relname = '" . $table_name . "')
+ AND (i.indisunique != 't')
+ AND (i.indisprimary != 't')";
+ $col = 'index_name';
+ break;
+
+ case 'mysql_40':
+ case 'mysql_41':
+ $sql = 'SHOW KEYS
+ FROM ' . $table_name;
+ $col = 'Key_name';
+ break;
+
+ case 'oracle':
+ $sql = "SELECT index_name
+ FROM user_indexes
+ WHERE table_name = '" . strtoupper($table_name) . "'
+ AND generated = 'N'
+ AND uniqueness = 'NONUNIQUE'";
+ $col = 'index_name';
+ break;
+
+ case 'sqlite':
+ $sql = "PRAGMA index_list('" . $table_name . "');";
+ $col = 'name';
+ break;
+ }
+
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique'])
+ {
+ continue;
+ }
+
+ // These DBMS prefix index name with the table name
+ switch ($this->sql_layer)
+ {
+ case 'firebird':
+ case 'oracle':
+ case 'postgres':
+ case 'sqlite':
+ $row[$col] = substr($row[$col], strlen($table_name) + 1);
+ break;
+ }
+
+ if (strtolower($row[$col]) == strtolower($index_name))
+ {
+ $this->db->sql_freeresult($result);
+ return true;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return false;
+ }
+
+ /**
+ * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes.
+ *
+ * @param string $table_name Table to check the index at
+ * @param string $index_name The index name to check
+ *
+ * @return bool True if index exists, else false
+ */
+ function sql_unique_index_exists($table_name, $index_name)
+ {
+ if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative')
+ {
+ $sql = "EXEC sp_statistics '$table_name'";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ // Usually NON_UNIQUE is the column we want to check, but we allow for both
+ if ($row['TYPE'] == 3)
+ {
+ if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
+ {
+ $this->db->sql_freeresult($result);
+ return true;
+ }
+ }
+ }
+ $this->db->sql_freeresult($result);
+ return false;
+ }
+
+ switch ($this->sql_layer)
+ {
+ case 'firebird':
+ $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name
+ FROM RDB\$INDICES
+ WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "'
+ AND RDB\$UNIQUE_FLAG IS NOT NULL
+ AND RDB\$FOREIGN_KEY IS NULL";
+ $col = 'index_name';
+ break;
+
+ case 'postgres':
+ $sql = "SELECT ic.relname as index_name, i.indisunique
+ FROM pg_class bc, pg_class ic, pg_index i
+ WHERE (bc.oid = i.indrelid)
+ AND (ic.oid = i.indexrelid)
+ AND (bc.relname = '" . $table_name . "')
+ AND (i.indisprimary != 't')";
+ $col = 'index_name';
+ break;
+
+ case 'mysql_40':
+ case 'mysql_41':
+ $sql = 'SHOW KEYS
+ FROM ' . $table_name;
+ $col = 'Key_name';
+ break;
+
+ case 'oracle':
+ $sql = "SELECT index_name, table_owner
+ FROM user_indexes
+ WHERE table_name = '" . strtoupper($table_name) . "'
+ AND generated = 'N'
+ AND uniqueness = 'UNIQUE'";
+ $col = 'index_name';
+ break;
+
+ case 'sqlite':
+ $sql = "PRAGMA index_list('" . $table_name . "');";
+ $col = 'name';
+ break;
+ }
+
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && ($row['Non_unique'] || $row[$col] == 'PRIMARY'))
+ {
+ continue;
+ }
+
+ if ($this->sql_layer == 'sqlite' && !$row['unique'])
+ {
+ continue;
+ }
+
+ if ($this->sql_layer == 'postgres' && $row['indisunique'] != 't')
+ {
+ continue;
+ }
+
+ // These DBMS prefix index name with the table name
+ switch ($this->sql_layer)
+ {
+ case 'oracle':
+ // Two cases here... prefixed with U_[table_owner] and not prefixed with table_name
+ if (strpos($row[$col], 'U_') === 0)
+ {
+ $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1);
+ }
+ else if (strpos($row[$col], strtoupper($table_name)) === 0)
+ {
+ $row[$col] = substr($row[$col], strlen($table_name) + 1);
+ }
+ break;
+
+ case 'firebird':
+ case 'postgres':
+ case 'sqlite':
+ $row[$col] = substr($row[$col], strlen($table_name) + 1);
+ break;
+ }
+
+ if (strtolower($row[$col]) == strtolower($index_name))
+ {
+ $this->db->sql_freeresult($result);
+ return true;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return false;
+ }
+
+ /**
* Private method for performing sql statements (either execute them or return them)
* @access private
*/
@@ -1139,6 +1411,11 @@ class phpbb_db_tools
*/
function sql_prepare_column_data($table_name, $column_name, $column_data)
{
+ if (strlen($column_name) > 30)
+ {
+ trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR);
+ }
+
// Get type
if (strpos($column_data[0], ':') !== false)
{
@@ -1371,24 +1648,29 @@ class phpbb_db_tools
switch ($this->sql_layer)
{
case 'firebird':
+ // Does not support AFTER statement, only POSITION (and there you need the column position)
$statements[] = 'ALTER TABLE ' . $table_name . ' ADD "' . strtoupper($column_name) . '" ' . $column_data['column_type_sql'];
break;
case 'mssql':
case 'mssqlnative':
+ // Does not support AFTER, only through temporary table
$statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default'];
break;
case 'mysql_40':
case 'mysql_41':
- $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'];
+ $after = (!empty($column_data['after'])) ? ' AFTER ' . $column_data['after'] : '';
+ $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'] . $after;
break;
case 'oracle':
+ // Does not support AFTER, only through temporary table
$statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql'];
break;
case 'postgres':
+ // Does not support AFTER, only through temporary table
if (version_compare($this->db->sql_server_info(true), '8.0', '>='))
{
$statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql'];
@@ -1774,6 +2056,13 @@ class phpbb_db_tools
{
$statements = array();
+ $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config)
+ if (strlen($table_name . $index_name) - strlen($table_prefix) > 24)
+ {
+ $max_length = strlen($table_prefix) + 24;
+ trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR);
+ }
+
switch ($this->sql_layer)
{
case 'firebird':
@@ -1804,6 +2093,13 @@ class phpbb_db_tools
{
$statements = array();
+ $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config)
+ if (strlen($table_name . $index_name) - strlen($table_prefix) > 24)
+ {
+ $max_length = strlen($table_prefix) + 24;
+ trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR);
+ }
+
// remove index length unless MySQL4
if ('mysql_40' != $this->sql_layer)
{
@@ -1957,6 +2253,7 @@ class phpbb_db_tools
}
else
{
+ // TODO: try to change pkey without removing trigger, generator or constraints. ATM this query may fail.
$statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql_type'];
}
break;
diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php
index 148f56b5a8..a61dc5f58a 100644
--- a/phpBB/includes/db/dbal.php
+++ b/phpBB/includes/db/dbal.php
@@ -246,7 +246,7 @@ class dbal
*
* @return bool Whether buffering is required.
*/
- function sql_buffer_nested_transaction()
+ function sql_buffer_nested_transactions()
{
return false;
}
@@ -767,12 +767,10 @@ class dbal
$mtime = explode(' ', microtime());
$totaltime = $mtime[0] + $mtime[1] - $starttime;
- echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
+ echo '<!DOCTYPE html>
+ <html dir="ltr">
<head>
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
- <meta http-equiv="Content-Style-Type" content="text/css" />
- <meta http-equiv="imagetoolbar" content="no" />
+ <meta charset="utf-8">
<title>SQL Report</title>
<link href="' . $phpbb_root_path . 'adm/style/admin.css" rel="stylesheet" type="text/css" media="screen" />
</head>
@@ -800,7 +798,7 @@ class dbal
</div>
</div>
<div id="page-footer">
- Powered by <a href="http://www.phpbb.com/">phpBB</a> &copy; phpBB Group
+ Powered by <a href="http://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Group
</div>
</div>
</body>
diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/firebird.php
index 8868d4e317..8acc84b1c0 100644
--- a/phpBB/includes/db/firebird.php
+++ b/phpBB/includes/db/firebird.php
@@ -497,7 +497,8 @@ class dbal_firebird extends dbal
*/
function cast_expr_to_bigint($expression)
{
- return 'CAST(' . $expression . ' as DECIMAL(255, 0))';
+ // Precision must be from 1 to 18
+ return 'CAST(' . $expression . ' as DECIMAL(18, 0))';
}
/**
diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php
index 710a054e5f..2287bc716e 100644
--- a/phpBB/includes/db/mssqlnative.php
+++ b/phpBB/includes/db/mssqlnative.php
@@ -261,7 +261,7 @@ class dbal_mssqlnative extends dbal
/**
* {@inheritDoc}
*/
- function sql_buffer_nested_transaction()
+ function sql_buffer_nested_transactions()
{
return true;
}
diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php
index 7c72fe9f01..db3846e7f7 100644
--- a/phpBB/includes/db/mysqli.php
+++ b/phpBB/includes/db/mysqli.php
@@ -33,14 +33,33 @@ class dbal_mysqli extends dbal
*/
function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false , $new_link = false)
{
- $this->persistency = $persistency;
+ // Mysqli extension supports persistent connection since PHP 5.3.0
+ $this->persistency = (version_compare(PHP_VERSION, '5.3.0', '>=')) ? $persistency : false;
$this->user = $sqluser;
- $this->server = $sqlserver;
+
+ // If persistent connection, set dbhost to localhost when empty and prepend it with 'p:' prefix
+ $this->server = ($this->persistency) ? 'p:' . (($sqlserver) ? $sqlserver : 'localhost') : $sqlserver;
+
$this->dbname = $database;
$port = (!$port) ? NULL : $port;
- // Persistant connections not supported by the mysqli extension?
- $this->db_connect_id = @mysqli_connect($this->server, $this->user, $sqlpassword, $this->dbname, $port);
+ // If port is set and it is not numeric, most likely mysqli socket is set.
+ // Try to map it to the $socket parameter.
+ $socket = NULL;
+ if ($port)
+ {
+ if (is_numeric($port))
+ {
+ $port = (int) $port;
+ }
+ else
+ {
+ $socket = $port;
+ $port = NULL;
+ }
+ }
+
+ $this->db_connect_id = @mysqli_connect($this->server, $this->user, $sqlpassword, $this->dbname, $port, $socket);
if ($this->db_connect_id && $this->dbname != '')
{
diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php
index e4727b9705..9d27a24c92 100644
--- a/phpBB/includes/functions.php
+++ b/phpBB/includes/functions.php
@@ -191,6 +191,43 @@ function unique_id($extra = 'c')
}
/**
+* Wrapper for mt_rand() which allows swapping $min and $max parameters.
+*
+* PHP does not allow us to swap the order of the arguments for mt_rand() anymore.
+* (since PHP 5.3.4, see http://bugs.php.net/46587)
+*
+* @param int $min Lowest value to be returned
+* @param int $max Highest value to be returned
+*
+* @return int Random integer between $min and $max (or $max and $min)
+*/
+function phpbb_mt_rand($min, $max)
+{
+ return ($min > $max) ? mt_rand($max, $min) : mt_rand($min, $max);
+}
+
+/**
+* Wrapper for getdate() which returns the equivalent array for UTC timestamps.
+*
+* @param int $time Unix timestamp (optional)
+*
+* @return array Returns an associative array of information related to the timestamp.
+* See http://www.php.net/manual/en/function.getdate.php
+*/
+function phpbb_gmgetdate($time = false)
+{
+ if ($time === false)
+ {
+ $time = time();
+ }
+
+ // getdate() interprets timestamps in local time.
+ // What follows uses the fact that getdate() and
+ // date('Z') balance each other out.
+ return getdate($time - date('Z'));
+}
+
+/**
* Return formatted string for filesizes
*
* @param int $value filesize in bytes
@@ -512,6 +549,34 @@ function phpbb_email_hash($email)
}
/**
+* Wrapper for version_compare() that allows using uppercase A and B
+* for alpha and beta releases.
+*
+* See http://www.php.net/manual/en/function.version-compare.php
+*
+* @param string $version1 First version number
+* @param string $version2 Second version number
+* @param string $operator Comparison operator (optional)
+*
+* @return mixed Boolean (true, false) if comparison operator is specified.
+* Integer (-1, 0, 1) otherwise.
+*/
+function phpbb_version_compare($version1, $version2, $operator = null)
+{
+ $version1 = strtolower($version1);
+ $version2 = strtolower($version2);
+
+ if (is_null($operator))
+ {
+ return version_compare($version1, $version2);
+ }
+ else
+ {
+ return version_compare($version1, $version2, $operator);
+ }
+}
+
+/**
* Global function for chmodding directories and files for internal use
*
* This function determines owner and group whom the file belongs to and user and group of PHP and then set safest possible file permissions.
@@ -2025,7 +2090,10 @@ function append_sid($url, $params = false, $is_amp = true, $session_id = false)
/**
* Generate board url (example: http://www.example.com/phpBB)
+*
* @param bool $without_script_path if set to true the script path gets not appended (example: http://www.example.com)
+*
+* @return string the generated board url
*/
function generate_board_url($without_script_path = false)
{
@@ -2229,10 +2297,10 @@ function redirect($url, $return = false, $disable_cd_check = false)
{
header('Refresh: 0; URL=' . $url);
- echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
- echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="' . $user->lang['DIRECTION'] . '" lang="' . $user->lang['USER_LANG'] . '" xml:lang="' . $user->lang['USER_LANG'] . '">';
+ echo '<!DOCTYPE html>';
+ echo '<html dir="' . $user->lang['DIRECTION'] . '" lang="' . $user->lang['USER_LANG'] . '">';
echo '<head>';
- echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />';
+ echo '<meta charset="utf-8">';
echo '<meta http-equiv="refresh" content="0; url=' . str_replace('&', '&amp;', $url) . '" />';
echo '<title>' . $user->lang['REDIRECT'] . '</title>';
echo '</head>';
@@ -2411,12 +2479,6 @@ function send_status_line($code, $message)
{
$version = $_SERVER['SERVER_PROTOCOL'];
}
- else if (!empty($_SERVER['HTTP_VERSION']))
- {
- // I cannot remember where I got this from.
- // This code path may never be reachable in reality.
- $version = $_SERVER['HTTP_VERSION'];
- }
else
{
$version = 'HTTP/1.0';
@@ -3605,10 +3667,19 @@ function phpbb_checkdnsrr($host, $type = 'MX')
{
return true;
}
+ break;
default:
- case 'A':
case 'AAAA':
+ // AAAA records returned by nslookup on Windows XP/2003 have this format.
+ // Later Windows versions use the A record format below for AAAA records.
+ if (stripos($line, "$host AAAA IPv6 address") === 0)
+ {
+ return true;
+ }
+ // No break
+
+ case 'A':
if (!empty($host_matches))
{
// Second line
@@ -3677,25 +3748,11 @@ function msg_handler($errno, $msg_text, $errfile, $errline)
if (strpos($errfile, 'cache') === false && strpos($errfile, 'template.') === false)
{
- // flush the content, else we get a white page if output buffering is on
- if ((int) @ini_get('output_buffering') === 1 || strtolower(@ini_get('output_buffering')) === 'on')
- {
- @ob_flush();
- }
-
- // Another quick fix for those having gzip compression enabled, but do not flush if the coder wants to catch "something". ;)
- if (!empty($config['gzip_compress']))
- {
- if (@extension_loaded('zlib') && !headers_sent() && !ob_get_level())
- {
- @ob_flush();
- }
- }
-
// remove complete path to installation, with the risk of changing backslashes meant to be there
$errfile = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $errfile);
$msg_text = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $msg_text);
- echo '<b>[phpBB Debug] PHP Notice</b>: in file <b>' . $errfile . '</b> on line <b>' . $errline . '</b>: <b>' . $msg_text . '</b><br />' . "\n";
+ $error_name = ($errno === E_WARNING) ? 'PHP Warning' : 'PHP Notice';
+ echo '<b>[phpBB Debug] ' . $error_name . '</b>: in file <b>' . $errfile . '</b> on line <b>' . $errline . '</b>: <b>' . $msg_text . '</b><br />' . "\n";
// we are writing an image - the user won't see the debug, so let's place it in the log
if (defined('IMAGE_OUTPUT') || defined('IN_CRON'))
@@ -3751,10 +3808,10 @@ function msg_handler($errno, $msg_text, $errfile, $errline)
// Try to not call the adm page data...
- echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
- echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">';
+ echo '<!DOCTYPE html>';
+ echo '<html dir="ltr">';
echo '<head>';
- echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />';
+ echo '<meta charset="utf-8">';
echo '<title>' . $msg_title . '</title>';
echo '<style type="text/css">' . "\n" . '/* <![CDATA[ */' . "\n";
echo '* { margin: 0; padding: 0; } html { font-size: 100%; height: 100%; margin-bottom: 1px; background-color: #E4EDF0; } body { font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; color: #536482; background: #E4EDF0; font-size: 62.5%; margin: 0; } ';
@@ -3784,7 +3841,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> &copy; phpBB Group';
+ echo ' Powered by <a href="http://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Group';
echo ' </div>';
echo '</div>';
echo '</body>';
@@ -4250,7 +4307,21 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
// gzip_compression
if ($config['gzip_compress'])
{
- if (@extension_loaded('zlib') && !headers_sent())
+ // to avoid partially compressed output resulting in blank pages in
+ // the browser or error messages, compression is disabled in a few cases:
+ //
+ // 1) if headers have already been sent, this indicates plaintext output
+ // has been started so further content must not be compressed
+ // 2) the length of the current output buffer is non-zero. This means
+ // there is already some uncompressed content in this output buffer
+ // so further output must not be compressed
+ // 3) if more than one level of output buffering is used because we
+ // cannot test all output buffer level content lengths. One level
+ // could be caused by php.ini output_buffering. Anything
+ // beyond that is manual, so the code wrapping phpBB in output buffering
+ // can easily compress the output itself.
+ //
+ if (@extension_loaded('zlib') && !headers_sent() && ob_get_level() <= 1 && ob_get_length() == 0)
{
ob_start('ob_gzhandler');
}
@@ -4371,6 +4442,12 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
$user_lang = substr($user_lang, 0, strpos($user_lang, '-x-'));
}
+ $s_search_hidden_fields = array();
+ if ($_SID)
+ {
+ $s_search_hidden_fields['sid'] = $_SID;
+ }
+
// The following assigns all _common_ variables that may be used at any point in a template.
$template->assign_vars(array(
'SITENAME' => $config['sitename'],
@@ -4460,11 +4537,13 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
'S_LOAD_UNREADS' => ($config['load_unreads_search'] && ($config['load_anon_lastread'] || $user->data['is_registered'])) ? true : false,
+ 'S_SEARCH_HIDDEN_FIELDS' => build_hidden_fields($s_search_hidden_fields),
+
'T_THEME_PATH' => "{$web_path}styles/" . $user->theme['theme_path'] . '/theme',
'T_TEMPLATE_PATH' => "{$web_path}styles/" . $user->theme['template_path'] . '/template',
'T_SUPER_TEMPLATE_PATH' => (isset($user->theme['template_inherit_path']) && $user->theme['template_inherit_path']) ? "{$web_path}styles/" . $user->theme['template_inherit_path'] . '/template' : "{$web_path}styles/" . $user->theme['template_path'] . '/template',
'T_IMAGESET_PATH' => "{$web_path}styles/" . $user->theme['imageset_path'] . '/imageset',
- 'T_IMAGESET_LANG_PATH' => "{$web_path}styles/" . $user->theme['imageset_path'] . '/imageset/' . $user->data['user_lang'],
+ 'T_IMAGESET_LANG_PATH' => "{$web_path}styles/" . $user->theme['imageset_path'] . '/imageset/' . $user->lang_name,
'T_IMAGES_PATH' => "{$web_path}images/",
'T_SMILIES_PATH' => "{$web_path}{$config['smilies_path']}/",
'T_AVATAR_PATH' => "{$web_path}{$config['avatar_path']}/",
@@ -4472,7 +4551,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
'T_ICONS_PATH' => "{$web_path}{$config['icons_path']}/",
'T_RANKS_PATH' => "{$web_path}{$config['ranks_path']}/",
'T_UPLOAD_PATH' => "{$web_path}{$config['upload_path']}/",
- 'T_STYLESHEET_LINK' => (!$user->theme['theme_storedb']) ? "{$web_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : append_sid("{$phpbb_root_path}style.$phpEx", 'id=' . $user->theme['style_id'] . '&amp;lang=' . $user->data['user_lang']),
+ 'T_STYLESHEET_LINK' => (!$user->theme['theme_storedb']) ? "{$web_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : append_sid("{$phpbb_root_path}style.$phpEx", 'id=' . $user->theme['style_id'] . '&amp;lang=' . $user->lang_name),
'T_STYLESHEET_NAME' => $user->theme['theme_name'],
'T_THEME_NAME' => $user->theme['theme_path'],
@@ -4628,7 +4707,7 @@ function exit_handler()
}
// As a pre-caution... some setups display a blank page if the flush() is not there.
- (empty($config['gzip_compress'])) ? @flush() : @ob_flush();
+ (ob_get_level() > 0) ? @ob_flush() : @flush();
exit;
}
diff --git a/phpBB/includes/functions_acp.php b/phpBB/includes/functions_acp.php
index f28bca91ee..c3806dc786 100644
--- a/phpBB/includes/functions_acp.php
+++ b/phpBB/includes/functions_acp.php
@@ -164,7 +164,7 @@ function build_select($option_ary, $option_default = false)
/**
* Build radio fields in acp pages
*/
-function h_radio($name, &$input_ary, $input_default = false, $id = false, $key = false)
+function h_radio($name, $input_ary, $input_default = false, $id = false, $key = false, $separator = '')
{
global $user;
@@ -173,7 +173,7 @@ function h_radio($name, &$input_ary, $input_default = false, $id = false, $key =
foreach ($input_ary as $value => $title)
{
$selected = ($input_default !== false && $value == $input_default) ? ' checked="checked"' : '';
- $html .= '<label><input type="radio" name="' . $name . '"' . (($id && !$id_assigned) ? ' id="' . $id . '"' : '') . ' value="' . $value . '"' . $selected . (($key) ? ' accesskey="' . $key . '"' : '') . ' class="radio" /> ' . $user->lang[$title] . '</label>';
+ $html .= '<label><input type="radio" name="' . $name . '"' . (($id && !$id_assigned) ? ' id="' . $id . '"' : '') . ' value="' . $value . '"' . $selected . (($key) ? ' accesskey="' . $key . '"' : '') . ' class="radio" /> ' . $user->lang[$title] . '</label>' . $separator;
$id_assigned = true;
}
@@ -203,7 +203,7 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
$size = (int) $tpl_type[1];
$maxlength = (int) $tpl_type[2];
- $tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="' . $name . '" value="' . $new[$config_key] . '" />';
+ $tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="' . $name . '" value="' . $new[$config_key] . '"' . (($tpl_type[0] === 'password') ? ' autocomplete="off"' : '') . ' />';
break;
case 'dimension':
@@ -329,7 +329,7 @@ function validate_config_vars($config_vars, &$cfg_array, &$error)
switch ($validator[$type])
{
case 'string':
- $length = strlen($cfg_array[$config_name]);
+ $length = utf8_strlen($cfg_array[$config_name]);
// the column is a VARCHAR
$validator[$max] = (isset($validator[$max])) ? min(255, $validator[$max]) : 255;
@@ -527,7 +527,7 @@ function validate_range($value_ary, &$error)
{
case 'string' :
$max = (isset($column[1])) ? min($column[1],$type['max']) : $type['max'];
- if (strlen($value['value']) > $max)
+ if (utf8_strlen($value['value']) > $max)
{
$error[] = sprintf($user->lang['SETTING_TOO_LONG'], $user->lang[$value['lang']], $max);
}
diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php
index ee59d77cdb..71f8ab572e 100644
--- a/phpBB/includes/functions_admin.php
+++ b/phpBB/includes/functions_admin.php
@@ -2596,6 +2596,31 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id
$sql_keywords .= 'LOWER(l.log_data) ' . implode(' OR LOWER(l.log_data) ', $keywords) . ')';
}
+ if ($log_count !== false)
+ {
+ $sql = 'SELECT COUNT(l.log_id) AS total_entries
+ FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . " u
+ WHERE l.log_type = $log_type
+ AND l.user_id = u.user_id
+ AND l.log_time >= $limit_days
+ $sql_keywords
+ $sql_forum";
+ $result = $db->sql_query($sql);
+ $log_count = (int) $db->sql_fetchfield('total_entries');
+ $db->sql_freeresult($result);
+ }
+
+ if ($log_count == 0)
+ {
+ // Save the queries, because there are no logs to display
+ return 0;
+ }
+
+ if ($offset >= $log_count)
+ {
+ $offset = ($offset - $limit < 0) ? 0 : $offset - $limit;
+ }
+
$sql = "SELECT l.*, u.username, u.username_clean, u.user_colour
FROM " . LOG_TABLE . " l, " . USERS_TABLE . " u
WHERE l.log_type = $log_type
@@ -2743,21 +2768,7 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id
}
}
- if ($log_count !== false)
- {
- $sql = 'SELECT COUNT(l.log_id) AS total_entries
- FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . " u
- WHERE l.log_type = $log_type
- AND l.user_id = u.user_id
- AND l.log_time >= $limit_days
- $sql_keywords
- $sql_forum";
- $result = $db->sql_query($sql);
- $log_count = (int) $db->sql_fetchfield('total_entries');
- $db->sql_freeresult($result);
- }
-
- return;
+ return $offset;
}
/**
@@ -2889,6 +2900,12 @@ function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $li
$user_count = (int) $db->sql_fetchfield('user_count');
$db->sql_freeresult($result);
+ if ($user_count == 0)
+ {
+ // Save the queries, because there are no users to display
+ return 0;
+ }
+
if ($offset >= $user_count)
{
$offset = ($offset - $limit < 0) ? 0 : $offset - $limit;
diff --git a/phpBB/includes/functions_content.php b/phpBB/includes/functions_content.php
index 179fd3c2f8..63e4a16fb6 100644
--- a/phpBB/includes/functions_content.php
+++ b/phpBB/includes/functions_content.php
@@ -691,6 +691,9 @@ function censor_text($text)
return '';
}
+ // Strip control characters
+ $text = preg_replace('/[\x00-\x0f]/', '', $text);
+
// We moved the word censor checks in here because we call this function quite often - and then only need to do the check once
if (!isset($censors) || !is_array($censors))
{
@@ -1107,7 +1110,7 @@ function extension_allowed($forum_id, $extension, &$extensions)
* @param int $max_length Maximum length of string (multibyte character count as 1 char / Html entity count as 1 char)
* @param int $max_store_length Maximum character length of string (multibyte character count as 1 char / Html entity count as entity chars).
* @param bool $allow_reply Allow Re: in front of string
-* NOTE: This parameter can cause undesired behavior (returning strings longer than $max_store_legnth) and is deprecated.
+* NOTE: This parameter can cause undesired behavior (returning strings longer than $max_store_length) and is deprecated.
* @param string $append String to be appended
*/
function truncate_string($string, $max_length = 60, $max_store_length = 255, $allow_reply = false, $append = '')
diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php
index abc5b3e29f..26a4e965a7 100644
--- a/phpBB/includes/functions_display.php
+++ b/phpBB/includes/functions_display.php
@@ -459,7 +459,6 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
'SUBFORUMS' => $s_subforums_list,
'L_SUBFORUM_STR' => $l_subforums,
- 'L_FORUM_FOLDER_ALT' => $folder_alt,
'L_MODERATOR_STR' => $l_moderator,
'U_UNAPPROVED_TOPICS' => ($row['forum_id_unapproved_topics']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=unapproved_topics&amp;f=' . $row['forum_id_unapproved_topics']) : '',
@@ -1041,7 +1040,7 @@ function display_user_activity(&$userdata)
/**
* Topic and forum watching common code
*/
-function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, $notify_status = 'unset', $start = 0)
+function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, $notify_status = 'unset', $start = 0, $item_title = '')
{
global $template, $db, $user, $phpEx, $start, $phpbb_root_path;
global $request;
@@ -1071,32 +1070,46 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id,
if (!is_null($notify_status) && $notify_status !== '')
{
-
if (isset($_GET['unwatch']))
{
$uid = request_var('uid', 0);
- if ($uid != $user_id)
- {
- $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&amp;start=$start");
- $message = $user->lang['ERR_UNWATCHING'] . '<br /><br />' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '<a href="' . $redirect_url . '">', '</a>');
- trigger_error($message);
- }
- if ($request->variable('unwatch', '', false, phpbb_request_interface::GET) == $mode)
+ $token = request_var('hash', '');
+
+ if (($token && check_link_hash($token, "{$mode}_$match_id")) || confirm_box(true))
{
- $is_watching = 0;
+ if (($uid != $user_id) || ($request->variable('unwatch', '', false, phpbb_request_interface::GET) != $mode))
+ {
+ $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&amp;start=$start");
+ $message = $user->lang['ERR_UNWATCHING'] . '<br /><br />' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '<a href="' . $redirect_url . '">', '</a>');
+ trigger_error($message);
+ }
$sql = 'DELETE FROM ' . $table_sql . "
WHERE $where_sql = $match_id
AND user_id = $user_id";
$db->sql_query($sql);
- }
-
- $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&amp;start=$start");
- meta_refresh(3, $redirect_url);
+ $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&amp;start=$start");
+ $message = $user->lang['NOT_WATCHING_' . strtoupper($mode)] . '<br /><br />' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '<a href="' . $redirect_url . '">', '</a>');
+ meta_refresh(3, $redirect_url);
+ trigger_error($message);
+ }
+ else
+ {
+ $s_hidden_fields = array(
+ 'uid' => $user->data['user_id'],
+ 'unwatch' => $mode,
+ 'start' => $start,
+ 'f' => $forum_id,
+ );
+ if ($mode != 'forum')
+ {
+ $s_hidden_fields['t'] = $topic_id;
+ }
- $message = $user->lang['NOT_WATCHING_' . strtoupper($mode)] . '<br /><br />' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '<a href="' . $redirect_url . '">', '</a>');
- trigger_error($message);
+ $confirm_box_message = (($item_title == '') ? 'UNWATCH_' . strtoupper($mode) : $user->lang('UNWATCH_' . strtoupper($mode) . '_DETAILED', $item_title));
+ confirm_box(false, $confirm_box_message, build_hidden_fields($s_hidden_fields));
+ }
}
else
{
@@ -1116,26 +1129,45 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id,
{
if (isset($_GET['watch']))
{
+ $uid = request_var('uid', 0);
$token = request_var('hash', '');
- $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&amp;start=$start");
- if ($request->variable('watch', '', false, phpbb_request_interface::GET) == $mode && check_link_hash($token, "{$mode}_$match_id"))
+ if (($token && check_link_hash($token, "{$mode}_$match_id")) || confirm_box(true))
{
+ if (($uid != $user_id) || ($request->variable('watch', '', false, phpbb_request_interface::GET) != $mode))
+ {
+ $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&amp;start=$start");
+ $message = $user->lang['ERR_WATCHING'] . '<br /><br />' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '<a href="' . $redirect_url . '">', '</a>');
+ trigger_error($message);
+ }
+
$is_watching = true;
$sql = 'INSERT INTO ' . $table_sql . " (user_id, $where_sql, notify_status)
VALUES ($user_id, $match_id, " . NOTIFY_YES . ')';
$db->sql_query($sql);
+
+ $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&amp;start=$start");
$message = $user->lang['ARE_WATCHING_' . strtoupper($mode)] . '<br /><br />' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '<a href="' . $redirect_url . '">', '</a>');
+ meta_refresh(3, $redirect_url);
+ trigger_error($message);
}
else
{
- $message = $user->lang['ERR_WATCHING'] . '<br /><br />' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '<a href="' . $redirect_url . '">', '</a>');
- }
-
- meta_refresh(3, $redirect_url);
+ $s_hidden_fields = array(
+ 'uid' => $user->data['user_id'],
+ 'watch' => $mode,
+ 'start' => $start,
+ 'f' => $forum_id,
+ );
+ if ($mode != 'forum')
+ {
+ $s_hidden_fields['t'] = $topic_id;
+ }
- trigger_error($message);
+ $confirm_box_message = (($item_title == '') ? 'WATCH_' . strtoupper($mode) : $user->lang('WATCH_' . strtoupper($mode) . '_DETAILED', $item_title));
+ confirm_box(false, $confirm_box_message, build_hidden_fields($s_hidden_fields));
+ }
}
else
{
@@ -1145,7 +1177,8 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id,
}
else
{
- if ($request->variable('unwatch', '', false, phpbb_request_interface::GET) == $mode)
+ if ((isset($_GET['unwatch']) && $request->variable('unwatch', '', false, phpbb_request_interface::GET) == $mode) ||
+ (isset($_GET['watch']) && $request->variable('watch', '', false, phpbb_request_interface::GET) == $mode))
{
login_box();
}
diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php
index 94bcb36698..91a09608c7 100644
--- a/phpBB/includes/functions_download.php
+++ b/phpBB/includes/functions_download.php
@@ -100,10 +100,10 @@ function send_avatar_to_browser($file, $browser)
*/
function wrap_img_in_html($src, $title)
{
- echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-Strict.dtd">';
+ echo '<!DOCTYPE html>';
echo '<html>';
echo '<head>';
- echo '<meta http-equiv="content-type" content="text/html; charset=UTF-8" />';
+ echo '<meta charset="utf-8">';
echo '<title>' . $title . '</title>';
echo '</head>';
echo '<body>';
diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php
index 0bb0ef8722..9e81533cea 100644
--- a/phpBB/includes/functions_posting.php
+++ b/phpBB/includes/functions_posting.php
@@ -21,7 +21,7 @@ if (!defined('IN_PHPBB'))
*/
function generate_smilies($mode, $forum_id)
{
- global $auth, $db, $user, $config, $template;
+ global $db, $user, $config, $template;
global $phpEx, $phpbb_root_path;
$start = request_var('start', 0);
@@ -803,7 +803,7 @@ function posting_gen_inline_attachments(&$attachment_data)
*/
function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_attach_box = true)
{
- global $template, $config, $phpbb_root_path, $phpEx, $user, $auth;
+ global $template, $config, $phpbb_root_path, $phpEx, $user;
// Some default template variables
$template->assign_vars(array(
@@ -2458,3 +2458,105 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
return $url;
}
+
+/**
+* Handle topic bumping
+* @param int $forum_id The ID of the forum the topic is being bumped belongs to
+* @param int $topic_id The ID of the topic is being bumping
+* @param array $post_data Passes some topic parameters:
+* - 'topic_title'
+* - 'topic_last_post_id'
+* - 'topic_last_poster_id'
+* - 'topic_last_post_subject'
+* - 'topic_last_poster_name'
+* - 'topic_last_poster_colour'
+* @param int $bump_time The time at which topic was bumped, usually it is a current time as obtained via time().
+* @return string An URL to the bumped topic, example: ./viewtopic.php?forum_id=1&amptopic_id=2&ampp=3#p3
+*/
+function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false)
+{
+ global $config, $db, $user, $phpEx, $phpbb_root_path;
+
+ if ($bump_time === false)
+ {
+ $bump_time = time();
+ }
+
+ // Begin bumping
+ $db->sql_transaction('begin');
+
+ // Update the topic's last post post_time
+ $sql = 'UPDATE ' . POSTS_TABLE . "
+ SET post_time = $bump_time
+ WHERE post_id = {$post_data['topic_last_post_id']}
+ AND topic_id = $topic_id";
+ $db->sql_query($sql);
+
+ // Sync the topic's last post time, the rest of the topic's last post data isn't changed
+ $sql = 'UPDATE ' . TOPICS_TABLE . "
+ SET topic_last_post_time = $bump_time,
+ topic_bumped = 1,
+ topic_bumper = " . $user->data['user_id'] . "
+ WHERE topic_id = $topic_id";
+ $db->sql_query($sql);
+
+ // Update the forum's last post info
+ $sql = 'UPDATE ' . FORUMS_TABLE . "
+ SET forum_last_post_id = " . $post_data['topic_last_post_id'] . ",
+ forum_last_poster_id = " . $post_data['topic_last_poster_id'] . ",
+ forum_last_post_subject = '" . $db->sql_escape($post_data['topic_last_post_subject']) . "',
+ forum_last_post_time = $bump_time,
+ forum_last_poster_name = '" . $db->sql_escape($post_data['topic_last_poster_name']) . "',
+ forum_last_poster_colour = '" . $db->sql_escape($post_data['topic_last_poster_colour']) . "'
+ WHERE forum_id = $forum_id";
+ $db->sql_query($sql);
+
+ // Update bumper's time of the last posting to prevent flood
+ $sql = 'UPDATE ' . USERS_TABLE . "
+ SET user_lastpost_time = $bump_time
+ WHERE user_id = " . $user->data['user_id'];
+ $db->sql_query($sql);
+
+ $db->sql_transaction('commit');
+
+ // Mark this topic as posted to
+ markread('post', $forum_id, $topic_id, $bump_time);
+
+ // Mark this topic as read
+ markread('topic', $forum_id, $topic_id, $bump_time);
+
+ // Update forum tracking info
+ if ($config['load_db_lastread'] && $user->data['is_registered'])
+ {
+ $sql = 'SELECT mark_time
+ FROM ' . FORUMS_TRACK_TABLE . '
+ WHERE user_id = ' . $user->data['user_id'] . '
+ AND forum_id = ' . $forum_id;
+ $result = $db->sql_query($sql);
+ $f_mark_time = (int) $db->sql_fetchfield('mark_time');
+ $db->sql_freeresult($result);
+ }
+ else if ($config['load_anon_lastread'] || $user->data['is_registered'])
+ {
+ $f_mark_time = false;
+ }
+
+ if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered'])
+ {
+ // Update forum info
+ $sql = 'SELECT forum_last_post_time
+ FROM ' . FORUMS_TABLE . '
+ WHERE forum_id = ' . $forum_id;
+ $result = $db->sql_query($sql);
+ $forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time');
+ $db->sql_freeresult($result);
+
+ update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time, false);
+ }
+
+ add_log('mod', $forum_id, $topic_id, 'LOG_BUMP_TOPIC', $post_data['topic_title']);
+
+ $url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;p={$post_data['topic_last_post_id']}") . "#p{$post_data['topic_last_post_id']}";
+
+ return $url;
+}
diff --git a/phpBB/includes/functions_profile_fields.php b/phpBB/includes/functions_profile_fields.php
index 44deffa162..ec29a1732d 100644
--- a/phpBB/includes/functions_profile_fields.php
+++ b/phpBB/includes/functions_profile_fields.php
@@ -149,7 +149,18 @@ class custom_profile
case FIELD_DROPDOWN:
$field_value = (int) $field_value;
-
+
+ // retrieve option lang data if necessary
+ if (!isset($this->options_lang[$field_data['field_id']]) || !isset($this->options_lang[$field_data['field_id']][$field_data['lang_id']]) || !sizeof($this->options_lang[$file_data['field_id']][$field_data['lang_id']]))
+ {
+ $this->get_option_lang($field_data['field_id'], $field_data['lang_id'], FIELD_DROPDOWN, false);
+ }
+
+ if (!isset($this->options_lang[$field_data['field_id']][$field_data['lang_id']][$field_value]))
+ {
+ return 'FIELD_INVALID_VALUE';
+ }
+
if ($field_value == $field_data['field_novalue'] && $field_data['field_required'])
{
return 'FIELD_REQUIRED';
@@ -302,6 +313,7 @@ class custom_profile
switch ($cp_result)
{
case 'FIELD_INVALID_DATE':
+ case 'FIELD_INVALID_VALUE':
case 'FIELD_REQUIRED':
$error = sprintf($user->lang[$cp_result], $row['lang_name']);
break;
diff --git a/phpBB/includes/mcp/mcp_logs.php b/phpBB/includes/mcp/mcp_logs.php
index 01f8584970..dc05ba4110 100644
--- a/phpBB/includes/mcp/mcp_logs.php
+++ b/phpBB/includes/mcp/mcp_logs.php
@@ -170,7 +170,7 @@ class mcp_logs
// Grab log data
$log_data = array();
$log_count = 0;
- view_log('mod', $log_data, $log_count, $config['topics_per_page'], $start, $forum_list, $topic_id, 0, $sql_where, $sql_sort, $keywords);
+ $start = view_log('mod', $log_data, $log_count, $config['topics_per_page'], $start, $forum_list, $topic_id, 0, $sql_where, $sql_sort, $keywords);
$template->assign_vars(array(
'PAGE_NUMBER' => on_page($log_count, $config['topics_per_page'], $start),
@@ -179,7 +179,7 @@ class mcp_logs
'L_TITLE' => $user->lang['MCP_LOGS'],
- 'U_POST_ACTION' => $this->u_action,
+ 'U_POST_ACTION' => $this->u_action . "&amp;$u_sort_param$keywords_param&amp;start=$start",
'S_CLEAR_ALLOWED' => ($auth->acl_get('a_clearlogs')) ? true : false,
'S_SELECT_SORT_DIR' => $s_sort_dir,
'S_SELECT_SORT_KEY' => $s_sort_key,
diff --git a/phpBB/includes/mcp/mcp_notes.php b/phpBB/includes/mcp/mcp_notes.php
index 0b22ff74fd..dfb6ed3b68 100644
--- a/phpBB/includes/mcp/mcp_notes.php
+++ b/phpBB/includes/mcp/mcp_notes.php
@@ -198,7 +198,7 @@ class mcp_notes
$log_data = array();
$log_count = 0;
- view_log('user', $log_data, $log_count, $config['topics_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort, $keywords);
+ $start = view_log('user', $log_data, $log_count, $config['topics_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort, $keywords);
if ($log_count)
{
diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php
index c6132d86d4..b3a48112ea 100644
--- a/phpBB/includes/message_parser.php
+++ b/phpBB/includes/message_parser.php
@@ -102,20 +102,22 @@ class bbcode_firstpass extends bbcode
/**
* Init bbcode data for later parsing
*/
- function bbcode_init()
+ function bbcode_init($allow_custom_bbcode = true)
{
static $rowset;
// This array holds all bbcode data. BBCodes will be processed in this
// order, so it is important to keep [code] in first position and
// [quote] in second position.
+ // To parse multiline URL we enable dotall option setting only for URL text
+ // but not for link itself, thus [url][/url] is not affected.
$this->bbcodes = array(
'code' => array('bbcode_id' => 8, 'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#uise' => "\$this->bbcode_code('\$1', '\$2')")),
'quote' => array('bbcode_id' => 0, 'regexp' => array('#\[quote(?:=&quot;(.*?)&quot;)?\](.+)\[/quote\]#uise' => "\$this->bbcode_quote('\$0')")),
'attachment' => array('bbcode_id' => 12, 'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#uise' => "\$this->bbcode_attachment('\$1', '\$2')")),
'b' => array('bbcode_id' => 1, 'regexp' => array('#\[b\](.*?)\[/b\]#uise' => "\$this->bbcode_strong('\$1')")),
'i' => array('bbcode_id' => 2, 'regexp' => array('#\[i\](.*?)\[/i\]#uise' => "\$this->bbcode_italic('\$1')")),
- 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](.*)\[/url\]#uiUe' => "\$this->validate_url('\$2', '\$3')")),
+ 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](?(1)((?s).*(?-s))|(.*))\[/url\]#uiUe' => "\$this->validate_url('\$2', ('\$3') ? '\$3' : '\$4')")),
'img' => array('bbcode_id' => 4, 'regexp' => array('#\[img\](.*)\[/img\]#uiUe' => "\$this->bbcode_img('\$1')")),
'size' => array('bbcode_id' => 5, 'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#uise' => "\$this->bbcode_size('\$1', '\$2')")),
'color' => array('bbcode_id' => 6, 'regexp' => array('!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!uise' => "\$this->bbcode_color('\$1', '\$2')")),
@@ -133,6 +135,11 @@ class bbcode_firstpass extends bbcode
$this->parsed_items[$tag] = 0;
}
+ if (!$allow_custom_bbcode)
+ {
+ return;
+ }
+
if (!is_array($rowset))
{
global $db;
diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php
index 893ec2c0cc..e36f44ddfa 100644
--- a/phpBB/includes/session.php
+++ b/phpBB/includes/session.php
@@ -222,7 +222,7 @@ class session
// if the forwarded for header shall be checked we have to validate its contents
if ($config['forwarded_for_check'])
{
- $this->forwarded_for = preg_replace('#[ ]{2,}#', ' ', str_replace(array(',', ' '), ' ', $this->forwarded_for));
+ $this->forwarded_for = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->forwarded_for));
// split the list of IPs
$ips = explode(' ', $this->forwarded_for);
@@ -268,11 +268,11 @@ class session
// Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests
// it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip.
- $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars((string) $_SERVER['REMOTE_ADDR']) : '';
- $this->ip = preg_replace('#[ ]{2,}#', ' ', str_replace(array(',', ' '), ' ', $this->ip));
+ $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? (string) $_SERVER['REMOTE_ADDR'] : '';
+ $this->ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->ip));
// split the list of IPs
- $ips = explode(' ', $this->ip);
+ $ips = explode(' ', trim($this->ip));
// Default IP if REMOTE_ADDR is invalid
$this->ip = '127.0.0.1';
@@ -297,26 +297,31 @@ class session
continue;
}
- // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly
- if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip))
+ if (preg_match(get_preg_expression('ipv4'), $ip))
{
- // Just break
- break;
+ $this->ip = $ip;
}
-
- // Quick check for IPv4-mapped address in IPv6
- if (stripos($ip, '::ffff:') === 0)
+ else if (preg_match(get_preg_expression('ipv6'), $ip))
{
- $ipv4 = substr($ip, 7);
-
- if (preg_match(get_preg_expression('ipv4'), $ipv4))
+ // Quick check for IPv4-mapped address in IPv6
+ if (stripos($ip, '::ffff:') === 0)
{
- $ip = $ipv4;
+ $ipv4 = substr($ip, 7);
+
+ if (preg_match(get_preg_expression('ipv4'), $ipv4))
+ {
+ $ip = $ipv4;
+ }
}
- }
- // Use the last in chain
- $this->ip = $ip;
+ $this->ip = $ip;
+ }
+ else
+ {
+ // We want to use the last valid address in the chain
+ // Leave foreach loop when address is invalid
+ break;
+ }
}
$this->load = false;
@@ -602,6 +607,7 @@ class session
// otherwise they'll index this page with the SID, duplicate content oh my!
if ($bot && isset($_GET['sid']))
{
+ send_status_line(301, 'Moved Permanently');
redirect(build_url(array('sid')));
}
@@ -1013,6 +1019,10 @@ class session
include($phpbb_root_path . "includes/captcha/captcha_factory." . $phpEx);
}
phpbb_captcha_factory::garbage_collect($config['captcha_plugin']);
+
+ $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . '
+ WHERE attempt_time < ' . (time() - (int) $config['ip_login_limit_time']);
+ $db->sql_query($sql);
}
return;
@@ -1251,6 +1261,12 @@ class session
$ip = $this->ip;
}
+ // Neither Spamhaus nor Spamcop supports IPv6 addresses.
+ if (strpos($ip, ':') !== false)
+ {
+ return false;
+ }
+
$dnsbl_check = array(
'sbl.spamhaus.org' => 'http://www.spamhaus.org/query/bl?ip=',
);
@@ -2287,9 +2303,44 @@ class user extends session
// Use URL if told so
$root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path;
- $img_data['src'] = $root_path . 'styles/' . rawurlencode($this->theme['imageset_path']) . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename'];
+ $path = 'styles/' . rawurlencode($this->theme['imageset_path']) . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename'];
+
+ $img_data['src'] = $root_path . $path;
$img_data['width'] = $this->img_array[$img]['image_width'];
$img_data['height'] = $this->img_array[$img]['image_height'];
+
+ // We overwrite the width and height to the phpbb logo's width
+ // and height here if the contents of the site_logo file are
+ // really equal to the phpbb_logo
+ // This allows us to change the dimensions of the phpbb_logo without
+ // modifying the imageset.cfg and causing a conflict for everyone
+ // who modified it for their custom logo on updating
+ if ($img == 'site_logo' && file_exists($phpbb_root_path . $path))
+ {
+ global $cache;
+
+ $img_file_hashes = $cache->get('imageset_site_logo_md5');
+
+ if ($img_file_hashes === false)
+ {
+ $img_file_hashes = array();
+ }
+
+ $key = $this->theme['imageset_path'] . '::' . $this->img_array[$img]['image_lang'];
+ if (!isset($img_file_hashes[$key]))
+ {
+ $img_file_hashes[$key] = md5(file_get_contents($phpbb_root_path . $path));
+ $cache->put('imageset_site_logo_md5', $img_file_hashes);
+ }
+
+ $phpbb_logo_hash = '0c461a32cd3621643105f0d02a772c10';
+
+ if ($phpbb_logo_hash == $img_file_hashes[$key])
+ {
+ $img_data['width'] = '149';
+ $img_data['height'] = '52';
+ }
+ }
}
$alt = (!empty($this->lang[$alt])) ? $this->lang[$alt] : $alt;
diff --git a/phpBB/includes/startup.php b/phpBB/includes/startup.php
new file mode 100644
index 0000000000..ca9665da29
--- /dev/null
+++ b/phpBB/includes/startup.php
@@ -0,0 +1,150 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2011 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/**
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+// Report all errors, except notices and deprecation messages
+if (!defined('E_DEPRECATED'))
+{
+ define('E_DEPRECATED', 8192);
+}
+error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
+
+/*
+* Remove variables created by register_globals from the global scope
+* Thanks to Matt Kavanagh
+*/
+function deregister_globals()
+{
+ $not_unset = array(
+ 'GLOBALS' => true,
+ '_GET' => true,
+ '_POST' => true,
+ '_COOKIE' => true,
+ '_REQUEST' => true,
+ '_SERVER' => true,
+ '_SESSION' => true,
+ '_ENV' => true,
+ '_FILES' => true,
+ 'phpEx' => true,
+ 'phpbb_root_path' => true
+ );
+
+ // Not only will array_merge and array_keys give a warning if
+ // a parameter is not an array, array_merge will actually fail.
+ // So we check if _SESSION has been initialised.
+ if (!isset($_SESSION) || !is_array($_SESSION))
+ {
+ $_SESSION = array();
+ }
+
+ // Merge all into one extremely huge array; unset this later
+ $input = array_merge(
+ array_keys($_GET),
+ array_keys($_POST),
+ array_keys($_COOKIE),
+ array_keys($_SERVER),
+ array_keys($_SESSION),
+ array_keys($_ENV),
+ array_keys($_FILES)
+ );
+
+ foreach ($input as $varname)
+ {
+ if (isset($not_unset[$varname]))
+ {
+ // Hacking attempt. No point in continuing unless it's a COOKIE (so a cookie called GLOBALS doesn't lock users out completely)
+ if ($varname !== 'GLOBALS' || isset($_GET['GLOBALS']) || isset($_POST['GLOBALS']) || isset($_SERVER['GLOBALS']) || isset($_SESSION['GLOBALS']) || isset($_ENV['GLOBALS']) || isset($_FILES['GLOBALS']))
+ {
+ exit;
+ }
+ else
+ {
+ $cookie = &$_COOKIE;
+ while (isset($cookie['GLOBALS']))
+ {
+ if (!is_array($cookie['GLOBALS']))
+ {
+ break;
+ }
+
+ foreach ($cookie['GLOBALS'] as $registered_var => $value)
+ {
+ if (!isset($not_unset[$registered_var]))
+ {
+ unset($GLOBALS[$registered_var]);
+ }
+ }
+ $cookie = &$cookie['GLOBALS'];
+ }
+ }
+ }
+
+ unset($GLOBALS[$varname]);
+ }
+
+ unset($input);
+}
+
+// If we are on PHP >= 6.0.0 we do not need some code
+if (version_compare(PHP_VERSION, '6.0.0-dev', '>='))
+{
+ /**
+ * @ignore
+ */
+ define('STRIP', false);
+}
+else
+{
+ @set_magic_quotes_runtime(0);
+
+ // Be paranoid with passed vars
+ if (@ini_get('register_globals') == '1' || strtolower(@ini_get('register_globals')) == 'on' || !function_exists('ini_get'))
+ {
+ deregister_globals();
+ }
+
+ define('STRIP', (get_magic_quotes_gpc()) ? true : false);
+}
+
+// Prevent date/time functions from throwing E_WARNING on PHP 5.3 by setting a default timezone
+if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get'))
+{
+ // For PHP 5.1.0 the date/time functions have been rewritten
+ // and setting a timezone is required prior to calling any date/time function.
+
+ // Since PHP 5.2.0 calls to date/time functions without having a timezone set
+ // result in E_STRICT errors being thrown.
+ // Note: We already exclude E_STRICT errors
+ // (to be exact: they are not included in E_ALL in PHP 5.2)
+
+ // In PHP 5.3.0 the error level has been raised to E_WARNING which causes problems
+ // because we show E_WARNING errors and do not set a default timezone.
+ // This is because we have our own timezone handling and work in UTC only anyway.
+
+ // So what we basically want to do is set our timezone to UTC,
+ // but we don't know what other scripts (such as bridges) are involved,
+ // so we check whether a timezone is already set by calling date_default_timezone_get().
+
+ // Unfortunately, date_default_timezone_get() itself might throw E_WARNING
+ // if no timezone has been set, so we have to keep it quiet with @.
+
+ // date_default_timezone_get() tries to guess the correct timezone first
+ // and then falls back to UTC when everything fails.
+ // We just set the timezone to whatever date_default_timezone_get() returns.
+ date_default_timezone_set(@date_default_timezone_get());
+}
+
+$starttime = explode(' ', microtime());
+$starttime = $starttime[1] + $starttime[0];
diff --git a/phpBB/includes/ucp/ucp_activate.php b/phpBB/includes/ucp/ucp_activate.php
index c10516c769..34b0b6d879 100644
--- a/phpBB/includes/ucp/ucp_activate.php
+++ b/phpBB/includes/ucp/ucp_activate.php
@@ -98,6 +98,13 @@ class ucp_activate
SET user_actkey = ''
WHERE user_id = {$user_row['user_id']}";
$db->sql_query($sql);
+
+ // Create the correct logs
+ add_log('user', $user_row['user_id'], 'LOG_USER_ACTIVE_USER');
+ if ($auth->acl_get('a_user'))
+ {
+ add_log('admin', 'LOG_USER_ACTIVE', $user_row['username']);
+ }
}
if ($config['require_activation'] == USER_ACTIVATION_ADMIN && !$update_password)
diff --git a/phpBB/includes/ucp/ucp_pm.php b/phpBB/includes/ucp/ucp_pm.php
index 84fa9b18dc..87d51ca613 100644
--- a/phpBB/includes/ucp/ucp_pm.php
+++ b/phpBB/includes/ucp/ucp_pm.php
@@ -115,7 +115,7 @@ class ucp_pm
case 'compose':
$action = request_var('action', 'post');
- get_folder($user->data['user_id']);
+ $user_folders = get_folder($user->data['user_id']);
if (!$auth->acl_get('u_sendpm'))
{
@@ -130,7 +130,7 @@ class ucp_pm
}
include($phpbb_root_path . 'includes/ucp/ucp_pm_compose.' . $phpEx);
- compose_pm($id, $mode, $action);
+ compose_pm($id, $mode, $action, $user_folders);
$tpl_file = 'posting_body';
break;
diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php
index 07aa25d67b..92297c1490 100644
--- a/phpBB/includes/ucp/ucp_pm_compose.php
+++ b/phpBB/includes/ucp/ucp_pm_compose.php
@@ -20,7 +20,7 @@ if (!defined('IN_PHPBB'))
* Compose private message
* Called from ucp_pm with mode == 'compose'
*/
-function compose_pm($id, $mode, $action)
+function compose_pm($id, $mode, $action, $user_folders = array())
{
global $template, $db, $auth, $user;
global $phpbb_root_path, $phpEx, $config;
@@ -130,6 +130,7 @@ function compose_pm($id, $mode, $action)
}
$sql = '';
+ $folder_id = 0;
// What is all this following SQL for? Well, we need to know
// some basic information in all cases before we do anything.
@@ -393,7 +394,7 @@ function compose_pm($id, $mode, $action)
unset($message_text);
$s_action = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&amp;mode=$mode&amp;action=$action", true, $user->session_id);
- $s_action .= ($msg_id) ? "&amp;p=$msg_id" : '';
+ $s_action .= (($folder_id) ? "&amp;f=$folder_id" : '') . (($msg_id) ? "&amp;p=$msg_id" : '');
// Delete triggered ?
if ($action == 'delete')
@@ -736,10 +737,30 @@ function compose_pm($id, $mode, $action)
$msg_id = submit_pm($action, $subject, $pm_data);
$return_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;mode=view&amp;p=' . $msg_id);
- $return_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=outbox');
- meta_refresh(3, $return_message_url);
+ $inbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=inbox');
+ $outbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=outbox');
+
+ $folder_url = '';
+ if (($folder_id > 0) && isset($user_folders[$folder_id]))
+ {
+ $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $folder_id);
+ }
+
+ $return_box_url = ($action === 'post' || $action === 'edit') ? $outbox_folder_url : $inbox_folder_url;
+ $return_box_lang = ($action === 'post' || $action === 'edit') ? 'PM_OUTBOX' : 'PM_INBOX';
+
- $message = $user->lang['MESSAGE_STORED'] . '<br /><br />' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '<a href="' . $return_message_url . '">', '</a>') . '<br /><br />' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . $return_folder_url . '">', '</a>', $user->lang['PM_OUTBOX']);
+ $message = $user->lang['MESSAGE_STORED'] . '<br /><br />' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '<a href="' . $return_message_url . '">', '</a>');
+
+ $last_click_type = 'CLICK_RETURN_FOLDER';
+ if ($folder_url)
+ {
+ $message .= '<br /><br />' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . $folder_url . '">', '</a>', $user_folders[$folder_id]['folder_name']);
+ $last_click_type = 'CLICK_GOTO_FOLDER';
+ }
+ $message .= '<br /><br />' . sprintf($user->lang[$last_click_type], '<a href="' . $return_box_url . '">', '</a>', $user->lang[$return_box_lang]);
+
+ meta_refresh(3, $return_message_url);
trigger_error($message);
}
diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php
index 74a32a68c9..8b288f5de1 100644
--- a/phpBB/includes/ucp/ucp_pm_viewmessage.php
+++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php
@@ -59,6 +59,18 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
$bbcode = new bbcode($message_row['bbcode_bitfield']);
}
+ // Load the custom profile fields
+ if ($config['load_cpf_pm'])
+ {
+ if (!class_exists('custom_profile'))
+ {
+ include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx);
+ }
+ $cp = new custom_profile();
+
+ $profile_fields = $cp->generate_profile_fields_template('grab', $author_id);
+ }
+
// Assign TO/BCC Addresses to template
write_pm_addresses(array('to' => $message_row['to_address'], 'bcc' => $message_row['bcc_address']), $author_id);
@@ -174,6 +186,25 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
$bbcode_status = ($config['allow_bbcode'] && $config['auth_bbcode_pm'] && $auth->acl_get('u_pm_bbcode')) ? true : false;
+ // Get the profile fields template data
+ $cp_row = array();
+ if ($config['load_cpf_pm'] && isset($profile_fields[$author_id]))
+ {
+ // Filter the fields we don't want to show
+ foreach ($profile_fields[$author_id] as $used_ident => $profile_field)
+ {
+ if (!$profile_field['data']['field_show_on_pm'])
+ {
+ unset($profile_fields[$author_id][$used_ident]);
+ }
+ }
+
+ if (isset($profile_fields[$author_id]))
+ {
+ $cp_row = $cp->generate_profile_fields_template('show', false, $profile_fields[$author_id]);
+ }
+ }
+
$template->assign_vars(array(
'MESSAGE_AUTHOR_FULL' => get_username_string('full', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']),
'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']),
@@ -232,11 +263,23 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
'S_SPECIAL_FOLDER' => in_array($folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)),
'S_PM_RECIPIENTS' => $num_recipients,
'S_BBCODE_ALLOWED' => ($bbcode_status) ? 1 : 0,
+ 'S_CUSTOM_FIELDS' => (!empty($cp_row['row'])) ? true : false,
'U_PRINT_PM' => ($config['print_pm'] && $auth->acl_get('u_pm_printpm')) ? "$url&amp;f=$folder_id&amp;p=" . $message_row['msg_id'] . "&amp;view=print" : '',
'U_FORWARD_PM' => ($config['forward_pm'] && $auth->acl_get('u_sendpm') && $auth->acl_get('u_pm_forward')) ? "$url&amp;mode=compose&amp;action=forward&amp;f=$folder_id&amp;p=" . $message_row['msg_id'] : '')
);
+ // Display the custom profile fields
+ if (!empty($cp_row['row']))
+ {
+ $template->assign_vars($cp_row['row']);
+
+ foreach ($cp_row['blockrow'] as $cp_block_row)
+ {
+ $template->assign_block_vars('custom_fields', $cp_block_row);
+ }
+ }
+
// Display not already displayed Attachments for this post, we already parsed them. ;)
if (isset($attachments) && sizeof($attachments))
{