代码之家  ›  专栏  ›  技术社区  ›  Alix Axel

用于验证SMTP响应的regex

  •  1
  • Alix Axel  · 技术社区  · 16 年前

    我正在编写一个正则表达式,一旦 SMTP dialog is completed 它应该通过以下regex(为了提高可读性,添加了一些括号):

    ^(220)(250){3,}(354)(250)(221)$
    

    或与( 外面的 )身份验证:

    ^(220)(250)((334){2}(235))?(250){2,}(354)(250)(221)$
    

    我正在尝试重写上面的正则表达式,以便 交互地 检查对话是否按预期进行,否则礼貌地发送 QUIT 命令并关闭连接可以节省带宽和时间,但是我很难编写一个最佳的regex。到目前为止,我已经设法想出了:

    ^(220(250(334(235(250(354(250(221)?)?)?){0,})?){0,2})?)?$
    

    除了匹配经过身份验证的连接之外,还有一些错误…例如,它匹配:

    220250334235250354250221
    220250334334235250354250221
    

    我还尝试了以下修改:

    ^(220(250)?)?((334(235)?){2})?(250(354(250(221)?)?)?){0,}$
    

    此响应接受未经身份验证的响应,但无法匹配 220250334 和错误的匹配 220250334334235250354250221 (至少2 250 354 响应代码)。

    有人能帮我吗?事先谢谢。


    我要做的一个例子:

    $smtp = fsockopen('mail.example.com', 25);
    $result = null;
    $commands = array('HELO', 'AUTH LOGIN', 'user', 'pass', 'MAIL FROM', 'RCPT TO', 'RCPT TO', 'DATA', "\r\n.", 'QUIT');
    
    foreach ($commands as $command)
    {
        $result .= substr(fgets($smtp), 0, 3);
    
        if (preg_match('~^(220(250)?)?((334){1,2}(235)?)?(250(354(250(221)?)?)?){0,}$~S', $result) > 0)
        {
            fwrite($smtp, $command . "\r\n");
        }
    
        else
        {
            fwrite($smtp, "QUIT\r\n");
            fclose($smtp);
            break;
        }
    }
    

    作为以下程序代码的替代:

    $smtp = fsockopen('mail.example.com', 25);
    $result = substr(fgets($smtp), 0, 3); // 220
    
    if ($result == '220')
    {
        fwrite($smtp, 'HELO' . "\r\n");
        $result = substr(fgets($smtp), 0, 3); // 220
    
        if ($result == '250')
        {
            fwrite($smtp, 'AUTH LOGIN' . "\r\n");
            $result = substr(fgets($smtp), 0, 3); // 334
    
            if ($result == '334')
            {
                fwrite($smtp, 'user' . "\r\n");
                $result = substr(fgets($smtp), 0, 3); // 334
    
                if ($result == '334')
                {
                    fwrite($smtp, 'pass' . "\r\n");
                    $result = substr(fgets($smtp), 0, 3); // 235
    
                    if ($result == '235')
                    {
                        fwrite($smtp, 'MAIL FROM' . "\r\n");
                        $result = substr(fgets($smtp), 0, 3); // 250
    
                        if ($result == '250')
                        {
                            foreach ($to as $mail)
                            {
                                fwrite($smtp, 'RCPT TO' . "\r\n");
                                $result = substr(fgets($smtp), 0, 3); // 250
    
                                if ($result != '250')
                                {
                                    fwrite($smtp, 'QUIT' . "\r\n");
                                    $result = substr(fgets($smtp), 0, 3); // 221
                                    fclose($smtp);
    
                                    break;
                                }
                            }
    
                            if ($result == '250')
                            {
                                fwrite($smtp, 'DATA' . "\r\n");
                                $result = substr(fgets($smtp), 0, 3); // 354
    
                                if ($result == '354')
                                {
                                    fwrite($smtp, "\r\n.\r\n");
                                    $result = substr(fgets($smtp), 0, 3); // 250
    
                                    if ($result == '250')
                                    {
                                        fwrite($smtp, 'QUIT' . "\r\n");
                                        $result = substr(fgets($smtp), 0, 3); // 221
                                        fclose($smtp);
    
                                        if ($result == '221')
                                        {
                                            echo 'SUCESS!';
                                        }
                                    }
    
                                    else
                                    {
                                        fwrite($smtp, 'QUIT' . "\r\n");
                                        $result = substr(fgets($smtp), 0, 3); // 221
                                        fclose($smtp);
                                    }
                                }
    
                                else
                                {
                                    fwrite($smtp, 'QUIT' . "\r\n");
                                    $result = substr(fgets($smtp), 0, 3); // 221
                                    fclose($smtp);
                                }
                            }
                        }
    
                        else
                        {
                            fwrite($smtp, 'QUIT' . "\r\n");
                            $result = substr(fgets($smtp), 0, 3); // 221
                            fclose($smtp);
                        }
                    }
    
                    else
                    {
                        fwrite($smtp, 'QUIT' . "\r\n");
                        $result = substr(fgets($smtp), 0, 3); // 221
                        fclose($smtp);
                    }
                }
    
                else
                {
                    fwrite($smtp, 'QUIT' . "\r\n");
                    $result = substr(fgets($smtp), 0, 3); // 221
                    fclose($smtp);
                }
            }
    
            else
            {
                fwrite($smtp, 'QUIT' . "\r\n");
                $result = substr(fgets($smtp), 0, 3); // 221
                fclose($smtp);
            }
        }
    
        else
        {
            fwrite($smtp, 'QUIT' . "\r\n");
            $result = substr(fgets($smtp), 0, 3); // 221
            fclose($smtp);
        }
    }
    
    else
    {
        fwrite($smtp, 'QUIT' . "\r\n");
        $result = substr(fgets($smtp), 0, 3); // 221
        fclose($smtp);
    }
    
    2 回复  |  直到 16 年前
        1
  •  4
  •   EMP    16 年前

    我猜你是在用收到的所有响应代码构建一个字符串,去掉其余的消息?

    这可能不是你想要的答案,但我忍不住觉得regex不是这里的正确工具。正则表达式擅长将文本解析为标记或从较大的字符串中提取有趣的子字符串。但是您已经有了令牌(SMTP响应代码),并且您正在尝试确保它们按预期的顺序到达。我只需要将响应代码添加到一个队列中,并在每次添加之后检查队列的开始是否符合您所处状态的预期模式之一。如果是,则从队列中删除该部分并转到下一个状态。只有几个状态,所以我只编写特定于这些状态的代码,而不尝试将其抽象为某种状态机。

    如果按照regex的方式,您可能希望在字符串中保留空格作为分隔符,这样不仅可以使代码匹配更容易,而且也更容易读取程序。

    编辑 :感谢您发布代码。这基本上是我想的。您基本上是在尝试为这个问题创建一个抽象的解决方案,因此您能够发送一个给定的命令数组并期望返回给定的响应模式。你真的不需要把它抽象化——增加的复杂性是巨大的,不太可能在重用中得到回报。只需编写代码: 发送x,如果收到y继续,否则退出 . 它将变得更加容易和可读。

        2
  •  1
  •   Alix Axel    16 年前

    令人惊讶的是,在一夜的睡眠之后,正则表达式变得如此简单,如下所示:

    (?>220(?>250(?>(?>334){1,2}(?>235)?)?(?>(?>250){1,}(?>354(?>250(?>221)?)?)?)?)?)?
    

    可以简化为:

    ^220(?>250(?>(?>334){1,2}(?>235)?)?(?>(?>250){1,}(?>354(?>250)?)?)?)?$
    

    由于第一个响应代码(220)不是可选的,我们将始终发送最后一个 QUIT 命令。

    推荐文章