mirror of
https://github.com/phpbb/phpbb.git
synced 2025-06-28 14:18:52 +00:00
Ok, so finally we have the code to update clean usernames from RC3 :D Updating code is really a pain as all functions are the buggy old versions :(
Our new method of finding clean usernames also fixes Bug #12143 git-svn-id: file:///svn/phpbb/trunk@7923 89ea8834-ac86-4346-8a33-228a782c2dd0
This commit is contained in:
parent
9350d33230
commit
0b9dab3ff6
3 changed files with 1051 additions and 4 deletions
File diff suppressed because one or more lines are too long
|
@ -84,6 +84,8 @@ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false);
|
|||
// We do not need this any longer, unset for safety purposes
|
||||
unset($dbpasswd);
|
||||
|
||||
$user->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '';
|
||||
|
||||
$sql = "SELECT config_value
|
||||
FROM " . CONFIG_TABLE . "
|
||||
WHERE config_name = 'default_lang'";
|
||||
|
@ -486,6 +488,377 @@ else
|
|||
$db->sql_query('DELETE FROM ' . CONFIG_TABLE . " WHERE config_name = 'version_update_from'");
|
||||
}
|
||||
|
||||
// Checks/Operations that have to be completed prior to starting the update itself
|
||||
$exit = false;
|
||||
if (version_compare($current_version, '3.0.RC3', '<='))
|
||||
{
|
||||
$submit = (isset($_POST['resolve_conflicts'])) ? true : false;
|
||||
$modify_users = request_var('modify_users', array(0 => ''));
|
||||
$new_usernames = request_var('new_usernames', array(0 => ''), true);
|
||||
|
||||
// the admin decided to change some usernames
|
||||
if (sizeof($modify_users) && $submit)
|
||||
{
|
||||
$sql = 'SELECT user_id, username, user_type
|
||||
FROM ' . USERS_TABLE . '
|
||||
WHERE ' . $db->sql_in_set('user_id', array_keys($modify_users));
|
||||
$result = $db->sql_query($sql);
|
||||
|
||||
$users = 0;
|
||||
while ($row = $db->sql_fetchrow())
|
||||
{
|
||||
$users++;
|
||||
$user_id = (int) $row['user_id'];
|
||||
|
||||
if (isset($modify_users[$user_id]))
|
||||
{
|
||||
$row['action'] = $modify_users[$user_id];
|
||||
$modify_users[$user_id] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
// only if all ids really existed
|
||||
if (sizeof($modify_users) == $users)
|
||||
{
|
||||
$user->data['user_id'] = ANONYMOUS;
|
||||
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
|
||||
foreach ($modify_users as $user_id => $row)
|
||||
{
|
||||
switch ($row['action'])
|
||||
{
|
||||
case 'edit':
|
||||
if (isset($new_usernames[$user_id]))
|
||||
{
|
||||
$data = array('username' => utf8_normalize_nfc($new_usernames[$user_id]));
|
||||
// Need to update config, forum, topic, posting, messages, etc.
|
||||
if ($data['username'] != $row['username'])
|
||||
{
|
||||
$check_ary = array('username' => array(
|
||||
array('string', false, $config['min_name_chars'], $config['max_name_chars']),
|
||||
array('username'),
|
||||
));
|
||||
// need a little trick for this to work properly
|
||||
$user->data['username_clean'] = utf8_clean_string($data['username']) . 'a';
|
||||
$errors = validate_data($data, $check_ary);
|
||||
|
||||
if ($errors)
|
||||
{
|
||||
include($phpbb_root_path . 'language/' . $language . '/ucp.' . $phpEx);
|
||||
echo '<div class="errorbox">';
|
||||
foreach ($errors as $error)
|
||||
{
|
||||
echo '<p>' . $lang[$error] . '</p>';
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
if (!$errors)
|
||||
{
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET ' . $db->sql_build_array('UPDATE', array(
|
||||
'username' => $data['username'],
|
||||
'username_clean' => utf8_clean_string($data['username'])
|
||||
)) . '
|
||||
WHERE user_id = ' . $user_id;
|
||||
$db->sql_query($sql);
|
||||
|
||||
add_log('user', $user_id, 'LOG_USER_UPDATE_NAME', $row['username'], $data['username']);
|
||||
user_update_name($row['username'], $data['username']);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'delete_retain':
|
||||
case 'delete_remove':
|
||||
if ($user_id != ANONYMOUS && $row['user_type'] != USER_FOUNDER)
|
||||
{
|
||||
user_delete(substr($row['action'], 7), $user_id, $row['username']);
|
||||
add_log('admin', 'LOG_USER_DELETED', $row['username']);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// after RC3 a different utf8_clean_string function is used, this requires that
|
||||
// the unique column username_clean is recalculated, during this recalculation
|
||||
// duplicates might be created. Since the column has to be unique such usernames
|
||||
// must not exist. We need identify them and let the admin decide what to do
|
||||
// about them.
|
||||
$sql = 'SELECT user_id, username, username_clean
|
||||
FROM ' . USERS_TABLE;
|
||||
$result = $db->sql_query($sql);
|
||||
|
||||
$colliding_users = $found_names = array();
|
||||
while ($row = $db->sql_fetchrow($result))
|
||||
{
|
||||
// Calculate the new clean name. If it differs from the old one we need
|
||||
// to make sure there is no collision
|
||||
$clean_name = utf8_new_clean_string($row['username']);
|
||||
if ($clean_name != $row['username_clean'])
|
||||
{
|
||||
$user_id = (int) $row['user_id'];
|
||||
|
||||
// If this clean name was not the result of another user already ...
|
||||
if (!isset($found_names[$clean_name]))
|
||||
{
|
||||
// then we need to figure out whether there are any other users
|
||||
// who already had this clean name with the old version
|
||||
$sql = 'SELECT user_id, username
|
||||
FROM ' . USERS_TABLE . '
|
||||
WHERE username_clean = \'' . $db->sql_escape($clean_name) . '\'';
|
||||
$result = $db->sql_query($sql);
|
||||
|
||||
$user_ids = array($user_id);
|
||||
while ($row = $db->sql_fetchrow())
|
||||
{
|
||||
// Make sure this clean name will still be the same with the
|
||||
// new function. If it is, then we have to add it to the list
|
||||
// of user ids for this clean name
|
||||
if (utf8_new_clean_string($row['username']) == $clean_name)
|
||||
{
|
||||
$user_ids[] = (int) $row['user_id'];
|
||||
}
|
||||
}
|
||||
$db->sql_freeresult();
|
||||
|
||||
// if we already found a collision save it
|
||||
if (sizeof($user_ids) > 1)
|
||||
{
|
||||
$colliding_users[$clean_name] = $user_ids;
|
||||
$found_names[$clean_name] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise just mark this name as found
|
||||
$found_names[$clean_name] = $user_id;
|
||||
}
|
||||
}
|
||||
// Else, if we already found the username
|
||||
else
|
||||
{
|
||||
// If the value in the found_names lookup table is only true ...
|
||||
if ($found_names[$clean_name] === true)
|
||||
{
|
||||
// then the actual data was already added to $colliding_users
|
||||
// and we only need to append the user_id
|
||||
$colliding_users[$clean_name][] = $user_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise it still keeps the first user_id for this name
|
||||
// and we need to move the data to $colliding_users, and set
|
||||
// the value in the found_names lookup table to true, so
|
||||
// following users will directly be appended to $colliding_users
|
||||
$colliding_users[$clean_name] = array($found_names[$clean_name], $user_id);
|
||||
$found_names[$clean_name] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($found_names);
|
||||
$db->sql_freeresult($result);
|
||||
|
||||
// now retrieve all information about the users and let the admin decide what to do
|
||||
if (sizeof($colliding_users))
|
||||
{
|
||||
$exit = true;
|
||||
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
|
||||
include($phpbb_root_path . 'language/' . $language . '/memberlist.' . $phpEx);
|
||||
include($phpbb_root_path . 'language/' . $language . '/acp/users.' . $phpEx);
|
||||
|
||||
// link a few things to the correct place so we don't get any problems
|
||||
$user->lang = &$lang;
|
||||
$user->data['user_id'] = ANONYMOUS;
|
||||
$user->date_format = $config['default_dateformat'];
|
||||
|
||||
// a little trick to get all user_ids
|
||||
$user_ids = call_user_func_array('array_merge', array_values($colliding_users));
|
||||
|
||||
$sql = 'SELECT session_user_id, MAX(session_time) AS session_time
|
||||
FROM ' . SESSIONS_TABLE . '
|
||||
WHERE session_time >= ' . (time() - $config['session_length']) . '
|
||||
AND ' . $db->sql_in_set('session_user_id', $user_ids) . '
|
||||
GROUP BY session_user_id';
|
||||
$result = $db->sql_query($sql);
|
||||
|
||||
$session_times = array();
|
||||
while ($row = $db->sql_fetchrow($result))
|
||||
{
|
||||
$session_times[$row['session_user_id']] = $row['session_time'];
|
||||
}
|
||||
$db->sql_freeresult($result);
|
||||
|
||||
$sql = 'SELECT *
|
||||
FROM ' . USERS_TABLE . '
|
||||
WHERE ' . $db->sql_in_set('user_id', $user_ids);
|
||||
$result = $db->sql_query($sql);
|
||||
|
||||
$users = array();
|
||||
while ($row = $db->sql_fetchrow($result))
|
||||
{
|
||||
if (isset($session_times[$row['user_id']]))
|
||||
{
|
||||
$row['session_time'] = $session_times[$row['user_id']];
|
||||
}
|
||||
else
|
||||
{
|
||||
$row['session_time'] = 0;
|
||||
}
|
||||
$users[(int) $row['user_id']] = $row;
|
||||
}
|
||||
$db->sql_freeresult($result);
|
||||
unset($session_times);
|
||||
|
||||
// now display a table with all users, some information about them and options
|
||||
// for the admin: keep name, change name (with text input) or delete user
|
||||
$u_action = "database_update.$phpEx?language=$language&type=$inline_update";
|
||||
?>
|
||||
<p><?php echo $lang['CHANGE_CLEAN_NAMES']; ?></p>
|
||||
<form id="change_clean_names" method="post" action="<?php echo $u_action; ?>">
|
||||
|
||||
|
||||
<?php
|
||||
foreach ($colliding_users as $clean_name => $user_ids)
|
||||
{
|
||||
?>
|
||||
<fieldset class="tabulated">
|
||||
<table>
|
||||
<caption><?php echo sprintf($lang['COLLIDING_CLEAN_USERNAME'], $clean_name); ?></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo $lang['RANK']; ?> <?php echo $lang['USERNAME']; ?></th>
|
||||
<th><?php echo $lang['POSTS']; ?></th>
|
||||
<th><?php echo $lang['INFORMATION']; ?></th>
|
||||
<th><?php echo $lang['JOINED']; ?></th>
|
||||
<th><?php echo $lang['LAST_ACTIVE']; ?></th>
|
||||
<th><?php echo $lang['ACTION']; ?></th>
|
||||
<th><?php echo $lang['NEW_USERNAME']; ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ($user_ids as $i => $user_id)
|
||||
{
|
||||
$row = $users[$user_id];
|
||||
|
||||
$rank_title = $rank_img = '';
|
||||
get_user_rank($row['user_rank'], $row['user_posts'], $rank_title, $rank_img, $rank_img_src);
|
||||
|
||||
$last_visit = (!empty($row['session_time'])) ? $row['session_time'] : $row['user_lastvisit'];
|
||||
|
||||
$info = '';
|
||||
switch ($row['user_type'])
|
||||
{
|
||||
case USER_INACTIVE:
|
||||
$info .= $lang['USER_INACTIVE'];
|
||||
break;
|
||||
|
||||
case USER_IGNORE:
|
||||
$info .= $lang['BOT'];
|
||||
break;
|
||||
|
||||
case USER_FOUNDER:
|
||||
$info .= $lang['FOUNDER'];
|
||||
break;
|
||||
|
||||
default:
|
||||
$info .= $lang['USER_ACTIVE'];
|
||||
}
|
||||
|
||||
if ($user_id == ANONYMOUS)
|
||||
{
|
||||
$info = $lang['GUEST'];
|
||||
}
|
||||
?>
|
||||
<tr class="bg<?php echo ($i % 2) + 1; ?>">
|
||||
<td>
|
||||
<span class="rank-img"><?php echo ($rank_img) ? $rank_img : $rank_title; ?></span>
|
||||
<?php echo get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']); ?>
|
||||
</td>
|
||||
<td class="posts"><?php echo $row['user_posts']; ?></td>
|
||||
<td class="info"><?php echo $info; ?></td>
|
||||
<td><?php echo $user->format_date($row['user_regdate']) ?></td>
|
||||
<td><?php echo (empty($last_visit)) ? ' - ' : $user->format_date($last_visit); ?> </td>
|
||||
<td>
|
||||
<label><input type="radio" class="radio" id="keep_user_<?php echo $user_id; ?>" name="modify_users[<?php echo $user_id; ?>]" value="keep" checked="checked" /> <?php echo $lang['KEEP_OLD_NAME']; ?></label><br />
|
||||
<label><input type="radio" class="radio" id="edit_user_<?php echo $user_id; ?>" name="modify_users[<?php echo $user_id; ?>]" value="edit" /> <?php echo $lang['EDIT_USERNAME']; ?></label><br />
|
||||
<?php
|
||||
// some users must not be deleted
|
||||
if ($user_id != ANONYMOUS && $row['user_type'] != USER_FOUNDER)
|
||||
{
|
||||
?>
|
||||
<label><input type="radio" class="radio" id="delete_user_retain_<?php echo $user_id; ?>" name="modify_users[<?php echo $user_id; ?>]" value="delete_retain" /> <?php echo $lang['DELETE_USER_RETAIN']; ?></label><br />
|
||||
<label><input type="radio" class="radio" id="delete_user_remove_<?php echo $user_id; ?>" name="modify_users[<?php echo $user_id; ?>]" value="delete_remove" /> <?php echo $lang['DELETE_USER_REMOVE']; ?></label>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<input id="new_username_<?php echo $user_id; ?>" type="text" name="new_usernames[<?php echo $user_id; ?>]" value="<?php echo $row['username']; ?>" />
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<p class="quick">
|
||||
<input class="button2" id="resolve_conflicts" type="submit" name="resolve_conflicts" value="<?php echo $lang['SUBMIT']; ?>" />
|
||||
</p>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql = 'SELECT user_id, username, username_clean
|
||||
FROM ' . USERS_TABLE;
|
||||
$result = $db->sql_query($sql);
|
||||
|
||||
while ($row = $db->sql_fetchrow($result))
|
||||
{
|
||||
$clean_name = utf8_new_clean_string($row['username']);
|
||||
if ($clean_name != $row['username_clean'])
|
||||
{
|
||||
$sql = 'UPDATE ' . USERS_TABLE . '
|
||||
SET username_clean = \'' . $db->sql_escape($clean_name) . '\'
|
||||
WHERE user_id = ' . (int) $row['user_id'];
|
||||
$db->sql_query($sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($colliding_users);
|
||||
}
|
||||
|
||||
if ($exit)
|
||||
{
|
||||
?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<span class="corners-bottom"><span></span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="page-footer">
|
||||
Powered by phpBB © 2000, 2002, 2005, 2007 <a href="http://www.phpbb.com/">phpBB Group</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<?php
|
||||
exit;
|
||||
}
|
||||
|
||||
// Schema updates
|
||||
?>
|
||||
</p><br /><br />
|
||||
|
@ -876,8 +1249,6 @@ else
|
|||
}
|
||||
|
||||
// Add database update to log
|
||||
|
||||
$user->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '';
|
||||
add_log('admin', 'LOG_UPDATE_DATABASE', $orig_version, $updates_to_version);
|
||||
|
||||
// Now we purge the session table as well as all cache files
|
||||
|
@ -1984,4 +2355,38 @@ function sql_column_change($dbms, $table_name, $column_name, $column_data)
|
|||
}
|
||||
}
|
||||
|
||||
function utf8_new_clean_string($text)
|
||||
{
|
||||
static $homographs = array();
|
||||
static $utf8_case_fold_nfkc = '';
|
||||
if (empty($homographs))
|
||||
{
|
||||
global $phpbb_root_path, $phpEx;
|
||||
if (!function_exists('utf8_case_fold_nfkc') || !file_exists($phpbb_root_path . 'includes/utf/data/confusables.' . $phpEx))
|
||||
{
|
||||
if (!file_exists($phpbb_root_path . 'install/data/confusables.' . $phpEx))
|
||||
{
|
||||
global $lang;
|
||||
trigger_error(sprintf($lang['UPDATE_REQUIRES_FILE'], $phpbb_root_path . 'install/data/confusables.' . $phpEx), E_USER_ERROR);
|
||||
}
|
||||
$homographs = include($phpbb_root_path . 'install/data/confusables.' . $phpEx);
|
||||
$utf8_case_fold_nfkc = 'utf8_new_case_fold_nfkc';
|
||||
}
|
||||
else
|
||||
{
|
||||
$homographs = include($phpbb_root_path . 'includes/utf/data/confusables.' . $phpEx);
|
||||
$utf8_case_fold_nfkc = 'utf8_case_fold_nfkc';
|
||||
}
|
||||
}
|
||||
|
||||
$text = $utf8_case_fold_nfkc($text);
|
||||
$text = strtr($text, $homographs);
|
||||
// Other control characters
|
||||
$text = preg_replace('#(?:[\x00-\x1F\x7F]+|(?:\xC2[\x80-\x9F])+)#', '', $text);
|
||||
|
||||
// we can use trim here as all the other space characters should have been turned
|
||||
// into normal ASCII spaces by now
|
||||
return trim($text);
|
||||
}
|
||||
|
||||
?>
|
|
@ -360,7 +360,9 @@ $lang = array_merge($lang, array(
|
|||
|
||||
'BACK' => 'Back',
|
||||
'BINARY_FILE' => 'Binary file',
|
||||
'BOT' => 'Spider/Robot',
|
||||
|
||||
'CHANGE_CLEAN_NAMES' => 'The method used to make sure a username is not used by multiple users has been changed. There are some users which have the same name when compared with the new method. You have to delete or rename these users to make sure that each name is only used by one user before you can proceed.',
|
||||
'CHECK_FILES' => 'Check files',
|
||||
'CHECK_FILES_AGAIN' => 'Check files again',
|
||||
'CHECK_FILES_EXPLAIN' => 'Within the next step all files will be checked against the update files - this can take a while if this is the first file check.',
|
||||
|
@ -375,6 +377,8 @@ $lang = array_merge($lang, array(
|
|||
|
||||
'DATABASE_TYPE' => 'Database type',
|
||||
'DATABASE_UPDATE_INFO_OLD' => 'The database update file within the install directory is outdated. Please make sure you uploaded the correct version of the file.',
|
||||
'DELETE_USER_REMOVE' => 'Delete user and remove posts',
|
||||
'DELETE_USER_RETAIN' => 'Delete user but keep posts',
|
||||
'DESTINATION' => 'Destination file',
|
||||
'DIFF_INLINE' => 'Inline',
|
||||
'DIFF_RAW' => 'Raw unified diff',
|
||||
|
@ -388,7 +392,8 @@ $lang = array_merge($lang, array(
|
|||
'DOWNLOAD_UPDATE_METHOD' => 'Download modified files archive',
|
||||
'DOWNLOAD_UPDATE_METHOD_EXPLAIN' => 'Once downloaded you should unpack the archive. You will find the modified files you need to upload to your phpBB root directory within it. Please upload the files to their respective locations then. After you have uploaded all files, please check the files again with the other button below.',
|
||||
|
||||
'ERROR' => 'Error',
|
||||
'ERROR' => 'Error',
|
||||
'EDIT_USERNAME' => 'Edit username',
|
||||
|
||||
'FILE_ALREADY_UP_TO_DATE' => 'File is already up to date.',
|
||||
'FILE_DIFF_NOT_ALLOWED' => 'File not allowed to be diffed.',
|
||||
|
@ -412,6 +417,8 @@ $lang = array_merge($lang, array(
|
|||
'INCOMPLETE_UPDATE_FILES' => 'The update files are incomplete.',
|
||||
'INLINE_UPDATE_SUCCESSFUL' => 'The database update was successful. Now you need to continue the update process.',
|
||||
|
||||
'KEEP_OLD_NAME' => 'Keep username',
|
||||
|
||||
'LATEST_VERSION' => 'Latest version',
|
||||
'LINE' => 'Line',
|
||||
'LINE_ADDED' => 'Added',
|
||||
|
@ -431,6 +438,7 @@ $lang = array_merge($lang, array(
|
|||
'MERGE_SELECT_ERROR' => 'Conflicting file merge modes are not correctly selected.',
|
||||
|
||||
'NEW_FILE' => 'New updated file',
|
||||
'NEW_USERNAME' => 'New username',
|
||||
'NO_AUTH_UPDATE' => 'Not authorised to update',
|
||||
'NO_ERRORS' => 'No errors',
|
||||
'NO_UPDATE_FILES' => 'Not updating the following files',
|
||||
|
@ -517,6 +525,7 @@ $lang = array_merge($lang, array(
|
|||
',
|
||||
'UPDATE_METHOD' => 'Update method',
|
||||
'UPDATE_METHOD_EXPLAIN' => 'You are now able to choose your preferred update method. Using the FTP upload will present you with a form you need to enter your FTP account details into. With this method the files will be automatically moved to the new location and backups of the old files being created by appending .bak to the filename. If you choose to download the modified files you are able to unpack and upload them to their correct location manually later.',
|
||||
'UPDATE_REQUIRES_FILE' => 'The updater requires that the following file is present: %s',
|
||||
'UPDATE_SUCCESS' => 'Update was successful',
|
||||
'UPDATE_SUCCESS_EXPLAIN' => 'Successfully updated all files. The next step involves checking all files again to make sure the files got updated correctly.',
|
||||
'UPDATE_VERSION_OPTIMIZE' => 'Updating version and optimising tables',
|
||||
|
@ -526,6 +535,8 @@ $lang = array_merge($lang, array(
|
|||
'UPLOAD_METHOD' => 'Upload method',
|
||||
|
||||
'UPDATE_DB_SUCCESS' => 'Database update was successful.',
|
||||
'USER_ACTIVE' => 'Active user',
|
||||
'USER_INACTIVE' => 'Inactive user',
|
||||
|
||||
'VERSION_CHECK' => 'Version check',
|
||||
'VERSION_CHECK_EXPLAIN' => 'Checks to see if the version of phpBB you are currently running is up to date.',
|
||||
|
|
Loading…
Add table
Reference in a new issue