メールアドレスにマッチする正規表現

PHP関連のメモ。

フォームを作っているときの永遠の課題。

それは メールアドレスにマッチする正規表現

大雑把にチェックするとチェックにならず、正確にチェックしようとすると、どのような正規表現が最適なのかわからない。

書籍、検索エンジン掲示板で調べるほど、本来ひとつであるはずの(あって欲しい)その解が多様であることに混乱してしまいます。

そして、

/* この正規表現ではもしかしたら、正しいメールアドレスを弾いているかもしれません */

とコメントを付加することになります。


前置きが長くなりましたが、いまさらながら凄く気になったので、究極のメールアドレスチェック正規表現を真剣に調べて見ました。


【調査方法】
・多くの実績があり、信頼性の高いと思われるライブラリ・オープンソースソフトウェアの正規表現を参考にする。
・具体的には PEAR(HTML_QuickForm), XOOPS, WordPress, OpenPNE を参考にさせていただきました。


【結果】

上記のライブラリ・オープンソースのメールアドレスに関する正規表現を含む部分を以下に抜粋します。バージョンは2007/2/1 現在の最新版です。(めんどくさいので省略させてください。すみません。)


1. XOOPS

html/class/xoopsmailer.php より抜粋

    function _checkValidEmail($addr) {
        if (!preg_match("/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+([\.][a-z0-9-]+)+$/i",$addr) ) {
            $this->errors[] = "Invalid Mail Address Format."; //ToDo : Use message catalog;
            return false;
        }
        return true;
    }

2. WordPress

wp-includes/functions-formatting.php より抜粋

function is_email($user_email) {
	$chars = "/^([a-z0-9+_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,6}\$/i";
	if(strstr($user_email, '@') && strstr($user_email, '.')) {
		if (preg_match($chars, $user_email)) {
			return true;
		} else {
			return false;
		}
	} else {
		return false;
	}
}

3. OpenPNE

webapp/ib/OpenPNE/KtaiMail.php より抜粋

    function _get_mail_address($str)
    {
        if (!$str) {
            return false;
        }

        // "(ダブルクォーテーション)を取り除く
        // "example"@docomo.ne.jp
        $str = str_replace('"', '', $str);

        // <example@docomo.ne.jp> というアドレスになることがある。
        //   日本語 <example@docomo.ne.jp>
        // のような場合に複数マッチする可能性があるので、
        // マッチした最後のものを取ってくるように変更
        $matches = array();
        $regx = '/([\.\w!#$%&\'*+-\/=?^`{|}~]+@[\w!#$%&\'*+-\/=?^`{|}~]+(\.[\w!#$%&\'*+-\/=?^`{|}~]+)*)/';
        if (preg_match_all($regx, $str, $matches)) {
            return array_pop($matches[1]);
        }

        return false;
    }

4. PEAR (HTML_QuickForm)

QuickForm/Rule/E-mail.php より抜粋
※ 表示上の都合で適当なところで改行していますが、実際のソースでは正規表現部分は1行で記述されています。

class HTML_QuickForm_Rule_Email extends HTML_QuickForm_Rule
{

    var $regex = '/^((\"[^\"\f\n\r\t\v\b]+\")|([\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+(\.[\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+)*))
                  @((\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.
                  ((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.
                  ((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.
                  ((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.
                  ((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\-])+\.)+[A-Za-z\-]+))$/';
    /**
     * Validates an email address
     *
     * @param     string    $email          Email address
     * @param     boolean   $checkDomain    True if dns check should be performed
     * @access    public
     * @return    boolean   true if email is valid
     */
    function validate($email, $checkDomain = false)
    {
        if (preg_match($this->regex, $email)) {
            if ($checkDomain && function_exists('checkdnsrr')) {
                $tokens = explode('@', $email);
                if (checkdnsrr($tokens[1], 'MX') || checkdnsrr($tokens[1], 'A')) {
                    return true;
                }
                return false;
            }
            return true;
        }
        return false;
    } // end func validate


    function getValidationScript($options = null)
    {
        return array("  var regex = " . $this->regex . ";\n", "{jsVar} != '' && !regex.test({jsVar})");
    } // end func getValidationScript

} // end class HTML_QuickForm_Rule_Email

【結論】

PEAR は別格です。正規表現が暗号化されたハッシュかと思いました 笑。正規表現は解読不能ですが、checkdnsrr関数 によるチェックまで実行されていたりと、おそらく究極形ではないかと。(適当ですみません。)


※ HTML_QuickForm_Rule_Email は HTML_QuickForm_Rule を継承していますが、HTML_QuickForm_Rule は抽象メソッドのみの抽象クラスなので、(お手軽用途なら)extends を削除してそのまま使うのもよいかもしれません。


【あとがき】

メールチェックとは関係ないですが、デザパタ入門レベルの私にとっては、PEARソースコードはエレガントの一言(基底クラスのエラーオブジェクトだけでも凄い!)。


個人的には WordPressソースコードが関数とクラスを効果的に使い分けており、PHPっぽくて好きでした。OpenPNE はスタイルが綺麗で、コメントも日本語なので時間を見つけては勉強材料にしたいと思いました。


XOOPS はカオスです…。