

PHPで文字列がメールアドレスかどうか判定する方法を教えてください。


CC BY-SA 3.0
2014-10-09T10:44:29.833
106
2015-01-22T08:28:15.557
37
question
php
PHPで文字列がメールアドレスか判定するには？


正規表現を使用した判定方法が以下のページに紹介されています.

  * [正規表現：メールアドレスかどうか調べる](http://phpspot.net/php/pg%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE%EF%BC%9A%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E8%AA%BF%E3%81%B9%E3%82%8B.html)
  * [メールアドレスを表す現実的な正規表現](http://qiita.com/sakuro/items/1eaa307609ceaaf51123)


CC BY-SA 3.0
2014-11-11T04:59:20.860
159
2014-12-05T01:25:51.390
2014-12-05T01:25:51.390
30
68
106
answer


アドレスっぽいかどうかチェックするだけならfilter_varで。

[code]

    $mail = filter_var($str, FILTER_VALIDATE_EMAIL)
    
[/code]

ただ、RFCに準拠させたりメールヘッダをパースする用途では使うのはNG。

いっそ、試しにメール送ってみればいいんじゃないかな


CC BY-SA 3.0
2014-11-11T14:11:24.887
161
2014-11-11T14:11:24.887
62
106
answer


Emailアドレスの検証を行うライブラリは多数存在しているので要件にあったものを選択して組み込むのがよいのではと思います。
特に日本ではキャリアのメールアドレスのような特殊なフォーマットをどう扱うか、に応じて事情が変わってきます。

Packgistで検索すると下記のライブラリが利用が多いようでした。

<https://packagist.org/packages/egulias/email-validator>


CC BY-SA 3.0
2014-12-02T05:41:36.063
235
2014-12-02T05:41:36.063
452
106
answer


UTF-8
の文字を認める国際化ドメインを前提にすると、通常の文章と区別がつかなくなるので、セキュリティ対策に議論を絞るとよいのではないかと思います。なお、Postfix
は 2.12 から [SMTPUTF8](http://www.postfix.org/SMTPUTF8_README.html)
に対応したので、Ubuntu や Debian であれば、2016年から2017年までには 2.12 を利用できるようになるでしょう。

国際化ドメインを扱う場合、従来の XSS や SQL インジェクション対策に加えて、キリル文字をラテン文字に混在させる
([偽キリル文字](http://ja.wikipedia.org/wiki/%E5%81%BD%E3%82%AD%E3%83%AA%E3%83%AB%E6%96%87%E5%AD%97))
など肉眼では区別できない文字を使ったなりすましドメインを識別する必要があるか、考える必要があります。2005年ごろにさまざまなブラウザーがなりすましドメインの対応に追われました。

なりすまし対策の例として Gmail を挙げます。  
Gmail
の[仕様](https://support.google.com/mail/answer/81126#format)では、なりすまし対策としてメールアドレスは
UTS#39 の「[Highly
Restrictive](http://www.unicode.org/reports/tr39/#Restriction_Level_Detection)」を満たすことを求めています。具体的には、それぞれの文字の
Unicode スクリプトプロパティが1種類もしくは複数の種類の場合、指定した組み合わせであることを要求します。

日本語のドメインを対象とするのであれば、スクリプトプロパティの組み合わせは Latin、Han、Hiragana、Katakana
で構成されなければなりません。ほかに認められる複数の組み合わせの例は Latin、Han、Bopomofo (台湾で使われる注音符号) もしくは Latin
+ Han + Hangul です。

スクリプトの組み合わせのほかの例として、Firefox の[IDN
表示アルゴリズム](https://wiki.mozilla.org/IDN_Display_Algorithm#Current_Algorithm)は制限レベルに
Moderately Restrictive を採用しています。

Unicode スクリプトプロパティの組み合わせを判定するには PCRE や intl の `Spoofchecker`
を使います。自分でライブラリを実装するのであれば、unicode.org で配布されている
[Scripts.txt](http://www.unicode.org/Public/7.0.0/ucd/Scripts.txt) を使います。

次のコードは ICU 51 とそれ以降のバージョンで確認したものです。ICU のバージョンを調べるには `INTL_ICU_VERSION`
を使います。ただし、この定数が導入されたバージョンは PHP 5.3.7 なので、それ以前のバージョンを利用していてかつ pecl
のリポジトリからインストールしていない場合、`phpinfo` 関数もしくはコマンドラインで `php -i | grep ICU` を実行します。C
言語で ICU のバージョン番号で求めるには uvernum.h のマニュアルをご参照ください。`isSuspicious` の実装に使われる
`uspoof_checkUTF8` は ICU 51 で非推奨になり、最新の ICU 54 でも使えるものの、長期的には intl
のアップグレードが必要になるでしょう。

[code]

    $spoof = new Spoofchecker;
    $spoof->setChecks(Spoofchecker::SINGLE_SCRIPT);
    
    // Cyrillic
    $str = 'Кириллица';
    // Latin + Han + Hiragana + Katakana
    $str2 = 'latin漢字ひらがなカタカナ';
    // Latin + Han + Hangul
    $str3 = 'latin漢字조선말';
    // Latin + Han + Bopomofo
    $str4 = 'latin漢字ㄅㄆㄇㄈ';
    
    var_dump(
        false === $spoof->isSuspicious($str),
        false === $spoof->isSuspicious($str2),
        false === $spoof->isSuspicious($str3),
        false === $spoof->isSuspicious($str4),
        true === $spoof->isSuspicious($str.$str2)
    );
    
[/code]

ロケールごとで認められるスクリプトの組み合わせを判定することもできます。

[code]

    // Latin + Han + Hiragana + Katakana
    $str = 'latin漢字ひらがなカタカナ';
    $pattern = '/\A[\p{Latin}\p{Han}\p{Hiragana}\p{Katakana}]+\z/u';
    
    $spoof = new Spoofchecker;
    $spoof->setAllowedLocales('en_US,ja_JP');
    
    var_dump(
        false === $spoof->isSuspicious('latin漢字ひらがなカタカナ'),
        1 === preg_match($pattern, $str)
    );
    
[/code]

ほかに、ドメイン名登録業サービスで登録可能な文字であるかどうかを判定するには準拠する IDNA のバージョンによって異なりますので、IDNA
の仕様書を調べる必要があります。IDNA2003 であれば参照される Unicode のバージョンは 3.2 です。IANA
は国際化ドメインに許可される文字のテーブルを配布しています ([Repository of IDN
Practices](https://www.iana.org/domains/idn-tables))。

濁点つきひらがなのように同じ文字を異なる表現で登録することを認めたくない場合、`normalizer_is_normalized`
を使ってチェックする必要があります。Nameprep で適用される正規化の形式は KC です。

許可する文字テーブルをもとに判定する方法を採用しているのが ZF2 の `Validator\EmailAddress` です
(判定のためのテーブルの[ディレクトリ](https://github.com/zendframework/zf2/tree/master/library/Zend/Validator/Hostname))。ただし、どこのリポジトリから採用したテーブルなのか明記されていないのと、2014年の時点では、ローカルパートは
UTF-8 に対応していません。


CC BY-SA 3.0
2014-12-22T07:17:06.803
2371
2015-01-14T00:35:03.527
2015-01-14T00:35:03.527
568
568
106
answer


何処まで確認したいかが分からないです。  
確認方法は上記に出揃っているので省くとして  
ドメイン名を取ってDNSで有効か確認(dns_get_record)までするのかな？

一応、配列取得してMXチェックすればメールが有効とか…やりすぎ感はあるけどね

[code]

    $results = dns_get_record("i.softbank.jp");
    $isMailDomain = false;
    foreach($results as $res){
        if($res['type'] == 'MX'){
            $isMailDomain = true;
            break;
        }
    }
    if($isMailDomain){echo "メールドメインだったよ";}
    else{echo "メールドメインじゃないよ";}
    /**
    Array ( 
        [0] => Array ( 
            [host] => i.softbank.jp 
            [type] => TXT 
            [txt] => v=spf1 ip4:101.110.8.0/23 ip4:126.240.66.0/24 ip4:117.46.5.64/27 ip4:117.46.7.32/27 ip4:117.46.9.96/27 ip4:117.46.11.64/27 -all 
            [class] => IN [ttl] => 1656 
        ) 
        [1] => Array ( 
            [host] => i.softbank.jp 
            [type] => MX 
            [pri] => 10 
            [target] => msv.softbank.jp 
            [class] => IN [ttl] => 75 
        ) 
    )
    **/
    
[/code]


CC BY-SA 3.0
2015-01-22T08:28:15.557
5068
2015-01-22T08:28:15.557
7676
106
answer