YouTube "Route 87" | 35歳からオーストラリアのシドニーでシェフを目指す男の日常をお届け。

【PHP】登録フォームで$_POST形式で値を受け取る際のエラーチェックを例題と共に解説




私がPHPを学んでいる中で一番理解するのに苦労したのが、「$_POST形式で値を受け取る際のエラーチェック」だったので、その例題と解答方法をまとめました。

なぜ苦労したかというと、アンケートフォームなどでユーザーが普通に入力して起こりうるエラーしか考えつかず、その他起こりうるエラーについて理解するのが困難だったためです。

POST形式の値の送受信の問題

フォームの作成

以下の内容のフォームを作成すること。

  • 名前
  • メールアドレス
  • 性別
  • 年代
  • お問い合わせ内容

送信について

送信先は「comfirm.php」とする。

送信方法は「POST」とする。

受信について

必須項目

  • 名前
  • お問い合わせ内容

上限値

  • 名前:20文字
  • メールアドレス:100文字
  • お問い合わせ内容:400文字

画面表示

ユーザー入力値に問題なければ 送られてきた値を表示。

ユーザー入力値に問題があるときは エラーメッセージを表示。

フォームパーツについて

名前は入力系パーツを使用しname属性「myname」とする。

メールアドレスは入力系パーツを使用しname属性「mail」とする。

性別は選択系パーツを使用しname属性「gender」とする。
送信する値は「選択しない」>「0」、 「男性」>「1」、 「女性」>「2」

年代はセレクトボックスを使用しname属性「age」とする。
送信する値は「選択しない」>「空文字」、 「10代」>「1」、 「20代」>「2」、 「30代」>「3」、 「40代」>「4」、 「50代以上」>「5」

お問い合わせ内容はテキストエリアを使用しname属性「body」とする。

「送信ボタン」と「リセットボタン」を下部に配置すること。

その他のルール

文章構成(divでグループ化や定義リストを使用する等)は自由に決めて構わない。

時間があればCSSで自由にデザインすること。

解答例

作成したお問い合わせフォーム

HTML

<h1>問題解答</h1>
<form action="comfirm.php" method="post">
  <fieldset>
    <legend>お問い合わせフォーム</legend>
    <dl>
      <dt>名前</dt>
      <dd>
        <input type="text" name="myname" required placeholder="例)山田 太郎">
      </dd>
      <dt>メールアドレス</dt>
      <dd>
        <input type="email" name="mail" placeholder="例)name@example.com">
      </dd>
      <dt>性別</dt>
      <dd>
        <label><input type="radio" name="gender" value="0">未選択</label>
        <label><input type="radio" name="gender" value="1">男性</label>
        <label><input type="radio" name="gender" value="2">女性</label>
      </dd>
      <dt>年代</dt>
      <dd>
        <select name="age">
          <option value="">選択してください</option>
          <option value="0">未回答</option>
          <option value="1">10代</option>
          <option value="2">20代</option>
          <option value="3">30代</option>
          <option value="4">40代</option>
          <option value="5">50代以上</option>
        </select>
      </dd>
      <dt>お問い合わせ内容</dt>
      <dd>
        <textarea name="body" cols="50" rows="10" required></textarea>
      </dd>
    </dl>
    <div class="button">
      <input class="btn" type="submit" value="送信">
      <input class="btn" type="reset" value="リセット">
    </div>
  </fieldset>
</form>

フォームパーツが多い場合は、fieldset要素を使ってグループを作成できる。
form要素内に入力パーツが少ない場合は、field要素とlegend要素は省略可能。

name属性はPHPの送受信には必須の属性で、値の送受信用の名前。
CSSでのclass属性、JSでのid属性のようなもの。

input要素をlabelタグで囲むと、クリック領域が広がりユーザーが使いやすくなる。

required属性を付与すると、必須項目になる。

placeholderを入力しておくと、名前やメールアドレスなどの入力欄に参考例をあらかじめ入力しておくことができ、ユーザーがわかりやすくなる。

