PHPでメールアドレスを検証する方法


218

私はメールアドレスを検証するためにこの機能を持っています:

function validateEMAIL($EMAIL) {
    $v = "/[a-zA-Z0-9_-.+]+@[a-zA-Z0-9-]+.[a-zA-Z]+/";

    return (bool)preg_match($v, $EMAIL);
}

メールアドレスが有効かどうかを確認してもよろしいですか?


1
うまくいけばうまくいきます。あなたは本当にそれを良くすることはできません、それは小さすぎます。良くないのはスタイルだけです。validateEmailcorretだけでなく、合格となり$email、ありません$EMAIL
スタン

私がすべてであるコードに大きな問題がないことを確認したかっただけです:)
Cameron

正規表現を使用してメールアドレスを検証する方法と使用しない方法の詳細については、stackoverflow.com / questions / 201323 /…もご覧ください。
レゴシア

5
これは、多くの有効な電子メールアドレスの検証に失敗します。たとえば、* @ example.comまたは'@example.comまたはme @ [127.0.0.1]またはyou @ [ipv6:08B0:1123:AAAA :: 1234]
jcoder

7
@jcoder、私はその正規表現をお勧めしているわけではありませんが、少なくとも、そのようなアドレスを使用して
サイン

回答:


568

メールアドレスが整形式かどうかを確認する最も簡単で安全な方法は、次のfilter_var()関数を使用することです。

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    // invalid emailaddress
}

さらに、ドメインがMXレコードを定義しているかどうかを確認できます。

if (!checkdnsrr($domain, 'MX')) {
    // domain is not valid
}

しかし、これはまだメールが存在することを保証しません。これを見つける唯一の方法は、確認メールを送信することです。


これで簡単な答えが得られたので、学習したい場合、または高速な答えを使用して次に進む場合は、メールアドレスの検証について自由に読んでください。何恨みっこない。

正規表現を使用してメールアドレスを検証しようとすることは「不可能」な作業です。あなたが作ったその正規表現は役に立たないと言って限ります。emailaddressesに関する3つのrfcと、間違ったemailadressesをキャッチするための正規表現の記述があり、同時に誤検知がないことは、人間にはできないことです。PHPの関数が使用する正規表現のテスト(失敗と成功の両方)については、このリストを確認してくださいfilter_var()

組み込みのPHP関数、電子メールクライアント、またはサーバーでも正しく機能しません。それでもほとんどの場合filter_var、これが最良のオプションです。

PHPが(現在)電子メールアドレスの検証に使用している正規表現パターンを知りたい場合は、PHPのソースを参照してください。

メールアドレスについて詳しく知りたい場合は、仕様を読むことをお勧めしますが、一気に読むのは簡単ではないことを警告します。

  • rfc5322
  • rfc5321
  • rfc3696
  • rfc6531(Unicode文字を許可しますが、多くのクライアント/サーバーはそれを受け入れません)

filter_var()既に述べたように、PHP 5.2以降でのみ利用可能であることに注意してください。以前のバージョンのPHPで動作させる場合は、PHPで使用されている正規表現を使用できます。

<?php

$pattern = '/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD';

$emailaddress = 'test@gmail.com';

if (preg_match($pattern, $emailaddress) === 1) {
    // emailaddress is valid
}

PS上記で使用された正規表現パターンに関するメモ(PHPソースから)。Michael Rushtonの著作権がいくつかあるようです。述べたように:「このコードを自由に使用して再配布してください。ただし、この著作権情報を保管してください。」


良い答えですが、このリンクによると:haacked.com/archive/2007/08/21/…ユーザー名またはローカルで部分的に引用符で囲まれた文字列を使用できますが、FILTER_VALIDATE_EMAILはそれを受け入れません。
Daniel

3
述べられているように、それはすべての電子メールアドレスに対して機能しません。また、私の回答の失敗したテストのリストを参照して、引用符付きの文字列が機能する場合と機能しない場合があることを確認してください。
PeeHaa 2013年

