3

Below is the part of the script that needs modifying. Currently it will match any word directly after the @ in the email address supplied by the user. I need it to be able to match any word either directly after the @ or with another word and dot (.) preceding, example: user@domain.com.au should match domain, user@someword.domain.com should also match domain regardless of the .someword in front (which changes user to user and is there for some but not others.

PHP CODE:

preg_match('|@([0-9a-zA-Z]+)\.|i', $username, $match);

And below is the entire code with sensitive information changed 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;
}

?>
WhitePointerNet
  • 43
  • 1
  • 10
  • possible duplicate of [How to validate an Email in PHP?](http://stackoverflow.com/questions/5855811/how-to-validate-an-email-in-php) – mmm Aug 04 '15 at 06:24
  • @mmm He's not talking about validating. Hes talking about fetching the domain out of the mail. Thats a difference. – C4d Aug 04 '15 at 06:50

3 Answers3

1

This would extract the domain out of the email:

  1. ([a-zA-Z0-9-\_]*)\.[a-zA-Z0-9\-\_]{2,4}$
  2. @-Char included: @.+?([a-zA-Z0-9-\_]*)\.[a-zA-Z0-9\-\_]{2,4}$

([a-zA-Z0-9-\_]*) this one groups the part before the last one, the domain obviously. Thats your match.

\.[a-zA-Z0-9\-\_]{2,4}$ this matches the last part of the string between 2 and 4 characters at the end of the string.(.com, .de, .it ...).

So you'll always get the 2nd last part in the string between dots.

Click me (Regex101)


Edit according comments:
As you want to ignore the fact, that domains are written in the 2nd last part, you would need to split the string into every part between dots and try to ping the domain if it is real.

Edit 2:
Check this article Wikipedia Email-format. There is a list of valid formats for emails. Every example in this article is covered by the regex I wrote. If you expect people typing in invalid mails like "paul@yahoo.mymom.com" (just to say -> invalid) you could also expect people writing "IhaveNoEmail" which wouldnt result in the right subdirectory either.

So I'm still on my point: Pick the regex or give me a real argument why the domain should be written somewhere else :).

C4d
  • 3,183
  • 4
  • 29
  • 50
  • Sorry, failed to mention the .com could be .com.au or .co.nz as this is going on an international site – WhitePointerNet Aug 04 '15 at 07:37
  • No problem. If it solved your problem, mark it as correct. Otherwise tell us your problems :). – C4d Aug 04 '15 at 07:45
  • So yeah, the php you made there will give the second last part between dots. I need it to work if it's second last or third last (or more.) eg: user@someword.domain.com.au or user@domain.someword.com.au should both return a match for domain.. My collegue has suggested maybe we need to have an array somewhere? I'm not skilled enough with php to see how though.. :) Cheers again – WhitePointerNet Aug 04 '15 at 08:26
  • "user@domain.someword.com" is not possible! The domain is always at the 2nd last part. It is always from format xxx@domain.com OR xxx@xxx.xxx.domain.com OR xxx@xxx.xxx.xxx.xxx.domain.com. – C4d Aug 04 '15 at 08:30
  • Thanks but these domain names do not necessarily link somewhere that is just the way they are already. They may well be impossible email addresses but my need to read and match the right part remains. Also that 2nd last always being the domain doesn't encompass .com.au or .edu.au etc. there are both those and .com "addresses" in the user list which is thousands strong. I can't change their naming convention for users as illogical as it may be. – WhitePointerNet Aug 05 '15 at 08:09
  • So you want to grab the domain even out of invalid email-formats? Because user@google.pickup.com cant be real. Only exception would be there is a real domain titled "www.google.pickup.com". But this wouldnt be a pointer to "www.google.com" Then the email would be "user@.......google.com". Check my edit – C4d Aug 05 '15 at 08:49
  • Yes please, validity of the email isn't what I need; it's just a user name with this terrible email looking format that they've been using. This script is actually part of a larger one in the child theme of my WP multisite network which grabs a 200 status off of an external auth server. All else works it's just this pesky preg_match bit that really confuses me :) – WhitePointerNet Aug 05 '15 at 08:57
  • Cant get why but ok. Added another way. What you are saying its the same as checking the part before "@" for a domain. Sounds unlogical to me. But for sure can be done. As said above you will need to ping every word then as C# cant know whats a domain or not. – C4d Aug 05 '15 at 09:04
  • Sorry, something is getting lost in translation here. I don't need to actually ping the domain. they are a label only. The script I have matches the part of the username entered at login by a user which refers to the subfolder of my site. eg: User with name logs in as joebloggs@thesubfolderiwant.com.au and another user logs in as jillbloggs@news.thesubfolderiwant.com.au – WhitePointerNet Aug 05 '15 at 09:42
  • They both authenticate fine elsewhere in the script, this preg_match part is only used to take the subfolder name out of the username so "$match1" result is used to redirect them to that subfolders home page. the redirect already works too just currently only for joebloggs@thesubfolderiwant.com.au not the latter – WhitePointerNet Aug 05 '15 at 09:46
  • So your users will be redirected into folders which a titled by domains? E.g. a user with "paul@gmx.de" would be redirected to "www.yourwebsite.com/gmx"? – C4d Aug 05 '15 at 09:51
  • Exactly :) Here is the script in context: – WhitePointerNet Aug 05 '15 at 11:04
  • THEN my friend, why cant you use point 1 or 2 in my answer? Ill extend my answer. – C4d Aug 05 '15 at 11:23
  • I added it about 6 mins ago, sorry I was having trouble copying the code in and having it accept. – WhitePointerNet Aug 05 '15 at 11:40
0

Note that the {2-4} restriction in C4ud3x's regex would disallow addresses from new/longer gTLDs which, although currently uncommon, should still be considered valid. You'll also want to consider users from countries where second-level domains are common, and not miss the 'real' domain because your regex captures just, say, .org.uk.

With the above in mind and borrowing from W3C's recommended regex, try:

[a-zA-Z0-9-_]*(\.[a-zA-Z0-9-_]{0,3})?\.([a-zA-Z0-9-_]{0,61})$ - see on RegExr

Of course, you should still validate the address in your PHP script before trying to extract the domain, so that you always capture a good result.

Community
  • 1
  • 1
0

My collegue found the answer, he is quite the PHP genius!

In place of this code in the question:

preg_match('|@([0-9a-zA-Z]+)\.|i', $username, $match);

                $path = '/'.$match[1].'/';

                $domain = 'the-wordpress-network-site.com';

Now the code 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;
                }

That has solved the riddle much to my amazement and gratitude. Thanks anyway for all the suggestions and advice, I will still be here to ask many more questions in the future I don't doubt :)

WhitePointerNet
  • 43
  • 1
  • 10
  • Update! Check out how this code has come along. All working version! http://stackoverflow.com/questions/35908534/change-register-lost-password-action-links-urls-titles-modify-error-pages – WhitePointerNet Mar 10 '16 at 06:12