CSS

fieldset{
  width: 50%;
  margin: 0 auto;
  background-color: aliceblue;
}

dt{
  background-color: #ccc;
}
dd{
  padding: 1em;
  margin: 0;
}

.btn{
  border-radius: 25px;
  background-color: #ccc;
  color: #000;
}

.button{
  text-align: right;
}

CSSは特に重要ではないですが、一応載せておきます。

PHP

<?php
echo '<pre>';
var_dump($_POST);
echo '</pre>';

$error = [];

echo '<pre>';
var_dump($error);
echo '</pre>';

$limit = 20;
if (isset($_POST['myname'])) {
  $myname = $_POST['myname'];
  if ($myname === '') {
    $error[] = '名前は必須項目です';
  } else if (mb_strlen($myname) > $limit) {
    $error[] = "名前は{$limit}文字以下で入力してください";
  }
} else {
  $error[] = '名前の値が届いていません';
}

$limit = 100;
if (isset($_POST['mail'])) {
  $mail = $_POST['mail'];
  if (mb_strlen($mail) > $limit) {
    $error[] = "メールアドレスは{$limit}文字以下で入力してください";
  }
} else {
  $error[] = 'メールアドレスの値が届いていません';
}

$limit = 400;
if (isset($_POST['body'])) {
  $body = $_POST['body'];
  if ($body === '') {
    $error[] = 'お問い合わせ内容は必須項目です';
  } else if (mb_strlen($body) > $limit) {
    $error[] = "お問い合わせ内容は{$limit}文字以下で入力してください";
  }
} else {
  $error[] = 'お問い合わせ内容の値が届いていません';
}

if (isset($_POST['gender'])) {
  $gender = $_POST['gender'];
  if (ctype_digit($gender)) {
    if ($gender < 0 || $gender > 2) {
      $error[] = '性別の値が不正です';
    }
  } else {
    $error[] = '性別の値が不正です';
  }
}

if (isset($_POST['age'])) {
  $age = $_POST['age'];
  if ($age !== '') {
    if (ctype_digit($age)) {
      if ($age < 0 || $age > 5) {
        $error[] = '年代の値が不正です:2';
      }
    } else {
      $error[] = '年代の値が不正です:1';
    }
  }
} else {
  $error[] = '年代の値が届いていません';
}

if (count($error) === 0) {
  $genderList = [
    0 => '選択してない',
    1 => '男性',
    2 => '女性',
  ];
  if (isset($gender)) {
    $genderStr = $genderList[$gender];
  } else {
    $genderStr = '選択していない';
  }

  if ($age === '') {
    $ageStr = '選択していない';
  } else if ($age === '0') {
    $ageStr = '未回答';
  } else if ($age === '5') {
    $ageStr = "{$age}0代以上";
  } else {
    $ageStr = "{$age}0代";
  }
}
?>

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>POST形式で送信された値を取得</title>
</head>
<body>
  <div class="box">
    <div class="inner">
      <?php if (count($error) > 0) : ?>
        <h1>エラー</h1>
        <ul class="error">
          <?php foreach ($error as $val) : ?>
            <li><?php echo $val; ?></li>
          <?php endforeach; ?>
        </ul>
      <?php else : ?>
        <h1>確認</h1>
        <dl>
          <dt>名前</dt>
          <dd><?php echo $myname; ?></dd>
          <dt>メールアドレス</dt>
          <dd><?php echo $mail; ?></dd>
          <dt>性別</dt>
          <dd><?php echo $genderStr; ?></dd>
          <dt>年代</dt>
          <dd><?php echo $ageStr; ?></dd>
          <dt>お問い合わせ内容</dt>
          <dd><?php echo nl2br($body); ?></dd>
        </dl>
      <?php endif; ?>
      <p>
        <a href="form.html">フォームに戻る</a>
      </p>
    </div>
  </div>
</body>
</html>

これが解答例です。
わかりやすいように各パーツごと分解して解説していきます。

