2008年2月25日月曜日
【PHP】メールアドレスをチェックする方法色々【正規表現】
正規表現によるメールアドレスの有効性のチェックは非常に複雑で困難である。
ソーシャルブックマークでも度々エントリが上位になる。
■ PHPでメールアドレスを確認する「正しい方法」(Linux Journal誌の記事より)
リンク先で紹介しているのは、以下の RFC 準拠によるメールアドレスチェック。
- メールアドレスは local part と domain が @ で区切られて構成されている。(RFC2822)
- local partは、アルファベット、数字、以下の記号 ! # $ % & ' * + - / = ? ^ _ ` { | } ~ で、ドット「 . 」で区切られている場合がある。ただし、最初、最後、他のドットの隣にあってはいけない。(つまり連続しないことということか) (RFC2822 3.2.4)
- local partは、 クオーテーションマーク「 " 」のなかにスペースを含むいろんな文字が入った quoted string を含むことがある (RFC2822 3.2.5)
- \@ などの "quoted pair" をlocal partに含むものも「正しい」が "obsolete" (RFC822、RFC2822 4.4) (RFC2822はRFC822をsupersedeしてobsoleteにした、とある)
- local partの最大長は 64文字 (RFC2821 4.5.3.1)
- domainは、labelがドットで区切られたものである (RFC1035 2.3.1)
- domainは、アルファベットで始まり、その後に、0文字以上のアルファベット、数字、ハイフン「 - 」が続き、最後の一字はアルファベットか数字。(RFC1035 2.3.1)
- labelの最大長は 63字 (RFC1035 2.3.1)
- domainの最大長は 255字 (RFC2821 4.5.3.1)
- domainは、fully qualifiedで、DNSのtype AもしくはMXレコードでresolvableでなければならない (RFC2821 3.6)
ソースは以下。
function check_email_address($email) {
// First, we check that there's one @ symbol, and that the lengths are right
if (!ereg("^[^@]{1,64}@[^@]{1,255}$", $email)) {
// Email invalid because wrong number of characters in one section, or wrong number of @ symbols.
return false;
}
// Split it into sections to make life easier
$email_array = explode("@", $email);
$local_array = explode(".", $email_array[0]);
for ($i = 0; $i < sizeof($local_array); $i++) {
if (!ereg("^(([A-Za-z0-9!#$%&'*+/=?^_`{|}~-][A-Za-z0-9!#$%&'*+/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$", $local_array[$i])) {
return false;
}
}
if (!ereg("^\[?[0-9\.]+\]?$", $email_array[1])) { // Check if domain is IP. If not, it should be valid domain name
$domain_array = explode(".", $email_array[1]);
if (sizeof($domain_array) < 2) {
return false; // Not enough parts to domain
}
for ($i = 0; $i < sizeof($domain_array); $i++) {
if (!ereg("^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$", $domain_array[$i])) {
return false;
}
}
}
return true;
}
PEAR::Mail_RFC822 というのがある。
mixed isValidInetAddress(string $data, [boolean $strict = false])
返り値: 正しければ、配列を返す。array("username","domain")
正しくなければ、False。 パラメータ: string $data - メールアドレス boolean $strict - メールアドレスチェックの厳格性。True の場合、英数字、ピリオド、ハイフン、アンダースコアのみ許可する
この関数は以下のように実装されている。
function isValidInetAddress($data, $strict = false)
{
$regex = $strict ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+¥.)+[0-9a-z]{2,})$/i' : '/^([*+!.$|¥'¥¥%¥/0-9a-z^_`{}=?‾:-]+)@(([0-9a-z-]+¥.)+[0-9a-z]{2,})$/i';
if (preg_match($regex, trim($data), $matches)) {
return array($matches[1], $matches[2]);
} else {
return false;
}
}
上記リンク先によると、実用的な「メールアドレスに一致する正規表現」はない。
正しいアドレスを通して、なるべく怪しいものをはじく正規表現は次のようなコード。
$mailre = '^[\x01-\x7F]+@(([-a-z0-9]+\.)*[a-z]+|\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\])';
以前も或るメールアドレスを調べる正規表現に関するエントリが上がり、それに関連するエントリが続いた。
その時に分かったことがあって上のエントリを書いた。
上のエントリの参照元に「「ユーザーが入力したそのメールアドレスで本当に連絡が取れるかを確認したい」 という本来の要求仕様=やりたいこと=がいつのまにか「メールアドレスの書式として正しいかを確認したい」」というのがあって、なるほどと思った。
メールアドレスが有効であるか(メールが送信できる、本人確認が可能など)を求めるなら、参照元の様に
仮登録->確認メール受信->メールのURLから本登録
という手順が必要。
実際、Web サービスの殆どはそうなっているだろう。
その場合は DNSからドメインの有効性チェックをするのもやりすぎでもないのかもしれない。
ただ、単なるメールフォームで確認メールを使ったら面倒だし、敷居が高すぎてメールしてくれないだろう。
結局、プログラマがどこまで拘るかによるのかもしれない。RFC 準拠してないアドレスも取得可能だしスペルミスもあるし、確認用のメールアドレス入力を用意してもコピペしたら意味がない。
メールを送信して確認を取らないのであれば全部一緒で、XSS等の悪意ある入力だけ気をつければ良いんじゃないかとも思う。無駄な送信処理で負担は増えるけど。
登録 投稿 [Atom]