お問い合わせフォームを作ってみる -実装編③:エラー時の処理と値を保持する処理の実装-

こんにちは、ユアサです。
前回までの記事ではValitronを使用した入力内容のバリデーションを実装しました。今回は、前回予告した通りバリデーションでエラーが発生した際に入力画面に戻り、エラー内容が表示される処理を実装していきます。
また、バリデーションエラー発生時や確認画面の「戻る」ボタンをクリックした時でも、入力内容を保持できる仕様も追加しようと思います。

↓前回の記事 tech.arms-soft.co.jp

入力画面

入力画面にsession_start();を追加しました。そして一度確認画面でエラーがあるかを判断する処理をして、エラーがあった場合にエラー内容を入力画面の見出しの下に表示させるようにしました。
また確認画面から入力画面に戻った際に、各項目に該当するSESSIONで値を渡し、各入力項目に入力・選択していた内容を再び表示させる仕様にしました。
全体のコードは以下の通りです。

<?php
session_start();

if(isset($_SESSION["errors"])){
    $errors = $_SESSION["errors"];
}
?>

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="sample.css">
    <title>お問い合わせフォーム 入力画面</title>
</head>
<body>
<div>
<h1>お問い合わせフォーム</h1>

<?php if(isset($errors)) : ?>
    <?php foreach($errors as $value): ?>
        <?php echo $value; ?><br />
    <?php endforeach; ?>
<?php endif; ?>

    <form method="post" action="confirm.php">
    <div>
        <label for="name">氏名</label>
        <input type="text" name="name" value="<?php if(isset($_SESSION['name'])){echo $_SESSION['name'];} ?>">
    </div>
    <div>
        <label for="email">メールアドレス</label>
        <input type="text" name="email" value="<?php if(isset($_SESSION['email'])){echo $_SESSION['email'];} ?>">
    </div>
    <div>
        <label for="contents">お問い合わせ内容</label>
        <select name="contents">
            <option value="">選択してください</option>
            <option value="contents1" <?php echo array_key_exists('contents', $_SESSION)&&$_SESSION['contents'] == 'contents1'?'selected':''; ?>>内容①</option>
            <option value="contents2" <?php echo array_key_exists('contents', $_SESSION)&&$_SESSION['contents'] == 'contents2'?'selected':''; ?>>内容②</option>
            <option value="contents3" <?php echo array_key_exists('contents', $_SESSION)&&$_SESSION['contents'] == 'contents3'?'selected':''; ?>>内容③</option>
            <option value="contents4" <?php echo array_key_exists('contents', $_SESSION)&&$_SESSION['contents'] == 'contents4'?'selected':''; ?>>内容④</option>
            <option value="contents5" <?php echo array_key_exists('contents', $_SESSION)&&$_SESSION['contents'] == 'contents5'?'selected':''; ?>>内容⑤</option>
        </select>
    </div>
    <div>
        <label for="remarks">備考</label><br>
        <textarea rows="6" cols="100" name="remarks"><?php if(isset($_SESSION['remarks'])){print($_SESSION['remarks']);} ?></textarea>
    </div>
    <button type="submit" name="btn_confirm">入力内容を確認する</button>
</form>
<?php session_destroy(); ?>
</div>
</body>
</html>

確認画面でエラー内容をSESSION['errors']に保存し、見出し「お問い合わせフォーム」の下に表示させます。

氏名やメールアドレスではSESSION内の各項目の値を取得して表示させます。SESSION内に値があった場合のみ取得するので、初期の状態では何も表示されない仕様になっています。
お問い合わせ内容ですが、こちらは他の項目と違いプルダウンなので、array_key_exists関数を使用することによって配列内に値が入っているか判定し、且つ各選択肢のvalueが入っていた場合に選択されている状態にする(selected)ようにしました。
備考はtextarea属性が元々valueを使用できないので、SESSION内に備考で入力した値があった場合のみprint()で表示させる仕様にしました。

また、SESSIONに入っている値が繰り返し使用されないようにするため、一番最後にsession_destroy();も追加しました。

<form method="post" action="confirm.php">
    <div>
        <label for="name">氏名</label>
        <input type="text" name="name" value="<?php if(isset($_SESSION['name'])){echo $_SESSION['name'];} ?>">
    </div>
    <div>
        <label for="email">メールアドレス</label>
        <input type="text" name="email" value="<?php if(isset($_SESSION['email'])){echo $_SESSION['email'];} ?>">
    </div>
    <div>
        <label for="contents">お問い合わせ内容</label>
        <select name="contents">
            <option value="">選択してください</option>
            <option value="contents1" <?php echo array_key_exists('contents', $_SESSION)&&$_SESSION['contents'] == 'contents1'?'selected':''; ?>>内容①</option>
            <option value="contents2" <?php echo array_key_exists('contents', $_SESSION)&&$_SESSION['contents'] == 'contents2'?'selected':''; ?>>内容②</option>
            <option value="contents3" <?php echo array_key_exists('contents', $_SESSION)&&$_SESSION['contents'] == 'contents3'?'selected':''; ?>>内容③</option>
            <option value="contents4" <?php echo array_key_exists('contents', $_SESSION)&&$_SESSION['contents'] == 'contents4'?'selected':''; ?>>内容④</option>
            <option value="contents5" <?php echo array_key_exists('contents', $_SESSION)&&$_SESSION['contents'] == 'contents5'?'selected':''; ?>>内容⑤</option>
        </select>
    </div>
    <div>
        <label for="remarks">備考</label><br>
        <textarea rows="6" cols="100" name="remarks"><?php if(isset($_SESSION['remarks'])){print($_SESSION['remarks']);} ?></textarea>
    </div>
    <button type="submit" name="btn_confirm">入力内容を確認する</button>
