@@ -2176,7 +2176,6 @@ function sanitize_user( $username, $strict = false ) {
21762176 return apply_filters ( 'sanitize_user ' , $ username , $ raw_username , $ strict );
21772177}
21782178
2179-
21802179/**
21812180 * Sanitizes a string key.
21822181 *
@@ -3602,14 +3601,7 @@ function convert_smilies( $text ) {
36023601/**
36033602 * Verifies that an email is valid.
36043603 *
3605- * This accepts the addresses that matches the WHATWG specifications,
3606- * i.e. what browsers use for `<input type=email>`. It also accepts some
3607- * additional addresses.
3608- *
3609- * By default this accepts addresses like info@grå.org (also accepted
3610- * by Firefox) `<input type=email>`. You can disable Unicode support by
3611- * using the wp_is_ascii_email filter instead of wp_is_unicode_email,
3612- * which is the default.
3604+ * Does not grok i18n domains. Not RFC compliant.
36133605 *
36143606 * @since 0.71
36153607 *
@@ -3622,65 +3614,84 @@ function is_email( $email, $deprecated = false ) {
36223614 _deprecated_argument ( __FUNCTION__ , '3.0.0 ' );
36233615 }
36243616
3625- /**
3626- * Filters whether an email address is valid.
3627- *
3628- * This filter is evaluated under several different contexts, such as
3629- * 'local_invalid_chars', 'domain_no_periods', or no specific context.
3630- * Filters registered on this hook perform the actual validation; the
3631- * default filter is registered in default-filters.php.
3632- *
3633- * @since 2.8.0
3634- *
3635- * @param string|false $is_email The email address if successfully passed the is_email() checks, false otherwise.
3636- * @param string $email The email address being checked.
3637- * @param string|null $context Context under which the email was tested, or null for the initial call.
3617+ // Test for the minimum length the email can be.
3618+ if ( strlen ( $ email ) < 6 ) {
3619+ /**
3620+ * Filters whether an email address is valid.
3621+ *
3622+ * This filter is evaluated under several different contexts, such as 'email_too_short',
3623+ * 'email_no_at', 'local_invalid_chars', 'domain_period_sequence', 'domain_period_limits',
3624+ * 'domain_no_periods', 'sub_hyphen_limits', 'sub_invalid_chars', or no specific context.
3625+ *
3626+ * @since 2.8.0
3627+ *
3628+ * @param string|false $is_email The email address if successfully passed the is_email() checks, false otherwise.
3629+ * @param string $email The email address being checked.
3630+ * @param string $context Context under which the email was tested.
3631+ */
3632+ return apply_filters ( 'is_email ' , false , $ email , 'email_too_short ' );
3633+ }
3634+
3635+ // Test for an @ character after the first position.
3636+ if ( false === strpos ( $ email , '@ ' , 1 ) ) {
3637+ /** This filter is documented in wp-includes/formatting.php */
3638+ return apply_filters ( 'is_email ' , false , $ email , 'email_no_at ' );
3639+ }
3640+
3641+ // Split out the local and domain parts.
3642+ list ( $ local , $ domain ) = explode ( '@ ' , $ email , 2 );
3643+
3644+ /*
3645+ * LOCAL PART
3646+ * Test for invalid characters.
36383647 */
3639- return apply_filters ( 'is_email ' , false , $ email , null );
3640- }
3648+ if ( ! preg_match ( '/^[a-zA-Z0-9!#$%& \'*+\/=?^_`{|}~\.-]+$/ ' , $ local ) ) {
3649+ /** This filter is documented in wp-includes/formatting.php */
3650+ return apply_filters ( 'is_email ' , false , $ email , 'local_invalid_chars ' );
3651+ }
36413652
3642- /**
3643- * Default is_email filter for databases that support Unicode (db charset is utf8mb4).
3644- *
3645- * Validates the email address using {@see WP_Email_Address::from_string()} with Unicode enabled.
3646- * Only acts when $context is null (which it is in the initial validation call); later rescue-context calls are passed through.
3647- *
3648- * @since 7.1.0
3649- *
3650- * @param string|false $value The current filter value.
3651- * @param string $email The email address being checked.
3652- * @param string|null $context Validation context, or null for the initial call.
3653- * @return string|false The email address if valid, false otherwise.
3654- */
3655- function wp_is_unicode_email ( $ value , $ email , $ context ) {
3656- if ( null !== $ context ) {
3657- return $ value ;
3653+ /*
3654+ * DOMAIN PART
3655+ * Test for sequences of periods.
3656+ */
3657+ if ( preg_match ( '/\.{2,}/ ' , $ domain ) ) {
3658+ /** This filter is documented in wp-includes/formatting.php */
3659+ return apply_filters ( 'is_email ' , false , $ email , 'domain_period_sequence ' );
36583660 }
36593661
3660- $ result = WP_Email_Address::from_string ( $ email , 'unicode ' );
3661- return $ result ? $ result ->get_unicode_address () : false ;
3662- }
3662+ // Test for leading and trailing periods and whitespace.
3663+ if ( trim ( $ domain , " \t\n\r\0\x0B. " ) !== $ domain ) {
3664+ /** This filter is documented in wp-includes/formatting.php */
3665+ return apply_filters ( 'is_email ' , false , $ email , 'domain_period_limits ' );
3666+ }
36633667
3664- /**
3665- * Default is_email filter for databases that do not support Unicode (db charset is not utf8mb4).
3666- *
3667- * Validates the email address using {@see WP_Email_Address::from_string()} with Unicode disabled.
3668- * Only acts when $context is null (which it is in the initial validation call); later rescue-context calls are passed through.
3669- *
3670- * @since 7.1.0
3671- *
3672- * @param string|false $value The current filter value.
3673- * @param string $email The email address being checked.
3674- * @param string|null $context Validation context, or null for the initial call.
3675- * @return string|false The email address if valid, false otherwise.
3676- */
3677- function wp_is_ascii_email ( $ value , $ email , $ context ) {
3678- if ( null !== $ context ) {
3679- return $ value ;
3668+ // Split the domain into subs.
3669+ $ subs = explode ( '. ' , $ domain );
3670+
3671+ // Assume the domain will have at least two subs.
3672+ if ( 2 > count ( $ subs ) ) {
3673+ /** This filter is documented in wp-includes/formatting.php */
3674+ return apply_filters ( 'is_email ' , false , $ email , 'domain_no_periods ' );
3675+ }
3676+
3677+ // Loop through each sub.
3678+ foreach ( $ subs as $ sub ) {
3679+ // Test for leading and trailing hyphens and whitespace.
3680+ if ( trim ( $ sub , " \t\n\r\0\x0B- " ) !== $ sub ) {
3681+ /** This filter is documented in wp-includes/formatting.php */
3682+ return apply_filters ( 'is_email ' , false , $ email , 'sub_hyphen_limits ' );
3683+ }
3684+
3685+ // Test for invalid characters.
3686+ if ( ! preg_match ( '/^[a-z0-9-]+$/i ' , $ sub ) ) {
3687+ /** This filter is documented in wp-includes/formatting.php */
3688+ return apply_filters ( 'is_email ' , false , $ email , 'sub_invalid_chars ' );
3689+ }
36803690 }
36813691
3682- $ result = WP_Email_Address::from_string ( $ email , 'ascii ' );
3683- return $ result ? $ result ->get_unicode_address () : false ;
3692+ // Congratulations, your email made it!
3693+ /** This filter is documented in wp-includes/formatting.php */
3694+ return apply_filters ( 'is_email ' , $ email , $ email , null );
36843695}
36853696
36863697/**
@@ -3809,96 +3820,109 @@ function iso8601_to_datetime( $date_string, $timezone = 'user' ) {
38093820}
38103821
38113822/**
3812- * Sanitizes an email address.
3813- *
3814- * Strips stray whitespace from the input, then strips trailing dots from the domain.
3815- * This is designed to recover from cut/paste mistakes without any risk of transforming
3816- * the input into a different address than the user intended.
3817- *
3818- * Validation and final form are determined by the 'sanitize_email' filter; the default
3819- * filter is registered in default-filters.php and delegates to {@see WP_Email_Address::from_string()}.
3823+ * Strips out all characters that are not allowable in an email.
38203824 *
38213825 * @since 1.5.0
3822- * @since 7.1.0 Accepts Unicode email addresses on supporting platforms.
38233826 *
3824- * @param string $email Email address to sanitize .
3825- * @return string The sanitized email address, or an empty string if invalid .
3827+ * @param string $email Email address to filter .
3828+ * @return string Filtered email address.
38263829 */
38273830function sanitize_email ( $ email ) {
3828- // Strip surrounding whitespace.
3829- $ email = trim ( $ email );
3831+ // Test for the minimum length the email can be.
3832+ if ( strlen ( $ email ) < 6 ) {
3833+ /**
3834+ * Filters a sanitized email address.
3835+ *
3836+ * This filter is evaluated under several contexts, including 'email_too_short',
3837+ * 'email_no_at', 'local_invalid_chars', 'domain_period_sequence', 'domain_period_limits',
3838+ * 'domain_no_periods', 'domain_no_valid_subs', or no context.
3839+ *
3840+ * @since 2.8.0
3841+ *
3842+ * @param string $sanitized_email The sanitized email address.
3843+ * @param string $email The email address, as provided to sanitize_email().
3844+ * @param string|null $message A message to pass to the user. null if email is sanitized.
3845+ */
3846+ return apply_filters ( 'sanitize_email ' , '' , $ email , 'email_too_short ' );
3847+ }
38303848
3831- // Extract the address from "Display Name <username@domain>" format.
3832- if ( 1 === preg_match ( '/<([^>]+)>$/ ' , $ email , $ matches ) ) {
3833- $ email = $ matches [1 ];
3849+ // Test for an @ character after the first position.
3850+ if ( false === strpos ( $ email , '@ ' , 1 ) ) {
3851+ /** This filter is documented in wp-includes/formatting.php */
3852+ return apply_filters ( 'sanitize_email ' , '' , $ email , 'email_no_at ' );
38343853 }
38353854
3855+ // Split out the local and domain parts.
3856+ list ( $ local , $ domain ) = explode ( '@ ' , $ email , 2 );
3857+
38363858 /*
3837- * Strip soft hyphens and whitespace adjacent to structural separators (dots and @),
3838- * e.g. copy-paste artifacts like "info@example\u{00AD}.com" or "info@example .com".
3839- *
3840- * In some cases, e.g. autocorrect, some older software has been seen to add the
3841- * space for unrecognized TLDs. This re-joins the parts for proper examination.
3859+ * LOCAL PART
3860+ * Test for invalid characters.
38423861 */
3843- $ email = preg_replace ( '/[\x{00AD}\s]*([.@])[\x{00AD}\s]*/u ' , '$1 ' , $ email ) ?? $ email ;
3844-
3845- // Strip a trailing dot from the domain (e.g. if pasted from the end of a sentence).
3846- if ( str_contains ( $ email , '@ ' ) ) {
3847- list ( $ local , $ domain ) = explode ( '@ ' , $ email , 2 );
3848- $ domain = rtrim ( $ domain , '. ' );
3849- $ email = $ local . '@ ' . $ domain ;
3862+ $ local = preg_replace ( '/[^a-zA-Z0-9!#$%& \'*+\/=?^_`{|}~\.-]/ ' , '' , $ local );
3863+ if ( '' === $ local ) {
3864+ /** This filter is documented in wp-includes/formatting.php */
3865+ return apply_filters ( 'sanitize_email ' , '' , $ email , 'local_invalid_chars ' );
38503866 }
38513867
3852- /**
3853- * Filters a sanitized email address.
3854- *
3855- * Filters registered on this hook perform the actual validation and return
3856- * the canonical email string on success or an empty string on failure.
3857- * The default filter is registered in default-filters.php.
3858- *
3859- * @since 2.8.0
3860- *
3861- * @param string $sanitized_email The sanitized email address, or empty string.
3862- * @param string $email The email address as provided to sanitize_email().
3863- * @param string|null $context Validation context, or null for the initial call.
3868+ /*
3869+ * DOMAIN PART
3870+ * Test for sequences of periods.
38643871 */
3865- return apply_filters ( 'sanitize_email ' , '' , $ email , null );
3866- }
3872+ $ domain = preg_replace ( '/\.{2,}/ ' , '' , $ domain );
3873+ if ( '' === $ domain ) {
3874+ /** This filter is documented in wp-includes/formatting.php */
3875+ return apply_filters ( 'sanitize_email ' , '' , $ email , 'domain_period_sequence ' );
3876+ }
38673877
3868- /**
3869- * Default sanitize_email filter for databases that support Unicode (db charset is utf8mb4).
3870- *
3871- * Returns the canonical address from {@see WP_Email_Address::from_string()} with Unicode
3872- * enabled, or an empty string if the address is invalid.
3873- *
3874- * @since 7.1.0
3875- *
3876- * @param string $value The current filter value.
3877- * @param string $email The email address being sanitized.
3878- * @param string|null $context Sanitization context, always null.
3879- * @return string The canonical email address if valid, empty string otherwise.
3880- */
3881- function wp_sanitize_unicode_email ( $ value , $ email , $ context ) {
3882- $ result = WP_Email_Address::from_string ( $ email , 'unicode ' );
3883- return $ result ? $ result ->get_unicode_address () : '' ;
3884- }
3878+ // Test for leading and trailing periods and whitespace.
3879+ $ domain = trim ( $ domain , " \t\n\r\0\x0B. " );
3880+ if ( '' === $ domain ) {
3881+ /** This filter is documented in wp-includes/formatting.php */
3882+ return apply_filters ( 'sanitize_email ' , '' , $ email , 'domain_period_limits ' );
3883+ }
38853884
3886- /**
3887- * Default sanitize_email filter for databases that do not support Unicode (db charset is not utf8mb4).
3888- *
3889- * Returns the canonical address from {@see WP_Email_Address::from_string()} with Unicode
3890- * disabled, or an empty string if the address is invalid.
3891- *
3892- * @since 7.1.0
3893- *
3894- * @param string $value The current filter value.
3895- * @param string $email The email address being sanitized.
3896- * @param string|null $context Sanitization context, always null.
3897- * @return string The canonical email address if valid, empty string otherwise.
3898- */
3899- function wp_sanitize_ascii_email ( $ value , $ email , $ context ) {
3900- $ result = WP_Email_Address::from_string ( $ email , 'ascii ' );
3901- return $ result ? $ result ->get_unicode_address () : '' ;
3885+ // Split the domain into subs.
3886+ $ subs = explode ( '. ' , $ domain );
3887+
3888+ // Assume the domain will have at least two subs.
3889+ if ( 2 > count ( $ subs ) ) {
3890+ /** This filter is documented in wp-includes/formatting.php */
3891+ return apply_filters ( 'sanitize_email ' , '' , $ email , 'domain_no_periods ' );
3892+ }
3893+
3894+ // Create an array that will contain valid subs.
3895+ $ new_subs = array ();
3896+
3897+ // Loop through each sub.
3898+ foreach ( $ subs as $ sub ) {
3899+ // Test for leading and trailing hyphens.
3900+ $ sub = trim ( $ sub , " \t\n\r\0\x0B- " );
3901+
3902+ // Test for invalid characters.
3903+ $ sub = preg_replace ( '/[^a-z0-9-]+/i ' , '' , $ sub );
3904+
3905+ // If there's anything left, add it to the valid subs.
3906+ if ( '' !== $ sub ) {
3907+ $ new_subs [] = $ sub ;
3908+ }
3909+ }
3910+
3911+ // If there aren't 2 or more valid subs.
3912+ if ( 2 > count ( $ new_subs ) ) {
3913+ /** This filter is documented in wp-includes/formatting.php */
3914+ return apply_filters ( 'sanitize_email ' , '' , $ email , 'domain_no_valid_subs ' );
3915+ }
3916+
3917+ // Join valid subs into the new domain.
3918+ $ domain = implode ( '. ' , $ new_subs );
3919+
3920+ // Put the email back together.
3921+ $ sanitized_email = $ local . '@ ' . $ domain ;
3922+
3923+ // Congratulations, your email made it!
3924+ /** This filter is documented in wp-includes/formatting.php */
3925+ return apply_filters ( 'sanitize_email ' , $ sanitized_email , $ email , null );
39023926}
39033927
39043928/**
0 commit comments