Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 1 year has passed since last update.

PHP+SQL教材

Last updated at Posted at 2022-03-20

PHPからDBを操作する

こちらの教材では、PHPで作成したプログラムを使ってDBとの通信やデータの操作を行っていきます。
※PHPの教材・課題とSQLの教材・課題がまだ終わっていない方は、それらから先に学習しましょう

PHPからDBを操作するために、事前準備に取り掛かりましょう!
SQLの教材の復習を兼ねて一緒に作成していきましょう!

事前準備①

以下の手順でphpMyAdminで学習用のデータベースを作成していきましょう!

1.メニュータブのデータベースをクリック
PHP_SQL_1.png

2.データベース名を入力
PHP_SQL_2.png

今回はsampleという名前のDB(データベース)を作りましょう。

sampleと入力し、作成をクリック

PHP_SQL_3.png

左側のメニューバーに先程作成したsampleが追加されましたね!
これでデータベースの作成は完了です。

★検索ワード
・phpMyAdmin DB作成

事前準備②

「事前準備①」で作成したsampleというデータベースの中にテーブル(表)を作りましょう!

1.テーブル名を入力
test01という名前のテーブルを作りましょう。
PHP_SQL_4.png

名前の入力欄にtest01を入力、カラムはで設定し、実行を押してください。

2.カラムを入力

ここではテーブルの項目の名前やデータ型、長さ等を入力します。
データ型についてはこちらを参考
https://blog.proglus.jp/695/

データ型がINTの長さは設定が必須ではないので今回は入力しません。
以下のように記入できたら右下の保存するを押して保存しましょう。
PHP_SQL_5.png

このようにsampleの中にtest01というテーブルができていれば、成功です。
PHP_SQL_6.png

事前準備③

続いて、データを登録していきます。
今回は下記のようなデータをtest01に登録したいと思います。

id name gender code
1 タロウ 男性 1
2 ハナコ 女性 1
3 イチロウ 男性 2
4 キョウコ 女性 2
5 タケシ 男性 3

以下の手順でphpMyAdminから登録できます。
1.データを登録したいテーブルをクリック
PHP_SQL_7.png

2.挿入をクリック
PHP_SQL_8.png

3.値を入力
まずは先程の表にあった、タロウのデータを作成します。
に表を参考にデータを入れます。
idに1、nameにタロウ、genderに男性、codeに001をそれぞれ入力してください。
PHP_SQL_9.png

入力ができたら実行をクリック
下記の画像のような画面が表示されればOKです!
PHP_SQL_10.png

それではメニュータブから、表示をクリックしデータを確認しましょう。

4.データの確認
データがうまく登録できているか確認しましょう!
下記の画像のようになっていればOKです!
PHP_SQL_11.png

ここまで出来たら、先ほどと同じ要領で残りのデータを登録しましょう!

id name gender code
1 タロウ 男性 1
2 ハナコ 女性 1
3 イチロウ 男性 2
4 キョウコ 女性 2
5 タケシ 男性 3

PHP_SQL_12.png

画像のように登録できたら、次へ進みましょう。

★検索ワード
・phpMyAdmin テーブル作成
・DB カラムとは

DBに接続する

フォルダ名:「db」

こちらの教材では、PHPのPDOクラスを使ってDBに接続していきます。
PDO(PHP Data Object)とは、PHP標準(5.1.0以降)のDB接続クラスのことです。
PHPは標準でMySQLやPostgreSQLやSQLiteなど、色々なDBに接続するための命令が用意されています。DBの種類によって条件分岐させて命令を呼び出せば、どのDBを利用する場合でも同じ関数を使うことができます。

htdocs内にdbというディレクトリを作成し、その配下にindex.phpを作成しましょう!
作成できたら、index.phpを下記の通り編集してください。

index.php
<?php

    try {
    // データベースに接続
    $pdo = new PDO(
        'mysql:dbname=sample;host=localhost;charset=utf8mb4',//dbname=で参照先のDB名を切り替えられます。
        'root',//初期設定ではユーザー名は「root」です。
        'root',//初期設定ではパスワードは「root」もしくは「''(空文字)」です。「'root'」でうまくいかない場合は「''」で試してみて下さい。
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]
    );
    echo "DB接続に成功しました。";

    } catch (PDOException $e) {
    //エラー発生時の処理
    echo $e->getMessage();
    exit;
    }
