PHP 郵便番号と住所を検索 正規表現


#郵便番号か住所で検索

![コメント 2020-03-28 222803.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560686/82cc8efc-5e16-3906-a9c4-f3534ddb6cb4.png)

##内容

郵便番号または都道府県を選択し市町村を入力すると
郵便のデータが検索できます。

１０件を超えた場合に”前へ”、”次へ”を押すと各々のページに飛ぶようになっています。

SQL脆弱性があると思いますが、今のところこのまま学習を進めていきます。


```php
// 変数を設定
$post_num ='';//郵便番号
$area ='';//都道府県選択
$city ='';//市町村
$town ='';//県域
$error1 = [];//エラー文
$error2 = [];//エラー文
$user_data = [];
$abc_data = [];
$query = '';
$host = 'localhost';
$username = '';
$passwd = '';
$dbname = '';
$link= mysqli_connect($host, $username, $passwd, $dbname);
$page = 1;
$count = '';//トータル件数
$totalpage = ceil($count/ 10);//切り上げ

```

##変数が存在するかを確認

```php
//どちらかに値が入っていた場合
if(isset($_GET['post_num']) === true || isset($_GET['area']) === true) {
//変数を代入する
    if(isset($_GET['post_num']) === true) {
        $post_num = $_GET['post_num'];
    }
        if(isset($_GET['area']) === true) {
        $area = $_GET['area'];
    }
        if(isset($_GET['city']) === true) {
        $city = $_GET['city'];
    }
        if(isset($_GET['town']) === true) {
        $town = $_GET['town'];
    }
        if(isset($_GET['page']) === true) {
        $page = $_GET['page'];
    }
```

```php
if(isset($_GET['post_num']) === true || isset($_GET['area']) === true)
```

このif文を書かないと空欄の状態でも変数の確認をしてしまうため、
後述のエラー文が出てしまいます

##空白の削除をします
```php
    $post_num = str_replace(array(" ","　"),"", $post_num);
    $area = str_replace(array(" ","　"),"", $area);
    $town = str_replace(array(" ","　"),"", $town);

```

str_replace（array（半角、全角空白）、空、変数）となっており
変数の中の半角、全角空白を空要素と入れ替えます。つまり、空白があった場合に削除します。


##エラーメッセージ

```php
    if(empty($post_num) === true && 
    ($area === '都道府県を選択' || empty($city) === true)) {
        $error1[] = '郵便番号を入力してください';
    }else if ((preg_match('/^[0-9]{7}$/', $post_num) !== 1) && 
    ($area === '都道府県を選択' || empty($city) === true)) {
        $error1[] = '７桁の数字で入力してください';
    }else {
        print "";
    }
```
areaとcityの入力がしていない場合でないと条件を付けないと
２つの値が入っているときにもエラー文が出てしまう。

```php
}else if ((preg_match('/^[0-9]{7}$/', $post_num) !== 1) && 
    ($area === '都道府県を選択' || empty($city) === true)) {
        $error1[] = '７桁の数字で入力してください';
```
preg_match（正規表現、文字列）で文字列が正規表現と一致しているかを
確認する
一致していれば１、していなければ０で、失敗するとfalseを返します。
正規表現は**０から９までの値を７桁**でとなっている。
なので、**post_numが７桁の数字出なかった場合、かつareaまたはcityの
値が空だった場合にエラー文が出るようになる。**　　

```php

    if ($area === '都道府県を選択' && 
    (empty($post_num) === true ||(preg_match('/^[0-9]{7}$/', $post_num) !== 1))) {
        $error2[] = '都道府県を選択してください';
    }
    if(empty($city) === true && 
    (empty($post_num) === true ||(preg_match('/^[0-9]{7}$/', $post_num) !== 1))){
        $error2[] = '市区町村名をを入力してください';
    }

```
前述とほぼ同じで、post_numに値が入っている場合にはエラー分が出ないようになっています。

##データベースに接続

```php

        if(count($error1) === 0 || count($error2) === 0) {
        if($link) {
            mysqli_set_charset($link, 'utf8');
            if($post_num !== '') {
                $query = "SELECT post_num, area , city, town FROM pt_table 
                WHERE post_num = '$post_num'";

```

エラー文がないときに接続します。文字化けを防止でutf8で表記します。
post_numが空ではない場合にsql文を代入します。