4
いいえ、そのパターンで失敗したテストが多すぎますemailtester.pieterhordijk.com/test-pattern/MTAz :-)
PeeHaa

1
このパターンは、メールが含まれている大きなテキスト文字列に対して「preg_match_all」などの関数で使用する必要がある場合に非常に複雑です。シンプルな方がいらっしゃいましたら、ぜひシェアしてください。つまり、あなたがしたい場合は:preg_match_all($ pattern、$ text_string、$ matches); 本当に大きなテキストを解析する必要がある場合、この複雑なパターンはサーバーに過負荷をかけます。
Vlado

4
@PeeHaa:Postfix 3.0は現在約2年間それをサポートしています:postfix.org/SMTPUTF8_README.html、そしてそれはUbuntu 16.04に含まれており、たとえば次のDebianリリースに含まれる予定です。Eximには実験的なサポートがあります。Gmailなどのウェブメールプロバイダーも、このようなメールの送受信のサポートを追加していますが、まだユニコードアカウントを作成することはできません。広範囲にわたる使用とサポートは手の届くところにありfilter_var、彼らが今それを変更したとしても、かなりの時間遅れます(私はバグレポートを投稿しました)。
iquito 2016年

43

これにはfilter_varを使用できます。

<?php
   function validateEmail($email) {
      return filter_var($email, FILTER_VALIDATE_EMAIL);
   }
?>

1
これはドメインを検証しないため、この関数の追加を停止します。some @ addressを追加する場合、これは有効です。そうではありません!
Herr Nentu '

1行関数を含むすべての1行関数とは何ですか?私はどこでもそれらを見ています。これはいつ「もの」になったのですか?(修辞的な)。これは停止する必要があります。
ブルーウォーター

15

私の経験では、regexソリューションには偽陽性が多すぎ、filter_var()ソリューションには偽陰性があります(特に、すべての新しいTLDの場合)。

代わりに、アドレスに電子メールアドレスの必要な部分(ユーザー、 "@"記号、ドメイン)がすべて含まれていることを確認し、ドメイン自体が存在することを確認することをお勧めします。

電子メールユーザーが外部ドメインに存在するかどうかを(サーバー側で)判断する方法はありません。

これは、Utilityクラスで作成したメソッドです。

public static function validateEmail($email)
{
    // SET INITIAL RETURN VARIABLES

        $emailIsValid = FALSE;

    // MAKE SURE AN EMPTY STRING WASN'T PASSED

        if (!empty($email))
        {
            // GET EMAIL PARTS

                $domain = ltrim(stristr($email, '@'), '@') . '.';
                $user   = stristr($email, '@', TRUE);

            // VALIDATE EMAIL ADDRESS

                if
                (
                    !empty($user) &&
                    !empty($domain) &&
                    checkdnsrr($domain)
                )
                {$emailIsValid = TRUE;}
        }

    // RETURN RESULT

        return $emailIsValid;
}

Neverbounceは、APIが97%の配信まで検証できると主張しています。もちろん、連絡先データベースの引き渡しを気にしない限り。
トムラッセル

stristr@記号が複数ある場合、ドメインの取得に失敗します。より良いにexplode('@',$email)して確認することsizeof($array)==2
アーロンGillion

@AaronGillionドメインパーツを取得するより良い方法までは正しいですがcheckdnsrr()、ドメインに@記号がある場合、メソッドはfalseを返すのと同じようにfalseを返します。
ジャバリ

11

PHPの組み込みフィルターを使用したほうがよいと思います-この特定の場合:

FILTER_VALIDATE_EMAILparamを指定すると、trueまたはfalseが返されます。


9

これはあなたの電子メールを検証するだけでなく、予期しない文字に対してそれを無害化します:

$email  = $_POST['email'];
$emailB = filter_var($email, FILTER_SANITIZE_EMAIL);

