aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/includes
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/includes')
-rw-r--r--phpBB/includes/acm/acm_file.php22
-rw-r--r--phpBB/includes/acp/acp_main.php39
-rw-r--r--phpBB/includes/acp/acp_modules.php2
-rw-r--r--phpBB/includes/acp/acp_profile.php100
-rw-r--r--phpBB/includes/acp/acp_styles.php12
-rw-r--r--phpBB/includes/constants.php2
-rw-r--r--phpBB/includes/db/dbal.php45
-rw-r--r--phpBB/includes/db/oracle.php2
-rw-r--r--phpBB/includes/functions.php63
-rw-r--r--phpBB/includes/functions_admin.php2
-rw-r--r--phpBB/includes/functions_content.php104
-rw-r--r--phpBB/includes/functions_display.php3
-rw-r--r--phpBB/includes/functions_messenger.php11
-rw-r--r--phpBB/includes/functions_module.php38
-rw-r--r--phpBB/includes/functions_posting.php22
-rw-r--r--phpBB/includes/functions_profile_fields.php42
-rw-r--r--phpBB/includes/mcp/mcp_queue.php8
-rw-r--r--phpBB/includes/search/fulltext_native.php25
-rw-r--r--phpBB/includes/session.php107
-rw-r--r--phpBB/includes/ucp/ucp_activate.php2
-rw-r--r--phpBB/includes/ucp/ucp_groups.php6
-rw-r--r--phpBB/includes/ucp/ucp_main.php11
-rw-r--r--phpBB/includes/ucp/ucp_pm_compose.php23
-rw-r--r--phpBB/includes/ucp/ucp_pm_viewmessage.php4
24 files changed, 475 insertions, 220 deletions
diff --git a/phpBB/includes/acm/acm_file.php b/phpBB/includes/acm/acm_file.php
index 577f893e77..f58f925506 100644
--- a/phpBB/includes/acm/acm_file.php
+++ b/phpBB/includes/acm/acm_file.php
@@ -93,6 +93,12 @@ class acm
@flock($fp, LOCK_UN);
fclose($fp);
+ if (!function_exists('phpbb_chmod'))
+ {
+ global $phpbb_root_path;
+ include($phpbb_root_path . 'includes/functions.' . $phpEx);
+ }
+
phpbb_chmod($this->cache_dir . 'data_global.' . $phpEx, CHMOD_WRITE);
}
else
@@ -193,10 +199,16 @@ class acm
if ($fp = @fopen($this->cache_dir . "data{$var_name}.$phpEx", 'wb'))
{
@flock($fp, LOCK_EX);
- fwrite($fp, "<?php\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n\n\$data = unserialize(" . var_export(serialize($var), true) . ");\n\n?>");
+ fwrite($fp, "<?php\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n\n\$data = " . (sizeof($var) ? "unserialize(" . var_export(serialize($var), true) . ");" : 'array();') . "\n\n?>");
@flock($fp, LOCK_UN);
fclose($fp);
+ if (!function_exists('phpbb_chmod'))
+ {
+ global $phpbb_root_path;
+ include($phpbb_root_path . 'includes/functions.' . $phpEx);
+ }
+
phpbb_chmod($this->cache_dir . "data{$var_name}.$phpEx", CHMOD_WRITE);
}
}
@@ -412,10 +424,16 @@ class acm
$file = "<?php\n\n/* " . str_replace('*/', '*\/', $query) . " */\n";
$file .= "\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n";
- fwrite($fp, $file . "\n\$this->sql_rowset[\$query_id] = unserialize(" . var_export(serialize($this->sql_rowset[$query_id]), true) . ");\n\n?>");
+ fwrite($fp, $file . "\n\$this->sql_rowset[\$query_id] = " . (sizeof($this->sql_rowset[$query_id]) ? "unserialize(" . var_export(serialize($this->sql_rowset[$query_id]), true) . ");" : 'array();') . "\n\n?>");
@flock($fp, LOCK_UN);
fclose($fp);
+ if (!function_exists('phpbb_chmod'))
+ {
+ global $phpbb_root_path;
+ include($phpbb_root_path . 'includes/functions.' . $phpEx);
+ }
+
phpbb_chmod($filename, CHMOD_WRITE);
$query_result = $query_id;
diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php
index d100c49381..a558fe6712 100644
--- a/phpBB/includes/acp/acp_main.php
+++ b/phpBB/includes/acp/acp_main.php
@@ -185,12 +185,36 @@ class acp_main
}
// Resync post counts
- $start = 0;
- $step = ($config['num_posts']) ? (max((int) ($config['num_posts'] / 5), 20000)) : 20000;
+ $start = $max_post_id = 0;
+
+ // Find the maximum post ID, we can only stop the cycle when we've reached it
+ $sql = 'SELECT MAX(forum_last_post_id) as max_post_id
+ FROM ' . FORUMS_TABLE;
+ $result = $db->sql_query($sql);
+ $max_post_id = (int) $db->sql_fetchfield('max_post_id');
+ $db->sql_freeresult($result);
+
+ // No maximum post id? :o
+ if (!$max_post_id)
+ {
+ $sql = 'SELECT MAX(post_id)
+ FROM ' . POSTS_TABLE;
+ $result = $db->sql_query($sql);
+ $max_post_id = (int) $db->sql_fetchfield('max_post_id');
+ $db->sql_freeresult($result);
+ }
+ // Still no maximum post id? Then we are finished
+ if (!$max_post_id)
+ {
+ add_log('admin', 'LOG_RESYNC_POSTCOUNTS');
+ break;
+ }
+
+ $step = ($config['num_posts']) ? (max((int) ($config['num_posts'] / 5), 20000)) : 20000;
$db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_posts = 0');
- do
+ while ($start < $max_post_id)
{
$sql = 'SELECT COUNT(post_id) AS num_posts, poster_id
FROM ' . POSTS_TABLE . '
@@ -207,16 +231,11 @@ class acp_main
$db->sql_query($sql);
}
while ($row = $db->sql_fetchrow($result));
-
- $start += $step;
- }
- else
- {
- $start = 0;
}
$db->sql_freeresult($result);
+
+ $start += $step;
}
- while ($start);
add_log('admin', 'LOG_RESYNC_POSTCOUNTS');
diff --git a/phpBB/includes/acp/acp_modules.php b/phpBB/includes/acp/acp_modules.php
index f3540941df..75bc5766a9 100644
--- a/phpBB/includes/acp/acp_modules.php
+++ b/phpBB/includes/acp/acp_modules.php
@@ -658,6 +658,8 @@ class acp_modules
$iteration++;
}
+ $db->sql_freeresult($result);
+
unset($padding_store);
return $module_list;
diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php
index 309f5d5e74..7ab6ff7cd6 100644
--- a/phpBB/includes/acp/acp_profile.php
+++ b/phpBB/includes/acp/acp_profile.php
@@ -77,7 +77,7 @@ class acp_profile
FROM ' . PROFILE_LANG_TABLE . '
ORDER BY lang_id';
$result = $db->sql_query($sql);
-
+
while ($row = $db->sql_fetchrow($result))
{
// Which languages are available for each item
@@ -206,7 +206,7 @@ class acp_profile
'field_id' => $field_id,
)));
}
-
+
break;
case 'activate':
@@ -216,7 +216,7 @@ class acp_profile
{
trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
-
+
$sql = 'SELECT lang_id
FROM ' . LANG_TABLE . "
WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'";
@@ -253,7 +253,7 @@ class acp_profile
{
trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
-
+
$sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . "
SET field_active = 0
WHERE field_id = $field_id";
@@ -285,7 +285,7 @@ class acp_profile
case 'create':
case 'edit':
-
+
$field_id = request_var('field_id', 0);
$step = request_var('step', 1);
@@ -354,18 +354,19 @@ class acp_profile
{
// We are adding a new field, define basic params
$lang_options = $field_row = array();
-
+
$field_type = request_var('field_type', 0);
-
+
if (!$field_type)
{
trigger_error($user->lang['NO_FIELD_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$field_row = array_merge($default_values[$field_type], array(
- 'field_ident' => utf8_clean_string(request_var('field_ident', '', true)),
+ 'field_ident' => str_replace(' ', '_', utf8_clean_string(request_var('field_ident', '', true))),
'field_required' => 0,
'field_hide' => 0,
+ 'field_show_profile'=> 0,
'field_no_view' => 0,
'field_show_on_reg' => 0,
'lang_name' => utf8_normalize_nfc(request_var('field_ident', '', true)),
@@ -378,7 +379,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', 'field_no_view'),
+ 1 => array('field_ident', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', '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')
);
@@ -400,25 +401,20 @@ class acp_profile
$cp->vars['lang_explain'] = utf8_normalize_nfc(request_var('lang_explain', $field_row['lang_explain'], true));
$cp->vars['lang_default_value'] = utf8_normalize_nfc(request_var('lang_default_value', $field_row['lang_default_value'], true));
- // Field option...
- if (isset($_REQUEST['field_option']))
- {
- $field_option = request_var('field_option', '');
+ // Visibility Options...
+ $visibility_ary = array(
+ 'field_required',
+ 'field_show_on_reg',
+ 'field_show_profile',
+ 'field_hide',
+ );
- $cp->vars['field_required'] = ($field_option == 'field_required') ? 1 : 0;
- $cp->vars['field_show_on_reg'] = ($field_option == 'field_show_on_reg') ? 1 : 0;
- $cp->vars['field_hide'] = ($field_option == 'field_hide') ? 1 : 0;
- }
- else
+ foreach ($visibility_ary as $val)
{
- $cp->vars['field_required'] = $field_row['field_required'];
- $cp->vars['field_show_on_reg'] = $field_row['field_show_on_reg'];
- $cp->vars['field_hide'] = $field_row['field_hide'];
-
- $field_option = ($field_row['field_required']) ? 'field_required' : (($field_row['field_show_on_reg']) ? 'field_show_on_reg' : (($field_row['field_hide']) ? 'field_hide' : ''));
+ $cp->vars[$val] = ($submit || $save) ? request_var($val, 0) : $field_row[$val];
}
- $cp->vars['field_no_view'] = request_var('field_no_view', $field_row['field_no_view']);
+ $cp->vars['field_no_view'] = request_var('field_no_view', (int) $field_row['field_no_view']);
// A boolean field expects an array as the lang options
if ($field_type == FIELD_BOOL)
@@ -481,7 +477,7 @@ class acp_profile
else if ($field_type == FIELD_DATE && $key == 'field_default_value')
{
$always_now = request_var('always_now', -1);
-
+
if ($always_now == 1 || ($always_now === -1 && $var == 'now'))
{
$now = getdate();
@@ -504,7 +500,7 @@ class acp_profile
{
list($cp->vars['field_default_value_day'], $cp->vars['field_default_value_month'], $cp->vars['field_default_value_year']) = explode('-', $var);
}
- }
+ }
}
/* else if ($field_type == FIELD_BOOL && $key == 'field_default_value')
{
@@ -533,7 +529,7 @@ class acp_profile
}
$db->sql_freeresult($result);
-
+
$sql = 'SELECT lang_id, lang_name, lang_explain, lang_default_value
FROM ' . PROFILE_LANG_TABLE . '
WHERE lang_id <> ' . $this->edit_lang_id . "
@@ -550,7 +546,7 @@ class acp_profile
}
$db->sql_freeresult($result);
}
-
+
foreach ($exclude[3] as $key)
{
$cp->vars[$key] = utf8_normalize_nfc(request_var($key, array(0 => ''), true));
@@ -569,7 +565,7 @@ class acp_profile
{
$cp->vars[$key][$lang_id] = explode("\n", $options);
}
-
+
}
}
@@ -709,7 +705,7 @@ class acp_profile
'L_TITLE' => $user->lang['STEP_' . $step . '_TITLE_' . strtoupper($action)],
'L_EXPLAIN' => $user->lang['STEP_' . $step . '_EXPLAIN_' . strtoupper($action)],
-
+
'U_ACTION' => $this->u_action . "&amp;action=$action&amp;step=$step",
'U_BACK' => $this->u_action)
);
@@ -719,13 +715,14 @@ class acp_profile
{
// Create basic options - only small differences between field types
case 1:
-
+
// Build common create options
$template->assign_vars(array(
'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_FIELD_HIDE' => ($cp->vars['field_hide']) ? true : false,
+ 'S_SHOW_PROFILE' => ($cp->vars['field_show_profile']) ? true : false,
'S_FIELD_NO_VIEW' => ($cp->vars['field_no_view']) ? true : false,
'L_LANG_SPECIFIC' => sprintf($user->lang['LANG_SPECIFIC_OPTIONS'], $config['default_lang']),
@@ -746,7 +743,7 @@ class acp_profile
'LANG_DEFAULT_VALUE' => $cp->vars['lang_default_value'])
);
}
-
+
if ($field_type == FIELD_BOOL || $field_type == FIELD_DROPDOWN)
{
// Initialize these array elements if we are creating a new field
@@ -775,11 +772,11 @@ class acp_profile
'SECOND_LANG_OPTION' => ($field_type == FIELD_BOOL) ? $cp->vars['lang_options'][1] : '')
);
}
-
+
break;
case 2:
-
+
$template->assign_vars(array(
'S_STEP_TWO' => true,
'L_NEXT_STEP' => (sizeof($this->lang_defs['iso']) == 1) ? $user->lang['SAVE'] : $user->lang['PROFILE_LANG_OPTIONS'])
@@ -817,7 +814,7 @@ class acp_profile
);
}
}
-
+
break;
}
@@ -829,7 +826,7 @@ class acp_profile
break;
}
-
+
$sql = 'SELECT *
FROM ' . PROFILE_FIELDS_TABLE . '
ORDER BY field_order';
@@ -905,14 +902,14 @@ class acp_profile
$languages[$row['lang_id']] = $row['lang_iso'];
}
$db->sql_freeresult($result);
-
+
$options = array();
$options['lang_name'] = 'string';
if ($cp->vars['lang_explain'])
{
$options['lang_explain'] = 'text';
}
-
+
switch ($field_type)
{
case FIELD_BOOL:
@@ -922,7 +919,7 @@ class acp_profile
case FIELD_DROPDOWN:
$options['lang_options'] = 'optionfield';
break;
-
+
case FIELD_TEXT:
case FIELD_STRING:
if ($cp->vars['lang_default_value'])
@@ -931,7 +928,7 @@ class acp_profile
}
break;
}
-
+
$lang_options = array();
foreach ($options as $field => $field_type)
@@ -957,7 +954,7 @@ class acp_profile
if ($field == 'lang_options')
{
$var = (!isset($cp->vars['l_lang_options'][$lang_id]) || !is_array($cp->vars['l_lang_options'][$lang_id])) ? $cp->vars['lang_options'] : $cp->vars['l_lang_options'][$lang_id];
-
+
switch ($field_type)
{
case 'two_options':
@@ -978,7 +975,7 @@ class acp_profile
);
break;
}
-
+
if (isset($user->lang['CP_' . strtoupper($field) . '_EXPLAIN']))
{
$lang_options[$lang_id]['fields'][$field]['EXPLAIN'] = $user->lang['CP_' . strtoupper($field) . '_EXPLAIN'];
@@ -992,7 +989,7 @@ class acp_profile
'TITLE' => $user->lang['CP_' . strtoupper($field)],
'FIELD' => ($field_type == 'string') ? '<dd><input class="medium" type="text" name="l_' . $field . '[' . $lang_id . ']" value="' . ((isset($value[$lang_id])) ? $value[$lang_id] : $var) . '" /></dd>' : '<dd><textarea name="l_' . $field . '[' . $lang_id . ']" rows="3" cols="80">' . ((isset($value[$lang_id])) ? $value[$lang_id] : $var) . '</textarea></dd>'
);
-
+
if (isset($user->lang['CP_' . strtoupper($field) . '_EXPLAIN']))
{
$lang_options[$lang_id]['fields'][$field]['EXPLAIN'] = $user->lang['CP_' . strtoupper($field) . '_EXPLAIN'];
@@ -1040,6 +1037,7 @@ class acp_profile
'field_required' => $cp->vars['field_required'],
'field_show_on_reg' => $cp->vars['field_show_on_reg'],
'field_hide' => $cp->vars['field_hide'],
+ 'field_show_profile' => $cp->vars['field_show_profile'],
'field_no_view' => $cp->vars['field_no_view']
);
@@ -1065,7 +1063,7 @@ class acp_profile
WHERE field_id = $field_id";
$db->sql_query($sql);
}
-
+
if ($action == 'create')
{
$field_ident = 'pf_' . $field_ident;
@@ -1082,7 +1080,7 @@ class acp_profile
{
$sql_ary['field_id'] = $field_id;
$sql_ary['lang_id'] = $default_lang_id;
-
+
$profile_sql[] = 'INSERT INTO ' . PROFILE_LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
}
else
@@ -1155,7 +1153,7 @@ class acp_profile
AND lang_id = " . (int) $default_lang_id;
$db->sql_query($sql);
}
-
+
foreach ($cp->vars['lang_options'] as $option_id => $value)
{
$sql_ary = array(
@@ -1258,7 +1256,7 @@ class acp_profile
$lang_id = $sql['lang_id'];
$option_id = $sql['option_id'];
unset($sql['lang_id'], $sql['field_id'], $sql['option_id']);
-
+
$this->update_insert(PROFILE_FIELDS_LANG_TABLE, $sql, array(
'lang_id' => $lang_id,
'field_id' => $field_id,
@@ -1278,7 +1276,7 @@ class acp_profile
$db->sql_query($sql);
}
}
-
+
$db->sql_transaction('commit');
if ($action == 'edit')
@@ -1324,7 +1322,7 @@ class acp_profile
if (!$row)
{
$sql_ary = array_merge($where_fields, $sql_ary);
-
+
if (sizeof($sql_ary))
{
$db->sql_query("INSERT INTO $table " . $db->sql_build_array('INSERT', $sql_ary));
@@ -1376,7 +1374,7 @@ class acp_profile
case FIELD_BOOL:
$sql .= 'TINYINT(2) ';
break;
-
+
case FIELD_DROPDOWN:
$sql .= 'MEDIUMINT(8) ';
break;
@@ -1612,4 +1610,4 @@ class acp_profile
}
}
-?> \ No newline at end of file
+?>
diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php
index e0fb1459c2..3a021bb4cf 100644
--- a/phpBB/includes/acp/acp_styles.php
+++ b/phpBB/includes/acp/acp_styles.php
@@ -2176,10 +2176,16 @@ parse_css_file = {PARSE_CSS_FILE}
$style_default = request_var('style_default', 0);
$store_db = request_var('store_db', 0);
- $sql = "SELECT {$mode}_id
+ // If the admin selected the style to be the default style, but forgot to activate it... we will do it for him
+ if ($style_default)
+ {
+ $style_active = 1;
+ }
+
+ $sql = "SELECT {$mode}_id, {$mode}_name
FROM $sql_from
WHERE {$mode}_id <> $style_id
- AND {$mode}_name = '" . $db->sql_escape(strtolower($name)) . "'";
+ AND LOWER({$mode}_name) = '" . $db->sql_escape(strtolower($name)) . "'";
$result = $db->sql_query($sql);
$conflict = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
@@ -3206,7 +3212,7 @@ parse_css_file = {PARSE_CSS_FILE}
{
$sql = "SELECT {$mode}_id, {$mode}_name, {$mode}_path, {$mode}_storedb
FROM $sql_from
- WHERE {$mode}_name = '" . $db->sql_escape(strtolower($cfg_data['inherit_from'])) . "'
+ WHERE {$mode}_name = '" . $db->sql_escape($cfg_data['inherit_from']) . "'
AND {$mode}_inherits_id = 0";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php
index 3a468e4952..61c1c963b8 100644
--- a/phpBB/includes/constants.php
+++ b/phpBB/includes/constants.php
@@ -25,7 +25,7 @@ if (!defined('IN_PHPBB'))
*/
// phpBB Version
-define('PHPBB_VERSION', '3.0.3');
+define('PHPBB_VERSION', '3.0.4-RC1');
// QA-related
// define('PHPBB_QA', 1);
diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php
index 179eff65d2..b530a572da 100644
--- a/phpBB/includes/db/dbal.php
+++ b/phpBB/includes/db/dbal.php
@@ -500,19 +500,62 @@ class dbal
$sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM ';
- $table_array = array();
+ // Build table array. We also build an alias array for later checks.
+ $table_array = $aliases = array();
+ $used_multi_alias = false;
+
foreach ($array['FROM'] as $table_name => $alias)
{
if (is_array($alias))
{
+ $used_multi_alias = true;
+
foreach ($alias as $multi_alias)
{
$table_array[] = $table_name . ' ' . $multi_alias;
+ $aliases[] = $multi_alias;
}
}
else
{
$table_array[] = $table_name . ' ' . $alias;
+ $aliases[] = $alias;
+ }
+ }
+
+ // We run the following code to determine if we need to re-order the table array. ;)
+ // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison.
+ // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is.
+ if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false)
+ {
+ // Take first LEFT JOIN
+ $join = current($array['LEFT_JOIN']);
+
+ // Determine the table used there (even if there are more than one used, we only want to have one
+ preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches);
+
+ // If there is a first join match, we need to make sure the table order is correct
+ if (!empty($matches[1]))
+ {
+ $first_join_match = trim($matches[1]);
+ $table_array = $last = array();
+
+ foreach ($array['FROM'] as $table_name => $alias)
+ {
+ if (is_array($alias))
+ {
+ foreach ($alias as $multi_alias)
+ {
+ ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias;
+ }
+ }
+ else
+ {
+ ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias;
+ }
+ }
+
+ $table_array = array_merge($table_array, $last);
}
}
diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php
index 8fdb29ce5b..a140c4b676 100644
--- a/phpBB/includes/db/oracle.php
+++ b/phpBB/includes/db/oracle.php
@@ -189,7 +189,7 @@ class dbal_oracle extends dbal
$out .= ' ' . $val[1] . '(';
$in_array = array();
- // constuct each IN() clause
+ // constuct each IN() clause
foreach ($in_clause as $in_values)
{
$in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')';
diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php
index b96024e4e3..55c4cc5b51 100644
--- a/phpBB/includes/functions.php
+++ b/phpBB/includes/functions.php
@@ -462,7 +462,7 @@ function _hash_crypt_private($password, $setting, &$itoa64)
/**
* 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.
-* The function determines owner and group from common.php file and sets the same to the provided file.
+* The function determines owner and group from common.php file and sets the same to the provided file. Permissions are mapped to the group, user always has rw(x) permission.
* The function uses bit fields to build the permissions.
* The function sets the appropiate execute bit on directories.
*
@@ -511,6 +511,7 @@ function phpbb_chmod($filename, $perms = CHMOD_READ)
// Will most likely not work
if (@chown($filename, $common_php_owner));
{
+ clearstatcache();
$file_uid = fileowner($filename);
}
}
@@ -520,6 +521,7 @@ function phpbb_chmod($filename, $perms = CHMOD_READ)
{
if (@chgrp($filename, $common_php_group));
{
+ clearstatcache();
$file_gid = filegroup($filename);
}
}
@@ -532,7 +534,7 @@ function phpbb_chmod($filename, $perms = CHMOD_READ)
// Who is PHP?
if ($file_uid === false || $file_gid === false || $php_uid === false || $php_gids === false)
{
- $php = null;
+ $php = NULL;
}
else if ($file_uid == $php_uid /* && $common_php_owner !== false && $common_php_owner === $file_uid*/)
{
@@ -564,16 +566,23 @@ function phpbb_chmod($filename, $perms = CHMOD_READ)
{
case null:
case 'owner':
+ /* ATTENTION: if php is owner or NULL we set it to group here. This is the most failsafe combination for the vast majority of server setups.
+
$result = @chmod($filename, ($owner << 6) + (0 << 3) + (0 << 0));
+ clearstatcache();
+
if (!is_null($php) || (is_readable($filename) && is_writable($filename)))
{
break;
}
+ */
case 'group':
$result = @chmod($filename, ($owner << 6) + ($perms << 3) + (0 << 0));
+ clearstatcache();
+
if (!is_null($php) || ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || is_writable($filename))))
{
break;
@@ -582,6 +591,8 @@ function phpbb_chmod($filename, $perms = CHMOD_READ)
case 'other':
$result = @chmod($filename, ($owner << 6) + ($perms << 3) + ($perms << 0));
+ clearstatcache();
+
if (!is_null($php) || ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || is_writable($filename))))
{
break;
@@ -1820,30 +1831,45 @@ function append_sid($url, $params = false, $is_amp = true, $session_id = false)
}
}
- // Assign sid if session id is not specified
- if ($session_id === false)
- {
- $session_id = $_SID;
- }
-
- $amp_delim = ($is_amp) ? '&amp;' : '&';
- $url_delim = (strpos($url, '?') === false) ? '?' : $amp_delim;
-
- // Appending custom url parameter?
- $append_url = (!empty($_EXTRA_URL)) ? implode($amp_delim, $_EXTRA_URL) : '';
+ $params_is_array = is_array($params);
+ // Get anchor
$anchor = '';
if (strpos($url, '#') !== false)
{
list($url, $anchor) = explode('#', $url, 2);
$anchor = '#' . $anchor;
}
- else if (!is_array($params) && strpos($params, '#') !== false)
+ else if (!$params_is_array && strpos($params, '#') !== false)
{
list($params, $anchor) = explode('#', $params, 2);
$anchor = '#' . $anchor;
}
+ // Handle really simple cases quickly
+ if ($_SID == '' && $session_id === false && empty($_EXTRA_URL) && !$params_is_array && !$anchor)
+ {
+ if ($params === false)
+ {
+ return $url;
+ }
+
+ $url_delim = (strpos($url, '?') === false) ? '?' : (($is_amp) ? '&amp;' : '&');
+ return $url . ($params !== false ? $url_delim. $params : '');
+ }
+
+ // Assign sid if session id is not specified
+ if ($session_id === false)
+ {
+ $session_id = $_SID;
+ }
+
+ $amp_delim = ($is_amp) ? '&amp;' : '&';
+ $url_delim = (strpos($url, '?') === false) ? '?' : $amp_delim;
+
+ // Appending custom url parameter?
+ $append_url = (!empty($_EXTRA_URL)) ? implode($amp_delim, $_EXTRA_URL) : '';
+
// Use the short variant if possible ;)
if ($params === false)
{
@@ -2190,12 +2216,17 @@ function build_url($strip_vars = false)
/**
* Meta refresh assignment
+* Adds META template variable with meta http tag.
+*
+* @param int $time Time in seconds for meta refresh tag
+* @param string $url URL to redirect to. The url will go through redirect() first before the template variable is assigned
+* @param bool $disable_cd_check If true, meta_refresh() will redirect to an external domain. If false, the redirect point to the boards url if it does not match the current domain. Default is false.
*/
-function meta_refresh($time, $url)
+function meta_refresh($time, $url, $disable_cd_check = false)
{
global $template;
- $url = redirect($url, true);
+ $url = redirect($url, true, $disable_cd_check);
$url = str_replace('&', '&amp;', $url);
// For XHTML compatibility we change back & to &amp;
diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php
index 0349cbc6a8..5ec51e44cf 100644
--- a/phpBB/includes/functions_admin.php
+++ b/phpBB/includes/functions_admin.php
@@ -2400,7 +2400,7 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id
{
// Check if there are more occurrences of % than arguments, if there are we fill out the arguments array
// It doesn't matter if we add more arguments than placeholders
- if (substr_count($log[$i]['action'], '%') - sizeof($log_data_ary))
+ if ((substr_count($log[$i]['action'], '%') - sizeof($log_data_ary)) > 0)
{
$log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($log[$i]['action'], '%') - sizeof($log_data_ary), ''));
}
diff --git a/phpBB/includes/functions_content.php b/phpBB/includes/functions_content.php
index 627e6a71cd..1228f8e567 100644
--- a/phpBB/includes/functions_content.php
+++ b/phpBB/includes/functions_content.php
@@ -501,7 +501,8 @@ function generate_text_for_edit($text, $uid, $flags)
*/
function make_clickable_callback($type, $whitespace, $url, $relative_url, $class)
{
- $orig_url = $url . $relative_url;
+ $orig_url = $url;
+ $orig_relative = $relative_url;
$append = '';
$url = htmlspecialchars_decode($url);
$relative_url = htmlspecialchars_decode($relative_url);
@@ -566,6 +567,12 @@ function make_clickable_callback($type, $whitespace, $url, $relative_url, $class
$url = substr($url, 0, -1);
}
break;
+
+ // set last_char to empty here, so the variable can be used later to
+ // check whether a character was removed
+ default:
+ $last_char = '';
+ break;
}
$short_url = (strlen($url) > 55) ? substr($url, 0, 39) . ' ... ' . substr($url, -10) : $url;
@@ -583,7 +590,7 @@ function make_clickable_callback($type, $whitespace, $url, $relative_url, $class
// don't touch it and let MAGIC_URL_FULL take care of it.
if (!$relative_url)
{
- return $whitespace . $orig_url . '/'; // slash is taken away by relative url pattern
+ return $whitespace . $orig_url . '/' . $orig_relative; // slash is taken away by relative url pattern
}
break;
@@ -1137,6 +1144,7 @@ function truncate_string($string, $max_length = 60, $max_store_length = 255, $al
/**
* Get username details for placing into templates.
+* This function caches all modes on first call, except for no_profile - determined by $user_id/$guest_username combination.
*
* @param string $mode Can be profile (for getting an url to the profile), username (for obtaining the username), colour (for obtaining the user colour), full (for obtaining a html string representing a coloured link to the users profile) or no_profile (the same as full but forcing no profile link)
* @param int $user_id The users id
@@ -1146,12 +1154,30 @@ function truncate_string($string, $max_length = 60, $max_store_length = 255, $al
* @param string $custom_profile_url optional parameter to specify a profile url. The user id get appended to this url as &amp;u={user_id}
*
* @return string A string consisting of what is wanted based on $mode.
+* @author BartVB, Acyd Burn
*/
function get_username_string($mode, $user_id, $username, $username_colour = '', $guest_username = false, $custom_profile_url = false)
{
+ static $_profile_cache;
+ static $_base_profile_url;
+
+ $cache_key = $user_id . (string) $guest_username;
+
+ // If the get_username_string() function had been executed once with an (to us) unkown mode, all modes are pre-filled and we can just grab it.
+ if (isset($_profile_cache[$cache_key][$mode]))
+ {
+ // If the mode is 'no_profile', we simply construct the TPL code due to calls to this mode being very very rare
+ if ($mode == 'no_profile')
+ {
+ $tpl = (!$_profile_cache[$cache_key]['colour']) ? '{USERNAME}' : '<span style="color: {USERNAME_COLOUR};" class="username-coloured">{USERNAME}</span>';
+ return str_replace(array('{USERNAME_COLOUR}', '{USERNAME}'), array($_profile_cache[$cache_key]['colour'], $_profile_cache[$cache_key]['username']), $tpl);
+ }
+
+ return $_profile_cache[$cache_key][$mode];
+ }
+
global $phpbb_root_path, $phpEx, $user, $auth;
- $profile_url = '';
$username_colour = ($username_colour) ? '#' . $username_colour : '';
if ($guest_username === false)
@@ -1163,64 +1189,42 @@ function get_username_string($mode, $user_id, $username, $username_colour = '',
$username = ($user_id && $user_id != ANONYMOUS) ? $username : ((!empty($guest_username)) ? $guest_username : $user->lang['GUEST']);
}
- // Only show the link if not anonymous
- if ($mode != 'no_profile' && $user_id && $user_id != ANONYMOUS)
+ // Build cache for all modes
+ $_profile_cache[$cache_key]['colour'] = $username_colour;
+ $_profile_cache[$cache_key]['username'] = $username;
+ $_profile_cache[$cache_key]['no_profile'] = true;
+
+ // Profile url - only show if not anonymous and permission to view profile if registered user
+ // For anonymous the link leads to a login page.
+ if ($user_id && $user_id != ANONYMOUS && ($user->data['user_id'] == ANONYMOUS || $auth->acl_get('u_viewprofile')))
{
- // Do not show the link if the user is already logged in but do not have u_viewprofile permissions (relevant for bots mostly).
- // For all others the link leads to a login page or the profile.
- if ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile'))
+ if (empty($_base_profile_url))
{
- $profile_url = '';
- }
- else
- {
- $profile_url = ($custom_profile_url !== false) ? $custom_profile_url . '&amp;u=' . (int) $user_id : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&amp;u=' . (int) $user_id);
+ $_base_profile_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&amp;u={USER_ID}');
}
+
+ $profile_url = ($custom_profile_url !== false) ? $custom_profile_url . '&amp;u=' . (int) $user_id : str_replace('={USER_ID}', '=' . (int) $user_id, $_base_profile_url);
+ $tpl = (!$username_colour) ? '<a href="{PROFILE_URL}">{USERNAME}</a>' : '<a href="{PROFILE_URL}" style="color: {USERNAME_COLOUR};" class="username-coloured">{USERNAME}</a>';
+ $_profile_cache[$cache_key]['full'] = str_replace(array('{PROFILE_URL}', '{USERNAME_COLOUR}', '{USERNAME}'), array($profile_url, $username_colour, $username), $tpl);
}
else
{
+ $tpl = (!$username_colour) ? '{USERNAME}' : '<span style="color: {USERNAME_COLOUR};" class="username-coloured">{USERNAME}</span>';
+ $_profile_cache[$cache_key]['full'] = str_replace(array('{USERNAME_COLOUR}', '{USERNAME}'), array($username_colour, $username), $tpl);
$profile_url = '';
}
- switch ($mode)
- {
- case 'profile':
- return $profile_url;
- break;
-
- case 'username':
- return $username;
- break;
-
- case 'colour':
- return $username_colour;
- break;
-
- case 'no_profile':
- case 'full':
- default:
-
- $tpl = '';
- if (!$profile_url && !$username_colour)
- {
- $tpl = '{USERNAME}';
- }
- else if (!$profile_url && $username_colour)
- {
- $tpl = '<span style="color: {USERNAME_COLOUR};" class="username-coloured">{USERNAME}</span>';
- }
- else if ($profile_url && !$username_colour)
- {
- $tpl = '<a href="{PROFILE_URL}">{USERNAME}</a>';
- }
- else if ($profile_url && $username_colour)
- {
- $tpl = '<a href="{PROFILE_URL}" style="color: {USERNAME_COLOUR};" class="username-coloured">{USERNAME}</a>';
- }
+ // Use the profile url from above
+ $_profile_cache[$cache_key]['profile'] = $profile_url;
- return str_replace(array('{PROFILE_URL}', '{USERNAME_COLOUR}', '{USERNAME}'), array($profile_url, $username_colour, $username), $tpl);
- break;
+ // If - by any chance - no_profile is called before any other mode, we need to do the calculation here
+ if ($mode == 'no_profile')
+ {
+ $tpl = (!$_profile_cache[$cache_key]['colour']) ? '{USERNAME}' : '<span style="color: {USERNAME_COLOUR};" class="username-coloured">{USERNAME}</span>';
+ return str_replace(array('{USERNAME_COLOUR}', '{USERNAME}'), array($_profile_cache[$cache_key]['colour'], $_profile_cache[$cache_key]['username']), $tpl);
}
+
+ return $_profile_cache[$cache_key][$mode];
}
/**
diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php
index 44bd0214fa..14ab079202 100644
--- a/phpBB/includes/functions_display.php
+++ b/phpBB/includes/functions_display.php
@@ -1150,6 +1150,7 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id,
* @param string &$rank_img the rank image as full img tag is stored here after execution
* @param string &$rank_img_src the rank image source is stored here after execution
*
+* Note: since we do not want to break backwards-compatibility, this function will only properly assign ranks to guests if you call it for them with user_posts == false
*/
function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank_img_src)
{
@@ -1167,7 +1168,7 @@ function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank
$rank_img = (!empty($ranks['special'][$user_rank]['rank_image'])) ? '<img src="' . $phpbb_root_path . $config['ranks_path'] . '/' . $ranks['special'][$user_rank]['rank_image'] . '" alt="' . $ranks['special'][$user_rank]['rank_title'] . '" title="' . $ranks['special'][$user_rank]['rank_title'] . '" />' : '';
$rank_img_src = (!empty($ranks['special'][$user_rank]['rank_image'])) ? $phpbb_root_path . $config['ranks_path'] . '/' . $ranks['special'][$user_rank]['rank_image'] : '';
}
- else
+ else if ($user_posts !== false)
{
if (!empty($ranks['normal']))
{
diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php
index b125a1586a..cbec2582a9 100644
--- a/phpBB/includes/functions_messenger.php
+++ b/phpBB/includes/functions_messenger.php
@@ -97,6 +97,12 @@ class messenger
*/
function im($address, $realname = '')
{
+ // IM-Addresses could be empty
+ if (!$address)
+ {
+ return;
+ }
+
$pos = isset($this->addresses['im']) ? sizeof($this->addresses['im']) : 0;
$this->addresses['im'][$pos]['uid'] = trim($address);
$this->addresses['im'][$pos]['name'] = trim($realname);
@@ -443,6 +449,11 @@ class messenger
return false;
}
+ if (empty($this->addresses['im']))
+ {
+ return false;
+ }
+
$use_queue = false;
if ($config['jab_package_size'] && $this->use_queue)
{
diff --git a/phpBB/includes/functions_module.php b/phpBB/includes/functions_module.php
index 3f1c6b39e2..d0e7c8cfc8 100644
--- a/phpBB/includes/functions_module.php
+++ b/phpBB/includes/functions_module.php
@@ -28,12 +28,48 @@ class p_master
var $p_mode;
var $p_parent;
+ var $include_path = false;
var $active_module = false;
var $active_module_row_id = false;
var $acl_forum_id = false;
var $module_ary = array();
/**
+ * Constuctor
+ * Set module include path
+ */
+ function p_master($include_path = false)
+ {
+ global $phpbb_root_path;
+
+ $this->include_path = ($include_path !== false) ? $include_path : $phpbb_root_path . 'includes/';
+
+ // Make sure the path ends with /
+ if (substr($this->include_path, -1) !== '/')
+ {
+ $this->include_path .= '/';
+ }
+ }
+
+ /**
+ * Set custom include path for modules
+ * Schema for inclusion is include_path . modulebase
+ *
+ * @param string $include_path include path to be used.
+ * @access public
+ */
+ function set_custom_include_path($include_path)
+ {
+ $this->include_path = $include_path;
+
+ // Make sure the path ends with /
+ if (substr($this->include_path, -1) !== '/')
+ {
+ $this->include_path .= '/';
+ }
+ }
+
+ /**
* List modules
*
* This creates a list, stored in $this->module_ary of all available
@@ -395,7 +431,7 @@ class p_master
{
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user;
- $module_path = $phpbb_root_path . 'includes/' . $this->p_class;
+ $module_path = $this->include_path . $this->p_class;
$icat = request_var('icat', '');
if ($this->active_module === false)
diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php
index 030ce72d7c..4d96fb9537 100644
--- a/phpBB/includes/functions_posting.php
+++ b/phpBB/includes/functions_posting.php
@@ -2137,10 +2137,20 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
// this post is the latest post in the forum, better update
if ($row['forum_last_post_id'] == $data['post_id'])
{
- if ($post_approved && $row['forum_last_post_subject'] !== $subject)
+ // If post approved and subject changed, or poster is anonymous, we need to update the forum_last* rows
+ if ($post_approved && ($row['forum_last_post_subject'] !== $subject || $data['poster_id'] == ANONYMOUS))
{
- // the only data that can really be changed is the post's subject
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_subject = \'' . $db->sql_escape($subject) . '\'';
+ // the post's subject changed
+ if ($row['forum_last_post_subject'] !== $subject)
+ {
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_subject = \'' . $db->sql_escape($subject) . '\'';
+ }
+
+ // Update the user name if poster is anonymous... just in case an admin changed it
+ if ($data['poster_id'] == ANONYMOUS)
+ {
+ $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape($username) . "'";
+ }
}
else if ($data['post_approved'] !== $post_approved)
{
@@ -2277,6 +2287,12 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
{
// only the subject can be changed from edit
$sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($subject) . "'";
+
+ // Maybe not only the subject, but also changing anonymous usernames. ;)
+ if ($data['poster_id'] == ANONYMOUS)
+ {
+ $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape($username) . "'";
+ }
}
}
else if (!$data['post_approved'] && ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || ($post_mode == 'edit_first_post' && !$data['topic_replies'])))
diff --git a/phpBB/includes/functions_profile_fields.php b/phpBB/includes/functions_profile_fields.php
index b621095df4..cc59648e54 100644
--- a/phpBB/includes/functions_profile_fields.php
+++ b/phpBB/includes/functions_profile_fields.php
@@ -40,14 +40,14 @@ class custom_profile
{
case 'register':
// If the field is required we show it on the registration page and do not show hidden fields
- $sql_where .= ' AND (f.field_show_on_reg = 1 OR f.field_required = 1) AND f.field_hide = 0';
+ $sql_where .= ' AND f.field_show_on_reg = 1 AND f.field_no_view = 0';
break;
case 'profile':
// Show hidden fields to moderators/admins
if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
{
- $sql_where .= ' AND f.field_hide = 0';
+ $sql_where .= ' AND f.field_show_profile = 1';
}
break;
@@ -106,7 +106,7 @@ class custom_profile
{
case FIELD_DATE:
$field_validate = explode('-', $field_value);
-
+
$day = (isset($field_validate[0])) ? (int) $field_validate[0] : 0;
$month = (isset($field_validate[1])) ? (int) $field_validate[1] : 0;
$year = (isset($field_validate[2])) ? (int) $field_validate[2] : 0;
@@ -154,14 +154,14 @@ class custom_profile
return 'FIELD_TOO_LARGE';
}
break;
-
+
case FIELD_DROPDOWN:
if ($field_value == $field_data['field_novalue'] && $field_data['field_required'])
{
return 'FIELD_REQUIRED';
}
break;
-
+
case FIELD_STRING:
case FIELD_TEXT:
if (empty($field_value) && !$field_data['field_required'])
@@ -205,7 +205,7 @@ class custom_profile
global $db, $user, $auth;
$this->profile_cache = array();
-
+
// Display hidden/no_view fields for admin/moderator
$sql = 'SELECT l.*, f.*
FROM ' . PROFILE_LANG_TABLE . ' l, ' . PROFILE_FIELDS_TABLE . ' f
@@ -234,7 +234,7 @@ class custom_profile
if ($preview)
{
$lang_options = (!is_array($this->vars['lang_options'])) ? explode("\n", $this->vars['lang_options']) : $this->vars['lang_options'];
-
+
foreach ($lang_options as $num => $var)
{
$this->options_lang[$field_id][$lang_id][($num + 1)] = $var;
@@ -271,14 +271,14 @@ class custom_profile
{
case 'register':
// If the field is required we show it on the registration page and do not show hidden fields
- $sql_where .= ' AND (f.field_show_on_reg = 1 OR f.field_required = 1) AND f.field_hide = 0';
+ $sql_where .= ' AND f.field_show_on_reg = 1 AND f.field_no_view = 0';
break;
case 'profile':
// Show hidden fields to moderators/admins
if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
{
- $sql_where .= ' AND f.field_hide = 0';
+ $sql_where .= ' AND f.field_show_profile = 1';
}
break;
@@ -316,12 +316,12 @@ class custom_profile
case 'FIELD_TOO_SMALL':
$error = sprintf($user->lang[$cp_result], $row['lang_name'], $row['field_minlen']);
break;
-
+
case 'FIELD_TOO_LONG':
case 'FIELD_TOO_LARGE':
$error = sprintf($user->lang[$cp_result], $row['lang_name'], $row['field_maxlen']);
break;
-
+
case 'FIELD_INVALID_CHARS':
switch ($row['field_validation'])
{
@@ -339,7 +339,7 @@ class custom_profile
}
break;
}
-
+
if ($error != '')
{
$cp_error[] = $error;
@@ -434,7 +434,7 @@ class custom_profile
'S_PROFILE_' . strtoupper($ident) => true
);
}
-
+
return $tpl_fields;
}
else
@@ -589,7 +589,7 @@ class custom_profile
else
{
$value = (isset($_REQUEST[$profile_row['field_ident']])) ? request_var($profile_row['field_ident'], $default_value, true) : ((!isset($user->profile_fields[$user_ident]) || $preview) ? $default_value : $user->profile_fields[$user_ident]);
-
+
if (gettype($value) == 'string')
{
$value = utf8_normalize_nfc($value);
@@ -672,7 +672,7 @@ class custom_profile
$profile_row['s_year_options'] .= '<option value="' . $i . '"' . (($i == $year) ? ' selected="selected"' : '') . ">$i</option>";
}
unset($now);
-
+
$profile_row['field_value'] = 0;
$template->assign_block_vars($this->profile_types[$profile_row['field_type']], array_change_key_case($profile_row, CASE_UPPER));
}
@@ -826,7 +826,7 @@ class custom_profile
$cp_data['pf_' . $row['field_ident']] = (in_array($row['field_type'], array(FIELD_TEXT, FIELD_STRING))) ? $row['lang_default_value'] : $row['field_default_value'];
}
$db->sql_freeresult($result);
-
+
return $cp_data;
}
@@ -838,9 +838,9 @@ class custom_profile
{
global $phpbb_root_path, $phpEx;
global $config;
-
+
$var_name = 'pf_' . $profile_row['field_ident'];
-
+
switch ($profile_row['field_type'])
{
case FIELD_DATE:
@@ -860,7 +860,7 @@ class custom_profile
$month = request_var($var_name . '_month', 0);
$year = request_var($var_name . '_year', 0);
}
-
+
$var = sprintf('%2d-%2d-%4d', $day, $month, $year);
break;
@@ -931,7 +931,7 @@ class custom_profile_admin extends custom_profile
return $validate_options;
}
-
+
/**
* Get string options for second step in ACP
*/
@@ -1086,4 +1086,4 @@ class custom_profile_admin extends custom_profile
}
}
-?> \ No newline at end of file
+?>
diff --git a/phpBB/includes/mcp/mcp_queue.php b/phpBB/includes/mcp/mcp_queue.php
index 1e368c4fc6..aa77dbdf16 100644
--- a/phpBB/includes/mcp/mcp_queue.php
+++ b/phpBB/includes/mcp/mcp_queue.php
@@ -505,8 +505,12 @@ function approve_post($post_id_list, $id, $mode)
$forum_id_list[$post_data['forum_id']] = 1;
}
- // User post update (we do not care about topic or post, since user posts are strictly connected to posts
- $user_posts_sql[$post_data['poster_id']] = (empty($user_posts_sql[$post_data['poster_id']])) ? 1 : $user_posts_sql[$post_data['poster_id']] + 1;
+ // User post update (we do not care about topic or post, since user posts are strictly connected to posts)
+ // But we care about forums where post counts get not increased. ;)
+ if ($post_data['post_postcount'])
+ {
+ $user_posts_sql[$post_data['poster_id']] = (empty($user_posts_sql[$post_data['poster_id']])) ? 1 : $user_posts_sql[$post_data['poster_id']] + 1;
+ }
// Topic or Post. ;)
if ($post_data['topic_first_post_id'] == $post_id)
diff --git a/phpBB/includes/search/fulltext_native.php b/phpBB/includes/search/fulltext_native.php
index 9bd3c81311..1c6a64d07c 100644
--- a/phpBB/includes/search/fulltext_native.php
+++ b/phpBB/includes/search/fulltext_native.php
@@ -455,6 +455,7 @@ class fulltext_native extends search_backend
);
$title_match = '';
+ $left_join_topics = false;
$group_by = true;
// Build some display specific sql strings
switch ($fields)
@@ -464,7 +465,7 @@ class fulltext_native extends search_backend
$group_by = false;
// no break
case 'firstpost':
- $sql_array['FROM'][TOPICS_TABLE] = 't';
+ $left_join_topics = true;
$sql_where[] = 'p.post_id = t.topic_first_post_id';
break;
@@ -476,11 +477,7 @@ class fulltext_native extends search_backend
if ($type == 'topics')
{
- if (!isset($sql_array['FROM'][TOPICS_TABLE]))
- {
- $sql_array['FROM'][TOPICS_TABLE] = 't';
- $sql_where[] = 'p.topic_id = t.topic_id';
- }
+ $left_join_topics = true;
$group_by = true;
}
@@ -688,11 +685,7 @@ class fulltext_native extends search_backend
break;
case 't':
- if (!isset($sql_array['FROM'][TOPICS_TABLE]))
- {
- $sql_array['FROM'][TOPICS_TABLE] = 't';
- $sql_where[] = 'p.topic_id = t.topic_id';
- }
+ $left_join_topics = true;
break;
case 'f':
@@ -700,6 +693,14 @@ class fulltext_native extends search_backend
$sql_where[] = 'f.forum_id = p.forum_id';
break;
}
+
+ if ($left_join_topics)
+ {
+ $sql_array['LEFT_JOIN'][$left_join_topics] = array(
+ 'FROM' => array(TOPICS_TABLE => 't'),
+ 'ON' => 'p.topic_id = t.topic_id'
+ );
+ }
$sql_array['WHERE'] = implode(' AND ', $sql_where);
$sql_array['GROUP_BY'] = ($group_by) ? (($type == 'posts') ? 'p.post_id' : 'p.topic_id') . ', ' . $sort_by_sql[$sort_key] : '';
@@ -1674,7 +1675,7 @@ class fulltext_native extends search_backend
</dl>
<dl>
<dt><label for="fulltext_native_common_thres">' . $user->lang['COMMON_WORD_THRESHOLD'] . ':</label><br /><span>' . $user->lang['COMMON_WORD_THRESHOLD_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_native_common_thres" type="text" size="3" maxlength="3" name="config[fulltext_native_common_thres]" value="' . (int) $config['fulltext_native_common_thres'] . '" /> %</dd>
+ <dd><input id="fulltext_native_common_thres" type="text" size="3" maxlength="3" name="config[fulltext_native_common_thres]" value="' . (double) $config['fulltext_native_common_thres'] . '" /> %</dd>
</dl>
';
diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php
index 2e697f6359..c7d287181b 100644
--- a/phpBB/includes/session.php
+++ b/phpBB/includes/session.php
@@ -1851,22 +1851,36 @@ class user extends session
$args = func_get_args();
$key = $args[0];
+ if (is_array($key))
+ {
+ $lang = &$this->lang[array_shift($key)];
+
+ foreach ($key as $_key)
+ {
+ $lang = &$lang[$_key];
+ }
+ }
+ else
+ {
+ $lang = &$this->lang[$key];
+ }
+
// Return if language string does not exist
- if (!isset($this->lang[$key]) || (!is_string($this->lang[$key]) && !is_array($this->lang[$key])))
+ if (!isset($lang) || (!is_string($lang) && !is_array($lang)))
{
return $key;
}
// If the language entry is a string, we simply mimic sprintf() behaviour
- if (is_string($this->lang[$key]))
+ if (is_string($lang))
{
if (sizeof($args) == 1)
{
- return $this->lang[$key];
+ return $lang;
}
// Replace key with language entry and simply pass along...
- $args[0] = $this->lang[$key];
+ $args[0] = $lang;
return call_user_func_array('sprintf', $args);
}
@@ -1878,7 +1892,7 @@ class user extends session
{
if (is_int($args[$i]))
{
- $numbers = array_keys($this->lang[$key]);
+ $numbers = array_keys($lang);
foreach ($numbers as $num)
{
@@ -1895,12 +1909,12 @@ class user extends session
// Ok, let's check if the key was found, else use the last entry (because it is mostly the plural form)
if ($key_found === false)
{
- $numbers = array_keys($this->lang[$key]);
+ $numbers = array_keys($lang);
$key_found = end($numbers);
}
// Use the language string we determined and pass it to sprintf()
- $args[0] = $this->lang[$key][$key_found];
+ $args[0] = $lang[$key_found];
return call_user_func_array('sprintf', $args);
}
@@ -2001,50 +2015,77 @@ class user extends session
/**
* Format user date
+ *
+ * @param int $gmepoch unix timestamp
+ * @param string $format date format in date() notation. | used to indicate relative dates, for example |d m Y|, h:i is translated to Today, h:i.
+ * @param bool $forcedate force non-relative date format.
+ *
+ * @return mixed translated date
*/
function format_date($gmepoch, $format = false, $forcedate = false)
{
static $midnight;
+ static $date_cache;
- $lang_dates = $this->lang['datetime'];
$format = (!$format) ? $this->date_format : $format;
+ $now = time();
+ $delta = $now - $gmepoch;
+
+ if (!isset($date_cache[$format]))
+ {
+ // Is the user requesting a friendly date format (i.e. 'Today 12:42')?
+ $date_cache[$format] = array(
+ 'is_short' => strpos($format, '|'),
+ 'zone_offset' => $this->timezone + $this->dst,
+ 'format_short' => substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1),
+ 'format_long' => str_replace('|', '', $format),
+ 'lang' => $this->lang['datetime'],
+ );
- // Short representation of month in format
- if ((strpos($format, '\M') === false && strpos($format, 'M') !== false) || (strpos($format, '\r') === false && strpos($format, 'r') !== false))
- {
- $lang_dates['May'] = $lang_dates['May_short'];
+ // Short representation of month in format? Some languages use different terms for the long and short format of May
+ if ((strpos($format, '\M') === false && strpos($format, 'M') !== false) || (strpos($format, '\r') === false && strpos($format, 'r') !== false))
+ {
+ $date_cache[$format]['lang']['May'] = $this->lang['datetime']['May_short'];
+ }
}
- unset($lang_dates['May_short']);
-
- if (!$midnight)
+ // Show date <= 1 hour ago as 'xx min ago'
+ // A small tolerence is given for times in the future and times in the future but in the same minute are displayed as '< than a minute ago'
+ if ($delta <= 3600 && ($delta >= -5 || (($now / 60) % 60) == (($gmepoch / 60) % 60)) && $date_cache[$format]['is_short'] !== false && !$forcedate && isset($this->lang['datetime']['AGO']))
{
- list($d, $m, $y) = explode(' ', gmdate('j n Y', time() + $this->timezone + $this->dst));
- $midnight = gmmktime(0, 0, 0, $m, $d, $y) - $this->timezone - $this->dst;
+ return $this->lang(array('datetime', 'AGO'), max(0, (int) floor($delta / 60)));
}
- if (strpos($format, '|') === false || ($gmepoch < $midnight - 86400 && !$forcedate) || ($gmepoch > $midnight + 172800 && !$forcedate))
+ if (!$midnight)
{
- return strtr(@gmdate(str_replace('|', '', $format), $gmepoch + $this->timezone + $this->dst), $lang_dates);
+ list($d, $m, $y) = explode(' ', gmdate('j n Y', time() + $date_cache[$format]['zone_offset']));
+ $midnight = gmmktime(0, 0, 0, $m, $d, $y) - $date_cache[$format]['zone_offset'];
}
- if ($gmepoch > $midnight + 86400 && !$forcedate)
- {
- $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1);
- return str_replace('||', $this->lang['datetime']['TOMORROW'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates));
- }
- else if ($gmepoch > $midnight && !$forcedate)
+ if ($date_cache[$format]['is_short'] !== false && !$forcedate)
{
- $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1);
- return str_replace('||', $this->lang['datetime']['TODAY'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates));
- }
- else if ($gmepoch > $midnight - 86400 && !$forcedate)
- {
- $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1);
- return str_replace('||', $this->lang['datetime']['YESTERDAY'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates));
+ $day = false;
+
+ if ($gmepoch > $midnight + 86400)
+ {
+ $day = 'TOMORROW';
+ }
+ else if ($gmepoch > $midnight)
+ {
+ $day = 'TODAY';
+ }
+ else if ($gmepoch > $midnight - 86400)
+ {
+ $day = 'YESTERDAY';
+ }
+
+ if ($day !== false)
+ {
+ return str_replace('||', $this->lang['datetime'][$day], strtr(@gmdate($date_cache[$format]['format_short'], $gmepoch + $date_cache[$format]['zone_offset']), $date_cache[$format]['lang']));
+ }
}
- return strtr(@gmdate(str_replace('|', '', $format), $gmepoch + $this->timezone + $this->dst), $lang_dates);
+ return strtr(@gmdate($date_cache[$format]['format_long'], $gmepoch + $date_cache[$format]['zone_offset']), $date_cache[$format]['lang']);
}
/**
diff --git a/phpBB/includes/ucp/ucp_activate.php b/phpBB/includes/ucp/ucp_activate.php
index 7de2511423..ad9dcc3659 100644
--- a/phpBB/includes/ucp/ucp_activate.php
+++ b/phpBB/includes/ucp/ucp_activate.php
@@ -51,7 +51,7 @@ class ucp_activate
trigger_error('ALREADY_ACTIVATED');
}
- if ($user_row['user_actkey'] != $key)
+ if (($user_row['user_inactive_reason'] == INACTIVE_MANUAL) || $user_row['user_actkey'] != $key)
{
trigger_error('WRONG_ACTIVATION');
}
diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php
index 32d24337c9..db3dbc5cac 100644
--- a/phpBB/includes/ucp/ucp_groups.php
+++ b/phpBB/includes/ucp/ucp_groups.php
@@ -414,6 +414,9 @@ class ucp_groups
$this->page_title = 'UCP_USERGROUPS_MANAGE';
$action = (isset($_POST['addusers'])) ? 'addusers' : request_var('action', '');
$group_id = request_var('g', 0);
+
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+
add_form_key('ucp_groups');
if ($group_id)
@@ -438,6 +441,7 @@ class ucp_groups
$group_name = $group_row['group_name'];
$group_type = $group_row['group_type'];
+
$avatar_img = (!empty($group_row['group_avatar'])) ? get_user_avatar($group_row['group_avatar'], $group_row['group_avatar_type'], $group_row['group_avatar_width'], $group_row['group_avatar_height'], 'GROUP_AVATAR') : '<img src="' . $phpbb_root_path . 'adm/images/no_avatar.gif" alt="" />';
$template->assign_vars(array(
@@ -458,8 +462,6 @@ class ucp_groups
{
case 'edit':
- include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
-
if (!$group_id)
{
trigger_error($user->lang['NO_GROUP'] . $return_page);
diff --git a/phpBB/includes/ucp/ucp_main.php b/phpBB/includes/ucp/ucp_main.php
index 73e4af8b04..6f4e525b2f 100644
--- a/phpBB/includes/ucp/ucp_main.php
+++ b/phpBB/includes/ucp/ucp_main.php
@@ -25,7 +25,7 @@ class ucp_main
{
var $p_master;
var $u_action;
-
+
function ucp_main(&$p_master)
{
$this->p_master = &$p_master;
@@ -70,7 +70,7 @@ class ucp_main
$sql = 'SELECT forum_id
FROM ' . FORUMS_TABLE . '
WHERE forum_type = ' . FORUM_POST;
-
+
if (sizeof($forum_ary))
{
$sql .= ' AND ' . $db->sql_in_set('forum_id', $forum_ary, true);
@@ -258,7 +258,7 @@ class ucp_main
{
$forbidden_forums = $auth->acl_getf('!f_read', true);
$forbidden_forums = array_unique(array_keys($forbidden_forums));
-
+
$sql_array = array(
'SELECT' => 'f.*',
@@ -339,6 +339,7 @@ class ucp_main
'FORUM_IMAGE' => ($row['forum_image']) ? '<img src="' . $phpbb_root_path . $row['forum_image'] . '" alt="' . $user->lang[$folder_alt] . '" />' : '',
'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '',
'FORUM_NAME' => $row['forum_name'],
+ 'FORUM_DESC' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']),
'LAST_POST_SUBJECT' => $row['forum_last_post_subject'],
'LAST_POST_TIME' => $last_post_time,
@@ -420,7 +421,7 @@ class ucp_main
}
$forbidden_forums = $auth->acl_getf('!f_read', true);
$forbidden_forums = array_unique(array_keys($forbidden_forums));
-
+
$this->assign_topiclist('bookmarks', $forbidden_forums);
break;
@@ -676,7 +677,7 @@ class ucp_main
'WHERE' => 'tw.user_id = ' . $user->data['user_id'] . '
AND t.topic_id = tw.topic_id
AND ' . $db->sql_in_set('t.forum_id', $forbidden_forum_ary, true, true),
-
+
'ORDER_BY' => 't.topic_last_post_time DESC'
);
diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php
index 060baaefa0..d451e25be4 100644
--- a/phpBB/includes/ucp/ucp_pm_compose.php
+++ b/phpBB/includes/ucp/ucp_pm_compose.php
@@ -259,6 +259,25 @@ function compose_pm($id, $mode, $action)
{
trigger_error('NOT_AUTHORISED');
}
+
+ // Passworded forum?
+ if ($post['forum_id'])
+ {
+ $sql = 'SELECT forum_password
+ FROM ' . FORUMS_TABLE . '
+ WHERE forum_id = ' . (int) $post['forum_id'];
+ $result = $db->sql_query($sql);
+ $forum_password = (string) $db->sql_fetchfield('forum_password');
+ $db->sql_freeresult($result);
+
+ if ($forum_password)
+ {
+ login_forum_box(array(
+ 'forum_id' => $post['forum_id'],
+ 'forum_password' => $forum_password,
+ ));
+ }
+ }
}
$msg_id = (int) $post['msg_id'];
@@ -424,7 +443,9 @@ function compose_pm($id, $mode, $action)
{
// We try to include every previously listed member from the TO Header
$list = rebuild_header(array('to' => $post['to_address']));
- $list = $list['u'];
+
+ // Can be an empty array too ;)
+ $list = (!empty($list['u'])) ? $list['u'] : array();
$list[$post['author_id']] = 'to';
if (isset($list[$user->data['user_id']]))
diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php
index 3f109b0771..bdd0e44ea8 100644
--- a/phpBB/includes/ucp/ucp_pm_viewmessage.php
+++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php
@@ -83,7 +83,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
if ($message_row['message_edit_count'] && $config['display_last_edited'])
{
$l_edit_time_total = ($message_row['message_edit_count'] == 1) ? $user->lang['EDITED_TIME_TOTAL'] : $user->lang['EDITED_TIMES_TOTAL'];
- $l_edited_by = '<br /><br />' . sprintf($l_edit_time_total, (!$message_row['message_edit_user']) ? $message_row['username'] : $message_row['message_edit_user'], $user->format_date($message_row['message_edit_time']), $message_row['message_edit_count']);
+ $l_edited_by = '<br /><br />' . sprintf($l_edit_time_total, (!$message_row['message_edit_user']) ? $message_row['username'] : $message_row['message_edit_user'], $user->format_date($message_row['message_edit_time'], false, true), $message_row['message_edit_count']);
}
else
{
@@ -221,7 +221,7 @@ 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)),
'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_pm_forward')) ? "$url&amp;mode=compose&amp;action=forward&amp;f=$folder_id&amp;p=" . $message_row['msg_id'] : '')
+ '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 not already displayed Attachments for this post, we already parsed them. ;)