如何使 preg_match PHP 函数匹配电子邮件地址格式中的域名?

3
以下是需要修改的脚本部分。当前它会匹配用户提供的电子邮件地址中@后面的任何单词。我需要它能够匹配直接在@后面或在另一个单词和点(.)之前的任何单词,例如:user@domain.com.au 应该匹配 domain,user@someword.domain.com 也应该匹配 domain,无论前面是否有.someword(这将把user更改为user,对于某些用户而言存在但对于其他用户则不存在。)
PHP代码:
preg_match('|@([0-9a-zA-Z]+)\.|i', $username, $match);

以下是已更改敏感信息以确保安全性的完整代码。
<?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;
}

?>

可能是重复的问题:如何在PHP中验证电子邮件? - mmm
@mmm他不是在谈论验证。他在谈论从邮件中获取域名。这是一个区别。 - C4d
3个回答

1

这里提取电子邮件中的域名:

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

([a-zA-Z0-9-\_]*)这个正则表达式匹配倒数第二部分(即域名)的前面一部分。这是你要匹配的内容。

\.[a-zA-Z0-9\-\_]{2,4}$这个正则表达式匹配字符串结尾处2到4个字符的最后一部分。(例如:.com、.de、.it等)。

因此,您将始终在点之间的字符串中获取倒数第二个部分。

点击这里(Regex101)


根据评论进行编辑:
由于您想忽略域名写在倒数第二部分的事实,您需要将字符串分割为每个点之间的部分,并尝试ping该域名是否真实。

编辑2:
请查看此文章维基百科电子邮件格式。其中列出了电子邮件的有效格式列表。我编写的正则表达式覆盖了本文中的每个示例。如果您期望人们输入无效的邮件地址,例如“paul@yahoo.mymom.com”(只是说 -> 无效),则还可以预期人们会写“ IhaveNoEmail”,这也不会导致正确的子目录。

所以我仍然坚持我的观点:选择正则表达式或给我一个真正的理由,为什么域名应该写在其他地方:)。


抱歉,之前没有提到“.com”可能是“.com.au”或“.co.nz”,因为这将用于国际网站。 - WhitePointerNet
没问题。如果它解决了你的问题,请将其标记为正确。否则告诉我们你的问题 :)。 - C4d
所以,你编写的 PHP 代码将在两个点之间给出倒数第二部分。我需要它能够在倒数第二或第三(或更多)个点之间工作。例如:user@someword.domain.com.auuser@domain.someword.com.au 都应该返回 domain 的匹配结果。我的同事建议我们可能需要在某个地方使用数组?但我不太擅长 PHP,无法看出如何实现... :) 再次感谢 - WhitePointerNet
谢谢,但这些域名不一定链接到某个地方,这只是它们已经存在的方式。它们很可能是无法使用的电子邮件地址,但我需要读取和匹配正确的部分。此外,倒数第二个始终是域名,并不包括.com.au或.edu.au等。在用户列表中,有成千上万个这些和.com“地址”。我不能改变他们对用户的命名惯例,尽管它可能是不合逻辑的。 - WhitePointerNet
好的,请注意,我不需要电子邮件的有效性;它只是一个使用他们一直在使用的可怕电子邮件格式的用户名。该脚本实际上是我的 WP多站点网络中的子主题中较大的一个部分,从外部 auth 服务器获取200状态。其他所有都可以正常工作,只有这个讨厌的 preg_match 部分真的很困扰我 :) - WhitePointerNet
显示剩余9条评论

0
请注意,C4ud3x的正则表达式中的{2-4}限制将禁止来自新/更长gTLDs的地址,尽管目前不常见,但仍应被视为有效。您还需要考虑来自second-level domains普遍的国家/地区的用户,并且不要因为您的正则表达式只捕获例如.org.uk而错过“真实”的域名。
考虑到上述内容并借鉴W3C的recommended regex,请尝试:
[a-zA-Z0-9-_]*(\.[a-zA-Z0-9-_]{0,3})?\.([a-zA-Z0-9-_]{0,61})$ - 在RegExr上查看

当然,在尝试提取域名之前,您仍应在PHP脚本中验证地址,以便始终捕获良好的结果。


谢谢你的回答 :) 我将运行一些测试并让你知道结果。 - WhitePointerNet

0

我的同事找到了答案,他是PHP天才!

在问题中,用这段代码代替:

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

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

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

现在代码读取如下:

$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;
                }

这解决了我的难题,让我感到惊讶和感激。无论如何,感谢您提供的所有建议和意见,我相信将来还会在这里提出更多问题 :)


更新!看看这段代码的进展。所有版本都可以工作!http://stackoverflow.com/questions/35908534/change-register-lost-password-action-links-urls-titles-modify-error-pages - WhitePointerNet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接