総合課題集

ここまで学んだ知識(HTML/CSS/JS/PHP/SQL)を総動員して挑む、3つの実践課題を用意しました。

難易度順になっています。ぜひ、答えを見る前に一度自分でコードを書いてみてください!


💻 課題1:【JavaScript】高機能・割り勘電卓

基礎編で作ったカウンターよりも少し複雑な計算ロジックを実装します。

📋 要件定義

  1. 入力項目:「合計金額」(数値)と「人数」(数値)。
  2. 機能:「計算する」ボタンを押すと、一人あたりの金額を表示する。
  3. 余り:割り切れない場合、「余り」も表示する(例:1人 3,300円、余り 100円)。
  4. 【追加チャレンジ】:100円単位で支払うように切り上げる機能をつける(3,333円 → 3,400円集める)。

💡 ヒント

  • 余りの計算には % を使います。
  • 切り上げには Math.ceil() を使いますが、100円単位にするには工夫が必要です(一度100で割って、切り上げて、100掛ける…?)。
▶︎ 解答コードを見る(クリックで展開)
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>割り勘電卓</title>
    <style>
        body { font-family: sans-serif; padding: 20px; max-width: 400px; margin: 0 auto; }
        input { padding: 10px; width: 100%; box-sizing: border-box; margin-bottom: 10px; }
        button { width: 100%; padding: 10px; background: #00bcd4; color: white; border: none; font-size: 16px; cursor: pointer; }
        #result { background: #f0f0f0; padding: 15px; margin-top: 20px; display: none; }
    </style>
</head>
<body>

    <h1>💰 割り勘電卓</h1>
    
    <label>合計金額(円)</label>
    <input type="number" id="price" placeholder="例:10000">
    
    <label>人数(人)</label>
    <input type="number" id="num" placeholder="例:3">

    <button id="btn">計算する</button>

    <div id="result">
        <!-- ここに結果が出る -->
        <p>一人あたり: <strong id="per-person" style="font-size:24px">0</strong> 円</p>
        <p>余り: <span id="remainder">0</span> 円</p>
    </div>

    <script>
        const btn = document.querySelector("#btn");
        const priceInput = document.querySelector("#price");
        const numInput = document.querySelector("#num");
        const resultBox = document.querySelector("#result");

        btn.addEventListener("click", () => {
            const price = Number(priceInput.value);
            const num   = Number(numInput.value);

            // バリデーション:0人や空欄を防ぐ
            if (price <= 0 || num <= 0) {
                alert("正しい数値を入力してください");
                return;
            }

            // === 計算ロジック(100円単位切り上げVer) ===
            
            // 1. まず単純に割る
            // 例:10000 ÷ 3 = 3333.333...
            
            // 2. 100円単位にするテクニック
            // 100で割る(33.33..) → 切り上げ(34) → 100掛ける(3400)
            const payment = Math.ceil((price / num) / 100) * 100;

            // 3. 余り(というか、多く集まりすぎる分)を計算
            // 支払い総額(3400 * 3) - 元の金額(10000) = 200円余る
            const totalPay = payment * num;
            const remainder = totalPay - price;

            // 画面表示
            document.querySelector("#per-person").textContent = payment;
            document.querySelector("#remainder").textContent = remainder;
            resultBox.style.display = "block";
        });
    </script>
</body>
</html>

🔐 課題2:【PHP & Session】秘密の合言葉ページ

データベースは使わず、PHPの「セッション」の挙動を完全に理解するための課題です。

📋 要件定義

  1. ログイン画面(login.php):パスワード入力欄が1つだけ。正しい合言葉(例:secret123)で管理画面へ移動。
  2. 管理画面(admin.php):URLを直打ちしても、ログインしていなければ入れない(強制送還)。ログアウトボタンで戻る。

💡 ヒント

  • パスワードが合っていたら $_SESSION['is_login'] = true; のようにフラグを立てましょう。
  • 管理画面の先頭で empty($_SESSION['is_login']) をチェックします。
▶︎ 解答コードを見る(クリックで展開)

/* --- ファイル1:login.php --- */

<?php
session_start();
$message = "";

// 送信されたら判定
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $pass = $_POST['password'];

    // 合言葉はここで設定(本来はDBのハッシュと比較します)
    if ($pass === 'secret123') {
        // セッションに「ログイン済み」の証拠を残す
        $_SESSION['is_login'] = true;
        
        // 管理画面へGo
        header("Location: admin.php");
        exit;
    } else {
        $message = "パスワードが違います";
    }
}
?>
<!DOCTYPE html>
<html>
<body>
    <h1>ログイン</h1>
    <p style="color:red"><?= $message ?></p>
    <form method="post">
        パスワード:<input type="password" name="password">
        <button type="submit">入室</button>
    </form>
</body>
</html>


/* --- ファイル2:admin.php --- */

<?php
session_start();