受信した値を確認

echo '<pre>';
var_dump($_POST);
echo '</pre>';

HTMLで作成したフォームからPOST形式で送られてきた値をvar_dumpして確認。

エラー変数

$error = []; 

$error(変数宣言)して、エラーをこの$errorに配列として溜めていく。

名前チェック

  • 届いているかチェック
  • 必須チェック(空文字チェック)
  • 上限値チェック(20文字)
$limit = 20;
if (isset($_POST['myname'])) {
  $myname = $_POST['myname'];
  if ($myname === '') {
    ※ 必須エラー
    $error[] = '名前は必須項目です';
  } else if (mb_strlen($myname) > $limit) {
    ※ 上限値エラー
    $error[] = "名前は{$limit}文字以下で入力してください";
  } else {
    ※ OK
  }
} else {
  ※ 届いているかエラー
  $error[] = '名前の値が届いていません';
}

if (isset($_POST[‘myname’])) → 値が届いているかチェック

if ($myname === ”) → 空文字かチェック

else if (mb_strlen($myname) > $limit) → 文字数上限値(20文字)チェック

isset($_調べる変数名):変数が定義されているか調べられる
定義されている場合はtrue、定義されていない場合はfalseを返す
値を受け取っていればtrueになる
→$_POSTの連想配列に箱があるかないかのチェック

※実際にフォームから値を送信してそのページに遷移した場合にはエラーは発生しません。しかし、直接そのページ(値を取得するページ)にアクセスした場合には$_POST[‘myname’]が未定義になるのでエラーが発生します。

mb_strlen(引数) :引数で指定した文字列の文字数を返す
[multi byte_strings length]
※JSの文字列に対するlengthと同じような感じ

メールアドレスチェック

  • 届いているかチェック
  • 上限値チェック(100文字)
$limit = 100;
if (isset($_POST['mail'])) {
  $mail = $_POST['mail'];
  if (mb_strlen($mail) > $limit) {
    $error[] = "メールアドレスは{$limit}文字以下で入力してください";
  } else {
    ※ OK
  }
} else {
  $error[] = 'メールアドレスの値が届いていません';
}

if (isset($_POST[‘mail’])) → 値が届いているかチェック

if (mb_strlen($mail) > $limit) → 文字数上限値(100文字)チェック

メールアドレスは必須項目ではないので、空文字チェックはなし

お問い合わせ内容チェック

  • 届いているかチェック
  • 必須チェック(空文字チェック)
  • 上限値チェック(400文字)
$limit = 400;
if (isset($_POST['body'])) {
  $body = $_POST['body'];
  if ($body === '') {
    $error[] = 'お問い合わせ内容は必須項目です';
  } else if (mb_strlen($body) > $limit) {
    $error[] = "お問い合わせ内容は{$limit}文字以下で入力してください";
  } else {
    ※ OK
  }
} else {
  $error[] = 'お問い合わせ内容の値が届いていません';
}

if (isset($_POST[‘body’])) → 値が届いているかチェック

if ($body === ”) → 空文字かチェック

else if (mb_strlen($body) > $limit)→ 文字数上限値(400文字)チェック

性別チェック

◇未選択は値が届かない
◇「0」「1」「2」が届く
OKルート:「届いていない」or「範囲内の数字」

  • 届いているかチェック → 届いていなくてもエラーにせずOKでチェックぬける
  • 数字チェック
  • 範囲チェック
if (isset($_POST['gender'])) {
  $gender = $_POST['gender'];
  if (ctype_digit($gender)) {
    if ($gender < 0 || $gender > 2) {
      $error[] = '性別の値が不正です';
    } else {
      ※ OK
    }
  } else {
    $error[] = '性別の値が不正です';
  }
} else {
  ※ OK:値が届いていない(選択していない)
  ※ 表示するときに変数がないので
    表示用変数を別途用意しなければならない
}

