sit in a circle and chat happily

データベース 6日目

投稿日:2022-02-08
更新日:2022-03-24
db

※編集の前に削除をやる

削除ページへのリンクを作成する

トップページから削除ページへのリンクを作成する。index.phpの該当箇所を下記のように変更する。

【変更前】
<td>削除</td>
【変更後】
<td><a href="delete.php?id=<?php echo h($data['id']); ?>"
onclick="return confirm('削除しますか?')">削除</a></td>

リンク先のURL「delete.php」の後ろにクエリ文字列を付加して編集用フォームにid番号を送る。このid番号を使って削除するレコードを決める。

onclick属性にJavaScriptで確認画面表示用のスクリプトを記述している。

商品情報の削除

<?php
$debug = true;
require_once dirname(__FILE__) . '/functions.php';

// クエリ文字列(GET)でID番号を受け取って
// DBから対象のレコードを削除する
$sql = '';
// デバック領域でSQL文を表示するので
// とりあえず空文字の入った変数を用意
if (isset($_GET['id'])) {
  // クエリ文字列(GET)でID番号を受け取っている
  $id = $_GET['id'];
  // 使用しやすい変数名に値を代入
  $dbobj = connectPractice();
  // DB接続関数を呼び出して
  // 接続許可証(オブジェクト)を変数$dbobjに代入
  $sql = sprintf(
    'DELETE FROM stationery WHERE id=%d',
    mysqli_real_escape_string($dbobj, $id)
  );
  // セキュリティを考慮してSQL文を作成
  // ・mysqli_real_escape_string関数
  // ・sprintf関数
//★SQLインジェクション攻撃を防ぐ★

  mysqli_query($dbobj, $sql) or die(mysqli_error($dbobj));
  // SQL文(DELETE文)を実行
  // DBから対象のレコードを削除
  // ※【補足】
  //  削除すると復元が難しくなるため
  //  実際のシステムではあまり削除しない
  //  削除用フィールドを用意して
  //  0(有効扱い)/1(削除扱い)管理することが多い

  // ビューファイルで表示するメッセージを作成
  // 条件:mysqli_affected_rows関数
  //  直前に実行したSQL文で影響を受けたレコード数を返す
  //  今回はDELETE文で削除した件数を返す
  // 削除OK:削除番号をmessage変数へ代入
  // 削除NG:NGメッセージをmessage変数へ代入
  if (mysqli_affected_rows($dbobj)) {
    // 戻り値「1」:削除OK
    // ※idフィールドは主キーなので
    //   該当レコードがあった場合は1件のみ
    $message = 'ID' . h($id) . 'を削除しました。';
  } else {
    // 戻り値「0」:削除NG
    $message = 'ID' . h($id) . 'は存在しません。';
  }
} else {
  $message = '不正な処理です';
}
?>
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <link href="style.css" type="text/css" rel="stylesheet">
  <title>商品管理システム</title>
</head>
<body>
  <?php if ($debug) { ?>
    <div class="debug">
      <p>デバッグ用</p>
      <p>$sql : <?php print $sql; ?></p>
      <pre>$_GET : <?php var_dump($_GET) ?></pre>
    </div>
  <?php } ?>
  <div id="container">
    <div id="head">
      <h1>商品削除</h1>
    </div>
    <div id="content">
      <p><?php echo $message; ?></p>
      <p><a href="index.php">一覧表示に戻る</a></p>
      <!--#content--></div>
      <!--#container--></div>
</body>
</html>

削除するレコードのIDを取得する

index.phpの削除リンクからクエリ文字列で送られてきたid番号をもとにレコードを削除する。まずはisset関数でid番号を取得できているか判定する。

if(isset($_GET['id'])){
  【IDを取得できた時の処理】
}else{
  【IDを取得できなかった時の処理】
}

idを取得できなかった時は、表示用変数$messageに「不正な処理です」と代入する。

$message = '不正な処理です';

データベースからレコードを削除する