```php

WHERE post_num = '$post_num'";

```
データベースにある郵便番号の値とpost_numが同じ場合になるのが条件。

```php
            } else {
                $limit = 10*$page-10;
                $query = "SELECT post_num, area , city, town FROM pt_table 
                WHERE (area = '$area') AND (city = '$city') LIMIT ".$limit.",10";
 
```

pageは１番最初のページ数を表しています。　LIMITは開始位置、終わりの位置までを指定。
つまり、１０件ごとにページに表示します。

変数limitは０、１０、２０、３０と増えていきます。

```php
                $query = "SELECT post_num, area , city, town FROM pt_table 
                WHERE (area = '$area') AND (city = '$city') LIMIT ".$limit.",10";

```
データベースのarea,cityの値がそれぞれ一致している場合という条件。
変数limitを”$limit”と書いた場合には文字列となってしまいます。カンマで囲うと数字として扱えます。

##総件数を出すために文字列を取得


```php
                $abc = "SELECT post_num, area , city, town FROM pt_table 
                WHERE (area = '$area') AND (city = '$city')";
                $result = mysqli_query($link, $abc);
                while($row = mysqli_fetch_array($result)) {
                    $abc_data[] = $row;
                }
            } 

```

まず、変数queryでデータを取得しようとすると最大１０件しか取得できません。理由はLIMITを使って１０件ずつ取得するプログラムになっているからです。なので、別の実行データを
１行ずつ取得し、文字列にしていきます。

##実行したデータを取得

```php
$result = mysqli_query($link, $query);
          while($row = mysqli_fetch_array($result)) {
          $user_data[] = $row;
          }      
```

１０件ずつ取得するデータを１行ずつ取得し文字列にします。

##メモリを開放しデータベースから閉じる

```php
            mysqli_free_result($result);
            mysqli_close($link);
            
        }else {
            echo 'DB接続失敗';
        }
        
    }

}

```
##総件数

```php

$count = count($abc_data);

```
##ページング
```php
    <?php if ($page > 1) { ?>   
      <a href="?page=<?php echo ($page - 1); ?>&area=<?php print $area; ?>
      &city=<?php print $city; ?>">前のページへ</a>
    <?php } ?>
    <?php if ($page < $totalpage) { ?>
    　　<a href="?page=<?php echo ($page + 1); ?>&area=<?php print $area; ?>
    　　&city=<?php print $city; ?>">次のページへ</a>
    <?php } ?>
```
ファイル名?post_num=&area=県名&city=市名とURLに表示させる事を目的にする。
GETで値を取得したときにはURLが表示され、その先頭は？が付きます。
現在のページが１よりも大きいは(page-1)つまり前のページにいきます。

トータルページが今のページよりも多い場合には次のページに行きます

##全コード