?>

コードが書けたら

http://localhost:8888/db/ または、http://localhost/db/ にアクセスしましょう!

PHP_SQL_13.png

画像のようにDB接続に成功しました。
が出力されたら、DB接続成功です!

もし、うまく接続できない場合は以下のポイントをもう一度確認しましょう!
・ユーザー名は正しいか
・パスワードは正しいか
・db_nameは正しいか
・アクセスしているURLは正しいか
・コードの内容に文法的な誤りがないか

データの取得

フォルダ名:「db」

DBとの接続ができたところで事前準備で用意した、DBからデータの取得をしてみましょう!

書き方の基本は以下のとおりです!


$stmt = $pdo->prepare(SQL文);
$stmt->execute();
$stmt->fetchAll(PDO::FETCH_ASSOC);

prepareは準備、executeは実行、fetchは読み込む動作です。

流れとしては
インスタンス化した$pdoクラスのprepare関数の引数にSQL文を渡し、execute関数を実行して準備したSQL文を送信。
fetchAllで結果を読み込んでいます。

SQL文は文字列として変数に格納してから使うのが良いでしょう。

基本的な書き方について学んだところで、早速実際にデータを取得してみましょう!
index.phpを下記の通り編集してください。

index.php
<?php

    try {
    // データベースに接続
    $pdo = new PDO(
        'mysql:dbname=sample;host=localhost;charset=utf8mb4',//dbname=で参照先のDB名を切り替えられます。
        'root',//初期設定ではユーザー名は「root」です。
        'root',//初期設定ではパスワードは「root」もしくは「''(空文字)」です。「'root'」でうまくいかない場合は「''」で試してみて下さい。
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]
    );
    // SQL実行

    $sql = "SELECT * FROM sample.test01";
    // SQL文を変数に代入

    $stmt = $pdo->prepare($sql);
    // SQL文が入った変数をprepare関数の引数に

    $stmt->execute();
    // SQL文を実行

    $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
    // 実行結果を読み込み変数dataに代入

    //結果の出力
    var_dump($data);

    } catch (PDOException $e) {
    //エラー発生時の処理
    echo $e->getMessage();
    exit;
    }
?>

ここまで書けたら、http://localhost:8888/db/ または、http://localhost/db/ にアクセスしましょう!
アクセスし、以下の画像のように表示されていればOKです!

PHP_SQL_14.png

これで、sampleデータベースのtest01テーブルのデータがすべて取得できました!

複数のファイルで処理を行う

フォルダ名:「commons」

先程までは、一つのファイルの中にDBへの接続処理とSQL文の実行処理を書いていましたが、
一つのファイル内に複数の処理を書いてしまうと、ファイルの行数が多くなってしまい、メンテナンスがしづらくなってしまいます。
そこで、DBと接続する処理とSQL文を実行する処理を、それぞれ別のファイルに記述してきましょう!

まずdbフォルダ内に、commonsフォルダを作成し、dbconnect.phpを作成しましょう。

dbconnect.phpにDBと接続する処理を書いていきます。
dbconnect.phpにDBと接続する処理を書いておけば、DB接続を行いたいタイミングでその関数を呼び出すことで使用することが可能になります。

dbconnect.phpを下記の通り編集してください。

dbconnect.php

<?php
  function dbconnection() {
    global $pdo, $e;
    try {
      // データベースに接続
      $pdo = new PDO(
        'mysql:dbname=sample;host=localhost;charset=utf8mb4',//dbname=で参照DB名を切り替えられます。
        'root',//初期設定ではユーザー名は「root」になっています。
        'root',//初期設定ではパスワードは「root」もしくは「''(空文字)」になっています。「'root'」でうまくいかない場合は「''」で試してみて下さい。
        [
          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
          PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]
    );
    } catch (PDOException $e) {
      //エラー発生時
      echo $e->getMessage();
      exit;
    }
  }
