PHPでデータベースのデータを安全に削除する方法【DELETE文と確認処理】

Webアプリケーションを運営していると、古くなった投稿や不要になったデータを削除したい場面が出てきます。データベースから特定のレコードを削除するには、SQLのDELETE文を使います。

しかし、削除処理の実装は、細心の注意を払わなければならない、非常にデリケートな作業です。安易に実装すると、誤操作や悪意のある攻撃によって、意図せず重要なデータを全て失ってしまう危険性があります。

この記事では、DELETE文の基本的な使い方と、誤削除を防ぎ、安全性を確保するための「確認画面を挟む」という必須のプロセスについて解説します。


目次

1. DELETE文の基本と最大の注意点

DELETEは、テーブルからレコード(行)を削除するためのSQL命令です。

基本構文: DELETE FROM テーブル名 WHERE 条件;

ここで、UPDATE文と同様に絶対に忘れてはならないのがWHEREです。もしWHERE句を付けずにDELETE FROM reviews;のようなSQLを実行してしまうと、テーブル内の全レコードが削除されてしまいます。

そのため、削除対象をidなどで一意に特定するWHERE句は、削除処理の生命線と言えます。


2. なぜ危険?リンクだけで削除する実装の問題点

初心者の方がやりがちな実装として、一覧ページに<a href="delete.php?id=5">削除</a>のようなリンクを置き、delete.php$_GETでIDを受け取って即座にDELETE文を実行してしまう、というものがあります。

この方法は、以下の理由から極めて危険です。

  • 誤クリック: ユーザーが誤って削除リンクをクリックしただけで、データが即座に消えてしまいます。
  • クローラによる誤作動: Googleなどの検索エンジンが見つけたリンクを辿ることで、意図せずデータが削除されてしまう可能性があります。
  • 悪意のある攻撃(CSRF): 攻撃者が、ログイン中の管理者に悪意のあるリンク(例: <img src="yoursite.com/delete.php?id=10">)を踏ませることで、管理者が意図しないままデータを削除させることができてしまいます。

鉄則:データの状態を変更する操作(特に削除)は、GETリクエスト(リンクをクリックするだけ)で実行してはいけません。


3. 安全な削除プロセスの実装フロー

安全な削除処理は、ユーザーに「本当に削除しますか?」と意思確認を求めるステップを挟むのが基本です。

安全なフロー: [一覧ページ][削除確認ページ (GET)][削除実行スクリプト (POST)]

Step 1: 一覧ページに「削除確認」へのリンクを設置

まず、一覧表示の各行に、削除確認ページへのリンクを設置します。

list.phpforeachループ内:

<td>
    <a href="delete_confirm.php?id=<?php echo htmlspecialchars($review['id'], ENT_QUOTES, 'UTF-8'); ?>">
        削除
    </a>
</td>

Step 2: 削除確認ページを作成する

delete_confirm.phpでは、削除対象の情報を表示し、本当に削除してよいかユーザーに確認を求めます。

delete_confirm.phpのサンプルコード:

<?php
// (try...catchやIDのバリデーション、DB接続処理は省略)
// $id を元に、削除対象のレビュー情報を$reviewとして取得済みと仮定

if (!$review) {
    // レビューが見つからない場合の処理
    exit('指定されたレビューは見つかりませんでした。');
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>レビュー削除確認</title>
</head>
<body>
    <h1>レビュー削除確認</h1>
    <p>以下のレビューを本当に削除しますか?</p>
    <dl>
        <dt>書籍名:</dt>
        <dd><?php echo htmlspecialchars($review['book_title'], ENT_QUOTES, 'UTF-8'); ?></dd>
    </dl>
    
    <form action="delete_process.php" method="post">
        <input type="hidden" name="id" value="<?php echo htmlspecialchars($review['id'], ENT_QUOTES, 'UTF-8'); ?>">
        <button type="submit">はい、削除します</button>
    </form>
    <br>
    <a href="list.php">いいえ、一覧に戻ります</a>
</body>
</html>

ポイント:

  • 削除の意思決定は、POSTメソッドのフォームで行います。
  • どのIDを削除するかを次のスクリプトに伝えるため、type="hidden"idをフォームに含めます。

Step 3: 削除を実行するスクリプトを作成する

最後に、確認フォームからPOST送信されたデータを受け取り、実際にDELETE文を実行するスクリプトを作成します。

delete_process.phpのサンプルコード:

<?php
// POSTリクエスト以外は処理を中断
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    exit('不正なリクエストです。');
}

// (データベース接続設定 $dsn, $user, $password は定義済みと仮定)

try {
    // hiddenで送られたidをバリデーションして受け取る
    if (empty($_POST['id']) || !ctype_digit($_POST['id'])) {
        throw new Exception('IDが不正です。');
    }
    $id = (int)$_POST['id'];

    // データベースに接続
    $pdo = new PDO($dsn, $user, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    // DELETE文を準備・実行
    $sql = "DELETE FROM reviews WHERE id = ?";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$id]);

    echo "ID: " . htmlspecialchars($id, ENT_QUOTES, 'UTF-8') . " のレビューを削除しました。";

} catch (Exception $e) {
    echo "エラー発生: " . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
} finally {
    $pdo = null;
}
?>
<br>
<a href="list.php">レビュー一覧に戻る</a>

ポイント:

  • スクリプトの冒頭でPOSTリクエストかどうかをチェックし、不正なアクセスを防ぎます。
  • $_POSTから受け取ったidを使い、安全なプリペアドステートメントでDELETEを実行します。

まとめ

  • DELETE文ではWHERE句が絶対に必要。
  • データの削除のような重要な操作は、リンク(GET)だけで実行してはならない。
  • **「確認ページ(GET)→フォーム送信(POST)→削除実行」**というフローを徹底することで、誤操作や攻撃のリスクを大幅に減らすことができる。

安全な削除処理の実装は、信頼性の高いWebアプリケーションを構築するための必須スキルです。この多段階のプロセスを必ず守るようにしましょう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次