if (filter_var($emailB, FILTER_VALIDATE_EMAIL) === false ||
    $emailB != $email
) {
    echo "This email adress isn't valid!";
    exit(0);
}

4

電子メールの検証に関する「よくある質問」でこれに答えましたhttps://stackoverflow.com/a/41129750/1848217

私にとって、メールをチェックする正しい方法は次のとおりです。

  1. 記号@が存在し、その前後にいくつかの非@記号があることを確認します。 /^[^@]+@[^@]+$/
  2. いくつかの「アクティベーションコード」を記載したメールをこのアドレスに送信してみてください。
  3. ユーザーがメールアドレスを「アクティブ化」すると、すべてが正しいことがわかります。

もちろん、ユーザーが「奇妙な」電子メールを入力したときにフロントエンドに警告またはツールチップを表示して、ドメイン部分にドットを付けない、引用符なしに名前にスペースを付けるなどの一般的な間違いを避けることができます。ただし、ユーザーが本当に必要な場合は、アドレス「hello @ world」を受け入れる必要があります。

また、メールアドレスの標準は以前からあり、進化する可能性があることを覚えておく必要があるため、「標準で有効な」正規表現を何度も入力することはできません。また、具体的なインターネットサーバーの中には、一般的な標準の詳細に失敗し、実際には独自の「変更された標準」で動作するものがあることを覚えておく必要があります。

したがって、@を確認し、フロントエンドでユーザーにヒントを与え、指定されたアドレスに確認メールを送信します。


1
あなたの正規表現はをチェックし@ますが、電子メールを管理するRFCのいずれかに対して有効かどうかは実際にはチェックしません。また、記載されているとおりに機能しません。regex101.comで実行したところ、有効なアドレスと一致しませんでした
Machavity

あなたは正規表現だけを読んだり、答え全体を読んだりしますか?完全にあなたに同意しません。ちょうど私に言ってください、どのRFCに従って、gmail.comサーバーはjoe@gmail.comとjo.e@gmail.comが同じアドレスであると想定していますか?標準またはFRESH標準で動作しないサーバーがたくさんあります。ただし、ユーザーのメールを配信します。正規表現を1回入力し、それだけで検証した場合、それが今後も正しく機能し、将来のユーザーが「新しい」メールで失敗しないという保証はありません。したがって、私の立場は同じです。メールアドレスを確認する場合の要点-アクティベーションメールを送信するだけです。
FlameStorm 16

@Machavityですが、正規表現のバグレポートに感謝します。修正しまし/^[^@]+@[^@+]$//^[^@]+@[^@]+$/
FlameStorm

正規表現を修正するための小道具ですが、それは方法をどのように改善しfilter_varますか?正しくフォーマットされていないアドレスを受け入れるという問題も修正されません。そうでjoe@domainない場合、正規表現は有効なメールアドレスとして喜んで受け入れます
Machavity

@Machavity、たとえば、サーバーに具体的なバージョンのPHPがあり、それを最新に更新することはできません。たとえば、php 5.5.15があります。2018年に有効なメールの基準が拡張されました。PHP 7.3.10ですぐに実現されます。そして、うまく機能する関数がありますfilter_var($email, FILTER_VALIDATE_EMAIL, $newOptions)。ただし、サーバーに古い機能があり、場合によっては更新できません。そして、あなたはいくつかの新しい有効なメールでクライアントを失います。また、もう一度気づきますが、すべてのメール配信サーバーが、一般的な最新のメールアドレスの標準に厳密に従っているわけではありません。
FlameStorm 16

3

メールアドレスから提供されたドメインが有効かどうかを確認したい場合は、次のようにします。

/*
* Check for valid MX record for given email domain
*/
if(!function_exists('check_email_domain')){
    function check_email_domain($email) {
        //Get host name from email and check if it is valid
        $email_host = explode("@", $email);     
        //Add a dot to the end of the host name to make a fully qualified domain name and get last array element because an escaped @ is allowed in the local part (RFC 5322)
        $host = end($email_host) . "."; 
        //Convert to ascii (http://us.php.net/manual/en/function.idn-to-ascii.php)
        return checkdnsrr(idn_to_ascii($host), "MX"); //(bool)       
    }
}

