PHP で電話番号のバリデーションを作る

目次

結論

固定電話番号

簡易的には、PCRE 関数preg_match を利用して正規表現のマッチングによるバリデーションを実装します。

function checkLandline(string $str): int|false {
  return preg_match("/\A0(\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1})[-)]?\d{4}\z/", $str);
}

正規表現の可視化図です。

正規表現の可視化図1

もっとシンプルに、ハイフンと丸括弧を取り除いてから/\A0\d{9}\z/を通す方法も良いでしょう。

携帯電話番号

簡易的には、PCRE 関数preg_match を利用して正規表現のマッチングによるバリデーションを実装します。

function checkPhoneNumber(string $str): int|false {
  return preg_match("/\A0[5789]0[-(]?\d{4}[-)]?\d{4}\z/", $str);
}

正規表現の可視化図です。

正規表現の可視化図2

もっとシンプルに、ハイフンと丸括弧を取り除いてから/\A0\d{10}\z/を通す方法も良いでしょう。

フリーダイヤル

簡易的には、PCRE 関数preg_match を利用して正規表現のマッチングによるバリデーションを実装します。

function checkFreephoneNumber(string $str): int|false {
  return preg_match("/\A0((12|99|18|57)0[-(]?\d{3}[-)]?\d{3}|800[-(]?\d{3}[-)]?\d{4})\z/", $str);
}

正規表現の可視化図です。

正規表現の可視化図3

もっとシンプルに、ハイフンと丸括弧を取り除いてから/\A0((12|99|18|57)0\d{6}|800\d{7})\z/を通す方法も良いでしょう。

固定電話番号 + 携帯電話番号

簡易的には、固定電話番号と携帯電話番号の正規表現を|(選択肢)で組み合わせて実装します。

function checkPhoneNumber2(string $str): int|false {
  return preg_match("/\A0(\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1}|[5789]0[-(]?\d{4})[-)]?\d{4}\z/", $str);
}

正規表現の可視化図です。

正規表現の可視化図4

もっとシンプルに、ハイフンと丸括弧を取り除いてから/\A0\d{9,10}\z/を通す方法も良いでしょう。

固定電話番号 + 携帯電話番号 + フリーダイヤル

簡易的には、固定電話番号、携帯電話番号、フリーダイヤルのバリデーションを組み合わせて実装します。

function checkPhoneNumber3(string $str): int|false {
  return preg_match("/\A0((\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1}|[5789]0[-(]?\d{4}|800[-(]?\d{3})[-)]?\d{4}|(12|99|18|57)0[-(]?\d{3}[-)]?\d{3})\z/", $str);
}

正規表現の可視化図です。

もっとシンプルに、ハイフンと丸括弧を取り除いてから/\A0\d{9,10}\z/を通す方法も良いでしょう。

環境

  1. MAMP 6.8
  2. Apache 2.4.54
  3. PHP 8.2.0

解説

固定電話番号

仕様

初めに、固定電話番号の仕様を理解する必要があります。

国内電話番号の仕様は、総務省の 電気通信番号制度 に情報があります。

電話番号に関するQ&AQ1 電話番号とはどのようなものですか?より、電話番号は 0 〜 9 の数字を組み合わせた番号で、固定電話の「0-市外局番-市内局番-加入者番号」以外にも下表の様に種類があると説明があります。

1 から始まる 110番 や 119番、2 〜 9 から始まる同一市外局番が入力されることは基本的に無いでしょう。

つまり、0 から始まる電話番号が対象であることが理解できます。

次に Q2 市外局番・市内局番とはどのようなものですか? より、電話番号の構成は下記のようになります。

固定電話番号は 10 桁、市外局番 + 市内局番は 5 桁であることが理解できます。

9 桁の電話番号に関しましては、平成18年度に実施する電話番号の変更 の平成 19 年 2 月 25 日に行った電話番号逼迫対策によって消滅しています。

又、下表の様に、市外局番 + 市内局番は地域によって桁が変動することが理解できます。

実装

PCRE 関数preg_match を利用して正規表現のマッチングによるバリデーションを実装します。

市外局番 + 市内局番の前後にハイフン、或いは丸括弧で囲まれた場合の入力値を考慮します。

function checkLandline(string $str): int|false {
  return preg_match("/\A0(\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1})[-)]?\d{4}\z/", $str);
}

正規表現の可視化図です。

正規表現の可視化図1

記述している PCRE 正規表現構文 の説明になります。

  1. /デリミタ
  2. \Aエスケープシーケンス 検索対象文字列の始端
  3. () : サブパターン
  4. \d : 10 進数字 [0-9] と同じ
  5. {} : 繰り返し
  6. [] : 文字クラス
  7. ? : 量指定子 {0,1} と同じ
  8. | : 選択肢
  9. \zエスケープシーケンス 検索対象文字列の終端

