Regex для проверки SMTP-ответов - PullRequest
1 голос
/ 27 мая 2010

Я пишу регулярное выражение, которое может интерактивно проверять коды ответов SMTP, как только диалоговое окно SMTP завершено оно должно передать следующее регулярное выражение (некоторые скобки добавлены для лучшей читаемости) :

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

Или с ( out ) аутентификацией:

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

Я пытаюсь переписать приведенные выше регулярные выражения, чтобы я мог в интерактивном режиме проверить, идет ли диалог должным образом, в противном случае вежливо отправить команду QUIT и закрыть соединение, сохраняя пропускную способность и время, но мне трудно написать оптимальное регулярное выражение. Пока мне удалось придумать:

^(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 ]

4 голосов
/ 27 мая 2010

Я предполагаю, что вы строите строку со всеми полученными кодами ответов, удаляя остальную часть сообщения?

Вероятно, это не тот ответ, который вам нужен, но я не могу не почувствовать, что регулярное выражение здесь просто не тот инструмент. Регулярные выражения хороши при разборе текста на токены или извлечении интересных подстрок из большой строки. Но у вас уже есть токены (коды ответов SMTP), и вы пытаетесь убедиться, что они приходят в ожидаемом порядке. Я бы просто добавил коды ответов в очередь и после каждого добавления проверял, соответствует ли начало очереди одному из ожидаемых шаблонов для состояния, в котором вы находитесь. Если это так, удалите эту часть из очереди и перейдите к следующее состояние. Есть только несколько состояний, так что я бы просто написал код, специфичный для них, а не пытался бы абстрагировать его в какой-то конечный автомат.

Если вы пойдете по Regex так, как вам захочется оставить пробел в строке в качестве разделителей - это не только облегчит сопоставление кодов, но и облегчит чтение программы.

Редактировать : Спасибо за размещение кода. Это в значительной степени то, что я предполагал. По сути, вы пытаетесь создать абстрактное решение этой проблемы, поэтому у вас есть возможность отправлять заданный массив команд и ожидать заданного шаблона ответов. Вы действительно не должны делать это абстрактным - сложность огромна и вряд ли окупится при повторном использовании. Просто напишите код, который гласит: отправьте X, если вы получите Y, продолжайте, иначе ВЫЙТИ . Это будет намного проще и понятнее.

1 голос
/ 27 мая 2010

Удивительно, как регулярные выражения становятся намного проще после хорошего сна, вот оно:

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

Что можно упростить до этого:

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

Поскольку первый код ответа (220) не является обязательным, и мы всегда будем отправлять последнюю команду QUIT.

...