?>

そしてindex.php(DBの値を使いたいファイル)に
・dbconnect.phpファイルを読み込む処理
・dbconnect.php内にある、dbconnection()関数を実行する処理
を書いていきます。

index.php

<?php
  require_once( "./commons/dbconnect.php" );
  //require_once関数で外部ファイルを読み込みます。
  dbconnection();
 //関数を実行
?>

上記のように記述することで、dbconnect.phpに記述した、dbconnection()関数を実行することが出来ます。

では実際にデータを取得しましょう。

index.phpを下記の通り編集してください。

index.php

<?php
  //DB接続処理
  require_once( "./commons/dbconnect.php" );
  dbconnection();

  // SQL実行
  $sql = "SELECT * FROM sample.test01";
  $stmt = $pdo->prepare($sql);
  $stmt->execute();
  $data = $stmt->fetchAll(PDO::FETCH_ASSOC);

  //結果の出力
  var_dump($data);
?>

ここまで書けたら、http://localhost:8888/db/ または、http://localhost/db/ にアクセスしましょう!
アクセスし、以下の画像のように表示されていればOKです!
PHP_SQL_15.png

DB接続の処理を別ファイルに書くことで、コードがスッキリしましたね。

取得したデータから任意の値を表示する

フォルダ名:「db」

DBからデータを取得して表示をする際に、単純に全てのデータを上から順番に表示するだけですべてのWebサービスが成り立っているというわけではありません。
ときには、自分が使いたいデータのみを表示させたい場合があります。
そこで今回はDBから取得したデータの中から使いたい情報のみを、表示させる方法について説明してきます。

index.phpを下記の通り編集してください。

<?php
  //DB接続処理
  require_once( "./commons/dbconnect.php" );
  dbconnection();

  $sql = "SELECT * FROM sample.test01";
  $stmt = $pdo->prepare($sql);
  $stmt->execute();
  $data = $stmt->fetchAll(PDO::FETCH_ASSOC);

  var_dump($data[0]);
?>

こうすることで
idが1、nameがタロウ、genserが男性、codeが1の
ひとつのレコードのデータ情報のみを表示することが出来ます!
ポイントは変数detaの後ろに[0]がついているところです。
配列と同じように扱うことが出来ます。

ブラウザで確認してみましょう!
http://localhost:8888/db/ または、http://localhost/db/ にアクセスしましょう!
アクセスし、以下の画像のように表示されていればOKです!

PHP_SQL_16.png

タロウさんの情報のみが取得できていますね。
ぜひ、変数detaの後ろについている[0]の値を1や2に変更してみると、どうなるか確認してみてください!

カラム名を指定する

先程のコードではレコードごとにタロウさんのデータを表示してみました。
今回は、カラムを指定して任意のデータを表示させてみましょう!

index.phpを下記の通り編集してください。

<?php
  //DB接続処理
  require_once( "./commons/dbconnect.php" );
  dbconnection();

  $sql = "SELECT * FROM sample.test01";
  $stmt = $pdo->prepare($sql);
  $stmt->execute();
  $data = $stmt->fetchAll(PDO::FETCH_ASSOC);

  var_dump($data[0]['name']);
?>

ファイルの編集が出来たら、ブラウザで確認してみましょう!
http://localhost:8888/db/ または、http://localhost/db/ にアクセスしましょう!
アクセスし、以下の画像のように表示されていればOKです!

PHP_SQL_17.png

$data[0]['name']とすることで、タロウという文字列のみ表示することが出来ました!
これは、test01テーブルにある一番上のレコードのカラム名nameのデータだけを表示したということです。

$data[0]のあとの['name']の値を['id']や['gender']などに変更してみると、どのようにデータが表示されるか確認してみてください!

foreachやwhileを使ったデータの取得

フォルダ名:「db」

一つ前のレクチャーで、DBから取得したデータから任意の値を表示する方法について学習していただきましたが、そこで「DBから取得したデータは配列のように扱うことができる」という説明をしました。
そこで、今回は配列から要素を取得する際によく使われているforeachと、繰り返し処理に使われるwhileを使用し、DBから取得したデータを一つずつ表示させてみましょう!