もっとシンプルに、ハイフンと丸括弧を取り除いてから/\A0\d{9}\z/を通す方法も良いでしょう。

携帯電話番号

仕様

初めに、携帯電話番号の仕様を理解する必要があります。

携帯電話番号の仕様は、総務省の 電気通信番号制度 に情報があります。

電話番号に関するQ&AQ5 携帯電話やPHSに電話するには? によると、携帯電話と PHS(Personal Handy-phone System)は「070」、「080」、「090」から始まる 11 桁の番号であると理解できます。

又、特定 IP 電話番号の「050」から始まる 11 桁の番号に関しても今回の対象に含めます。

「060」から始まる FMC(Fixed-Mobile Convergence)サービスの番号に関しては、電気通信番号規則等の一部を改正する省令案に対する意見募集 より、番号を携帯電話に開放するという発表があったが、現在は検討段階にあるので除外します。

「0204」から始まる発信者課金ポケベルの番号に関しては、「02049」の沖縄テレメッセージ は 2017 年(平成 29 年)2 月 28 日にポケットベル事業から撤退、「02046」の東京テレメッセージ株式会社は 2019 年(令和元年) 9 月 30 日にページャー(マジックメール)サービスを終了しているので除外します。

又、「0201 ~ 3, 0205 ~ 9」から始まる M2M 通信等専用の電気通信番号 に関しても除外します。

実装

PCRE 関数preg_match を利用して正規表現のマッチングによるバリデーションを実装します。

ハイフン、或いは丸括弧で囲まれた場合の入力値を考慮します。

function checkPhoneNumber(string $str): int|false {
  return preg_match("/\A0[5789]0[-(]?\d{4}[-)]?\d{4}\z/", $str);
}

正規表現の可視化図です。

正規表現の可視化図2

記述している PCRE 正規表現構文 の説明になります。

  1. /:デリミタ
  2. \A:エスケープシーケンス 検索対象文字列の始端
  3. [] : 文字クラス
  4. () : サブパターン
  5. \d : エスケープシーケンス [0-9] と同じ
  6. {} : 繰り返し
  7. ? : 量指定子 {0,1} と同じ
  8. | : 選択肢
  9. \z:エスケープシーケンス 検索対象文字列の終端

もっとシンプルに、ハイフンと丸括弧を取り除いてから/\A0\d{10}\z/を通す方法も良いでしょう。

フリーダイヤル

仕様

初めに、フリーダイヤルの仕様を理解する必要があります。

因みに、「フリーダイヤル」という言葉は NTT コミュニケーションズの登録商標で、和製英語です。英語では toll-free number、Freephone、Freecall などと呼ばれます。

Q6「0△△0」型の電話番号はどのように使われているのですか? によると、料金着信払い通話(フリーフォンサービス)用の「0120」から始まる 10 桁、「0800」から始まる 11 桁、情報料回収代行の「0990」から始まる 10 桁、テレドームの「0180」から始まる 10 桁、ナビダイヤルの「0570」から始まる 10 桁の番号があると理解できます。

テレゴングの「0180」から始まる 10 桁の番号は、2012 年 5 月 31 日にサービスを終了しています。

「0AB0(A, B は 0 以外)」から始まる市外局番が存在するので、判定条件にはご注意下さい。例えば、静岡県御殿場市と静岡県駿東郡小山町の市外局番は「0550」から始まる番号です。

又、フリーダイヤルは登録者が好きな位置で番号を区切ることが可能です。

  • 0120 – A – BCDEF
  • 0120 – AB – CDEF
  • 0120 – ABC – DEF
  • 0120 – ABCD – EF
  • 0120 – ABCDE – F
  • 0120 – ABCDEF

実装

PCRE 関数preg_match を利用して正規表現のマッチングによるバリデーションを実装します。

フリーダイヤルの区切りに関して、全てに対応するのは非現実的です。今回、10 桁なら 4 桁 – 3 桁 – 3 桁、11 桁なら 4 桁 – 3 桁 – 4桁で対応します。

function checkFreephoneNumber(string $str): int|false {
  return preg_match("/\A0((12|99|18|57)0[-(]?\d{3}[-)]?\d{3}|800[-(]?\d{3}[-)]?\d{4})\z/", $str);
}

正規表現の可視化図です。

正規表現の可視化図3

記述している PCRE 正規表現構文 の説明になります。

  1. /:デリミタ
  2. \A:エスケープシーケンス 検索対象文字列の始端
  3. () : サブパターン
  4. | : 選択肢
  5. [] : 文字クラス
  6. \d : エスケープシーケンス [0-9] と同じ
  7. {} : 繰り返し
  8. ? : 量指定子 {0,1} と同じ
  9. \z:エスケープシーケンス 検索対象文字列の終端

