Index: src/wp-admin/includes/user.php
===================================================================
--- src/wp-admin/includes/user.php	(revision 25329)
+++ src/wp-admin/includes/user.php	(working copy)
@@ -28,7 +28,7 @@
  * @return int user id of the updated user
  */
 function edit_user( $user_id = 0 ) {
-	global $wp_roles, $wpdb;
+	global $wp_roles;
 	$user = new stdClass;
 	if ( $user_id ) {
 		$update = true;
@@ -39,9 +39,6 @@
 		$update = false;
 	}
 
-	if ( !$update && isset( $_POST['user_login'] ) )
-		$user->user_login = sanitize_user($_POST['user_login'], true);
-
 	$pass1 = $pass2 = '';
 	if ( isset( $_POST['pass1'] ) )
 		$pass1 = $_POST['pass1'];
@@ -102,12 +99,23 @@
 	if ( !empty($_POST['use_ssl']) )
 		$user->use_ssl = 1;
 
-	$errors = new WP_Error();
+	if ( ! $update ) {
+		if ( isset( $_POST['user_login'] ) )
+			$user_login = $_POST['user_login'];
+		else
+			$user_login = '';
 
-	/* checking that username has been typed */
-	if ( $user->user_login == '' )
-		$errors->add( 'user_login', __( '<strong>ERROR</strong>: Please enter a username.' ) );
+		$user_login_validation_results = wp_validate_user_login( $user_login );
 
+		if ( isset( $user_login_validation_results['errors'] ) )
+			$errors = $user_login_validation_results['errors'];
+
+		$user->user_login = $user_login_validation_results['user_login'];
+	}
+
+	if ( ! isset( $errors ) )
+		$errors = new WP_Error();
+
 	/* checking the password has been typed twice */
 	do_action_ref_array( 'check_passwords', array( $user->user_login, &$pass1, &$pass2 ) );
 
@@ -134,12 +142,6 @@
 	if ( !empty( $pass1 ) )
 		$user->user_pass = $pass1;
 
-	if ( !$update && isset( $_POST['user_login'] ) && !validate_username( $_POST['user_login'] ) )
-		$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ));
-
-	if ( !$update && username_exists( $user->user_login ) )
-		$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ));
-
 	/* checking e-mail address */
 	if ( empty( $user->user_email ) ) {
 		$errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please enter an e-mail address.' ), array( 'form-field' => 'email' ) );
Index: src/wp-includes/ms-functions.php
===================================================================
--- src/wp-includes/ms-functions.php	(revision 25329)
+++ src/wp-includes/ms-functions.php	(working copy)
@@ -424,49 +424,25 @@
  * @uses username_exists()
  * @uses email_exists()
  *
- * @param string $user_name The login name provided by the user.
+ * @param string $user_login The login name provided by the user.
  * @param string $user_email The email provided by the user.
  * @return array Contains username, email, and error messages.
  */
-function wpmu_validate_user_signup($user_name, $user_email) {
+function wpmu_validate_user_signup( $user_login, $user_email ) {
 	global $wpdb;
 
-	$errors = new WP_Error();
+	$user_login_validation_result = wp_validate_user_login( $user_login );
 
-	$orig_username = $user_name;
-	$user_name = preg_replace( '/\s+/', '', sanitize_user( $user_name, true ) );
+	if ( isset( $user_login_validation_result['errors'] ) )
+		$errors = $user_login_validation_result['errors'];
+	else
+		$errors = new WP_Error();
 
-	if ( $user_name != $orig_username || preg_match( '/[^a-z0-9]/', $user_name ) ) {
-		$errors->add( 'user_name', __( 'Only lowercase letters (a-z) and numbers are allowed.' ) );
-		$user_name = $orig_username;
-	}
-
 	$user_email = sanitize_email( $user_email );
 
-	if ( empty( $user_name ) )
-	   	$errors->add('user_name', __( 'Please enter a username.' ) );
-
-	$illegal_names = get_site_option( 'illegal_names' );
-	if ( is_array( $illegal_names ) == false ) {
-		$illegal_names = array(  'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' );
-		add_site_option( 'illegal_names', $illegal_names );
-	}
-	if ( in_array( $user_name, $illegal_names ) == true )
-		$errors->add('user_name',  __( 'That username is not allowed.' ) );
-
 	if ( is_email_address_unsafe( $user_email ) )
 		$errors->add('user_email',  __('You cannot use that email address to signup. We are having problems with them blocking some of our email. Please use another email provider.'));
 
-	if ( strlen( $user_name ) < 4 )
-		$errors->add('user_name',  __( 'Username must be at least 4 characters.' ) );
-
-	if ( strpos( ' ' . $user_name, '_' ) != false )
-		$errors->add( 'user_name', __( 'Sorry, usernames may not contain the character &#8220;_&#8221;!' ) );
-
-	// all numeric?
-	if ( preg_match( '/^[0-9]*$/', $user_name ) )
-		$errors->add('user_name', __('Sorry, usernames must have letters too!'));
-
 	if ( !is_email( $user_email ) )
 		$errors->add('user_email', __( 'Please enter a valid email address.' ) );
 
@@ -477,27 +453,10 @@
 			$errors->add('user_email', __('Sorry, that email address is not allowed!'));
 	}
 
-	// Check if the username has been used already.
-	if ( username_exists($user_name) )
-		$errors->add( 'user_name', __( 'Sorry, that username already exists!' ) );
-
 	// Check if the email address has been used already.
 	if ( email_exists($user_email) )
 		$errors->add( 'user_email', __( 'Sorry, that email address is already used!' ) );
 
-	// Has someone already signed up for this username?
-	$signup = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->signups WHERE user_login = %s", $user_name) );
-	if ( $signup != null ) {
-		$registered_at =  mysql2date('U', $signup->registered);
-		$now = current_time( 'timestamp', true );
-		$diff = $now - $registered_at;
-		// If registered more than two days ago, cancel registration and let this signup go through.
-		if ( $diff > 2 * DAY_IN_SECONDS )
-			$wpdb->delete( $wpdb->signups, array( 'user_login' => $user_name ) );
-		else
-			$errors->add('user_name', __('That username is currently reserved but may be available in a couple of days.'));
-	}
-
 	$signup = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->signups WHERE user_email = %s", $user_email) );
 	if ( $signup != null ) {
 		$diff = current_time( 'timestamp', true ) - mysql2date('U', $signup->registered);
@@ -508,7 +467,7 @@
 			$errors->add('user_email', __('That email address has already been used. Please check your inbox for an activation email. It will become available in a couple of days if you do nothing.'));
 	}
 
-	$result = array('user_name' => $user_name, 'orig_username' => $orig_username, 'user_email' => $user_email, 'errors' => $errors);
+	$result = array( 'user_name' => $user_login_validation_result['user_login'], 'orig_username' => $user_login, 'user_email' => $user_email, 'errors' => $errors );
 
 	return apply_filters('wpmu_validate_user_signup', $result);
 }
Index: src/wp-includes/user.php
===================================================================
--- src/wp-includes/user.php	(revision 25329)
+++ src/wp-includes/user.php	(working copy)
@@ -1239,6 +1239,85 @@
 }
 
 /**
+ * Validate a provided user_login
+ *
+ * user_login requirements:
+ *     - minimum of 4 characters
+ *     - only contains (case-insensitive) characters: a-z 0-9 _ . - @
+ *     - no whitespace
+ *     - not on blacklist of illegal names
+ *     - contains at least one letter
+ *     - must be unique
+ *     - not pending signup already
+ *
+ * @since 3.7.0
+ *
+ * @param string $user_login The user_login value to be be validated.
+ *
+ * @return array Contains user_login, original_user_login, and any generated errors
+ */
+function wp_validate_user_login( $user_login ) {
+	global $wpdb;
+
+	$original_user_login = $user_login;
+	$result = array();
+	$result['errors'] = new WP_Error();
+
+	// User login cannot be empty
+	if( empty( $user_login ) )
+		$result['errors']->add( 'user_name', __( 'Please enter a username.' ) );
+
+	// User login must be at least 4 characters
+	if ( strlen( $user_login ) < 4 )
+		$result['errors']->add( 'user_name',  __( 'Username must be at least 4 characters.' ) );
+
+	// Strip any whitespace and then match against case insensitive characters a-z 0-9 _ . - @
+	$user_login = preg_replace( '/\s+/', '', sanitize_user( $user_login, true ) );
+
+	// If the previous operation generated a different value, the username is invalid
+	if ( $user_login !== $original_user_login )
+		$result['errors']->add( 'user_name', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
+
+	// Check the user_login against an array of illegal names
+	$illegal_names = get_site_option( 'illegal_names' );
+	if ( false == is_array( $illegal_names ) ) {
+		$illegal_names = array(  'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' );
+		add_site_option( 'illegal_names', $illegal_names );
+	}
+
+	if ( true === in_array( $user_login, $illegal_names ) )
+		$result['errors']->add( 'user_name',  __( 'That username is not allowed.' ) );
+
+	// User login must have at least one letter
+	if ( preg_match( '/^[0-9]*$/', $user_login ) )
+		$result['errors']->add( 'user_name', __( 'Sorry, usernames must have letters too!' ) );
+
+	// Check if the username has been used already.
+	if ( username_exists( $user_login ) )
+		$result['errors']->add( 'user_name', __( 'Sorry, that username already exists!' ) );
+
+	if ( is_multisite() ) {
+		// Is a signup already pending for this user login?
+		$signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE user_login = %s ", $user_login ) );
+		if ( $signup != null ) {
+			$registered_at =  mysql2date( 'U', $signup->registered );
+			$now = current_time( 'timestamp', true );
+			$diff = $now - $registered_at;
+			// If registered more than two days ago, cancel registration and let this signup go through.
+			if ( $diff > 2 * DAY_IN_SECONDS )
+				$wpdb->delete( $wpdb->signups, array( 'user_login' => $user_login ) );
+			else
+				$result['errors']->add( 'user_name', __( 'That username is currently reserved but may be available in a couple of days.' ) );
+		}
+	}
+
+	$result['user_login']          = $user_login;
+	$result['original_user_login'] = $original_user_login;
+
+	return apply_filters( 'wp_validate_user_login', $result );
+}
+
+/**
  * Insert an user into the database.
  *
  * Can update a current user or insert a new user based on whether the user's ID
@@ -1602,21 +1681,15 @@
  * @return int|WP_Error Either user's ID or error on failure.
  */
 function register_new_user( $user_login, $user_email ) {
-	$errors = new WP_Error();
-
-	$sanitized_user_login = sanitize_user( $user_login );
 	$user_email = apply_filters( 'user_registration_email', $user_email );
 
-	// Check the username
-	if ( $sanitized_user_login == '' ) {
-		$errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.' ) );
-	} elseif ( ! validate_username( $user_login ) ) {
-		$errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
-		$sanitized_user_login = '';
-	} elseif ( username_exists( $sanitized_user_login ) ) {
-		$errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) );
-	}
+	$user_login_validation_results = wp_validate_user_login( $user_login );
 
+	if ( isset( $user_login_validation_results['errors'] ) )
+		$errors = $user_login_validation_results['errors'];
+	else
+		$errors = new WP_Error();
+
 	// Check the e-mail address
 	if ( $user_email == '' ) {
 		$errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your e-mail address.' ) );
@@ -1627,15 +1700,15 @@
 		$errors->add( 'email_exists', __( '<strong>ERROR</strong>: This email is already registered, please choose another one.' ) );
 	}
 
-	do_action( 'register_post', $sanitized_user_login, $user_email, $errors );
+	do_action( 'register_post', $user_login_validation_results['user_login'], $user_email, $errors );
 
-	$errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
+	$errors = apply_filters( 'registration_errors', $errors, $user_login_validation_results['user_login'], $user_email );
 
 	if ( $errors->get_error_code() )
 		return $errors;
 
 	$user_pass = wp_generate_password( 12, false );
-	$user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email );
+	$user_id = wp_create_user( $user_login_validation_results['user_login'], $user_pass, $user_email );
 	if ( ! $user_id || is_wp_error( $user_id ) ) {
 		$errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you&hellip; please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
 		return $errors;
Index: tests/phpunit/data/images/a2-small-100x75.jpg
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