idを取得できた場合は、DBからidを指定してレコードを削除する。

 $sql = sprintf('DELETE FROM stationery WHERE id=%d',
                 mysqli_real_escape_string($dbobj, $id));
  // セキュリティを考慮してSQL文を作成
  // ・mysqli_real_escape_string関数
  // ・sprintf関数
//★SQLインジェクション攻撃を防ぐ★

  mysqli_query($dbobj, $sql) or die(mysqli_error($dbobj));
  // SQL文(DELETE文)を実行
  // DBから対象のレコードを削除
  // ※【補足】
  //  削除すると復元が難しくなるため
  //  実際のシステムではあまり削除しない
  //  削除用フィールドを用意して
  //  0(有効扱い)/1(削除扱い)管理することが多い

mysqli_affected_rows()関数で削除した件数を取得する。「1」がかえってkるえば削除成功のメッセージを表示用変数$messageに代入する。
既に削除済み等で「0」が返ってきたときはその旨を伝えるメッセージを表示用変数に代入する。

  // ビューファイルで表示するメッセージを作成
  // 条件:mysqli_affected_row関数
  //  直前に実行したSQL文で影響を受けたレコード数を返す
  //  今回はDELETE文で削除した件数を返す
  // 削除OK:削除番号をmessage変数へ代入
  // 削除NG:NGメッセージをmessage変数へ代入
  if (mysqli_affected_rows($dbobj)) {
    // 戻り値「1」:削除OK
    // ※idフィールドは主キーなので
    //   該当レコードがあった場合は1件のみ
    $message = 'ID' . h($id) . 'を削除しました。';
  } else {
    // 戻り値「0」:削除NG
    $message = 'ID' . h($id) . 'は存在しません。';
  }

実行結果を出力する

表示用変数$messageの内容を出力する。

<p><?php echo $message; ?></p>
// ・mysqli_real_escape_string関数
// ・sprintf関数
//★SQLインジェクション攻撃を防ぐ★

  // $sql = sprintf(
  //   'DELETE FROM stationery WHERE id=%d',
  //   mysqli_real_escape_string($dbobj, $id)
  // );
  // セキュリティを考慮してSQL文を作成
  // ・mysqli_real_escape_string関数
  // ・sprintf関数

  // 1.文字列連結でSQL文作成
  // $sql = 'DELETE FROM stationery WHERE id=' . $id;
  // 5 or item='クレヨン'
  // DELETE FROM stationery WHERE id=5 or item='クレヨン'

  // 2.mysqli_real_escape_string関数と文字列連結
  // $id = mysqli_real_escape_string($dbobj, $id);
  // $sql = 'DELETE FROM stationery WHERE id=' . $id;
  // 5 or item='クレヨン'
  // DELETE FROM stationery WHERE id=5 or item=\'クレヨン\'
  // 文字列開始のクォートがエスケープされたことで
  // 不正なSQL文の実行を阻止できた

  // 5 or id=3
  // DELETE FROM stationery WHERE id=5 or id=3
  // クォートを使わない不正な値の場合は
  // 削除を実行されてしまう

  // 5 or 0=0
  // DELETE FROM stationery WHERE id=5 or 0=0
  // SQLインジェクション攻撃でよく使う文字列
  // 「 or 0=0」に対応しなければいけない
  // この文字列でSQL文を実行されると
  // 今回の場合は全レコードを削除される

  // 3.mysqli_real_escape_string関数と
  //    sprintf関数を組み合わせる
  $sql = sprintf(
    'DELETE FROM stationery WHERE id=%d',
    mysqli_real_escape_string($dbobj, $id)
  );
  // SQLインジェクションの対象になる
  // 条件にはsprintf関数で「%d」を指定する
  // ※「%s」を使うと意味ないので注意

  // 5 or 0=0
  // DELETE FROM stationery WHERE id=5
  // 最初の数値「5」だけ使われて
  // 残りの文字列は「%d」変換指定子によって
  // 削除されている
  // 結果第2条件の悪意ある条件が無視される

カテゴリー