先週は郵便番号のフォーマットを自動で統一化する方法についての記事を書きました。
書いていて次の疑問がわきました。
フォーマットは正しいけれど実在しない郵便番号をエラーにできないものか?
郵便番号が実在するかどうかは、計算式では求められません。
既存情報と比較照合し、存在するかどうかをチェックしなければいけません。
PHPでそもそもそんなことが可能なのでしょうか?
いろいろ疑問に思いつつも、いつものごとくググりながら調べ、対応してみました。
結論:PHPで郵便番号の実在チェックは可能です。
まずは論より証拠です。
以下のサンプルでは、実在しない郵便番号をエラーにしています。
ソースはこちらです
<?php
// 初期値設定
$input_postno = null;
$output_postno = null;
if ((isset($_REQUEST["postno"]) == true) /* URLが送信された ? */
&& (isset($_REQUEST["reset"]) != true)) /* リセットボタンでない ? */
{
/** 郵便番号取得 */
$input_postno = $_REQUEST["postno"];
/** メッセージ初期化 */
$msg = "入力された郵便番号は正しいです。";
$class = null;
/** 郵便番号チェック */
$sts = postno_chk($input_postno);
/** 郵便番号セット */
$postno = $sts["postno"];
if ($sts["sts"] != true) /* 正しくない ? */
{
/** エラーメッセージセット */
$msg = $sts["err"];
$class = " class='err'";
}
else
{
/** 住所セット */
$msg .= "<br>" . $sts["address"];
}
$date = date("Y-m-d H:i:s");
/** メッセージセット */
$output_postno = "<div${class}><p>${date}</p><p>${postno}</p><p>${msg}</p></div>";
}
function postno_chk($postno)
{
/** ステータス初期化 */
$sts = array("sts"=>false, "err"=>null, "postno"=>null, "address"=>null);
/** 数字を半角に変換する */
$postno = mb_convert_kana($postno, "n");
/** 数字以外を削除する */
$postno = preg_replace("/[^0-9]/", "", $postno);
if (mb_strlen($postno) != 7) /* 7桁の数字でない ? */
{
/** エラーメッセージセット */
$sts["err"] = "郵便番号の桁数が正しくありません";
/** 処理破棄 */
return $sts;
}
/** ▼▼▼▼ 郵便番号照合部分 ここから ▼▼▼▼ */
/** 照合用URLセット */
$posturl = "http://zipcloud.ibsnet.co.jp/api/search?zipcode=${postno}";
/** 郵便番号照合 */
$json = json_decode(file_get_contents($posturl), true);
/** 文字コード変換 */
$post_code = mb_convert_encoding($json, "SJIS-win", "UTF-8");
if ($post_code["results"] == null) /* 照合データなし ? */
{
/** エラーメッセージセット */
$sts["err"] = "該当の郵便番号がありません";
/** 処理破棄 */
return $sts;
}
/** ▲▲▲▲ 郵便番号照合部分 ここまで ▲▲▲▲ */
/** 郵便番号のフォーマット変換 */
$postno_01 = substr($postno, 0, 3);
$postno_02 = substr($postno, -4, 4);
$sts["postno"] = "${postno_01}-${postno_02}";
/** 住所セット */
$sts["address"] = $post_code["results"][0]["address1"] . $post_code["results"][0]["address2"] . $post_code["results"][0]["address3"] . "(". $post_code["results"][0]["kana1"] . $post_code["results"][0]["kana2"] . $post_code["results"][0]["kana3"] . ")";
/** チェックOKセット */
$sts["sts"] = true;
/** 処理終了 */
return $sts;
}
?>
<!doctype html>
<html>
<head>
<meta charset="shift_jis">
<title>郵便番号入力</title>
<style type="text/css">
section
{
text-align: center;
width: 600px;
margin-right: auto;
margin-left: auto;
padding-top: 20px;
padding-bottom: 20px;
border: 1px solid #ddd;
border-radius: 6px;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
}
div
{
padding: 10px;
width: 80%;
border: 10px solid #0C0;
color: #0C0;
margin-right: auto;
margin-left: auto;
margin-top: 10px;
}
.err
{
border: 10px solid #F00;
color: #F00;
text-align: left;
}
</style>
</head>
<body>
<section>
<form action="" method="post" enctype="multipart/form-data">
<h1>郵便番号を入力してください</h1>
<p>※ハイフンありなしどちらでもOKです。</p>
<input name="postno" type="text" value="<?php echo $input_postno; ?>" style="width: 400px">
<input name="submit" type="submit" value="送信">
<input name="reset" type="submit" value="リセット">
<?php echo $output_postno ?>
</form>
</section>
</body>
</html>
郵便局には郵便番号を照合できるサービスがありこれを利用します
郵便局のサイトには、だれでも利用できる郵便番号検索照合サービスがあります。
例えば939-1324であれば、次のURLを入力すれば照合できます。
http://zipcloud.ibsnet.co.jp/api/search?zipcode=9391324
郵便番号を渡すと、その結果該当する住所が帰ってきます。
正しくない場合は住所が返ってきません。
これを利用し、郵便番号が実在するかどうかをチェックしています。
疑問:PHPでどうやって実現するの?
郵便番号照合サービスは、どちらかといえばJqueryで使うことを前提としています。
つまり、郵便番号を入力すると住所が自動で入る処理などに利用されます。
ではこれをどうやれば、PHPで実現できるのでしょう?
今回最も疑問に感じた部分でしたが、ちゃんとやり方がありました。
PHPにもちゃんと対応した関数があります
PHPからでも、郵便番号照合サービスを呼び出すことができます。
そのためには2つの関数を使用します。
(1)照合サービス呼び出しにfile_get_contents()を使います
file_get_contents()関数は、URLなどを引数として渡すとその結果をテキストとして返してくれます。
例えば、正しい郵便番号で呼び出すと以下のテキストが返ってきます。
{
"message": null,
"results": [
{
"address1": "富山県",
"address2": "砺波市",
"address3": "荒高屋",
"kana1": "トヤマケン",
"kana2": "トナミシ",
"kana3": "アラダカヤ",
"prefcode": "16",
"zipcode": "9391324"
}
],
"status": 200
}
ちなみに存在しない郵便番号の場合は、以下のようなテキストが返ります。
{
"message": null,
"results": null,
"status": 200
}
“results”の項目がnullの場合「該当郵便番号は存在しない」と判断できます。
しかしながら、この状態ではPHPでは細かく参照することができません。
なぜならば、{}も[]もただのテキストでしかないためです。
そこで次の関数を使用します。
(2)PHPで参照できるようにjson_decode()関数を使って配列に変換します。
PHPで参照するためには、配列化するほうが使いやすいです。
そのために、json_decode()関数を使用します。
この関数は郵便番号照合サービスのように、JSON形式での結果を配列形式に変換してくれます。
上記の例だと、以下のように変換されます。
array(
"message"=>NULL,
"results"=>array(
0=>array("address1"=>"富山県", "address2"=>"砺波市", "address3"=>"荒高屋", "kana1"=>"トヤマケン", "kana2"=>"トナミシ", "kana3"=>"アラダカヤ", "prefcode"=>"16", "zipcode"=>"9391324")
),
"status"=>200
);
この形になれば、PHPから容易に参照できるようになります。
これを踏まえて今回のソースを見るとわかりやすいです
今回のソースはちょっと長いですが、ほとんど先週の記事と同じです。
今回付け足した部分は以下の部分になります。
/** ▼▼▼▼ 郵便番号照合部分 ここから ▼▼▼▼ */
/** 照合用URLセット */
$posturl = "http://zipcloud.ibsnet.co.jp/api/search?zipcode=${postno}";
/** 郵便番号照合 */
$json = json_decode(file_get_contents($posturl), true);
/** 文字コード変換 */
$post_code = mb_convert_encoding($json, "SJIS-win", "UTF-8");
if ($post_code["results"] == null) /* 照合データなし ? */
{
/** エラーメッセージセット */
$sts["err"] = "該当の郵便番号がありません";
/** 処理破棄 */
return $sts;
}
/** ▲▲▲▲ 郵便番号照合部分 ここまで ▲▲▲▲ */
思ったより少ない行数で実在チェックができています。
しかも照合を実行しているのは1行だけです。
$json = json_decode(file_get_contents($posturl), true);
このやり方にたどり着くまでは長かったですが、やり方は思ったより簡単な記述だけで済みました。
思い付きは調べれば何とかなるものです
今回は郵便番号のフォーマットチェック処理を作っていて、ふと郵便番号実在チェックを盛り込めば、より精度の高いチェックになるのではないか?と思いついたことから始めました。
そこでググり、調べ、試し、郵便番号実在チェックを盛り込むことができました。
言うは易し。
確かに易かったです。
思いのほかどうすればいいかわからず、四苦八苦いたしましたが、一つ一つ問題をクリアしていったら実現できていました。
今回も大変良い経験をいたしました。
本記事がお役に立てば幸いです。