index.phpを下記の通り編集してください。

<?php
  //DB接続処理
  require_once( "./commons/dbconnect.php" );
  dbconnection();

  $data = $pdo->query("SELECT * FROM test01");
  foreach ($data as $row) {
    $id = $row['id'];
    $name = $row['name'];
    $gender = $row['gender'];
    $code = $row['code'];
    echo 'idは' . $id . 'です ';
    echo 'nameは' . $name. 'です ';
    echo 'genderは' . $gender. 'です ';
    echo 'codeは' . $code. 'です' . '<br>';
  }
?>

ファイルの編集が出来たら、ブラウザで確認してみましょう!
http://localhost:8888/db/ または、http://localhost/db/ にアクセスしましょう!
アクセスし、以下の画像のように表示されていればOKです!

PHP_SQL_18.png

このようにforeachを使用することで、DBから取得したデータすべてを順番に表示することが出来ます!

whileを使用する

foreachで表示させる方法がわかったところで、続いてwhileを使用していきます。

index.phpを下記の通り編集してください。

<?php
  //DB接続処理
  require_once( "./commons/dbconnect.php" );
  dbconnection();

  $data = $pdo->query("SELECT * FROM test01");
  while ($row = $data->fetch()) {
    $id = $row['id'];
    $name = $row['name'];
    $gender = $row['gender'];
    $code = $row['code'];
    echo 'idは' . $id . 'です ';
    echo 'nameは' . $name. 'です ';
    echo 'genderは' . $gender. 'です ';
    echo 'codeは' . $code. 'です' . '<br>';
  }
?>

ファイルの編集が出来たら、ブラウザで確認してみましょう!
http://localhost:8888/db/ または、http://localhost/db/ にアクセスしましょう!
アクセスし、以下の画像のように表示されていればOKです!

PHP_SQL_19.png

このようにwhileとforeachを使用し、まとめて表示することも可能です!
また、今回はprepare()やexecute()を使用せず、query()を使用しました。
query()とprepare()やexecute()の書き方の違いにも注意しましょう!

FORMからデータ検索

フォルダ名:「search」

今回はHTMLのform送信でPHPで値を受け取り、受け取った値を使ってDBからデータを取得してみましょう。

以下の流れを機能を実装する予定です。
①HTMLでidをPOSTで送信
②PHPでidを受け取る
③DB(sample)のtest01テーブルから、受け取ったidをもつレコードを取得。
④取得したものを画面に出力する。

まずはindex.htmlを作成し、下記の通り編集してください。

<!DOCTYPE html>
<html>
  <head>
    <title>DB</title>
    <meta charset="UTF-8">
  </head>
  <body>
    <form action="./receive.php" method="POST">
      <h1>ID検索</h1>
      id:<input type="text" name="id">
      <input type="submit" value="検索">
    </form>
  </body>
</html>

ファイルの編集が出来たら、ブラウザで確認してみましょう!
http://localhost:8888/search/ または、http://localhost/search/ にアクセスしましょう!
アクセスし、以下の画像のように表示されていればOKです!
PHP_SQL_20.png

送信フォームが完成したので、受け取る処理を作成しましょう。

searchフォルダ内に、commonsフォルダを作成し、dbconnect.phpを作成しましょう。

前回同様に、dbconnect.phpにDBと接続する処理を書いていきます。

dbconnect.phpを下記の通り編集してください。


<?php
  function dbconnection() {
    global $pdo, $e;
    try {
      // データベースに接続
      $pdo = new PDO(
        'mysql:dbname=sample;host=localhost;charset=utf8mb4',//dbname=で参照DB名を切り替えられます。
        'root',//初期設定ではユーザー名は「root」になっています。
        'root',//初期設定ではパスワードは「root」もしくは「''(空文字)」になっています。「'root'」でうまくいかない場合は「''」で試してみて下さい。
        [
          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
          PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]
    );
    } catch (PDOException $e) {
      //エラー発生時
      echo $e->getMessage();
      exit;
    }
  }
?>

