J0hn D0e の日誌

2007-06-02 「正しい方法」でメールアドレスを確認するには

PHPメールアドレスを確認する「正しい方法」(Linux Journal誌の記事より)

本屋で立ち読みしてたら、Linux Journalって雑誌に "Validate an E-Mail Address with PHP, the Right Way" って記事が載っているのを発見したので、簡単に要約を。

まず、以下のメールアドレスは「正しい」アドレスである、と紹介。

  • Abc\@def@example.com
  • customer/department=shipping@example.com
  • !def!xyz%abc@example.com

これは、RFC3696からの引用。

RFC3696は、Application Techniques for Checking and Transformation of Names

(名前の検査と変換のアプリケーション技法) ってやつで、そのなかに、 "Restrictions on email addresses" って章があるみたい。

続いて、例として

http://www.devshed.com/c/a/PHP/Email-Address-Verification-with-PHP/2/

を挙げ、


function checkEmail($email) {
 if(preg_match("/^( [a-zA-Z0-9] )+( [a-zA-Z0-9\._-] )*@長いんでここで改行入れますね
( [a-zA-Z0-9_-] )+( [a-zA-Z0-9\._-] +)+$/" , $email)){
  list($username,$domain)=split('@',$email);
  if(!checkdnsrr($domain,'MX')) {
   return false;
  }
  return true;
 }
 return false;
}

この関数の間違ってるところを指摘。

正規表現が足りないのはすぐわかるからいいんだけど、DNSのチェックもおかしい、MXレコードが必ずあるとは限らないから、とも書いてある。(symfonyのは、ちゃんと調べてるみたいだ)

さらに

http://www.ilovejackdaniels.com/php/email-address-validation/

スクリプトも紹介。

このスクリプトの著者Dave氏は、RFC2822をきちんと読んでvalidなメールアドレスの "local-part" が、1文字から64文字であることを理解している、と紹介。

このスクリプトの"the only major flaw" は、ユーザー名中に、 \@ が含まれるときうまく処理できないことらしい。

で、このあとが面白くて、「正しいメールアドレスの条件」10か条が、RFCの参照付きで紹介されている。

  1. メールアドレスは local part と domain が @ で区切られて構成されている。(RFC2822)
  2. local partは、アルファベット、数字、以下の記号 ! # $ % & ' * + - / = ? ^ _ ` { | } ~ で、ドット「 . 」で区切られている場合がある。ただし、最初、最後、他のドットの隣にあってはいけない。(つまり連続しないことということか) (RFC2822 3.2.4)
  3. local partは、 クオーテーションマーク「 " 」のなかにスペースを含むいろんな文字が入った quoted string を含むことがある (RFC2822 3.2.5)
  4. \@ などの "quoted pair" をlocal partに含むものも「正しい」が "obsolete" (RFC822、RFC2822 4.4) (RFC2822はRFC822をsupersedeしてobsoleteにした、とある)
  5. local partの最大長は 64文字 (RFC2821 4.5.3.1)
  6. domainは、labelがドットで区切られたものである (RFC1035 2.3.1)
  7. domainは、アルファベットで始まり、その後に、0文字以上のアルファベット、数字、ハイフン「 - 」が続き、最後の一字はアルファベットか数字。(RFC1035 2.3.1)
  8. labelの最大長は 63字 (RFC1035 2.3.1)
  9. domainの最大長は 255字 (RFC2821 4.5.3.1)
  10. domainは、fully qualifiedで、DNSのtype AもしくはMXレコードでresolvableでなければならない (RFC2821 3.6)

んで、このあと3ページにわたって、色々解説しながら、PHPによるメールアドレス検証関数を実際に作っている。(それをここに写すのは、面倒なのとちょっと悪いような気がするので省略しますが、ご希望があるようなら考えます)

また、記事の最後に面白いことが書いてあるんだけど、 世間のメールアドレス検証は結構いい加減だ、てことは、 spamボットよけに、 {^c\@**Dog^}@example.com といったメールアドレスを使えるんじゃないか、という提案。

よく、webページに画像でメールアドレスを載せたりするけど、(アンカータグはらずに)このようなメールアドレスを文字で載せておけば、人間はコピペできて楽だし、ボットは正しく認識しない可能性が高いので安全じゃないか? みたいな。

……微妙かな。

今回、

正規表現:メールアドレスかどうか調べる - phpspot

PHPでメールアドレスかどうか調べる方法

re: PHPでメールアドレスかどうか調べる方法 (ハズレ日記)

と話題が進んできて(紹介漏れがあったらごめんなさい) ちょっと思ったんだけど、 メールアドレスに一致する正規表現に、「メールアドレスに一致する正規表現は「ありません」」って書いてあるけど、よくよむと、「クオートすればなんでも入るから」って話ですよね。

(このクソ長い正規表現て、確か、Oreillyの "Perl in a Nutshell" かなにかに載っていたような気がするんだけど、昔それ読んで、へー、メールアドレスの検証って大変なんだなーと思ったんだけど)

でも今回の記事読んで、ある程度現実的な線でちゃんとした検証する方法もあるんだなーと。思いました。(DNSはひかんでもいいような気がするけど)

あと、ちょっと文句みたいになるけど、「メールアドレスはこうやって検証すればいい」ってサンプルを紹介するときは、RFCなどの根拠を出さないとあまり意味がないような気がした。(この記事読んでそう思ったんだけど)

あ、あと今回読んだ記事は、Linux Journal の#158, June 2007号 に掲載されていたものでした。

http://www.linuxjournal.com/issue/158