もっとシンプルに、ハイフンと丸括弧を取り除いてから/\A0((12|99|18|57)0\d{6}|800\d{7})\z/を通す方法も良いでしょう。

固定電話番号 + 携帯電話番号

固定電話番号と携帯電話番号の正規表現を|(選択肢)で組み合わせて実装します。

function checkPhoneNumber2(string $str): int|false {
  return preg_match("/\A0(\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1}|[5789]0[-(]?\d{4})[-)]?\d{4}\z/", $str);
}

正規表現の可視化図です。

正規表現の可視化図4

もっとシンプルに、ハイフンと丸括弧を取り除いてから/\A0\d{9,10}\z/を通す方法も良いでしょう。

固定電話番号 + 携帯電話番号 + フリーダイヤル

固定電話番号、携帯電話番号、フリーダイヤルの正規表現を|(選択肢)で組み合わせて実装します。

function checkPhoneNumber3(string $str): int|false {
  return preg_match("/\A0((\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1}|[5789]0[-(]?\d{4}|800[-(]?\d{3})[-)]?\d{4}|(12|99|18|57)0[-(]?\d{3}[-)]?\d{3})\z/", $str);
}

正規表現の可視化図です。

もっとシンプルに、ハイフンと丸括弧を取り除いてから/\A0\d{9,10}\z/を通す方法も良いでしょう。

検証

検証用の簡単なプログラムを書きました。

<?php
$land_line = $_POST['landline'] ?? '';
$phone_number = $_POST['phoneNumber'] ?? '';
$freephone_number = $_POST['freephoneNumber'] ?? '';
$phone_number_2 = $_POST['phoneNumber2'] ?? '';
$phone_number_3 = $_POST['phoneNumber3'] ?? '';

if ($land_line) {

  if (checkLandline($land_line)) echo '<p>固定電話番号の入力チェック結果 : OK</p>';
  else echo '<p>固定電話番号の入力チェック結果 : NG</p>';
}

if ($phone_number) {

  if (checkPhoneNumber($phone_number)) echo '<p>携帯電話番号の入力チェック結果 : OK</p>';
  else echo '<p>携帯電話番号の入力チェック結果 : NG</p>';
}

if ($freephone_number) {

  if (checkFreephoneNumber($freephone_number)) echo '<p>フリーダイヤルの入力チェック結果 : OK</p>';
  else echo '<p>フリーダイヤルの入力チェック結果 : NG</p>';
}

if ($phone_number_2) {

  if (checkPhoneNumber2($phone_number_2)) echo '<p>固定電話番号 + 携帯電話番号の入力チェック結果 : OK</p>';
  else echo '<p>固定電話番号 + 携帯電話番号の入力チェック結果 : NG</p>';
}

if ($phone_number_3) {

  if (checkPhoneNumber3($phone_number_3)) echo '<p>固定電話番号 + 携帯電話番号 + フリーダイヤルの入力チェック結果 : OK</p>';
  else echo '<p>固定電話番号 + 携帯電話番号 + フリーダイヤルの入力チェック結果 : NG</p>';
}

function checkLandline(string $str): int|false {
  return preg_match("/\A0(\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1})[-)]?\d{4}\z/", $str);
}

function checkPhoneNumber(string $str): int|false {
  return preg_match("/\A0[5789]0[-(]?\d{4}[-)]?\d{4}\z/", $str);
}

function checkFreephoneNumber(string $str): int|false {
  return preg_match("/\A0((12|99|18|57)0[-(]?\d{3}[-)]?\d{3}|800[-(]?\d{3}[-)]?\d{4})\z/", $str);
}

function checkPhoneNumber2(string $str): int|false {
  return preg_match("/\A0(\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1}|[5789]0[-(]?\d{4})[-)]?\d{4}\z/", $str);
}

function checkPhoneNumber3(string $str): int|false {
  return preg_match("/\A0((\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1}|[5789]0[-(]?\d{4}|800[-(]?\d{3})[-)]?\d{4}|(12|99|18|57)0[-(]?\d{3}[-)]?\d{3})\z/", $str);
}

?>

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
</head>
<body>

<hr>
<form method="post">
  <p>
    固定電話番号:<input type="tel" name="landline" placeholder="03-1234-5678">
  </p>
  <p>
    携帯電話番号:<input type="tel" name="phoneNumber" placeholder="080-1234-5678">
  </p>
  <p>
    フリーダイヤル:<input type="tel" name="freephoneNumber" placeholder="0120-123-456">
  </p>
  <p>
    固定電話番号 + 携帯電話番号:<input type="tel" name="phoneNumber2">
  </p>
  <p>
    固定電話番号 + 携帯電話番号 + フリーダイヤル:<input type="tel" name="phoneNumber3">
  </p>
  <input type="submit" value="送信する">