// ★セキュリティチェック
// セッションに証拠がない、またはfalseなら追い出す
if (empty($_SESSION['is_login'])) {
    header("Location: login.php");
    exit;
}

// ログアウト処理
if (isset($_POST['logout'])) {
    session_destroy(); // セッション破壊
    header("Location: login.php");
    exit;
}
?>
<!DOCTYPE html>
<html>
<body>
    <h1>秘密の管理画面</h1>
    <p>ようこそ、選ばれし者よ。</p>
    
    <form method="post">
        <button type="submit" name="logout">ログアウト</button>
    </form>
</body>
</html>

📝 課題3:【PHP & DB】Todoリスト(完全版)

データベースを使った、みんなで共有できるTodoリストです。

📋 要件定義

  1. データベース: DB名 todo_app、テーブル名 tasks
  2. カラム: id, title, status(0:未完了, 1:完了)。
  3. 機能: 追加(INSERT)、一覧表示(SELECT)、完了(UPDATE)、削除(DELETE)。

💡 ヒント

  • 1つのファイル(index.php)で処理する場合、ボタンの name 属性を変えて分岐させます(例:name=”add”, name=”delete”)。
  • 完了・削除ボタンのフォームにも input type="hidden" でIDを仕込むのを忘れずに。
▶︎ 解答コードを見る(クリックで展開)

/* --- まずphpMyAdminでSQLを実行 --- */
/*
CREATE DATABASE todo_app DEFAULT CHARACTER SET utf8mb4;
USE todo_app;
CREATE TABLE tasks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255),
    status INT DEFAULT 0
);
*/

/* --- ファイル:index.php --- */
<?php
// DB接続
try {
    $pdo = new PDO('mysql:dbname=todo_app;host=localhost;charset=utf8mb4', 'root', ''); // MAMPはroot/root
} catch (PDOException $e) {
    exit('DBError:'.$e->getMessage());
}

// === POST処理(追加・完了・削除) ===
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    
    // 1. 追加ボタンが押された
    if (isset($_POST['add'])) {
        $title = $_POST['title'];
        if (!empty($title)) {
            $stmt = $pdo->prepare("INSERT INTO tasks (title, status) VALUES (:title, 0)");
            $stmt->bindValue(':title', $title, PDO::PARAM_STR);
            $stmt->execute();
        }
    }

    // 2. 完了ボタンが押された(UPDATE)
    if (isset($_POST['done_id'])) {
        $id = $_POST['done_id'];
        $stmt = $pdo->prepare("UPDATE tasks SET status = 1 WHERE id = :id");
        $stmt->bindValue(':id', $id, PDO::PARAM_INT);
        $stmt->execute();
    }

    // 3. 削除ボタンが押された(DELETE)
    if (isset($_POST['delete_id'])) {
        $id = $_POST['delete_id'];
        $stmt = $pdo->prepare("DELETE FROM tasks WHERE id = :id");
        $stmt->bindValue(':id', $id, PDO::PARAM_INT);
        $stmt->execute();
    }
}

// === 全データ取得 ===
// 未完了(0)を上に、完了(1)を下に表示したい場合、ORDER BY status ASC, id DESC
$sql = "SELECT * FROM tasks ORDER BY status ASC, id DESC";
$tasks = $pdo->query($sql)->fetchAll();
?>

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>DB版Todoリスト</title>
    <style>
        .done { text-decoration: line-through; color: gray; }
        ul { list-style: none; padding: 0; }
        li { border-bottom: 1px solid #ddd; padding: 10px; display: flex; justify-content: space-between; }
        form { display: inline; }
    </style>
</head>
<body>
    <h1>Todoリスト(共有版)</h1>

    <!-- 追加フォーム -->
    <form method="post">
        <input type="text" name="title" required placeholder="新しいタスク">
        <button type="submit" name="add">追加</button>
    </form>

    <ul>
    <?php foreach ($tasks as $task): ?>
        <li>
            <!-- タイトル(statusが1なら .done クラスをつける) -->
            <span class="<?= $task['status'] == 1 ? 'done' : '' ?>">
                <?= htmlspecialchars($task['title'], ENT_QUOTES, 'UTF-8') ?>
            </span>

            <div>
                <!-- 完了ボタン(未完了の時だけ表示) -->
                <?php if ($task['status'] == 0): ?>
                    <form method="post">
                        <input type="hidden" name="done_id" value="<?= $task['id'] ?>">
                        <button type="submit">完了</button>
                    </form>
                <?php else: ?>
                    [済]
                <?php endif; ?>

                <!-- 削除ボタン -->
                <form method="post" onsubmit="return confirm('削除しますか?');">
                    <input type="hidden" name="delete_id" value="<?= $task['id'] ?>">
                    <button type="submit">削除</button>
                </form>
            </div>
        </li>
    <?php endforeach; ?>
    </ul>

</body>
</html>

 

タイトルとURLをコピーしました