PHP でフォームデータをメールアドレス入力チェックする方法

はじめに

実務にて、フォームデータをメールアドレス入力チェックするバリデーション(入力値の検証)を実装する作業があり、それを解決した情報になります。Web 開発の初心者、初学者の方にもわかりやすいように、ソースコードを編集してサンプルを公開しています、ご参考になれば幸いです。

検証環境

サンプル

解説

サンプルのソースコードを基に、メールアドレス入力チェック(メールアドレスの形式チェック、DNS レコードチェック)について説明します。

メールアドレスの形式チェック

メールアドレス とは、電子メールの送受信元を示す文字列です。

メールアドレスの標準仕様は、 RFC 5321(Simple Mail Transfer Protocol)と RFC 5322(Internet Message Format)に情報があります。

RFC(Request for Comments)とは、IETF(Internet Engineering Task Force)によるインターネットの技術仕様を纏めた文書群のことです。

メールアドレスの形式は、下記のようになっています。

local-part@domain-part

@ の前にある local-part とは、送り先を示す文字列です。下記のような仕様があります。

  1. 最大 64 文字(プロバイダー、又はメールソフトの制約によって変動する)
  2. ラテン文字 を書ける
  3. 数字 を書ける
  4. ! # $ % & ' * + - / = ? ^ _ ` { | } ~ を書ける(プロバイダーの制限による)
  5. 先端と終端に . は書けない
  6. . は連続して書けない
  7. " で囲むと ( ) < > [ ] : ; @ , を書ける
  8. " で囲むと制限なしで . を書ける
  9. " で囲むと スペース を書ける
  10. " 内で \ を前に書くと \ " を書ける

@ の後にある domain-part とは、メールサーバーを示す文字列です。下記のような仕様があります。

  1. 最大 253 文字
  2. ラテン文字 を書ける
  3. 数字 を書ける
  4. - (先端をラテン文字、又は数字で書いた場合)
  5. DNS レコードに名前解決される FQDN を書ける
  6. [ ] で囲まれた IP アドレス を書ける

メールアドレスは、最大 254 文字です。

前述の仕様を満たす、且つ RFC 6531(SMTP Extension for Internationalized Email)と RFC 6532(Internationalized Email Headers)の UTF-8 対応を含めた RFC に完全に準拠した正規表現を導き出すことは、晦日に月が出るようなもんです。

そこで、下記のように filter_var でチェックします。

検証フィルタ の FILTER_VALIDATE_EMAIL を指定すると、メールアドレスが RFC 822(Standard for the Format of ARPA Internet Text Messages)の addr-spec 形式 に沿っているか検証してくれます。コメント、空白の折り返し、. が無いドメイン名に対応していないことに気を付けてください。

function checkEmail(string $email): bool {
  return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

下記の文字列とマッチします。

Localpart@example.com
Localpart.123@example.com
local+part/Local=part@example.com
Localpart@www.example.com
Localpart@[192.0.2.1]
{Localpart}@example.com
!#$%&'*+-/=?^_`.{|}~@example.com
"Local@part"@example.com
"Local\ Part"@example.com
"Local.\\Part"@example.com
":Localpart"@example.com
123@example.com
Localpart@xn--wgv71a119e.com

下記の文字列とマッチしません。

Localpart.@example.com
Localpart..123@example.com
localpart@com
(Localpart)@example.com
"lo cal p@rt!"@example.com
"lo.cal part"@example.com
"()<>[]:,;@\\"\\\\!#$%&\'*+-/=?^_`{}| ~.a"@example.com
" "@example.com
Localpart@日本語.com
Localpart@🚑.com

IDN を含む有効なメールアドレスにマッチしないことに気を付けてください。domain-part が Punycode にエンコードされたアドレスにはマッチします。

検証フィルタがどのように動作しているのか情報が必要な場合は、PHP の ソースコード に処理が書いてあります。

DNS レコードのチェック

DNS レコードとは、DNS サーバーが持っているゾーンファイルの一行一行のことです。

DNS(Domain Name System)とは、IP アドレスとドメイン名の正引き、逆引きを管理するシステムのことです。正引き(せいひき)とは、ドメイン名を IP アドレスに変換することで、逆引きは IP アドレスをドメイン名に変換することです。

DNS サーバーとは、DNS の機能が実装されているサーバーのことです。ゾーンファイルとは、ドメイン名と IP アドレスの対応表のことです。

厳密には、DNS サーバーは DNS コンテンツサーバーと DNS キャッシュサーバーに大別されていて、ゾーンファイルは DNS コンテンツサーバーが保持しています。

下記のように、checkdnsrr で domain-part に対応する DNS レコード(MX / A / AAAA レコード)のチェックができます。メールを送信する前に、メールを送信できるかどうかを確認ができます。第 2 引数が無い場合、MX が指定されます。

function checkEmail(string $email): bool {
  $array = explode('@', $email);
  $domain_part = array_pop($array);

  return filter_var($email, FILTER_VALIDATE_EMAIL) !== false &&
    (checkdnsrr($domain_part) || checkdnsrr($domain_part, 'A') || checkdnsrr($domain_part, 'AAAA'));
}

MX レコードとは、メールの配送先(メールサーバー)が書かれている行です。

A レコードとは、IPv4(Internet Protocol version 4)でドメイン名に対応する IP アドレスが書かれている行です。AAAA レコードとは、IPv6(Internet Protocol version 6)でドメイン名に対応する IP アドレスが書かれている行です。

IPv4 と IPv6 は、インターネットの通信規約のことです。

MX レコードのチェック以外に、A / AAAA レコードのチェックも含めているのは、RFC 5321(Simple Mail Transfer Protocol)にある下記の記述によるものです。

If an empty list of MXs is returned, the address is treated as if it was associated with an implicit MX RR, with a preference of 0, pointing to that host.

(MX レコードの空リストが返された場合、アドレスは、そのホストを示す、優先度 0 の暗黙の MX レコードに関連付けられているかのように扱われます。)

RFC 5321 5.1. Locating the Target Host

つまり、アドレスがメールを受け付けない場合でも、A / AAAAレコードがメールサーバーアドレスであると解釈するということです。

この仕様に対して、RFC 7505(A “Null MX” No Service Resource Record for Domains That Accept No Mail)が発行されています。詳細の説明は、話が逸れてしまうので省略します。

まとめ

基本的に filter_varcheckdnsrr でチェックすると良いと思います。しかし、filter_var でチェックする場合に、気を付けなければならない問題があります。

現在は禁止されていますが、2009 年以前まで、携帯電話のメールアドレス(docomo.ne.jp、ezweb.ne.jp、i.softbank.jp)では、local-part に . の連続、終端に . を使用している RFC(Request for Comments)に違反しているアドレスを作成することができました。

中年層、高齢層のユーザーが今でも RFC 違反アドレスを使用している可能性があります。

サービスを利用するユーザーの年齢層を考慮して、メールアドレスの形式チェックをやめる選択も視野に入れる必要があります。

以上です。

おわりに

サンプルのソースコードを再利用する際は、要件定義やコーディング規約にお気を付けください。