フォルダとファイル名
php-db フォルダに db08.php を作成します。
このページでは、これまでに学んだ 追加(INSERT)・更新(UPDATE)・削除(DELETE)・検索(SELECT) をすべて1つのページで実装します。
完成イメージ

基本コード
- ユーザーの一覧を表示
- ユーザーの表示(SELECT)
- ユーザーの追加(INSERT)
- ID指定での更新(UPDATE)
- ID指定での削除(DELETE)
<?php
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4';
$user = 'root';
$password = '';
// HTMLエスケープ用
function h($str)
{
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
try {
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$msg = '';
$searchKeyword = '';
$rows = [];
$errors = [];
// -----------------------------
// 表示処理
// -----------------------------
// 通常の一覧表示
$stmt = $pdo->query("SELECT * FROM users ORDER BY id ASC");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
// -----------------------------
// 追加処理(POST)
// -----------------------------
if (isset($_POST['action']) && $_POST['action'] === 'add') {
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
if ($name === '') {
$errors[] = '名前は必須です。';
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'メールアドレスの形式が正しくありません。';
}
if (count($errors) === 0) {
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->execute([$name, $email]);
header("Location: " . $_SERVER['PHP_SELF'] . "?msg=" . urlencode("ユーザー「{$name}」を追加しました。"));
exit;
}
}
// -----------------------------
// 更新処理(POST)
// -----------------------------
if (isset($_POST['action']) && $_POST['action'] === 'update') {
$id = (int)($_POST['id'] ?? 0);
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
if ($id <= 0) {
$errors[] = 'IDが正しくありません。';
}
if ($name === '') {
$errors[] = '名前は必須です。';
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'メールアドレスの形式が正しくありません。';
}
if (count($errors) === 0) {
$stmt = $pdo->prepare("UPDATE users SET name = ?, email = ? WHERE id = ?");
$stmt->execute([$name, $email, $id]);
header("Location: " . $_SERVER['PHP_SELF'] . "?msg=" . urlencode("ID {$id} のユーザーを更新しました。"));
exit;
}
}
// -----------------------------
// 削除処理(POST)
// -----------------------------
if (isset($_POST['action']) && $_POST['action'] === 'delete') {
$id = (int)($_POST['id'] ?? 0);
if ($id <= 0) {
$errors[] = 'IDが正しくありません。';
}
if (count($errors) === 0) {
$stmt = $pdo->prepare("DELETE FROM users WHERE id = ?");
$stmt->execute([$id]);
$count = $stmt->rowCount();
$msg = ($count > 0) ? "ID {$id} を削除しました。" : "該当IDが見つかりませんでした。";
header("Location: " . $_SERVER['PHP_SELF'] . "?msg=" . urlencode($message));
exit;
}
}
} catch (PDOException $e) {
// 本番ではエラーメッセージは表示せずログに記録する
echo "エラーが発生しました(詳細はログ参照)";
// error_log($e->getMessage());
exit;
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ユーザー管理</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>ユーザー管理</h1>
<div class="success">
<?php if ($msg): ?>
<p><strong><?= h($msg) ?></strong></p>
<?php endif; ?>
</div>
<div class="error">
<?php if ($errors): ?>
<ul style="color:red;">
<?php foreach ($errors as $error): ?>
<li><?= h($error) ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
</header>
<div class="content">
<main>
<!-- 一覧表示 -->
<table>
<tr>
<th>ID</th>
<th>名前</th>
<th>メール</th>
<th>登録日時</th>
</tr>
<?php foreach ($rows as $row): ?>
<tr>
<td><?= h($row['id']) ?></td>
<td><?= h($row['name']) ?></td>
<td><?= h($row['email']) ?></td>
<td><?= h($row['created_at']) ?></td>
</tr>
<?php endforeach; ?>
</table>
</main>
<aside>
<section>
<!-- 追加フォーム -->
<h2>追加</h2>
<form method="post">
<input type="hidden" name="action" value="add">
<p>
<label for="name">名前</label>
<input id="name" type="text" name="name" required>
</p>
<p>
<label for="email">メール</label>
<input id="email" type="email" name="email" required>
</p>
<p>
<button type="submit">追加する</button>
</p>
</form>
</section>
<section>
<!-- 更新フォーム -->
<h2>更新</h2>
<form method="post">
<input type="hidden" name="action" value="update">
<p>
<label for="update-id">ID</label>
<input id="update-id" type="number" name="id" required>
</p>
<p>
<label for="update-name">名前</label>
<input id="update-name" type="text" name="name" required>
</p>
<p>
<label for="update-email">メール</label>
<input id="update-email" type="email" name="email" required>
</p>
<button type="submit">更新する</button>
</form>
</section>
<section>
<!-- 削除フォーム -->
<h2>削除</h2>
<form method="post">
<input type="hidden" name="action" value="delete">
<p>
<label for="delete-id">ID</label>
<input id="delete-id" type="number" name="id" required>
</p>
<button type="submit">削除する</button>
</form>
</section>
</aside>
</div>
</body>
</html>
* {
margin: 0;
padding: 0;
}
body {
font-family: sans-serif;
padding: 1em;
}
header,
.content {
max-width: 960px;
margin: auto;
}
.content {
display: grid;
column-gap: 3rem;
grid-template-columns: 3fr 1fr;
}
.error ul {
color: red;
margin-bottom: 1rem;
}
.success p {
color: green;
}
table {
border-collapse: collapse;
margin-bottom: 2em;
width: 100%;
}
th,
td {
border: 1px solid #ccc;
padding: .5em 1em;
}
form {
margin-bottom: 2em;
}
form input[type=text],
form input[type=email] {
width: 100%;
padding: 0.25rem;
box-sizing: border-box;
}
form button[type=submit] {
background-color: #ccc;
padding: 0.25rem 1rem;
border: none;
margin-top: 0.5rem;
border-radius: 0.2rem;
}
label {
display: block;
}
section {
border: 1px solid #ddd;
padding: 0.5rem;
margin-bottom: 1rem;
border-radius: 0.5rem;
}
処理の順番が大事な理由
このページでは、以下のような4つの処理を順番に書いています
// ① 表示処理(SELECT)
$stmt = $pdo->query("SELECT * FROM users ORDER BY id ASC");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
// ② 追加処理(POST)
if (isset($_POST['action']) && $_POST['action'] === 'add') { ... }
// ③ 更新処理(POST)
if (isset($_POST['action']) && $_POST['action'] === 'update') { ... }
// ④ 削除処理(POST)
if (isset($_POST['action']) && $_POST['action'] === 'delete') { ... }
正しい順番の理由
| 処理 | なぜこの順番が必要か |
|---|---|
| ① 表示処理(SELECT) | まず一覧を取得して $rows に入れておくと、このあとどの処理が走っても最終的に画面に反映できます。 |
| ② 追加処理(POST) | 新しいデータを登録したら、次のリロード時に追加後の一覧が見えるようにします。 |
| ③ 更新処理(POST) | 既存データを上書きする処理なので、追加の後に実行するのが自然です。 |
| ④ 削除処理(POST) | 一番最後に実行すると、追加や更新が終わったあとで安全に消せます。 |
よくある間違いとその影響
もし削除や更新の処理を「表示処理の後」に書いてしまうと、こうなります:
- フォームから POST でデータを削除
- でも先に
$rowsに一覧を取得してしまっている - 削除前のデータが表示される!
つまり、画面に反映されない状態になります。
データを変更する処理は一覧表示の前に書くか、処理後にリダイレクト(PRGパターン)して一覧を再取得する必要があります。
処理順のまとめ
| 優先順位 | 処理内容 | 理由 |
|---|---|---|
| 1 | 表示処理(一覧の取得) | $rows に一覧を入れるため先頭で実行 |
| 2 | POST(追加) | 登録内容を先に処理し、次の画面で反映 |
| 3 | POST(更新) | 更新内容を上書きして次の表示に反映 |
| 4 | POST(削除) | 最後に安全に削除して、次の表示で消えている状態にする |
課題:キーワード検索をつけてみよう
現在のページでは、すべてのユーザーを一覧表示しています。
ここに 「名前」や「メールアドレス」を部分一致で検索できる機能 を追加してみましょう。
ヒント
1. フォームを作成する
一覧の上部に検索フォームを追加します。
<form method="get">
<input type="text" name="keyword" placeholder="名前やメールを検索">
<button type="submit">検索</button>
</form>
2.PHPでキーワードを取得する
PHPの上の方で、$_GET からキーワードを受け取ります。
$searchKeyword = trim($_GET['keyword'] ?? '');
3.SQLに条件を追加する
キーワードがあれば WHERE name LIKE ? OR email LIKE ? を使って検索します。
if ($searchKeyword !== '') {
$stmt = $pdo->prepare(
"SELECT * FROM users WHERE name LIKE ? OR email LIKE ? ORDER BY id ASC"
);
$like = '%' . $searchKeyword . '%';
$stmt->execute([$like, $like]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
} else {
$stmt = $pdo->query("SELECT * FROM users ORDER BY id ASC");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