</form>
<?php session_destroy(); ?>

確認画面

こちらで入力内容をSESSIONに保存します。エラーがあった場合はエラー内容をSESSION['errors']として保存し、header関数で入力画面にリダイレクトさせます。
前回までは確認画面でエラー表示をさせる仕様でしたが、その処理を入力画面にしたことによってコードも多少変わりました。

<?php
require_once( 'vendor/autoload.php' );
Valitron\Validator::lang('ja');
session_start();

// Valitronクラスを実行
$v = new Valitron\Validator($_POST);

// 入力必須の項目が記入されているか確認
// 入力項目のうち備考のみ任意項目にしてみる
$v->rule('required', 'name')->message('{field}を入力してください');
$v->rule('required', 'email')->message('{field}を入力してください');
$v->rule('required', 'contents')->message('{field}を入力してください');
// 入力された文字がメール形式かを確認
$v->rule('email', 'email')->message('{field}が正しい形式ではありません');
// 項目名を指定
$v->labels([
               'name' => '名前',
               'email' => 'メールアドレス',
               'contents' => 'お問い合わせ内容',
               'remarks' => '備考'
           ]);

$_SESSION['name'] = htmlspecialchars($_POST['name']);
$_SESSION['email'] = htmlspecialchars($_POST['email']);
$_SESSION['contents'] = htmlspecialchars($_POST['contents']);
$_SESSION['remarks'] = htmlspecialchars($_POST['remarks']);
// バリデーションを実行
if($v->validate()) {
    // 値の受け取り
    $name = $_SESSION['name'];
    $email = $_SESSION['email'];
    $contents = $_SESSION['contents'];
    $remarks = $_SESSION['remarks'];
} else {
    $errors = [];
    foreach ($v->errors() as $error) {
        foreach ($error as $value) {
            $errors[] =  $value;
        }
    }

    $_SESSION['errors'] = $errors;
    header("location: input.php");
}
?>
<!DOCTYPE>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>お問い合わせフォーム 確認画面</title>
    <link rel="stylesheet" href="sample.css">
</head>
<body>
    <div>
        <h1>お問い合わせフォーム</h1>
        <p>以下の内容でよろしければ「送信する」をクリックしてください。<br>
            内容を変更する場合は「戻る」をクリックして入力画面にお戻りください。</p>
        <form method="post" action="confirm.php">
            <div>
                <label for="name">氏名</label>
                <p><?php echo $name; ?></p>
            </div>
            <div>
                <label for="email">メールアドレス</label>
                <p><?php echo $email; ?></p>
            </div>
            <div>
                <label for="contents">お問い合わせ内容</label>
                <p><?php echo $contents; ?></p>
            </div>
            <div>
                <label for="remarks">備考</label><br>
                <p><?php echo $remarks; ?></p>
            </div>
        </form>
        <form action="input.php" method="get">
            <button type="submit">戻る</button>
        </form>
        <form action="complete.php" method="post">
            <button type="submit" class="btn btn-success">送信する</button>
        </form>
    </div>
</body>
</html>

動作確認

それでは実際に動作させてみます。
必須項目であるお問い合わせ内容以外の項目を入力した状態にしました。確認画面から入力画面に戻ったことを分かりやすくするために、SESSION内に値が何かしら入っていた場合にechoで文章を表示するコードを一時的に追加しました。

f:id:Felly00505:20210208024713p:plain この状態で「入力内容を確認する」ボタンをクリックします。

f:id:Felly00505:20210208024921p:plain 確認画面に進まず、見出しの下にエラー内容が表示されました! また入力した項目に値が保持されているのも確認できました。

続いて、全項目入力しエラーのない状態で一度確認画面へ遷移し、「戻る」ボタンで入力画面に戻った際の動作について確認します。

f:id:Felly00505:20210208030153p:plain この状態で「入力内容を確認する」ボタンをクリックします。

f:id:Felly00505:20210208030243p:plain 確認画面へ遷移できました。「戻る」ボタンをクリックして入力画面に戻ります。

f:id:Felly00505:20210208030358p:plain 値が正しく保持されていました!

まとめ

今回はエラー時に入力画面へ戻ってエラー内容を表示させる処理と値を保持する処理の実装をしました。
前回に比べると色々試行錯誤してコードを書いたので、少しだけステップアップできたような気がします。
次回は完了画面と自動返信メールの実装をしていこうと思います。
最後まで読んでいただきありがとうございました(^人^)