これで、DBと接続を行うための準備が完了したので、DBから検索する処理を作成していきましょう!

receive.phpを作成し、下記の通り編集してください。

<?php
  // 受け取る処理
  if (isset($_POST['id'])) {// 受け取ったときのみ実行
    $input_id = $_POST['id'];

    // DB接続
    require_once( "./commons/dbconnect.php" );
    dbconnection();

    // 検索
    $sql = "SELECT * FROM sample.test01 WHERE id = " . $input_id . ";";
    $stmt = $pdo->prepare($sql);
    $stmt->execute();
    $data = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // 表示
    var_dump($data);
  }
?>

これで、フォームから入力されたidを受け取り、DBから検索する処理が作成できました。

ここまで作成したsearchフォルダの構造は以下のようになっています。

search
├── index.html
├── receive.php
└── commons
    └── dbconnect.php

searchフォルダの配下にindex.htmlrecieve.phpcommonsフォルダがあり、commonsフォルダ配下にdbconnect.phpが配置されている構造になっています。

実際に動かして確認してみましょう!
http://localhost:8888/search/ または、http://localhost/search/ にアクセスしましょう!
アクセスし、今回はidが2のレコードを検索してみましょう!
PHP_SQL_21.png

画像のようにinput要素に2を入力して検索ボタンをクリックしてください。

PHP_SQL_22.png

画像のように、idが2のハナコさんのデータが取得できていればOKです。

input要素に他のidを入れてみて他のデータが取得できるか確認してみてください。

データのハッシュ化

フォルダ名:「hash」

ハッシュ化とは、ハッシュ関数によって文字列を置換して、元の文字を推測できなくすることです。

例えば通販サイトの会員登録をするときにユーザーがフォームにパスワードを入力します。
そしてPHPで受け取ったデータを、DBに保存する際にハッシュ化してから保存します。
ハッシュ化をする理由は2つあります。
・パスワードをサイトの管理者に知られないようにするため。
・DBへの攻撃によるパスワード情報の流出や不正利用を防止するため。

ハッシュ化の必要性がわかったところで、パスワードをハッシュ化する方法を学んでいきましょう!

パスワードをハッシュ化するために、password_hash関数を使います。
使い方は以下のとおりです。

password_hash(ハッシュ化したいデータ , アルゴリズムの指定 , オプションの指定(任意))

使い方がわかったところで、文字列をハッシュ化すると、どのような形になるのか確認してみましょう!
index.phpを作成し、以下のように編集しましょう!

<?php
  var_dump(password_hash("abcdefghijklmnopqqrstu", PASSWORD_BCRYPT));
?>

ファイルの編集が出来たら、ブラウザで確認してみましょう!
http://localhost:8888/hash/
または
http://localhost/hash/
にアクセスしましょう!
アクセスし、以下の画像のようにもとの文字列とは違った形に、変換されていればOKです!
PHP_SQL_23.png

今回学んだハッシュ化と、次に学ぶ暗号化をうまく使って、ユーザーのデータが不正利用されないようにしてあげましょう!

データの暗号化

フォルダ名:「encrypted」

暗号化とは
元のデータに対して処理を行い、別データに変換する処理のことです。
それに対して暗号化されたデータを元のデータに戻す処理のことを復号化と言います。

暗号化や復号化の処理にはアルゴリズムに応じたが必要になります。
同じ暗号アルゴリズムを採用しても、が違っていると、処理の結果が変わります。

暗号アルゴリズムについて簡単に説明すると、どのような方法で暗号化を行うかということです。

今回の暗号化にはopensslを使います。

index.phpを作成し、以下のように編集しましょう!

index.php
<?php
  // 暗号化するデータ
  $str = "test@test.com";

  // 暗号化パスワード
  $password = 'abcdefg';

  // 暗号化方式
  $method = 'aes-256-cbc';

  // 方式に応じたIVに必要な長さを取得 ランダムな文字列
  $ivLength = openssl_cipher_iv_length($method);

  // IV を自動で生成
  $iv = openssl_random_pseudo_bytes($ivLength);

  // OPENSSL_RAW_DATA と OPENSSL_ZERO_PADDING を指定可
  $options = 0;

  // 暗号化
  $encrypted = openssl_encrypt($str, $method, $password, $options, $iv);
  echo "<br>";
  echo $encrypted;
