---
layout: "@/layouts/MarkdownLayout.astro"
---
import Toc from "../../components/Toc.astro";
import Details from "@/components/Details.astro";
export const title = "クイズを作ってみよう";
import DockerLink from "@/components/DockerLink.astro";
# {title}
これまで学んだPHPの知識を使って、クイズアプリを作ってみましょう。
## TOC
## 演習の目的
この演習では、以下のPHPの機能を実践的に学びます。
- フォームデータの受け取り(`$_POST`)
- 条件分岐(`if`文)
- 変数の使い方
- `htmlspecialchars()`によるセキュリティ対策
## 課題
`/workspace/php/`ディレクトリにテンプレートファイルが用意されています。
これを編集して、オリジナルのクイズを作成してください。
### 必要なファイル
- `quiz.php` - クイズ問題を表示するPHPファイル(**TODOを実装してください**)
- `submit.php` - 答えを判定するPHPファイル(**TODOを実装してください**)
### 実装する内容
#### quiz.phpの実装(4つのTODO)
##### TODO 1: 問題と選択肢を定義する
変数を使って問題文と選択肢を定義します。
<Details summary="ヒント1: どうやって定義する?">
文字列の変数と、配列を使います。
```php
$question = "ここに問題文を書く";
$options = ["選択肢1", "選択肢2", "選択肢3"];
```
</Details>
<Details summary="ヒント2: サンプルコード">
```php
// 問題文
$question = "日本の首都はどこ?";
// 選択肢(配列)
$options = ["東京", "大阪", "京都"];
```
自分の好きな問題に変更してください。
</Details>
##### TODO 2: 正解を定義する
正解の選択肢を変数に保存します。
<Details summary="ヒント1: どの値を設定する?">
正解の選択肢の文字列をそのまま設定します。
例えば、「東京」が正解なら `$correctAnswer = "東京";` です。
</Details>
<Details summary="ヒント2: サンプルコード">
```php
$correctAnswer = "東京";
```
TODO 1で定義した選択肢の中から、正解のものを設定してください。
</Details>
##### TODO 3: 問題を表示する
定義した問題文をHTMLに埋め込みます。
<Details summary="ヒント1: どうやって表示する?">
`<?php echo ... ?>`を使って、変数の内容を出力します。
</Details>
<Details summary="ヒント2: サンプルコード">
```php
<p>問題: <?php echo htmlspecialchars($question); ?></p>
```
`htmlspecialchars()`は、特殊文字を安全に表示するための関数です。
</Details>
##### TODO 4: 選択肢を表示する
配列に入れた選択肢を、繰り返し処理で表示します。
<Details summary="ヒント1: どうやって繰り返す?">
`foreach`を使って、配列の要素を1つずつ取り出して表示します。
</Details>
<Details summary="ヒント2: サンプルコード">
```php
<?php foreach ($options as $index => $option): ?>
<div>
<label>
<input type="radio" name="answer" value="<?php echo htmlspecialchars($option); ?>" <?php echo $index === 0 ? 'required' : ''; ?>>
<?php echo htmlspecialchars($option); ?>
</label>
</div>
<?php endforeach; ?>
```
- `$index`は0から始まる番号、`$option`は選択肢の文字列です
- `value`属性に選択肢の文字列を設定することで、submit.phpで判定できます
- 最初の選択肢だけ`required`を付けています
</Details>
#### submit.phpの実装(4つのTODO)
##### TODO 1: フォームから送信されたかチェックする
直接このページにアクセスされた場合にエラーを表示します。
<Details summary="ヒント1: どうやってチェックする?">
`$_SERVER["REQUEST_METHOD"]`という特別な変数を使います。
フォームが`method="post"`で送信された場合、この値は`"POST"`になります。
</Details>
<Details summary="ヒント2: サンプルコード">
```php
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
echo '<h1>エラー</h1>';
echo '<p>不正なアクセスです。</p>';
exit; // ここで処理を終了
}
```
`!==`は「等しくない」という意味です。POSTメソッド以外でアクセスされた場合はエラーを表示して終了します。
</Details>
##### TODO 2: 送信された答えを取得する
フォームから送信されたユーザーの答えを変数に保存します。
<Details summary="ヒント1: どうやって取得する?">
`$_POST`という特別な配列を使います。
`quiz.php`のinputタグの`name="answer"`に対応して、`$_POST["answer"]`で値を取得できます。
</Details>
<Details summary="ヒント2: サンプルコード">
```php
$userAnswer = $_POST["answer"] ?? "";
```
`??`は「左側の値が存在しない場合は右側の値を使う」という意味です。
これにより、値が送信されなかった場合でもエラーにならず、空文字列が入ります。
</Details>
##### TODO 3: 正解を設定する
正解の値を変数に保存します。
<Details summary="ヒント1: どの値を設定する?">
`quiz.php`で定義した正解と同じ文字列を設定します。
例えば、`quiz.php`で`$correctAnswer = "東京";`と定義したなら、ここでも`"東京"`です。
</Details>
<Details summary="ヒント2: サンプルコード">
```php
$correctAnswer = "東京";
```
`quiz.php`のTODO 2で設定した値と同じにしてください。
</Details>
##### TODO 4: 正誤判定をする
ユーザーの答えと正解を比較して、結果を表示します。
<Details summary="ヒント1: どうやって比較する?">
`if`文を使って、`$userAnswer`と`$correctAnswer`が等しいかをチェックします。
等しい場合は正解、そうでない場合は不正解のメッセージを表示します。
</Details>
<Details summary="ヒント2: サンプルコード">
```php
if ($userAnswer === $correctAnswer) {
echo '<h1>正解です!</h1>';
echo '<p>よくできました。</p>';
} else {
echo '<h1>不正解です</h1>';
echo '<p>残念!もう一度考えてみましょう。</p>';
}
```
`===`は「完全に等しい」という意味です。メッセージの内容は自由に変更できます。
</Details>
## 確認方法
作成したクイズは以下の方法で確認できます。
<DockerLink href="workspace/php/quiz.php" />
1. リンクをクリックしてクイズページを開く
2. 問題を読んで答えを選択する
3. 「答えを送信」ボタンをクリック
4. 正誤判定の結果が表示されることを確認する
## 発展課題
基本的なクイズができたら、Sessionを使ってランダム出題機能を追加してみましょう。
Sessionを使って、毎回ランダムに問題を出題する機能を実装します。
<Details summary="実装のヒント">
**quiz.phpの変更:**
```php
<?php
session_start();
// 複数の問題を定義
$questions = [
[
"question" => "日本の首都はどこ?",
"options" => ["東京", "大阪", "京都"],
"answer" => "東京"
],
[
"question" => "1 + 1 は?",
"options" => ["1", "2", "3"],
"answer" => "2"
],
// 問題を追加
];
// ランダムに1問選択
$randomIndex = array_rand($questions);
$selectedQuestion = $questions[$randomIndex];
// Sessionに正解を保存
$_SESSION["correct_answer"] = $selectedQuestion["answer"];
// 問題と選択肢を変数に設定
$question = $selectedQuestion["question"];
$options = $selectedQuestion["options"];
?>
```
**submit.phpの変更(TODO 3):**
```php
// Sessionから正解を取得
$correctAnswer = $_SESSION["correct_answer"] ?? "";
```
これで、ブラウザの開発者ツールでHTMLを見ても正解が分からなくなります!
</Details>
## まとめ
この演習では、PHPの基本的な機能を使ってインタラクティブなウェブアプリケーションを作成しました。
- 変数と配列の使い方
- HTMLへのデータ埋め込み
- フォームからのデータ受け取り
- 条件分岐による処理の切り替え
- エラーハンドリング
- (発展)Sessionを使った状態管理
これらはウェブアプリケーション開発の基礎となる重要な概念です。
ぜひ自分なりにアレンジして、さまざまなクイズを作ってみてください。