if (isset($_POST[‘gender’]) → 値が届いているかチェック
値が届いていない場合でもOK

if (ctype_digit($gender)) → 値が数字かチェック

if ($gender < 0 || $gender > 2) → 値の範囲チェック

ctype_digit(引数):引数が数字かどうかを調べる関数
→ 与えられた文字列textのすべての文字が 数字であるかどうかを調べる

trueの場合
①引数は文字列型
②文字列がすべて数字
③小数点をNGとして、整数かをチェック

例)
100 = false
‘100’ = true
0.5 = false
‘0.5’ = false

※ 表示するときに変数がないので、表示用変数を別途のちに用意する必要がある

年代チェック

◇未選択は空文字
◇「0」「1」「2」「3」「4」「5」が届く
OKルート:「空文字」or「範囲内の数字」

  • 届いているかチェック
  • 空文字じゃないかチェック → 空文字でもエラーにせずOKでチェックぬける
  • 数字チェック
  • 範囲チェック
if (isset($_POST['age'])) {
  $age = $_POST['age'];
  if ($age !== '') {
    ※ 範囲内数字のチェック
    if (ctype_digit($age)) {
      if ($age < 0 || $age > 5) {
        $error[] = '年代の値が不正です:2';
      } else {
        ※ OK:範囲内の数字
      }
    } else {
      $error[] = '年代の値が不正です:1';
    }
  } else {
    ※ OK:空文字の時(選択しなかった時)
  }
} else {
  $error[] = '年代の値が届いていません';
}

if (isset($_POST[‘age’])) → 値が届いているかチェック

if ($age !== ”) → 空文字じゃないかチェック
この場合、空文字のときにfalseとなる

if (ctype_digit($age)) → 値が数字かチェック

if ($age < 0 || $age > 5) → 値の範囲チェック

性別・年代の表示用変数を準備

if (count($error) === 0) {
  ※ エラーがないときは表示変数を整える
  ※ 選択項目表示用
  $genderList = [
    0 => '選択してない',
    1 => '男性',
    2 => '女性',
  ];
  if (isset($gender)) {
    ※ 性別の値が届いたとき
    $genderStr = $genderList[$gender];
  } else {
    ※ 性別の値が届いていないとき
    ※ $genderが存在しないとき
    $genderStr = '選択していない';
  }

  if ($age === '') {
    $ageStr = '選択していない';
  } else if ($age === '0') {
    $ageStr = '未回答';
  } else if ($age === '5') {
    $ageStr = "{$age}0代以上";
  } else {
    $ageStr = "{$age}0代";
  }
}

view画面

HTMLにPHPを組み込んで、view画面を作成

<body>
  <div class="box">
    <div class="inner">
      <?php if (count($error) > 0) : ?>
        <h1>エラー</h1>
        <ul class="error">
          <?php foreach ($error as $val) : ?>
            <li><?php echo $val; ?></li>
          <?php endforeach; ?>
        </ul>
      <?php else : ?>
        <h1>確認</h1>
        <dl>
          <dt>名前</dt>
          <dd><?php echo $myname; ?></dd>
          <dt>メールアドレス</dt>
          <dd><?php echo $mail; ?></dd>
          <dt>性別</dt>
          <dd><?php echo $genderStr; ?></dd>
          <dt>年代</dt>
          <dd><?php echo $ageStr; ?></dd>
          <dt>お問い合わせ内容</dt>
          <dd><?php echo nl2br($body); ?></dd>
        </dl>
      <?php endif; ?>
      <p>
        <a href="form.html">フォームに戻る</a>
      </p>
    </div>
  </div>
</body>

<?php if (count($error) > 0) : ?> → エラーがあればエラー文を表示

<?php else : ?> → エラーがない場合は、フォームからPOST形式で取得した値を各々表示

<?php endif; ?> → PHPのif文終了タグ

nl2br関数(new line to br): 改行コード前にbr要素を挿入してくれる
ブラウザ画面上で改行をサポートしてくれる
→ テキストエリアの内容を表示する時によく使う