-1, "EditType" => 9, "TelEdit" => "", "ErrId" => 0] // Target = "Type" の場合、下記の連想配列 // ["TelType" => -1, "SizeAll" => 0, "Size1" => 0, "Size2" => 0, "Size3" => 0, "ErrId" => 0] //------------------------------------------------------------------------------- function InitTelephone($Target = "Value") { $Target2 = ""; if (is_string($Target)) { if (mb_strtoupper($Target) == "VALUE") { $Target2 = "Value"; } else if (mb_strtoupper($Target) == "TYPE") { $Target2 = "Type"; } else { $Target2 = "Value"; } } else { $Target2 = "Value"; } if ($Target2 == "Value") { return ["TelType" => -1, "EditType" => 9, "TelEdit" => "", "ErrId" => 0]; } else { return ["TelType" => -1, "SizeAll" => 0, "Size1" => 0, "Size2" => 0, "Size3" => 0, "ErrId" => 0]; } } //------------------------------------------------------------------------------- // 電話番号の検証 ( ValidateTelephone ) // // TelCode -- 半角文字列[ 0-9, -, (, ) ] // 固定電話/携帯電話などの[ハイフン/括弧]編集 // // 返却値 -- [TelType, EditType, TelEdit, ErrId] の連想配列 // TelType 1:固定電話(10桁), 2:携帯電話(070/080/090,11桁), 3:着信課金(0120,10桁), // 4:着信課金(0800,11桁), 5:IP電話(050,11桁), 6:M2M(020x,11桁,x≠4), // 7:ポケベル(0204,11桁), 8:FMC(0600,11桁), 9:情報料徴収(0990,10桁), // 10:統一番号(0570,10桁), -1:other // // EditType 1or4: 0AB-CDE-FGHJ, 2or5: 0AB(CDE)FGHJ, 3or6: (0AB)CDE-FGHJ, 9:other // 携帯電話のみ、[3-4-4 桁]で区切る⇒1~3 , [3-3-5 桁]で区切る⇒4~6 // // TelEdit TelType/EditType で編集し直された電話番号(正しい編集結果) // ErrId=0/1/3/5 : 同じパターンで編集し直された電話番号 // 〃 =8 : ハイフン編集した電話番号 // 〃 =2 : TelCode のまま(未使用局番なので正誤は判断しない) // 〃 =4/6/9 : 空文字 // // ErrId 0:OK, 1:区切り位置不正, 2:未使用局番(固定電話), 3:市内局番1桁目が[0 or 1](固定電話), // 4:引数不正([数字,ハイフン,括弧]以外がある or 編集パターン不正 or '0'始まりでない or 桁数不足), // 5:引数不正(局番タイプに応じた桁数と不一致), // 6:その他のエラー, 8:OK(数字のみ指定), 9:引数未定義(TelCode) //------------------------------------------------------------------------------- function ValidateTelephone($TelCode = "") { // 返却値 $Result = InitTelephone("Value"); // FormatTelephoneの返却値 $ResultFormat = InitTelephone("Value"); // 携帯電話(3-3-5桁区切り編集の再取得用) $ResultFormat2 = InitTelephone("Value"); $strTelCode = ""; // PHP5では引数に型指定(string)が無いのでチェック&変換する $TelNumber = ""; // ハイフン,括弧除去(数字のみ) $EditType = ""; // 厳密なチェックは FormatTelephone の結果と比較して行なうので // 下記のパターンチェックでは桁数については曖昧で構わない('0'始まりのみチェックする) $pattern0 = "/^0\d+$/"; // 0123456789 $pattern1 = "/^0\d+-\d+-\d+$/"; // 012-345-6789 $pattern2 = "/^0\d+\(\d+\)\d+$/"; // 012(345)6789 $pattern3 = "/^\(0\d+\)\d+-\d+$/"; // (012)345-6789 // PHP5 では約20億を超える数値は int ではなく float になる // 電話番号を数値で指定すると int を超える if (is_string($TelCode)) { $strTelCode = $TelCode; } elseif (is_float($TelCode) || is_int($TelCode)) { $strTelCode = (string)$TelCode; // 数値の場合、先頭'0'が取れるので次の判定でエラーで返る } else { $Result["ErrId"] = 9; return $Result; } // 引数(TelCode)省略の場合、既定値(空文字)により以下でエラー判定される if (preg_match($pattern0, $strTelCode) == true) { // (数字のみ) 0123456789 // 数字のみ指定 ⇒ 編集のみ行って比較検証は無し $ResultFormat = FormatTelephone($strTelCode, 1); // ハイフン編集で固定 $Result["TelType"] = $ResultFormat["TelType"]; $Result["EditType"] = 1; $Result["TelEdit"] = $ResultFormat["TelEdit"]; // ValidateTephone用エラーコードに差替え switch ($ResultFormat["ErrId"]) { case 0: $Result["ErrId"] = 8; // OK(数字のみ指定) break; case 1: $Result["ErrId"] = 2; // 未使用局番(固定電話番号) break; case 2: $Result["ErrId"] = 3; // 市内局番1桁目が[0 or 1](固定電話) break; case 3: $Result["ErrId"] = 4; // 桁数不足(数字が10桁未満) break; case 4: $Result["ErrId"] = 5; // 局番タイプに応じた桁数と不一致 break; default: $Result["ErrId"] = 6; // その他のエラー } return $Result; } elseif (preg_match($pattern1, $strTelCode) == true) { // EditType:1 012-345-6789 $EditType = 1; $Result["EditType"] = 1; } elseif (preg_match($pattern2, $strTelCode) == true) { // EditType:2 012(345)6789 $EditType = 2; $Result["EditType"] = 2; } elseif (preg_match($pattern3, $strTelCode) == true) { // EditType:3 (012)345-6789 $EditType = 3; $Result["EditType"] = 3; } else { // [数字,ハイフン,括弧]以外がある or 編集パターン不正 or '0'始まりでない $Result["ErrId"] = 4; $Result["TelEdit"] = $strTelCode; return $Result; } // FormatTelephone 用に[ハイフン,括弧]を除去して「数字のみ」にする $TelNumber = preg_replace('/(-)|(\()|(\))/', "", $strTelCode); $ResultFormat = FormatTelephone($TelNumber, $EditType); // FormatTelephone で編集し直した結果と比較して検証する // ErrId で返るのは // 0:OK, 1:未使用局番(固定電話), 2:市内局番1桁目が[0 or 1](固定電話) // 3:引数不正(TelCode: 数字が10桁未満), // 4:引数不正(TelCode: 局番タイプの桁数と不一致) // 下記状態は既にチェック済なので、その値が返ることは無い // 3:引数不正(TelCode: ['0'始まりの数字]以外) // 6:引数不正(EditType) // 9:引数未定義(TelCode/EditType) $Result["TelType"] = $ResultFormat["TelType"]; $Result["TelEdit"] = $ResultFormat["TelEdit"]; // ValidateTephone用エラーコードに差替え switch ($ResultFormat["ErrId"]) { case 0: // FormatTelephoneでOK ⇒ 正しい電話番号 if ($strTelCode === $ResultFormat["TelEdit"]) { $Result["ErrId"] = 0; // OK (区切り位置も正しい) } else { if ($ResultFormat["TelType"] == 2) { // 携帯電話(070/080/090) // 携帯電話の場合、別の区切り方[3-3-5 桁]で再チェック $ResultFormat2 = FormatTelephone($TelNumber, $EditType + 3); if ($strTelCode === $ResultFormat2["TelEdit"]) { // OK (3-3-5桁で一致) $Result["ErrId"] = 0; // OK $Result["TelEdit"] = $ResultFormat2["TelEdit"]; $Result["EditType"] = $EditType + 3; } else { $Result["ErrId"] = 1; // 区切り位置不正 } } else { // 携帯電話 以外 $Result["ErrId"] = 1; // 区切り位置不正 } } break; case 1: $Result["ErrId"] = 2; // 未使用局番(固定電話番号) $Result["TelEdit"] = TelCode; // ResultFormat.TelEdit(=TelNumber)なので入力値に差し替える break; case 2: $Result["ErrId"] = 3; // 市内局番1桁目が[0 or 1](固定電話) break; case 3: $Result["ErrId"] = 4; // 桁数不足(数字が10桁未満) break; case 4: $Result["ErrId"] = 5; // 局番タイプに応じた桁数と不一致 break; default: $Result["ErrId"] = 6; // その他のエラー } return $Result; } //------------------------------------------------------------------------------- // 電話番号のハイフン編集 ( FormatTelephone ) // // TelCode -- 半角数字文字列[ 0-9 ], 10 or 11桁(先頭'0'固定) // 固定電話/携帯電話などの電話番号 // // EditType -- 数値 // 1or4: 0AB-CDE-FGHJ , 2or5: 0AB(CDE)FGHJ , 3or6: (0AB)CDE-FGHJ // 携帯電話のみ、[3-4-4 桁]で区切る⇒1~3 , [3-3-5 桁]で区切る⇒4~6 // // 返却値 -- [TelType, EditType, TelEdit, ErrId] の連想配列 // TelType 1:固定電話(10桁), 2:携帯電話(070/080/090,11桁), 3:着信課金(0120,10桁), // 4:着信課金(0800,11桁), 5:IP電話(050,11桁), 6:M2M(020x,11桁,x≠4), // 7:ポケベル(0204,11桁), 8:FMC(0600,11桁), 9:情報料徴収(0990,10桁), // 10:統一番号(0570,10桁), -1:other // // EditType 1or4: 0AB-CDE-FGHJ, 2or5: 0AB(CDE)FGHJ, 3or6: (0AB)CDE-FGHJ, 9:other // // TelEdit 編集された電話番号 // ErrId=0/2/4 : 編集された電話番号 // 〃 =1 : TelCode の内容のまま // 〃 =3/6/9 : 空文字 // // ErrId 0:OK, 1:未使用局番(固定電話), 2:市内局番1桁目が[0 or 1](固定電話), // 3:引数不正(TelCode: ['0'始まりの数字]以外 or 10桁未満), // 4:引数不正(TelCode: 局番タイプに応じた桁数と不一致) // 6:引数不正(EditType), 9:引数未定義(TelCode/EditType) //------------------------------------------------------------------------------- function FormatTelephone($TelCode = "", $EditType = 0) { // 返却値 $Result = InitTelephone("Value"); // GetTypeTelephone 返却値 $ResultType = InitTelephone("Type"); $strTelCode = ""; // PHP5では引数に型指定(string)が無いのでチェック&変換する $intEditType = 0; // PHP5では引数に型指定(int)が無いのでチェック&変換する $TelPattern = "/^0\d{9,}$/"; // '0'始まりの数字文字列(10桁以上) $EditTypePattern = "/^[1-6]$/"; // '1' ~ '6'(1文字) // PHP5 では約20億を超える数値は int ではなく float になる // 電話番号を数値で指定すると int を超える if (is_string($TelCode)) { $strTelCode = $TelCode; } elseif (is_float($TelCode) || is_int($TelCode)) { $strTelCode = (string)$TelCode; // 数値の場合、先頭'0'が取れるので次の判定でエラーで返る } else { $Result["ErrId"] = 9; return $Result; } // 引数(TelCode)省略の場合、既定値(空文字)により以下でエラー判定される // ['0'始まりの数字文字列(10桁以上)]のチェック // (番号翻訳(GetTypeTelephone)後に完全な桁数チェックを行なう。ここでは10桁未満のみNG) if (preg_match($TelPattern, $strTelCode) == false) { $Result["ErrId"] = 3; return $Result; } // 引数(EditType)省略の場合、既定値(0)により以下でエラー判定される // EditTypeのチェック if (is_string($EditType)) { if (preg_match($EditTypePattern, $EditType) == true) { $intEditType = (int)$EditType; } else { $Result["ErrId"] = 6; return $Result; } } else if (is_int($EditType)) { if ($EditType >= 1 && $EditType <= 6) { $intEditType = $EditType; } else { $Result["ErrId"] = 6; return $Result; } } else { $Result["ErrId"] = 6; return $Result; } $Result["EditType"] = $intEditType; $ResultType = GetTypeTelephone($strTelCode); // 番号翻訳して電話番号の種別と桁区切り情報を取得する // ErrId で返るのは // 0:OK, 1:未使用局番(固定電話), 2:市内局番1桁目が[0 or 1](固定電話) // 下記状態は既にチェック済なので、その値が返ることは無い // 3:電話番号種別が不明(桁数不足で番号翻訳未了)← 10桁以上なので未了は無い // 8:引数不正(TelCode: ['0'始まりの数字]以外) // 9:引数未定義(TelCode) $Result["TelType"] = $ResultType["TelType"]; $Result["ErrId"] = $ResultType["ErrId"]; if ($ResultType["ErrId"] == 1) { // 未使用局番(固定電話) $Result["TelEdit"] = $strTelCode; } else { // 0:OK or 2:市内局番1桁目が[0 or 1](固定電話) if ($ResultType["TelType"] == 2 && $intEditType >= 4) { // 携帯電話(070/080/090)で[3-3-5 桁区切り, 0x0-CDE-FGHJK]を指定された場合 $Result["TelEdit"] = InsertSeparator($strTelCode, $intEditType, 3, 3); } else { // 携帯電話(3-4-4桁区切り)を含め、他は返却値で区切りパターンが得られる // 固定電話では[市外局番桁数/市内局番桁数/加入者番号桁数(4)]が得られる if ($ResultType["Size2"] == 0) { // 固定電話で、市内局番なし [ 0ABCDE-FGHJ ] (現在、この地域は存在しない) $Result["TelEdit"] = mb_substr($strTelCode, 0, 6) . "-" . mb_substr($strTelCode, 6); } else { $Result["TelEdit"] = InsertSeparator($strTelCode, $intEditType, $ResultType["Size1"], $ResultType["Size2"]); } } if (mb_strlen($strTelCode) != $ResultType["SizeAll"]) { $Result["ErrId"] = 4; // 桁数エラー(局番タイプに応じた桁数と不一致) } } return $Result; } function InsertSeparator($TelCode, $EditType, $Size1, $Size2) { $Result = ""; $EditCode1 = mb_substr($TelCode, 0, $Size1); // 1st section :固定電話では市外局番(先頭'0') $EditCode2 = mb_substr($TelCode, $Size1, $Size2); // 2nd section :固定電話では市内局番 $EditCode3 = mb_substr($TelCode, $Size1 + $Size2); // 3rd section :固定電話では加入者番号(末尾まで取り出す) switch ($EditType) { case 1: // 0AB-CDE-FGHJ case 4: $Result = $EditCode1 . "-" . $EditCode2 . "-" . $EditCode3; break; case 2: // 0AB(CDE)FGHJ case 5: $Result = $EditCode1 . "(" . $EditCode2 . ")" . $EditCode3; break; case 3: // (0AB)CDE-FGHJ case 6: $Result = "(" . $EditCode1 . ")" . $EditCode2 . "-" . $EditCode3; } return $Result; } //------------------------------------------------------------------------------- // 電話番号タイプの取得 ( GetTypeTelephone ) // // TelCode -- 半角数字文字列(2桁以上, 先頭'0'固定) // 固定電話/携帯電話などの電話番号(途中までの内容でも可) // // 返却値 -- [TelType, SizeAll, Size1, Size2, Size3, ErrId] の連想配列 // TelType 1:固定電話(10桁), 2:携帯電話(070/080/090,11桁), 3:着信課金(0120,10桁), // 4:着信課金(0800,11桁), 5:IP電話(050,11桁), 6:M2M(020x,11桁,x≠4), // 7:ポケベル(0204,11桁), 8:FMC(0600,11桁), 9:情報料徴収(0990,10桁), // 10:統一番号(0570,10桁), -1:other // // SizeAll ErrId=0/2 : TelType に応じた電話番号の桁数(10 or 11, Size1~3の合計値) // ErrId=1/3/8/9 : 0 // // Size1-3 ErrId=0/2 : TelType に応じた電話番号の区切り桁数(Size1 には先頭'0'含む) // ErrId=1/3/8/9 : 0 // (携帯電話(TelType=2)は[3-4-4 桁区切り]のみで返す) // // ErrId 0:OK, 1:未使用局番(固定電話), 2:市内局番1桁目が[0 or 1](固定電話), // 3:電話番号種別が不明(桁数不足で番号翻訳未了) // 8:引数不正(TelCode: ['0'始まりの数字]以外), 9:引数未定義(TelCode) //------------------------------------------------------------------------------- function GetTypeTelephone($TelCode = "") { // 返却値 $Result = InitTelephone("Type"); global $AreaCodeArray; // 番号翻訳テーブル $strTelCode = ""; // PHP5では引数に型指定(string)が無いのでチェック&変換する $AreaCodeLength = 0; $CityCodeLength = 0; $CityCode1 = ""; // 市内局番の1桁目 $idx = 0; $cnt = 0; $num = 0; $LinkValue = 0; $TelType = 0; $TelPattern = "/^0\d+$/"; // '0'始まりの数字文字列(桁数制限なし) // ( 1)固定電話 10桁 [ 桁区切りは番号翻訳結果に拠る ] // ( 2)携帯電話 11桁 [ 0x0-CDEF-GHJK , 070/080/090 ] // ( 3)着信課金 10桁 [ 0120-DEF-GHJ ] // ( 4)着信課金 11桁 [ 0800-DEF-GHJK ] // ( 5)IP電話 11桁 [ 050-CDEF-GHJK ] // ( 6)M2M 11桁 [ 020-CDE-FGHJK ] // ( 7)ポケベル 11桁 [ 020-4DE-FGHJK ] // ( 8)FMC 11桁 [ 0600-DEF-GHJK ] // ( 9)情報料代理徴収 10桁 [ 0990-DEF-GHJ ] // (10)全国統一番号 10桁 [ 0570-DEF-GHJ ] // SizeInfo [SizeAll, Size1, Size2, Size3] $SizeInfo = [ [0,0,0,0], [10,0,0,0], [11,3,4,4], [10,4,3,3], [11,4,3,4], [11,3,4,4], [11,3,3,5], [11,3,3,5], [11,4,3,4], [10,4,3,3], [10,4,3,3] ]; // PHP5 では約20億を超える数値は int ではなく float になる // 電話番号を数値で指定すると int を超える if (is_string($TelCode)) { $strTelCode = $TelCode; } elseif (is_float($TelCode) || is_int($TelCode)) { $strTelCode = (string)$TelCode; // 数値の場合、先頭'0'が取れるので次の判定でエラーで返る } else { $Result["ErrId"] = 9; return $Result; } // 引数(TelCode)省略の場合、既定値(空文字)により以下でエラー判定される // ['0'始まりの数字文字列(桁数制限なし)]のチェック if (preg_match($TelPattern, $strTelCode) == false) { $Result["ErrId"] = 8; return $Result; } // ※ 番号翻訳テーブルをソースコード内に直に収録しているので // JSONファイルの読み込み処理は必要ない。 // 番号翻訳テーブルから局番情報(市外局番の桁数 or [携帯番号 等]のTelType情報)を取得する。 // [TelCode]の長さが[局番桁数 未満]も受け入れているので『番号翻訳 途中』でのループ終了(TelType= -1)もある。 $idx = 0; $TelType = -1; $AreaCodeLength = 0; for ($cnt = 1; ($cnt <= 5) && ($cnt < mb_strlen($strTelCode)); $cnt++) { // 番号翻訳テーブルはA~Eコードの5段 $num = (int)mb_substr($strTelCode, $cnt, 1); // 電話番号の2桁目以降(1桁目は'0')を順次取り出す $LinkValue = $AreaCodeArray[$idx][$num]; if ($LinkValue == 0) { // 番号翻訳 終了(固定電話 未使用局番) $TelType = 1; $AreaCodeLength = 0; break; } elseif ($LinkValue < 0) { // 番号翻訳 終了 if ($LinkValue > -100) { // 固定電話の市外局番桁数(符号反転値) 実際の収録値[ -2 ~ -5 ] $TelType = 1; $AreaCodeLength = $LinkValue * (-1); // 市外局番 桁数決定(先頭の "0" 含む) } else { // 携帯電話 等のTelType値(符号反転値 - 100) 実際の収録値[ -102 ~ -110 ] $TelType = ($LinkValue * (-1)) - 100; } break; } else { // プラス値 $idx = $LinkValue; // 検索継続(収録値は NextIndex) } } // TelType に応じた桁区切りを設定する // 固定電話(TelType=1)では市外局番桁数(AreaCodeLength)に従って設定する // Size1 の値は[先頭'0'含む] $Result["TelType"] = $TelType; switch ($TelType) { case -1: // 電話番号種別が不明(桁数不足で番号翻訳未了) $Result["ErrId"] = 3; break; case 1: // 固定電話 if ($AreaCodeLength == 0) { // 未使用 局番 $Result["ErrId"] = 1; } elseif ($AreaCodeLength == 6) { // 市内局番なし [ 0ABCDE-FGHJ ] (現在、この地域は存在しない) $Result["ErrId"] = 0; $Result["SizeAll"] = 10; $Result["Size1"] = 6; $Result["Size2"] = 0; $Result["Size3"] = 4; } else { $CityCodeLength = 6 - $AreaCodeLength; // 10 - AreaCodeLength - 4(加入者番号) if (mb_strlen($strTelCode) < ($AreaCodeLength + 1)) { // [TelCode]が市内局番の桁位置までないので市内局番適否の判定不可⇒ OK で返す $Result["ErrId"] = 0; } else { // FormatTelephone から呼ばれる場合は 10桁以上なので必ず判定可能 $CityCode1 = mb_substr($strTelCode, $AreaCodeLength, 1); // 市内局番 1桁目 if ($CityCode1 === "0" || $CityCode1 === "1") { $Result["ErrId"] = 2; // 市内局番1桁目に0/1は割り当てられない } else { $Result["ErrId"] = 0; // OK } } $Result["SizeAll"] = 10; $Result["Size1"] = $AreaCodeLength; $Result["Size2"] = $CityCodeLength; $Result["Size3"] = 4; } break; default: // TelType = 2~10, SizeInfoテーブルから桁情報を設定する $Result["ErrId"] = 0; // OK $Result["SizeAll"] = $SizeInfo[$TelType][0]; $Result["Size1"] = $SizeInfo[$TelType][1]; $Result["Size2"] = $SizeInfo[$TelType][2]; $Result["Size3"] = $SizeInfo[$TelType][3]; } return $Result; } ?>