我正在编写一个可以交互式验证SMTP响应代码的正则表达式,一旦SMTP dialog is completed它应该通过以下正则表达式(为了更好的可读性而添加了一些括号):
^(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
(250
响应代码前需要至少2 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);
}
答案 0 :(得分:4)
我假设您正在构建一个包含您收到的所有响应代码的字符串,并删除其余的消息?
这可能不是你想要的答案,但我不禁感到正则表达式不是正确的工具。正则表达式擅长将文本解析为标记或从较大的字符串中提取有趣的子字符串。但是您已经拥有令牌(SMTP响应代码),并且您正在尝试确保它们按预期顺序到达。我只是将响应代码添加到队列中,并在每次添加后检查队列的开头是否与您所处的状态的预期模式之一匹配。如果是,请从队列中删除该部分并转到下一个州。只有少数状态,所以我只是编写特定于那些的代码,而不是尝试将其抽象为某种状态机。
如果你采用Regex方式,你可能希望将字符串中的空格保留为分隔符 - 它不仅可以更容易地匹配代码,而且更容易阅读程序。
修改:感谢您发布代码。这几乎就是我的假设。您基本上是在尝试为此问题创建一个抽象解决方案,因此您可以发送给定的命令数组并期望返回给定的响应模式。你真的不需要把它抽象化 - 增加的复杂性是巨大的,并且不太可能在重复使用中得到回报。只需编写代码:发送X,如果收到Y则继续,否则退出。它会更容易,更易读。
答案 1 :(得分:1)
令人惊讶的是,经过一夜安眠后正规表达变得如此简单,这就是:
(?>220(?>250(?>(?>334){1,2}(?>235)?)?(?>(?>250){1,}(?>354(?>250(?>221)?)?)?)?)?)?
可以简化为:
^220(?>250(?>(?>334){1,2}(?>235)?)?(?>(?>250){1,}(?>354(?>250)?)?)?)?$
由于第一个响应代码(220)不是可选的,我们将始终发送最后一个QUIT
命令。