?>

ファイルの編集が出来たら、ブラウザで確認してみましょう!
http://localhost:8888/encrypted/
または
http://localhost/encrypted/
にアクセスしましょう!
アクセスし、以下の画像のようにもとの文字列とは違った形に、変換されていればOKです!
PHP_SQL_24.png

復号化

復号化とは、暗号化されているデータをもとの形に戻すことです。
先程も少し触れましたが、暗号化は復号化(もとに戻す)ことが出来ます!
もとに戻すには、暗号化した際に使用したパスワードを使用するので、それを知っている必要があります。

では早速、先程暗号化したデータを復号化してみましょう!

index.phpを以下のように編集してください。

index.php
<?php
  // 暗号化するデータ
  $mail = "test@example.com";

  // 暗号化パスワード
  $password = 'secpass';

  // 暗号化方式
  $method = 'aes-256-cbc';

  // 方式に応じたIVに必要な長さを取得 ランダムな文字列
  $ivLength = openssl_cipher_iv_length($method);

  // IV を自動で生成
  $iv = openssl_random_pseudo_bytes($ivLength);

  // OPENSSL_RAW_DATA と OPENSSL_ZERO_PADDING を指定可
  $options = 0;

  // 暗号化
  $encrypted = openssl_encrypt($mail, $method, $password, $options, $iv);
  echo $encrypted;

  // 復号化(ここを追記)
  $decrypted = openssl_decrypt($encrypted, $method, $password, $options, $iv);
  echo "<br>";
  echo $decrypted;
?>

ファイルの編集が出来たら、ブラウザで確認してみましょう!
http://localhost:8888/encrypted/ または、http://localhost/encrypted/ にアクセスしましょう!
アクセスし、以下の画像のように暗号化されたデータと復号化されたデータが表示されていればOKです!
PHP_SQL_25.png

ハッシュ化と暗号化の違い

ハッシュ化と暗号化の使い方について学んだところで、ハッシュ化と暗号化はどのような違いがあるのかについて学んでいきましょう!

ハッシュ化は一度変換してしまうと元に戻せませんが、暗号化はがあれば元に戻すことが出来ます。

以下のようなイメージで使い分けます。

・メールアドレスは 個人情報であるが、サイトから案内メールを送信する際に必要となるので暗号化する
・パスワードは ユーザーのみが知っていればよいのでハッシュ化する
というように使い分けます。

メールアドレスは暗号化、パスワードはハッシュ化というように覚えてしまってOKです!

暗号化参考サイト
https://qiita.com/asksaito/items/1793b8d8b3069b0b8d68

SQLインジェクション

フォルダ名:「search」
今回は、FORMからデータ検索で作成したソースコードをもとに説明していきます。

SQLインジェクションとは「不正なSQLの命令を、攻撃対象のウェブサイトに注入する(インジェクションする)」ことです。
つまりハッキング(厳密に言うとクラッキング)の一種です。
過去多くの企業がSQLインジェクションによる攻撃を受け、莫大な被害を被っています。
webサービスを作る上でSQLインジェクションへの対策は必須なので、学んでいきましょう。

原理としては簡単です。
以下のコードを見てください。

receive.phpを下記の通り編集してください。

// 検索
$sql = "SELECT * FROM sample.test01 WHERE id = " . $input_id . ";";

こちらはフォームで入力されたidをSQL文に入れて、DBからidを指定してデータの検索を行う処理です。

例えば$input_id の中身が2であったときには

SELECT * FROM sample.test01 WHERE id = 2;

というSQL文を実行することになります。

2のところは、ユーザーがフォームで入力したものが入るので2 OR trueというようにフォームに入力し検索すると

その場合には

SELECT * FROM sample.test01 WHERE id = 2 OR true;

というSQL文を実行することになります。

こちらを実行してみましょう。
PHP_SQL_26.png

画像のようにフォームに2 or trueが入力できたら、検索ボタンをクリックしましょう!

