1

SMTP 応答コードをインタラクティブに検証できる正規表現を作成しています。SMTP ダイアログが完了すると、次の正規表現が渡されます (読みやすくするためにいくつかの括弧が追加されています)。

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

または(アウト)認証あり:

^(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 つ必要です)。250354

誰かがこれで私を助けることができますか? 前もって感謝します。


私がやろうとしていることの例:

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

2 に答える 2

4

受信したすべての応答コードを使用して文字列を作成し、残りのメッセージを削除していると思いますか?

これはおそらくあなたが望む答えではありませんが、正規表現はここでは適切なツールではないと感じずにはいられません。正規表現は、テキストをトークンに解析したり、大きな文字列から興味深い部分文字列を抽出したりするのに適しています。しかし、既にトークン (SMTP 応答コード) があり、それらが期待どおりの順序で到着することを確認しようとしています。応答コードをキューに追加するだけで、追加するたびに、キューの開始が現在の状態の予想されるパターンのいずれかと一致するかどうかを確認します。一致する場合は、キューからその部分を削除してに移動します次の状態。いくつかの状態しかないので、ある種の状態マシンに抽象化しようとするのではなく、それらに固有のコードを記述します。

正規表現を使用する場合は、文字列に区切り文字としてスペースを入れておきたい場合があります。これにより、コードの照合が容易になるだけでなく、プログラムも読みやすくなります。

編集:コードを投稿していただきありがとうございます。それはほとんど私が想定したものです。基本的に、この問題に対する抽象的な解決策を作成しようとしているので、特定のコマンド配列を送信し、特定のパターンの応答を期待することができます。抽象化する必要はまったくありません。追加された複雑さは非常に大きく、再利用で報われる可能性はほとんどありません。次のようなコードを書くだけです: X を送信し、Y を受信した場合は続行し、それ以外の場合は QUIT を送信します。はるかに簡単で読みやすくなります。

于 2010-05-27T01:58:49.127 に答える
1

ぐっすり眠った後、正規表現が非常に簡単になるのは驚くべきことです。

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

これはこれに簡略化できます:

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

最初の応答コード(220)はオプションではないため、常に最後のQUITコマンドを送信します。

于 2010-05-27T16:52:10.153 に答える