</form>

</body>
</html>

固定電話番号

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

0123456789
01-2345-6789
012-345-6789
0123-45-6789
01234-5-6789
01(2345)6789
012(345)6789
0123(45)6789
01234(5)6789

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

012345678
01234567890
01-2345-678
012-34-56789
0-1234-5678
012345-6-7890
01)2345)6789
012(345(6789
0123((456789
012345))6789

下記の文字列とマッチしてしまうことにご注意下さい。

01(2345-6789
012-345)6789
01(23456789
012345-6789

携帯電話番号

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

05012345678
07012345678
08012345678
09012345678
050-1234-5678
070-1234-5678
080-1234-5678
090-1234-5678
050(1234)5678
070(1234)5678
080(1234)5678
090(1234)5678

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

06012345678
0501234567
050123456789
050-123-5678
050-1234-567
070-12345-6789
070-1234-56789
080-1-2345678
080-1234567-8
090)1234)5678
090(1234(5678
090-1234--5678
090--1234-5678

下記の文字列とマッチしてしまうことにご注意下さい。

090(1234-5678
090-1234)5678
090(12345678
0901234-5678

フリーダイヤル

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

0120123456
08001234567
0990123456
0180123456
0570123456
0120-123-456
0800-123-4567
0990-123-456
0180-123-456
0570-123-456
0120(123)456
0800(123)4567
0990(123)456
0180(123)456
0570(123)456

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

0550123456
012012345
01201234567
0800123456
080012345678
0000-123-456
0000-123-4567
0120-123-4567
0800-123-456
0570-123--456
0570((123)456
0(120)123456
080(0123)4567
0990)123)456
0990(123(456
018(012)3456

下記の文字列とマッチしてしまうことにご注意下さい。

0120(123-456
0120-123)456
0120(123456
0120123-456

固定電話番号 + 携帯電話番号

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

0123456789
01-2345-6789
012-345-6789
0123-45-6789
01234-5-6789
01(2345)6789
012(345)6789
0123(45)6789
01234(5)6789
05012345678
07012345678
08012345678
09012345678
050-1234-5678
070-1234-5678
080-1234-5678
090-1234-5678
050(1234)5678
070(1234)5678
080(1234)5678
090(1234)5678

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

012345678
01234567890
01-2345-678
012-34-56789
0-1234-5678
012345-6-7890
01)2345)6789
012(345(6789
0123((456789
012345))6789
06012345678
050123456789
050-1234-567
070-12345-6789
070-1234-56789
080-1-2345678
080-1234567-8
090)1234)5678
090(1234(5678
090-1234--5678
090--1234-5678

下記の文字列とマッチしてしまうことにご注意下さい。

01(2345-6789
012-345)6789
01(23456789
012345-6789
090(1234-5678
090-1234)5678
090(12345678
0901234-5678

固定電話番号 + 携帯電話番号 + フリーダイヤル

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

0123456789
01-2345-6789
012-345-6789
0123-45-6789
01234-5-6789
01(2345)6789
012(345)6789
0123(45)6789
01234(5)6789
05012345678
07012345678
08012345678
09012345678
050-1234-5678
070-1234-5678
080-1234-5678
090-1234-5678
050(1234)5678
070(1234)5678
080(1234)5678
090(1234)5678
0120123456
08001234567
0990123456
0180123456
0570123456
0120-123-456
0800-123-4567
0990-123-456
0180-123-456
0570-123-456
0120(123)456
0800(123)4567
0990(123)456
0180(123)456
0570(123)456

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

012345678
01234567890
01-2345-678
012-34-56789
0-1234-5678
012345-6-7890
01)2345)6789
012(345(6789
0123((456789
012345))6789
06012345678
050123456789
050-1234-567
070-12345-6789
070-1234-56789
080-1-2345678
080-1234567-8
090)1234)5678
090(1234(5678
090-1234--5678
090--1234-5678
012012345
01201234567
080012345678
0000-123-456
0000-123-4567
0120-123-4567
0800-123-456
0570-123--456
0570((123)456
0(120)123456
0990)123)456
0990(123(456

下記の文字列とマッチしてしまうことにご注意下さい。

0120(123-456
0120-123)456
0120(123456
0120123-456
01(2345-6789
012-345)6789
01(23456789
012345-6789
090(1234-5678
090-1234)5678
090(12345678
0901234-5678

以上です。

参考

  1. PHP マニュアル
  2. 総務省|電気通信番号制度
  3. Debuggex
目次