これは、有効なメール形式が有効なメールを意味しないため、標準的なメール検証とともに、多くの無効なメールアドレスをフィルタリングする便利な方法です。

idn_to_ascii()(または彼の姉妹関数idn_to_utf8())関数 PHPインストールで使用できない場合があることに注意してください。拡張PECL intl> = 1.0.2およびPECL idn> = 0.1が必要です。

また、電子メールのドメイン部分としてのIPv4またはIPv6(などuser@[IPv6:2001:db8::1])は検証できず、名前付きホストのみが検証できることに注意してください。

詳細はこちら


メールアドレスのホスト部分がIPv6形式のIPアドレスである場合は機能しないと思います
GordonM

2

ここで答えを読んだ後、これは私が終わったものです:

public static function isValidEmail(string $email) : bool
{
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        return false;
    }

    //Get host name from email and check if it is valid
    $email_host = array_slice(explode("@", $email), -1)[0];

    // Check if valid IP (v4 or v6). If it is we can't do a DNS lookup
    if (!filter_var($email_host,FILTER_VALIDATE_IP, [
        'flags' => FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE,
    ])) {
        //Add a dot to the end of the host name to make a fully qualified domain name
        // and get last array element because an escaped @ is allowed in the local part (RFC 5322)
        // Then convert to ascii (http://us.php.net/manual/en/function.idn-to-ascii.php)
        $email_host = idn_to_ascii($email_host.'.');

        //Check for MX pointers in DNS (if there are no MX pointers the domain cannot receive emails)
        if (!checkdnsrr($email_host, "MX")) {
            return false;
        }
    }

    return true;
}

1

さまざまなドット、アンダースコア、ダッシュを使用できる実際の正規表現を探している場合は、次のようになります[a-zA-z0-9.-]+\@[a-zA-z0-9.-]+.[a-zA-Z]+。これにより、かなり愚かなメールtom_anderson.1-neo@my-mail_matrix.comを検証することができます。


0
/(?![[:alnum:]]|@|-|_|\.)./

現在、HTML5フォームを使用するとtype=email、ブラウザーエンジンには独自のバリデーターがあるため、既に80%の安全性があります。それを補完するには、この正規表現をあなたに追加してpreg_match_all()否定します:

if (!preg_match_all("/(?![[:alnum:]]|@|-|_|\.)./",$email)) { .. }

検証のためにHTML5フォームで使用される正規表現を見つける
https://regex101.com/r/mPEKmy/1


説明なしで反対投票も嫌いです。まあ私は彼が言うかもしれないと思います:ブラウザーのメールチェック(クライアント側)はまったく安全ではありません。コードを変更することで、誰でも何でもサーバーに送信できます。したがって、サーバー側で(もう一度)チェックを行うのは明白で最も安全な方法です。ここでの質問はPHPに基づいているため、Cameronはクライアントソリューションではなくサーバーソリューションを探していました。
ジョニー

この回答は完全にPHP関連ではないかもしれませんが、HTML提案は電話/ PCのみを使用する「標準」ユーザーをカバーしています。また、ユーザーはサイトを使用しているときに「彼の」ブラウザで直接情報を取得します。サーバーサイドでの実際のチェックはこれでカバーされていません。ところで、@ ThieliciousはPHPの変更について言及しているため、彼のコメントはIMHOに関連しています。
k00ni

「ブラウザーエンジンには独自のバリデーターがあるため、80%安全である」という仮定のために、おそらく反対票を受け取りました。ブラウザ経由以外にhttpリクエストを送信する方法は他にもたくさんあるため、ブラウザエージェントをチェックしても、リクエストが安全であるとは限りません。
ジャバリ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.