diff options
Diffstat (limited to 'phpBB/includes')
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 . "&action=$action&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) ? '&' : '&'; - $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) ? '&' : '&'); + 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) ? '&' : '&'; + $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('&', '&', $url); // For XHTML compatibility we change back & to & 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 &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 . '&u=' . (int) $user_id : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . (int) $user_id); + $_base_profile_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u={USER_ID}'); } + + $profile_url = ($custom_profile_url !== false) ? $custom_profile_url . '&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&f=$folder_id&p=" . $message_row['msg_id'] . "&view=print" : '', - 'U_FORWARD_PM' => ($config['forward_pm'] && $auth->acl_get('u_pm_forward')) ? "$url&mode=compose&action=forward&f=$folder_id&p=" . $message_row['msg_id'] : '') + 'U_FORWARD_PM' => ($config['forward_pm'] && $auth->acl_get('u_sendpm') && $auth->acl_get('u_pm_forward')) ? "$url&mode=compose&action=forward&f=$folder_id&p=" . $message_row['msg_id'] : '') ); // Display not already displayed Attachments for this post, we already parsed them. ;) |