そうすると
PHP_SQL_27.png

画像のように、DBにあるすべてのデータが取得できてしまします。

こちらを実行したとしても、sampleの中に登録されているデータはレコード5つ程度なので、被害は全くありませんが、もっと規模の大きいwebサービスでは何千万ものレコードを持つサービスもあります。
そのサービスで上記のようなSQLインジェクションを引き起こさせると、サーバーが停止してしまったり、莫大な損害を与えてしまします。

さらに、被害が大きくなるようなSQLインジェクションも存在します。

データを全件検索するだけでなく、テーブルを削除することも、データを改竄することもできます。

では実際に実行してみましょう。
(他のサイトで試すと犯罪になります。必ず学習環境でのみ実行してください。)

以下のSQLを実行したいので

SELECT * FROM sample.test01 WHERE id = 2; DROP TABLE sample.test01;

入力欄には
2; DROP TABLE sample.test01

と入力すればOKですね。

そして検索を押すと、
SELECTの後にDROP処理が実行されます。
phpMyAdminを見てみましょう。

PHP_SQL_28.png

test01テーブルが削除されてしまっていることが確認できると思います。

これがもし、実際のサービスのデータだったら非常に恐ろしいですよね。
次からはこの対策をやっていきます。

ちなみに消してしまったtest01テーブルとそのデータは以下SQLで作り直しておきましょう。

CREATE TABLE sample.test01 (
  id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(255) NOT NULL,
  gender VARCHAR(255) NULL,
  code INT NOT NULL
);
INSERT INTO 
  sample.test01
  (id, name, gender, code)
  VALUES 
  (1, 'タロウ', '男性', 1),
  (2, 'ハナコ', '女性', 1),
  (3, 'イチロウ', '男性', 2),
  (4, 'キョウコ', '女性', 2),
  (5, 'タケシ', '男性', 3);

SQLインジェクションの対策

フォルダ名:「search」
今回も、FORMからデータ検索で作成したソースコードをもとに説明していきます。

SQLインジェクションの恐ろしさについて学んだところで、今回はその対策について学んでいきましょう!
SQLインジェクションは対策を行うことができるので、しっかりと学んでいきましょう!

対策としては
SQL文の組み立てをプレースホルダで実装する。
というものがあります。

プレースホルダーとは
変数のように値が変動する箇所データベースへ登録する処理の間に挟むことで変動する箇所をとして処理するしくみです。入力フォームに万が一不正な値(SQL文)が入力されても、SQL命令に関わるような特殊文字は無効化されるため、SQL文として実行されることはありません。

プレースホルダを使うための手順は2つです。
①SQL文の変動箇所をプレースホルダ(:で始まる代替文字列)で指定する。
②bindValueで実際の値をプレースホルダにバインドする。

②にはbindValueというメソッドを使います。
使用方法は以下のとおりです。

bindValue('プレースホルダ名', '実際にバインドするデータ', 'データの型');

第3引数の型の指定は、あらかじめ用意されている設定値から選択します。
よく使うのは以下のような型です。

文字列型の場合:PARAM_STR
数値型の場合:PARAM_INT
ラージオブジェクト(画像データなど)の場合:PARAM_LOB
NULLの場合:PARAM_NULL

では実際に、プレースホルダを使ったSQL文の組み立てを実装していきます。

receive.phpを以下のように編集しましょう。

$sql = "SELECT * FROM sample.test01 WHERE id = :input_id";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':input_id', $input_id, PDO::PARAM_INT);
$stmt->execute();

今回はidで検索を行っているので、PARAM_INTを使用してバインドを行っています。

実装が完了したら実際にSQLインジェクション対策が行われているかを確認しましょう。

2 OR TRUE

と入力しても全てのデータを取られることはありません。

2; DROP TABLE sample.test01

と入力しても、テーブルは消えません。

PHPでユーザー入力のあるSQL文を書く場合はプレースホルダを必ず実装しましょう。

また、セキュリティ対策については以下のURLが参考になりますので、
目を通しておきましょう。
https://blog.codecamp.jp/php_security

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?