ホームページ  >  記事  >  バックエンド開発  >  PHP は RFC 準拠の電子メール アドレス検証を実装します

PHP は RFC 準拠の電子メール アドレス検証を実装します

WBOY
WBOYオリジナル
2016-07-25 08:56:421392ブラウズ
  1. /*

  2. Copyright 2009 Dominic Sayers
  3. (dominic_sayers@hotmail.com)
  4. (http://www.dominicsayers.com)

  5. このソース ファイルは Common Public Attribution License バージョンの対象です1.0 (CPAL) ライセンス。

  6. ライセンス条項は、ワールドワイドウェブ (http://www.opensource.org/licenses/cpal_1.0) から入手できます
  7. */
  8. function is_email ($email, $checkDNS = false) {
  9. // チェックしてください$email は有効なアドレスです
  10. // (http://tools.ietf.org/html/rfc3696)
  11. // (http://tools.ietf.org/html/rfc5322#section-3.4.1)
  12. / / (http://tools.ietf.org/html/rfc5321#section-4.1.3)
  13. // (http://tools.ietf.org/html/rfc4291#section-2.2)
  14. // (http: //tools.ietf.org/html/rfc1123#section-2.1)
  15. // 現在の電子メール アドレスは、
  16. から区切られた「ローカル部分」で構成されます。 // 「ドメイン部分」 (完全修飾ドメイン名) は、アットマーク ("@")。
  17. // (http://tools.ietf.org/html/rfc3696#section-3)
  18. $index = strrpos($email,'@');

  19. if ($index === false) は false を返します。 // アットマークはありません

  20. if ($index === 0) return false; // ローカル部分はありません
  21. if ($index > 64) return false; // ローカル部分が長すぎます

  22. $localPart = substr($email, 0, $index);

  23. $domain = substr($email, $index + 1);
  24. $domainLength = strlen($domain);
  25. if ($domainLength === 0) は false を返します。 // ドメイン部分はありません
  26. if ($domainLength > 255) return false; // ドメイン部分が長すぎます

  27. // RFC に準拠しているかどうかローカル部分を確認してみましょう...

  28. //
  29. // ピリオド (".") は...表示される場合がありますが、
  30. // ローカル部分の開始または終了に使用することはできません。または複数の連続するピリオドが表示されます。
  31. // (http://tools.ietf.org/html/rfc3696#section-3)
  32. if (preg_match('/^\.|\.\.|\.$/', $localPart) > 0 ) false を返します。 // ドットが間違った場所にあります

  33. //

  34. // アットマーク ("@")、バックスラッシュ、二重引用符、カンマ、または角括弧以外の ASCII グラフィック (印刷) 文字は、
  35. // 引用符なしで使用できます。 除外される文字のリスト
  36. // が出現する場合は、引用符で囲む必要があります
  37. // (http://tools.ietf.org/html/rfc3696#section-3)
  38. if (preg_match('/^" (?:.)*"$/', $localPart) > 0) {
  39. // ローカル部分は引用符で囲まれた文字列
  40. if (preg_match('/(?:.)+[^\\]"(?: .)+/', $localPart) > return false // 引用符付き文字列内のエスケープされていない引用符
  41. } else {
  42. if (preg_match('/[ @\[\]\\",]/', $ localPart) > 0)
  43. // 除外された文字がすべてエスケープされていることを確認します
  44. $stripped = preg_replace('/\\[ @\[\]\\",]/', '', $localPart);
  45. if (preg_match ('/[ @\[\]\\",]/', $tripped) > 0) false を返します。 // 引用符で囲まれていない除外文字
  46. }

  47. // 次に、ドメイン部分を確認してみましょう...

  48. // ドメイン名は角かっこ内の IP アドレスに置き換えることもできます

  49. // (http://tools.ietf.org/html/rfc3696#section-3)
  50. // (http://tools.ietf. org/html/rfc5321#section-4.1.3)
  51. // (http://tools.ietf.org/html/rfc4291#section-2.2)
  52. if (preg_match('/^\[(.)+]$ /', $domain) === 1) {
  53. // これはアドレスリテラルです
  54. $addressLiteral = substr($domain, 1, $domainLength - 2);
  55. $matchesIP = array();
  56. // アドレスリテラルの末尾から IPv4 部分を抽出します (存在する場合)
  57. if (preg_match('/\b(?:(?:25[0-5]|2[0-4][ 0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[ 01]?[0-9][0-9]?)$/', $addressLiteral, $matchesIP) > 0) {
  58. $index = strrpos($addressLiteral, $matchesIP[0]);
  59. if ($index === 0) {
  60. // 有効な IPv4 アドレス以外には何もないので...
  61. return true;
  62. }else {
  63. // 混合アドレス (IPv6 + IPv4) での試行であると仮定します
  64. if ($addressLiteral[$index - 1] !== ':') return false; // IPv4 アドレスの前の文字は ':' である必要があります
  65. if (substr($addressLiteral, 0, 5) !== 'IPv6:') return false; // RFC5321 セクション 4.1.3

  66. $IPv6 = substr($addressLiteral, 5, ($index ===7) ? 2 : $index - 6);

  67. $groupMax = 6;
  68. }
  69. } else {
  70. // 純粋な IPv6 での試みである必要があります
  71. if (substr($addressLiteral, 0, 5) !== 'IPv6:') return false; // RFC5321 セクション 4.1.3
  72. $IPv6 = substr($addressLiteral, 5);
  73. $groupMax = 8;
  74. }

  75. $groupCount = preg_match_all('/^[0-9a-fA-F]{0,4}|\:[0-9a-fA-F]{0,4}|(.)/', $IPv6, $ IP に一致します);

  76. $index = strpos($IPv6,'::');

  77. if ($index === false) {

  78. // 正確に正しい数のグループが必要です
  79. if ($groupCount !== $groupMax) return false; // RFC5321 セクション 4.1.3
  80. } else {
  81. if ($index !== strrpos($IPv6,'::')) return false; // 複数の '::'
  82. $groupMax = ($index === 0 || $index === (strlen($IPv6) - 2)) ? $groupMax : $groupMax - 1;
  83. if ($groupCount > $groupMax) は false を返します。 // アドレス内の IPv6 グループが多すぎます
  84. }

  85. // 一致しない文字をチェック

  86. array_multisort($matchesIP[1], SORT_DESC);
  87. if ($matchesIP[1][0] !== '') は false を返します。 // アドレスに不正な文字があります

  88. // これは有効な IPv6 アドレスなので...

  89. return true;
  90. } else {
  91. // これはドメイン名です...

  92. // 正当なインターネット ホスト名の構文は RFC-952 で指定されました

  93. // ホスト名の構文の 1 つの側面が変更されました:
  94. // 最初の文字の制限が緩和され、
  95. // 文字または桁。
  96. // (http://tools.ietf.org/html/rfc1123#section-2.1)
  97. //
  98. // NB RFC 1123 は RFC 1035 を更新しますが、これは現時点では RFC 1035 を読んでも明らかではありません。
  99. //
  100. // 電子メールや Web などの最も一般的なアプリケーションでは、通常、エスケープされた文字列は許可されません
  101. // (http://tools.ietf.org/html/rfc3696#section-2)
  102. //
  103. // 文字アルファベット文字、数字、ハイフンのセット以外をドメイン名に含めてはなりません
  104. // SMTP クライアントまたはサーバーのラベル
  105. // (http://tools.ietf.org/html/rfc5321#section-4.1.2)
  106. //
  107. // RFC5321 では、SMTP 目的でドメイン名の末尾のドットを使用することを禁止しています
  108. // (http://tools.ietf.org/html/rfc5321#section-4.1.2)
  109. $matches = array ();
  110. $groupCount = preg_match_all('/(?:[0-9a-zA-Z][0-9a-zA-Z-]{0,61}[0-9a-zA-Z]|[a-zA- Z])(?:\.|$)|(.)/', $domain, $matches);
  111. $level = count($matches[0]);

  112. if ($level == 1) は false を返します。 // メールホストを TLD にすることはできません

  113. $TLD = $matches[0][$level - 1];

  114. if (substr($TLD, strlen($TLD) - 1, 1) === '.') は false を返します。 // TLD はドットで終わることはできません
  115. if (preg_match('/^[0-9]+$/', $TLD) > 0) return false; // TLD をすべて数値にすることはできません

  116. // 一致しない文字をチェック

  117. array_multisort($matches[1], SORT_DESC);
  118. if ($matches[1][0] !== '') は false を返します。 // ドメイン内の不正な文字、または 63 文字を超えるラベル

  119. // DNSをチェックしますか?

  120. if ($checkDNS && function_exists('checkdnsrr')) {
  121. if (!(checkdnsrr($domain, 'A') || checkdnsrr($domain, 'MX'))) {
  122. false を返します。 // ドメインは実際には存在しません
  123. }
  124. }

  125. // 他の要素をすべて削除し、残ったものが真実でなければなりません。

  126. // (シャーロック ホームズ、The Sign of Four)
  127. return true;
  128. }
  129. }

  130. 関数unitTest ($email, $reason = '') {

  131. $expected = ($reason === '') ?真/偽;
  132. $valid = is_email($email);
  133. $not = ($valid) ? '' : ' ない';
  134. $unexpected = ($valid !== $expected) ? 「 これは予想外でした!」 : '';
  135. $reason = ($reason === '') ? "" : " 理由: $reason";
  136. return "アドレス $email は $無効です。$unexpected$reason
    n";
  137. }

  138. // 電子メール検証テスト ケース (Dominic Sayers、2009 年 1 月)

  139. // 有効なアドレス
  140. echo UnitTest('first.last@example.com');
  141. echounitTest('1234567890123456789012345678901234567890123456789012345678901234@example.com');
  142. echounitTest('"最初と最後"@example.com');
  143. echounitTest('"first\"last"@example.com'); // これが有効かどうか完全にはわかりません
  144. echounitTest('first\@last@example.com');
  145. echounitTest(' "first@last"@example.com');
  146. echounitTest('first\\last@example.com'); // これは一重引用符の文字列でもエスケープされるため、「first\last」をテストしていることに注意してください。 @example.com
  147. echo UnitTest('first.last@x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x 23456789.x23456789.x23456789.x23456789.
  148. x23456789.x23456789.x23456789.x23456789。 x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x2345');
  149. echounitTest('first.last@[12.34.56.78]'); first.last@[IPv6:::12.34 .56.78]');
  150. エコーユニットテスト('first.last@[IPv6:1111:2222:3333::4444:12.34.56.78]');
  151. エコーユニットテスト('first.last@[IPv6:1111:2222: 3333:4444:5555:6666:12.34.56.78]');
  152. echounitTest('first.last@[IPv6:::1111:2222:3333:4444:5555:6666]'); .last@[IPv6:1111:2222:3333::4444:5555:6666]');
  153. echounitTest('first.last@[IPv6:1111:2222:3333:4444:5555:6666::]');
  154. echounitTest('first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]');
  155. echounitTest('first.last@x23456789012345678901234567890123456789012345678901234567890123.example.com');
  156. echounitTest('first.last@1xample.com');
  157. echounitTest('first.last@123.example.com');

  158. // 無効なアドレス

  159. echounitTest('first.last', "No @");
  160. echounitTest('@example.com', "ローカル部分がありません");
  161. echo UnitTest('12345678901234567890123456789012345678901234567890123456789012345@example.com', "64 文字を超えるローカル部分");
  162. echounitTest('.first.last@example.com', "ローカル部分はドットで始まります");
  163. echounitTest('first.last.@example.com', "ローカル部分はドットで終わります");
  164. echounitTest('first..last@example.com', "ローカル部分に連続したドットがあります");
  165. echo UnitTest('"first"last"@example.com', "ローカル部分にはエスケープされていない除外文字が含まれています");
  166. echo UnitTest('first\\@last@example.com', "ローカル部分にはエスケープされていない除外文字が含まれています" );
  167. echo unitTest('first.last@', "ドメインなし"); 9.x23456789.x23456789.x23456789。 x23456789.x23456789.x23456789.
  168. x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x2345678 9.x23456789.x23456789.x23456', "ドメインが 255 文字を超えています");
  169. echounitTest('first.last@[ .12.34.56.78]', "IPv4 アドレスの前に付けられる文字は ':' のみです");
  170. echo UnitTest('first.last@[12.34.56.789]', "IPv4 として解釈できないため、IPv6 タグは欠落しています");
  171. echo UnitTest('first.last@[::12.34.56.78]', "IPv6 タグが欠落しています");
  172. echo UnitTest('first.last@[IPv5:::12.34.56.78]', "IPv6 タグが間違っています");
  173. echounitTest('first.last@[IPv6:1111:2222:3333::4444:5555:12.34.56.78]', "IPv6 グループが多すぎます (最大 4 つ)"); echounitTest('first.last@[IPv6:1111:2222:3333:4444:5555:12.34.56.78]', "IPv6 グループが不足しています");
  174. echounitTest('first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:12.34.56.78]', "IPv6 グループが多すぎます (最大 6 つ)");
  175. echounitTest('first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777]', "IPv6 グループが不足しています");
  176. echounitTest('first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]', "IPv6 グループが多すぎます (最大 8 つ)");
  177. echounitTest('first.last@[IPv6:1111:2222::3333::4444:5555:6666]', "「::」が多すぎます (なしまたは 1 つ)");
  178. echounitTest('first.last@[IPv6:1111:2222:3333::4444:5555:6666:7777]', "IPv6 グループが多すぎます (最大 6 つ)");
  179. echounitTest('first.last@[IPv6:1111:2222:333x::4444:5555]', "x は IPv6 アドレスでは無効です");
  180. echounitTest('first.last@[IPv6:1111:2222:33333::4444:5555]', "33333 は IPv6 アドレスの有効なグループではありません");
  181. echounitTest('first.last@example.123', "TLD をすべて数字にすることはできません");
  182. echounitTest('first.last@com', "メールホストは 2 番目以下のレベルである必要があります");
  183. echounitTest('first.last@-xample.com', "ラベルをハイフンで始めることはできません");
  184. echounitTest('first.last@exampl-.com', "ラベルはハイフンで終わることはできません");
  185. echo UnitTest('first.last@x234567890123456789012345678901234567890123456789012345678901234.example.com', "ラベルは 63 オクテットを超えることはできません");

  186. // RFC3696 のテスト ケース (2004 年 2 月、http://tools.ietf.org/html/rfc3696#section-3)

  187. echo UnitTest('Abc\@def@example.com');
  188. echounitTest('Fred\ Bloggs@example.com');
  189. echounitTest('Joe.\\Blow@example.com');
  190. echounitTest('"Abc@def"@example.com');
  191. echounitTest('"Fred Bloggs"@example.com');
  192. echounitTest('user+mailbox@example.com');
  193. echounitTest('customer/Department=shipping@example.com');
  194. echounitTest('$A12345@example.com');
  195. echounitTest('!def!xyz%abc@example.com');
  196. echo UnitTest('_somename@example.com');

  197. // Doug Lovell のテスト ケース (LinuxJournal、2007 年 6 月、http://www.linuxjournal.com/article/9585)

  198. echounitTest("dclo@us.ibm.com");
  199. echounitTest("abc\@def@example.com");
  200. echounitTest("abc\\@example.com");
  201. echounitTest("Fred\ Bloggs@example.com");
  202. echounitTest("Joe.\\Blow@example.com");
  203. echounitTest(""Abc@def"@example.com");
  204. echounitTest(""Fred Bloggs"@example.com");
  205. echounitTest("customer/Department=shipping@example.com");
  206. echounitTest("$A12345@example.com");
  207. echounitTest("!def!xyz%abc@example.com");
  208. echounitTest("_somename@example.com");
  209. echounitTest("user+mailbox@example.com");
  210. echounitTest("peter.piper@example.com");
  211. echo UnitTest("Doug\ \"Ace\"\ Lovell@example.com");
  212. echounitTest(""Doug \"Ace\" L."@example.com");
  213. echo UnitTest("abc@def@example.com", "Doug Lovell 氏は、これは失敗するはずだと言っています");
  214. echounitTest("abc\\@def@example.com", "Doug Lovell 氏は、これは失敗するはずだと言っています");
  215. echounitTest("abc\@example.com", "Doug Lovell 氏は、これは失敗するはずだと言っています");
  216. echounitTest("@example.com", "Doug Lovell 氏は、これは失敗するはずだと言っています");
  217. echounitTest("doug@", "Doug Lovell はこれは失敗するはずだと言います");
  218. echo UnitTest(""qu@example.com", "Doug Lovell 氏はこれは失敗するはずだと言います");
  219. echo UnitTest("ote"@example.com", "Doug Lovell 氏はこれは失敗するはずだと言います");
  220. echounitTest(".dot@example.com", "Doug Lovell 氏は、これは失敗するはずだと言っています");
  221. echo UnitTest("dot.@example.com", "Doug Lovell 氏は、これは失敗するはずだと言っています");
  222. echo UnitTest("two..dot@example.com", "Doug Lovell 氏は、これは失敗するはずだと言っています");
  223. echounitTest(""Doug "Ace" L."@example.com", "Doug Lovell はこれは失敗するはずと言っています");
  224. echounitTest("Doug\ \"Ace\"\ L\.@example.com", "Doug Lovell はこれは失敗するはずと言っています");
  225. echounitTest("hello world@example.com", "Doug Lovell 氏は、これは失敗するはずだと言っています");
  226. echounitTest("gatsby@f.sc.ot.t.f.i.tzg.era.l.d.", "Doug Lovell はこれは失敗するはずと言っています");
  227. ?>

复制帽


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。