はじめに
実装に苦戦したので、備忘録として記事にしました。
まだまだ勉強中の身なので、知らないことがたくさんあります。
参考になると嬉しいです。
実装したいこと
問題1で「織田信長」と「ショパン」を選択し、問題2を選択せずに送信ボタンを押したとき、選択を保持したままエラーメッセージを表示する。
複数の入力画面があってエラーがでたとき、全て入力しなおすなんてことにならないように。
環境
- XAMPP Version 8.1.10
- Visual Studio Code Version 1.74.2
データベースの構造(phpMyadmin)
phpファイル
<?php
//セッション開始
session_start();
try {
// データベースに接続
$pdo = new PDO(
'mysql:dbname=xxx;host=localhost;charset=utf8',
'xxx',
'xxx',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES =>false
]
);
//変数の定義とシリアライズ
if(isset($_POST['question1'])){
$question1 = $_POST['question1'];
$question1_db = serialize($question1);
}
if(isset($_POST['question2'])){
$question2 = $_POST['question2'];
$question2_db = serialize($question2);
}
//form送信したら
if( !empty($_POST['btn_submit']) ) {
// 選択されているかチェック
if(empty($question1)) {
$error_message[] = '問題1を選択してください。';
}
if(empty($question2)) {
$error_message[] = '問題2を選択してください。';
}
//未選択がないとき
if( empty($error_message) ) {
//データベースの挿入とトランザクションの開始
$sql = "INSERT INTO xxx (question1,question2) VALUES (:question1,:question2)";
$stmt = $pdo->prepare($sql);
$pdo->beginTransaction();
try{
$stmt->bindvalue( ':question1', $question1_db);
$stmt->bindvalue( ':question2', $question2_db);
$stmt->execute();
$pdo->commit();
$result = $stmt->fetchAll();
}catch (PDOException $e) {
$pdo->rollBack();
throw $e;
}
header('Location: xxx');
exit;
}
}
}catch(PDOException $e) {
$error_message[] = $e->getMessage();
header('Content-Type: text/plain; charset=UTF-8', true, 500);
exit($e->getMessage());
}
header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>example1</title>
<!-- リンク -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/reset.css">
</head>
<body>
<main>
<?php if( !empty($error_message) ){ ?>
<p class="alert alert-danger col-3" role="alert">
<?php foreach( $error_message as $value ){?>
<?php echo $value; ?><br>
<?php } ?>
</p>
<?php } ?>
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post" class="p-4">
<div class="mb-3">
<label class="form-label">問題1:三英傑は誰?(複数回答可)</label><br>
<input type="checkbox" name="question1[]" value="織田信長" <?php if(isset($question1) && in_array('織田信長',$question1)) { echo "checked";} ?>>織田信長
<input type="checkbox" name="question1[]" value="ショパン" <?php if(isset($question1) && in_array('ショパン',$question1)) { echo "checked";} ?>>ショパン
<input type="checkbox" name="question1[]" value="毛沢東" <?php if(isset($question1) && in_array('毛沢東',$question1)) { echo "checked";} ?>>毛沢東
</div>
<div class="mb-3">
<label class="form-label">問題2:日本国民の三大義務は?(複数回答可)</label><br>
<input type="checkbox" name="question2[]" value="休息の義務" <?php if(isset($question2) && in_array('休息の義務',$question2)) { echo "checked";} ?>>休息の義務
<input type="checkbox" name="question2[]" value="勤労の義務" <?php if(isset($question2) && in_array('勤労の義務',$question2)) { echo "checked";} ?>>勤労の義務
<input type="checkbox" name="question2[]" value="納税の義務" <?php if(isset($question2) && in_array('納税の義務',$question2)) { echo "checked";} ?>>納税の義務
</div>
<div class="form-group">
<input type="submit" name="btn_submit" class="btn btn-primary" value="送信">
</div>
</form>
</main>
</body>
</html>
解説
<?php
//セッション開始
session_start();
try {
// データベースに接続
$pdo = new PDO(
'mysql:dbname=xxx;host=localhost;charset=utf8',
'xxx',
'xxx',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES =>false
]
);
セッションを開始して、データベースに接続する。
xxx
部分は順に、データベース名、ユーザー名、パスワードを入力する。
//変数の定義とシリアライズ
if(isset($_POST['question1'])){
$question1 = $_POST['question1'];
$question1_db = serialize($question1);
}
if(isset($_POST['question2'])){
$question2 = $_POST['question2'];
$question2_db = serialize($question2);
}
送信されてきたquestion1
とquestion2
に値があるとき、$question1
と$question2
にPOST変数を代入する。
また、この2つは配列なのでデータベースに格納できないため、シリアライズをして格納できる形にする。
//form送信したら
if( !empty($_POST['btn_submit']) ) {
// 選択されているかチェック
if(empty($question1)) {
$error_message[] = '問題1を選択してください。';
}
if(empty($question2)) {
$error_message[] = '問題2を選択してください。';
}
送信ボタンがおされたとき$question1
と$question2
が空であったら、$error_message[]
に各エラーメッセージを入れる。
//未選択がないとき
if( empty($error_message) ) {
//データベースの挿入とトランザクションの開始
$sql = "INSERT INTO xxx (question1,question2) VALUES (:question1,:question2)";
$stmt = $pdo->prepare($sql);
$pdo->beginTransaction();
try{
$stmt->bindvalue( ':question1', $question1_db);
$stmt->bindvalue( ':question2', $question2_db);
$stmt->execute();
$pdo->commit();
$result = $stmt->fetchAll();
}catch (PDOException $e) {
$pdo->rollBack();
throw $e;
}
header('Location: xxx');
exit;
}
}
}catch(PDOException $e) {
$error_message[] = $e->getMessage();
header('Content-Type: text/plain; charset=UTF-8', true, 500);
exit($e->getMessage());
}
header('Content-Type: text/html; charset=utf-8');
?>
エラーメッセージが空、つまり2つの選択肢が選択されているときデータベースにデータを挿入する。
xxx
には順に、テーブル名、リダイレクトするファイル名を入力する。今回はファイル自身を設定する。
接続エラー処理の中にトランザクション処理を行ってデータの整合性を保つ。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>example1</title>
<!-- リンク -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/reset.css">
</head>
デザインテンプレートとしてBootstrapを使用している。
<main>
<?php if( !empty($error_message) ){ ?>
<p class="alert alert-danger col-3" role="alert">
<?php foreach( $error_message as $value ){?>
<?php echo $value; ?><br>
<?php } ?>
</p>
<?php } ?>
$error_message
に値が入っているとき、エラーメッセージを表示する。
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post" class="p-4">
<div class="mb-3">
<label class="form-label">問題1:三英傑は誰?(複数回答可)</label><br>
<input type="checkbox" name="question1[]" value="織田信長" <?php if(isset($question1) && in_array('織田信長',$question1)) { echo "checked";} ?>>織田信長
<input type="checkbox" name="question1[]" value="ショパン" <?php if(isset($question1) && in_array('ショパン',$question1)) { echo "checked";} ?>>ショパン
<input type="checkbox" name="question1[]" value="毛沢東" <?php if(isset($question1) && in_array('毛沢東',$question1)) { echo "checked";} ?>>毛沢東
</div>
<div class="mb-3">
<label class="form-label">問題2:日本国民の三大義務は?(複数回答可)</label><br>
<input type="checkbox" name="question2[]" value="休息の義務" <?php if(isset($question2) && in_array('休息の義務',$question2)) { echo "checked";} ?>>休息の義務
<input type="checkbox" name="question2[]" value="勤労の義務" <?php if(isset($question2) && in_array('勤労の義務',$question2)) { echo "checked";} ?>>勤労の義務
<input type="checkbox" name="question2[]" value="納税の義務" <?php if(isset($question2) && in_array('納税の義務',$question2)) { echo "checked";} ?>>納税の義務
</div>
<div class="form-group">
<input type="submit" name="btn_submit" class="btn btn-primary" value="送信">
</div>
</form>
</main>
</body>
</html>
自分自身にデータを送信するformを作成する。
inputタグのname属性は配列にするため、最後に[]
をつけるのを忘れずにする。
なお、[]
はphpでは記述しなくてよい。
$question1
が空の配列ではなくてかつ、$question1
に「織田信長」が入っているとき、チェックボックスを選択済みにする。