PHPでお問い合わせフォームを作る　その３　入力チェック

#はじめに
この**お問い合わせフォームを作ろう**シリーズですが、[第1回](https://qiita.com/hotate_chan/items/b8ac6b270eac50b0b8e2)は最低限のデータ引き渡しが出来るようにしました。
[第2回](https://qiita.com/hotate_chan/items/dc95f9880f6a1dfa3490)ではPHPファイルとhtmlファイルを分けるようにしました~~なんちゃってテンプレート~~。

で、第3回は何をやるかというと、入力画面で入力されたデータのチェックを行おうと思います。


##入力チェックとは

まずは画面とデータの流れをざっくりと確認しましょう。
![Qiita](https://p79.tr0.n0.cdn.getcloudapp.com/items/NQuvmzeY/aaaa.png?v=ace47e289d63181c8a970eb060562d57)

上図のように画面は「入力画面」「確認画面」「完了画面」という風に進んでいきます。
確認画面から入力画面に戻ることも考えなければいけませんが、今時点では考えないものとします。

で、どこで入力チェックをするのかというと「確認画面」と「完了画面」です。
[第1回](https://qiita.com/hotate_chan/items/b8ac6b270eac50b0b8e2)[第2回](https://qiita.com/hotate_chan/items/dc95f9880f6a1dfa3490)で作成したプログラムのファイル名で言うと confirm.php と complete.php です。

###なぜチェックするの？

####プログラムで必要だから
では、なぜ入力チェックをするの？と言うことですが、まず何も入力されなかったらこのプログラムの意味がありません。このプログラムでは最後の完了画面でメール送信しています。メールアドレスが入力画面で**入力されなかったら**メールの送り先が存在しない事になります。また、メールアドレスが入力されていても**正しいメールアドレス形式でないと**メール送信されません。
こういった事を防ぐために入力チェックを行うのです。
####セキュリティ担保のため
また、入力チェックを行う目的として上記よりも大切な事があります。**セキュリティ面からの入力チェック**です。
簡単に言うと安全なプログラムであるために入力されたデータが正しいものであるか、危険なものでないか確認するために入力されたデータのチェックを行います。
例えば2019年はECサイト等から多くの個人情報が流出しました。攻撃の手段が増えている、巧妙になっていると言う理由もありますが、これらを防ぐための一つの手段としてプログラム内で入力チェックを行うのです。
#####入力チェック以外のセキュリティ担保の方法
セキュリティ担保のためには入力チェック以外の方法がたくさんあります。サイトを[SSL](https://ssl.sakura.ad.jp/column/ssl/)対応するとか、[二段階認証](https://cybersecurity-jp.com/security-measures/29203)を行うとか、プログラムでの対応以外にも色々とあります。
ここでは深く踏み込みませんが、そんなものがあるのだと思っていてください。


##入力チェックの実装
前置きが長くなったので、早速実際にチェック処理を入れていきましょう。
チェックを入れる箇所はまずは「確認画面」です。

###確認画面での入力チェック
まず、今時点での confirm.php を確認しましょう。

```php:confirm.php
<?php

    $name = $_POST['name'];
    $mail = $_POST['mail'];
    $toiawase = $_POST['toiawase'];

    // confirm.html 読み込み
    $htmlString = file_get_contents("./confirm.html");

    // html内の変換文字列を使ってconfirm.html内の文字列を変換
    $printHtml = str_replace("****replace_onamae****", $name, $htmlString);  // 名前の変換
    $printHtml = str_replace("****replace_mailaddress****", $mail, $printHtml);  // メールアドレスの変換
    $printHtml = str_replace("****replace_toiawase****", $toiawase, $printHtml);  // メールアドレスの変換

    echo $printHtml;
```
気になる箇所は・・・・・

+ 1　POSTで渡されたデータ`$_POST['name']` `$_POST['mail']` `$_POST['toiawase']` って空じゃないよね？
* 2　メールアドレス形式になってるよね？
- 3　渡されたデータって安全？javascriptとか入ってない？？

と言う事で一つずつ対応していきます。

####未入力チェック
POSTで渡されたデータが空でないかチェックしましょう。

```php:confirm.php(修正後)
<?php

    $name = is_null($_POST['name']) || empty($_POST['name']) ? false : $_POST['name'];
    $mail = is_null($_POST['mail']) || empty($_POST['mail']) ? false : $_POST['mail'];
    $toiawase = is_null($_POST['toiawase']) || empty($_POST['toiawase']) ? false : $_POST['toiawase'];

    // confirm.html 読み込み
    $htmlString = file_get_contents("./confirm.html");

    // html内の変換文字列を使ってconfirm.html内の文字列を変換
    $printHtml = str_replace("****replace_onamae****", $name, $htmlString);  // 名前の変換
    $printHtml = str_replace("****replace_mailaddress****", $mail, $printHtml);  // メールアドレスの変換
    $printHtml = str_replace("****replace_toiawase****", $toiawase, $printHtml);  // メールアドレスの変換

    echo $printHtml;
```
以下が変わりました。

```
    $name = is_null($_POST['name']) || empty($_POST['name']) || !is_string($_POST['name'])) ? false : $_POST['name'];
    $mail = is_null($_POST['mail']) || empty($_POST['mail'] || !is_string($_POST['name'])) ? false : $_POST['mail'];
    $toiawase = is_null($_POST['toiawase']) || empty($_POST['toiawase'] || !is_string($_POST['name'])) ? false : $_POST['toiawase'];
```
何をやっているかと言うと `is_null($_POST['name']) || empty($_POST['name'])`ここで空じゃないかチェックしています。また、ここでは文字列のみ許可する仕様として`is_string`関数を利用して文字列である場合のみ受け取ったデータを使用します。その結果、空であれば`false`を空でなければPOSTで投げられたデータを`$name` `$mail` `$toiawase` にセットしています。
上記では三項演算子と言うものを使っています。これを使わない場合は以下のような書き方もできます。

```
    if(is_null($_POST['name']) || empty($_POST['name']) || !is_string($_POST['name'])){
        $name = false;
    }else{
        $name = $_POST['name'];
    }
```
どちらでも良いのですが、三項演算子を使ったら一行ですむので三項演算子を使ってます。
さて、これで未入力チェックがやっと終わりました。

####メールアドレスチェック
あれ？？POSTでメールアドレスが送られてきてるけど空じゃなかったらそのまま使われてる。
メールアドレスとして正しいものでないかチェックしなければいけないんじゃないの？
と言う事でメールアドレスチェックをいかに記します。

```
    if(!filter_var($mail, FILTER_VALIDATE_EMAIL)){
        $mail = false;
    }
```

[上記メールアドレスチェック処理の参考](https://qiita.com/yamikoo@github/items/2cd76f2f993175a365a3)
こちらの処理でPOSTで受け取ったメールアドレス文字列がメールアドレス形式でない場合は false を入れてます。


####エスケープ処理
もし入力画面のテキストボックス、テキストエリアに悪意のあるjavascriptが埋め込まれており、エスケープ処理を行っていなくて、以下のような入力がされた場合。


![Qiita](https://p79.tr0.n0.cdn.getcloudapp.com/items/jkunBoP6/bbbb.png?v=641b14f3e5190ec077053669c5764077)

確認ボタンをクリックするとこうなります。

![Qiita](https://p79.tr0.n0.cdn.getcloudapp.com/items/P8uYzp16/ccc.png?v=847d448d75bdb98ebda5de1f7e02b32c)


簡単に攻撃されちゃうんですね。
じゃあ、どうしたら良いのかと言うと**エスケープ処理**を行います。
処理は簡単です。**htmlspecialchars**関数を使いましょう。

```
$toiawase = htmlspecialchars($toiawase);
```

この関数を使う事によって対象となる文字列と変換後の文字列は以下の通りです。

|変換前|変換後|
|:-----------|:------------|
|& (アンパサンド)|&amp;|
|" (ダブルクォート)|ENT_NOQUOTES が指定されていない場合、&quot;|
|' (シングルクォート)|&#039; (ENT_HTML401 の場合) あるいは &apos; ( ENT_XML1、ENT_XHTML、 ENT_HTML5 の場合)。ただし ENT_QUOTES が指定されている場合に限る|
|< (小なり)|&lt;|
|> (大なり)|&gt;|

[引用元 : php.net htmlspecialchars](https://www.php.net/manual/ja/function.htmlspecialchars.php)


##終わりに

長くなってきたので以下の３つの入力チェックが終わったところで本記事も終わりにします。

+ 1　POSTで渡されたデータ`$_POST['name']` `$_POST['mail']` `$_POST['toiawase']` って空じゃないよね？
* 2　メールアドレス形式になってるよね？
- 3　渡されたデータって安全？javascriptとか入ってない？？

次は入力チェックでエラーとなった際に `false` を入れていましたがこれをどうするの？と言うところをやっていきます。
`入力チェック結果のエラー処理`ですね。

#### 修正履歴
2020.01.27　@technote-space さんの指摘を受け受け取るデータを文字列のみに変更

#### 参考ページ
[$_GET, $_POSTなどを受け取る際の処理](https://qiita.com/mpyw/items/2f9955db1c02eeef43ea)
[【PHP超入門】HTTP（GET・POST）について](https://qiita.com/7968/items/4bf4d6f28284146c288f)