Intereting Posts
PHP Разница между array () и Проблема выбора кометного сервера класс шифрования и mcrypt_create_iv медленно Как предотвратить загрузку страницы моего сайта через сторонний фрейм сайта iFrame Перестановка для строки в php Почему мой конструктор все еще звонит, даже если случай класса и конструктора отличается? Twilio PHP – сертификат SSL: самоподписанный сертификат в цепочке сертификатов Ограничить выполнение скрипта PHP одним реферированием Как установить ZF2 в ubuntu 12.04 + виртуальный хост + mod_rewrite Доступ к нескольким иностранным полям в виртуальном поле? как я могу изменить dpi на изображение с расширением imagick строка в массив, разделенная на одиночные и двойные кавычки Weird формат массива $ _FILES при наличии нескольких полей Невозможно перенаправить с большим количеством переменных. Заголовок может содержать не более одного заголовка, обнаружена новая строка. в Не можете повторно назначить $ this?

Regex для проверки SMTP-ответов

Я пишу регулярное выражение, которое может интерактивно проверять коды ответов 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 ( 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); } 

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

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

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

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

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

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

Что может быть упрощено:

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

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