```php
<?php
// 変数を設定
$post_num ='';
$area ='';
$city ='';
$town ='';
$error1 = [];
$error2 = [];
$user_data = [];
$abc_data = [];
$query = '';
$host = 'localhost';
$username = 'codecamp31549';
$passwd = 'RXFXXBTL';
$dbname = 'codecamp31549';
$link= mysqli_connect($host, $username, $passwd, $dbname);
$page = 1;
$count = '';//トータル件数
$totalpage = ceil($count/ 10);//切り上げ
/*変数が存在する確認*/ 
if(isset($_GET['post_num']) === true || isset($_GET['area']) === true) {
    if(isset($_GET['post_num']) === true) {
        $post_num = $_GET['post_num'];
    }
        if(isset($_GET['area']) === true) {
        $area = $_GET['area'];
    }
        if(isset($_GET['city']) === true) {
        $city = $_GET['city'];
    }
        if(isset($_GET['town']) === true) {
        $town = $_GET['town'];
    }
        if(isset($_GET['page']) === true) {
        $page = $_GET['page'];
    }
    
/*空白削除*/
    $post_num = str_replace(array(" ","　"),"", $post_num);
    $area = str_replace(array(" ","　"),"", $area);
    $town = str_replace(array(" ","　"),"", $town);

/*エラーメッセージ*/
    if(empty($post_num) === true && 
    ($area === '都道府県を選択' || empty($city) === true)) {
        $error1[] = '郵便番号を入力してください';
    }else if ((preg_match('/^[0-9]{7}$/', $post_num) !== 1) && 
    ($area === '都道府県を選択' || empty($city) === true)) {
        $error1[] = '７桁の数字で入力してください';
    }else {
        print "";
    }
    if ($area === '都道府県を選択' && 
    (empty($post_num) === true ||(preg_match('/^[0-9]{7}$/', $post_num) !== 1))) {
        $error2[] = '都道府県を選択してください';
    }
    if(empty($city) === true && 
    (empty($post_num) === true ||(preg_match('/^[0-9]{7}$/', $post_num) !== 1))){
        $error2[] = '市区町村名をを入力してください';
    }
/*データベースに接続*/ 
    
        if(count($error1) === 0 || count($error2) === 0) {
        if($link) {
            mysqli_set_charset($link, 'utf8');
            if($post_num !== '') {
                $query = "SELECT post_num, area , city, town FROM pt_table 
                WHERE post_num = '$post_num'";
                // var_dump($query);
            } else {
                $limit = 10*$page-10;
                $query = "SELECT post_num, area , city, town FROM pt_table 
                WHERE (area = '$area') AND (city = '$city') LIMIT ".$limit.",10";
                $abc = "SELECT post_num, area , city, town FROM pt_table 
                WHERE (area = '$area') AND (city = '$city')";
                $result = mysqli_query($link, $abc);
                while($row = mysqli_fetch_array($result)) {
                    $abc_data[] = $row;
                }
            } 
            // var_dump($query);
                $result = mysqli_query($link, $query);
                while($row = mysqli_fetch_array($result)) {
                    $user_data[] = $row;
                    
                }
            mysqli_free_result($result);
            mysqli_close($link);
            
        }else {
            echo 'DB接続失敗';
        }
        
    }

}

$count = count($abc_data);



        

?>

<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <title>郵便</title>
</head>
<body>
    <form action="./17-6.php" method="get">
        <h1>郵便番号検索</h1>
        <h2>郵便番号から検索</h2>
        <?php print "総件数" . htmlspecialchars($count,ENT_QUOTES,'UTF-8') . "件";?>
        <input type="search" name="post_num" value="">
        <input type="submit" value="検索">
        <h2>地名から検索</h2>
        <label>都道府県を選択
            <select name="area">
                <option>都道府県を選択</option>
                <option>北海道</option>
                <option>兵庫県</option>
                <option>新潟県</option>
            </select>
        </label>
        <label>市区町村
            <input type="seach" name="city">
            <input type="submit" value="検索">
        </label>
    </form>
    <p><?php foreach($error1 as $key1 => $string1) {
                print htmlspecialchars($string1,ENT_QUOTES,'UTF-8');
            }
    ?></p>
        <p><?php foreach($error2 as $key2 => $string2) {
                print htmlspecialchars($string2,ENT_QUOTES,'UTF-8');;
            }
    ?></p>
        <?php 
    foreach($user_data as $read) {?>
        <table>
           <style type="text/css">
       table, td, th {
           border: solid black 1px;
       }
       table {
           width: 600px;
       }
       tr td {
           width: 150px;
       }
   </style>
    
            <tr>
                <th>郵便番号</th>
                <th>都道府県</th>
                <th>市町村</th>
                <th>町域</th>
            </tr>
            <tr>
                <td><?php print htmlspecialchars($read['post_num'],ENT_QUOTES,'UTF-8'); ?></td>
                <td><?php print htmlspecialchars($read['area'],ENT_QUOTES,'UTF-8'); ?></td>                
                <td><?php print htmlspecialchars($read['city'],ENT_QUOTES,'UTF-8'); ?></td>            
                <td><?php print htmlspecialchars($read['town'],ENT_QUOTES,'UTF-8'); ?></td>            
            </tr>
        </table>
    <?php } ?>  
<p>
    <!--GETを使用するときは?からスタートする-->
    <?php if ($page > 1) : ?>   
      <a href="?page=<?php echo ($page - 1); ?>&area=<?php print $area; ?>
      &city=<?php print $city; ?>">前のページへ</a>
    <?php endif; ?>
    <?php if ($page < $totalpage) : ?>
    　　<a href="?page=<?php echo ($page + 1); ?>&area=<?php print $area; ?>
    　　&city=<?php print $city; ?>">次のページへ</a>
    <?php endif; ?>

  </p>    
 
</body>

</html>   

```php