How do I make PHP's preg_match function match the domain in the email address format?
Below is the part of the script that needs modification. Currently, it will match any word immediately after @ in a user-supplied email address. I need it to match any word either immediately after @ or another word and period (.) Preceding, for example: user@domain.com.au must match the domain, user@someword.domain.com must also match the domain regardless of .someword in front (which changes user to user and exists for some but not others.
PHP CODE:
preg_match('|@([0-9a-zA-Z]+)\.|i', $username, $match);
And below is all the code with sensitive information modified for security.
<?php
// PHP code in child theme of WordPress multisite network functions.php
add_filter( 'authenticate', 'external_auth', 10, 3 );
add_filter( 'login_redirect', 'ds_login_redirect', 10, 3 );
function external_auth( $user, $username, $password ){
// Make sure a username and password are present for us to work with
if($username == '' || $password == '') return;
// Try to log into the external service or database with username and password
$args = array(
'method' => 'POST',
'timeout' => 45,
'redirection' => 5,
'httpversion' => '1.0',
'blocking' => true,
'headers' => array(),
'body' => array( 'username' => $username, 'password' => $password ),
'cookies' => array()
);
$ext_auth = wp_remote_post("http://auth-server:port-number/api-token-auth/",$args);
// if external authentication was successful
if($ext_auth['response']['code'] == 200) {
$userobj = new WP_User();
$user = $userobj->get_data_by( 'login', $username );
// Does not return a WP_User object :(
$user = new WP_User($user->ID);
// Attempt to load up the user with that ID
if( $user->ID == 0 ) {
// The user does not currently exist in the WordPress user table.
// If you do not want to add new users to WordPress if they do not
// already exist uncomment the following line and remove the user creation code
//$user = new WP_Error( 'denied', __("ERROR: Not a valid user for this system") );
// Setup the minimum required user information
$new_user_id = wpmu_create_user($username, $password, $username);
// A new user has been created
preg_match('|@([0-9a-zA-Z]+)\.|i', $username, $match);
$path = '/'.$match[1].'/';
$domain = 'the-wordpress-network-site.com';
// Figure out their blog to add permission to
$blog_id = get_blog_id_from_url ( $domain, $path );
// Specify their role
$role = 'subscriber';
// Give the user access to their blog.
add_user_to_blog($blog_id, $new_user_id, $role);
// Load the new user info
$user = new WP_User ($new_user_id);
}
}else if($ext_auth['response']['code'] == 400){
$user = new WP_Error( 'denied', __("ERROR: User/pass bad") );
}
// Comment this line if you wish to fall back on WordPress authentication
remove_action('authenticate', 'wp_authenticate_username_password', 20);
return $user;
}
function ds_login_redirect( $redirect_to, $request_redirect_to, $user )
{
if ($user->ID != 0) {
$user_info = get_userdata($user->ID);
if ($user_info->primary_blog) {
$primary_url = get_blogaddress_by_id($user_info->primary_blog) . 'index/';
if ($primary_url) {
//echo $primary_url; die();
wp_redirect($primary_url);
die();
}
}
}
return $redirect_to;
}
?>
source to share
A colleague of mine found the answer, it's pretty genius PHP!
Instead of this code in the question:
preg_match('|@([0-9a-zA-Z]+)\.|i', $username, $match);
$path = '/'.$match[1].'/';
$domain = 'the-wordpress-network-site.com';
The code now reads:
$domain_end = explode('@', $username);
$match = explode('.', $domain_end[1]);
$domain = 'the-wordpress-network-site.com';
foreach ($match as $blog_key){
$path = '/'.$blog_key.'/';
$blog_id = get_blog_id_from_url ( $domain, $path );
if ($blog_id != 0) break;
}
This solved the puzzle to my surprise and appreciation. Thanks anyway for all the suggestions and advice, I will still be asking many more questions here in the future, I have no doubt :)
source to share
This will extract the domain from the email:
-
([a-zA-Z0-9-\_]*)\.[a-zA-Z0-9\-\_]{2,4}$
- @ - Char included:
@.+?([a-zA-Z0-9-\_]*)\.[a-zA-Z0-9\-\_]{2,4}$
([a-zA-Z0-9-\_]*)
this group groups the part down to the last, and obviously the region. This is your match.
\.[a-zA-Z0-9\-\_]{2,4}$
this matches the last part of the line with 2 to 4 characters at the end of the line. (. com, .de, .it ...).
So, you always get the second last piece in the line between the dots.
Edit as per the comments:
Since you want to ignore the fact that the domains are written in the second part, you need to split the line into each part between periods and try to ping the domain if it is real.
Edit 2:
Check out Wikipedia in email format . There is a list of valid email formats. Every example in this article extends to a regular expression that I wrote. If you expect people to type invalid emails like " paul@yahoo.mymom.com " (just say -> invalid), you can also expect people writing "IhaveNoEmail" to not lead to the correct subdirectory either.
So I'm still at the point: pick a regex or give me a real argument why the domain should be written somewhere else :).
source to share
Note that the {2-4} constraint in the C4ud3x regex disallows addresses from newer / longer gTLDs , which, although not uncommon today, should still be considered valid. You will also want to consider users from countries where second-level domains are generic and do not skip the "real" domain, because your regex captures just, say, .org.uk.
With the above and borrowing from the W3C the recommended regex , try:
[a-zA-Z0-9-_]*(\.[a-zA-Z0-9-_]{0,3})?\.([a-zA-Z0-9-_]{0,61})$
- see RegExr
Of course, you must validate the address in your PHP script before trying to fetch the domain, in order to always get a good result.
source to share