0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PHPで学生管理に「更新機能」をつける(Docker編・CRUDのUpdate)

0
Last updated at Posted at 2026-06-29

前回の「追加機能」に続き、今回は 更新(編集)機能 を実装します。CRUD の U(Update) にあたる部分です。

  • 一覧の各行に「編集」リンクを置く
  • リンクを押すと、その学生の現在の値が入った編集フォームが出る
  • 更新すると一覧画面に戻り、変更が反映される

主キー(学籍番号)をどう扱うか、既存値をフォームにどう反映するか、といった更新ならではのポイントを押さえます。

前提

Docker編 + 追加機能まで実装済みの状態から始めます。

myportal/
├── docker-compose.yml
├── Dockerfile
├── init.sql
├── db.php
├── manage_students.php   # 学生一覧
├── add_student.php       # 追加
└── style.css

ステップ1: 一覧に「編集」リンクを置く

manage_students.php のテーブルに「操作」列を足し、各行に編集画面へのリンクを出します。学籍番号をクエリパラメータで渡すのがポイント。

        <tr><th>学籍番号</th><th>氏名</th><th>学科</th><th>セメスター</th><th>メール</th><th>操作</th></tr>
        <?php
        $result = mysqli_query($con, "SELECT * FROM students ORDER BY s_id");
        while ($row = mysqli_fetch_assoc($result)) {
            $editUrl = "edit_student.php?s_id=" . urlencode($row['s_id']);
            echo "<tr>";
            echo "<td>".htmlspecialchars($row['s_id'])."</td>";
            echo "<td>".htmlspecialchars($row['name'])."</td>";
            echo "<td>".htmlspecialchars($row['department'])."</td>";
            echo "<td>".htmlspecialchars($row['semester'])."</td>";
            echo "<td>".htmlspecialchars($row['email'])."</td>";
            echo "<td><a class='btn btn-sm' href='".htmlspecialchars($editUrl)."'>編集</a></td>";
            echo "</tr>";
        }
        ?>

urlencode() で学籍番号をURLに安全に埋め込み、リンクテキストは htmlspecialchars() でエスケープします。

ステップ2: 編集画面 edit_student.php

1ファイルで「既存データの表示(GET)」と「更新処理(POST)」を兼ねます。

<?php
include 'db.php';

$error = "";

// 対象の学籍番号(主キー)。GET/POST どちらからでも受ける
$s_id = trim($_GET['s_id'] ?? $_POST['s_id'] ?? '');
if ($s_id === '') {
    header("Location: manage_students.php");
    exit;
}

// 更新処理
if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $name       = trim($_POST['name'] ?? '');
    $department = trim($_POST['department'] ?? '');
    $semester   = trim($_POST['semester'] ?? '');
    $email      = trim($_POST['email'] ?? '');

    if ($name === '') {
        $error = "氏名は必須です。";
    } else {
        // SQLインジェクション対策のプリペアドステートメント
        $stmt = $con->prepare(
            "UPDATE students SET name=?, department=?, semester=?, email=? WHERE s_id=?"
        );
        $sem = ($semester === '') ? 0 : (int)$semester;
        $stmt->bind_param("ssiss", $name, $department, $sem, $email, $s_id);
        $stmt->execute();
        // 更新成功 → 一覧画面に戻る(PRGパターン)
        header("Location: manage_students.php");
        exit;
    }
    // エラー時はPOST値を表示に使う
    $student = [
        's_id' => $s_id, 'name' => $name, 'department' => $department,
        'semester' => $semester, 'email' => $email,
    ];
} else {
    // 初回表示:既存データを取得してフォームに反映
    $stmt = $con->prepare("SELECT * FROM students WHERE s_id=?");
    $stmt->bind_param("s", $s_id);
    $stmt->execute();
    $student = $stmt->get_result()->fetch_assoc();
    if (!$student) {
        // 存在しない学籍番号
        header("Location: manage_students.php");
        exit;
    }
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>学生を編集</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>学生を編集</h1>

    <?php if ($error !== ''): ?>
        <p class="error"><?= $error ?></p>
    <?php endif; ?>

    <form method="post" action="edit_student.php" class="form">
        <input type="hidden" name="s_id" value="<?= htmlspecialchars($student['s_id']) ?>">

        <label>学籍番号(変更不可)
            <input type="text" value="<?= htmlspecialchars($student['s_id']) ?>" disabled>
        </label>
        <label>氏名 <span class="req">*</span>
            <input type="text" name="name" value="<?= htmlspecialchars($student['name']) ?>" required>
        </label>
        <label>学科
            <input type="text" name="department" value="<?= htmlspecialchars($student['department']) ?>">
        </label>
        <label>セメスター
            <input type="number" name="semester" min="1" max="12" value="<?= htmlspecialchars($student['semester']) ?>">
        </label>
        <label>メール
            <input type="email" name="email" value="<?= htmlspecialchars($student['email']) ?>">
        </label>

        <div class="actions">
            <button type="submit" class="btn">更新</button>
            <a class="btn btn-cancel" href="manage_students.php">キャンセル</a>
        </div>
    </form>
</body>
</html>

ここが重要なポイント

  1. 主キー(学籍番号)は変更させない
    学籍番号はレコードを一意に識別するキー。これを編集対象にすると参照関係が壊れやすい。フォームでは disabled の入力欄で見せつつ、実際の値は hidden で保持して WHERE s_id=? の識別に使う。

  2. GETで既存値を読み込み、フォームに反映
    初回表示時に SELECT ... WHERE s_id=? で取得し、各 value="..." に流し込む。これにより「現在の値が入った状態」で編集を始められる。

  3. UPDATE もプリペアドステートメント
    追加(INSERT)と同様、値はすべてバインドしてSQLインジェクションを防ぐ。"ssiss" は name, department, semester(整数), email, s_id の型指定。

  4. PRG(Post/Redirect/Get)パターン
    更新後に header("Location: ...") でリダイレクト。再読み込みによる二重送信を防ぐ。

  5. 不正・存在しないIDの防御
    s_id が空、または該当レコードがなければ一覧へリダイレクトして安全に処理を打ち切る。

ステップ3: CSS(小さい編集ボタン)

style.css に一覧内で使う小さめのボタンを追記。

.btn-sm { padding:4px 10px; font-size:13px; }

ステップ4: 動作確認

ファイルはボリュームマウントで即時反映。

http://localhost:8081/manage_students.php
  1. 一覧の「編集」を押す → 現在の値が入ったフォームが出る
  2. 値を変えて「更新」
  3. 一覧に戻り、変更が反映されている

CLIでも確認できる。

curl -i -X POST http://localhost:8081/edit_student.php \
  --data "s_id=ktu1&name=Jack%20Updated&department=MECH&semester=9&email=jack2@example.com"
# → HTTP/1.1 302 Found / Location: manage_students.php

まとめ

CRUDの「U(Update)」を実装しました。要点は3つ。

  • 主キーは編集させず識別キーとして固定する
  • GETで既存値を読み込み、フォームに反映する
  • UPDATEもプリペアドステートメント+PRGパターンで安全に

残るは削除(Delete)。これを付ければ基本的なCRUDが完成します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?