メールアドレスにマッチする正規表現
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 はカオスです…。