PHPからDBを操作する
こちらの教材では、PHPで作成したプログラムを使ってDBとの通信やデータの操作を行っていきます。
※PHPの教材・課題とSQLの教材・課題がまだ終わっていない方は、それらから先に学習しましょう
PHPからDBを操作するために、事前準備に取り掛かりましょう!
SQLの教材の復習を兼ねて一緒に作成していきましょう!
事前準備①
以下の手順でphpMyAdminで学習用のデータベースを作成していきましょう!
今回はsample
という名前のDB(データベース)を作りましょう。
sampleと入力し、作成
をクリック
左側のメニューバーに先程作成したsample
が追加されましたね!
これでデータベースの作成は完了です。
★検索ワード
・phpMyAdmin DB作成
事前準備②
「事前準備①」で作成したsampleというデータベースの中にテーブル(表)
を作りましょう!
1.テーブル名を入力
test01
という名前のテーブルを作りましょう。
名前の入力欄にtest01
を入力、カラムは4
で設定し、実行
を押してください。
2.カラムを入力
ここではテーブルの項目の名前やデータ型、長さ等を入力します。
データ型についてはこちらを参考
https://blog.proglus.jp/695/
データ型がINT
の長さは設定が必須ではないので今回は入力しません。
以下のように記入できたら右下の保存する
を押して保存しましょう。
このようにsampleの中にtest01というテーブルができていれば、成功です。
事前準備③
続いて、データを登録していきます。
今回は下記のようなデータをtest01に登録したいと思います。
id | name | gender | code |
---|---|---|---|
1 | タロウ | 男性 | 1 |
2 | ハナコ | 女性 | 1 |
3 | イチロウ | 男性 | 2 |
4 | キョウコ | 女性 | 2 |
5 | タケシ | 男性 | 3 |
以下の手順でphpMyAdminから登録できます。
1.データを登録したいテーブルをクリック
3.値を入力
まずは先程の表にあった、タロウのデータを作成します。
値
に表を参考にデータを入れます。
idに1
、nameにタロウ
、genderに男性
、codeに001
をそれぞれ入力してください。
入力ができたら実行をクリック
下記の画像のような画面が表示されればOKです!
それではメニュータブから、表示をクリックしデータを確認しましょう。
4.データの確認
データがうまく登録できているか確認しましょう!
下記の画像のようになっていればOKです!
ここまで出来たら、先ほどと同じ要領で残りのデータを登録しましょう!
id | name | gender | code |
---|---|---|---|
1 | タロウ | 男性 | 1 |
2 | ハナコ | 女性 | 1 |
3 | イチロウ | 男性 | 2 |
4 | キョウコ | 女性 | 2 |
5 | タケシ | 男性 | 3 |
画像のように登録できたら、次へ進みましょう。
★検索ワード
・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
を下記の通り編集してください。
<?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/ にアクセスしましょう!
画像のように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
を下記の通り編集してください。
<?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です!
これで、sampleデータベースのtest01テーブルのデータがすべて取得できました!
複数のファイルで処理を行う
フォルダ名:「commons」
先程までは、一つのファイルの中にDBへの接続処理とSQL文の実行処理を書いていましたが、
一つのファイル内に複数の処理を書いてしまうと、ファイルの行数が多くなってしまい、メンテナンスがしづらくなってしまいます。
そこで、DBと接続する処理とSQL文を実行する処理を、それぞれ別のファイルに記述してきましょう!
まずdbフォルダ内に、commons
フォルダを作成し、dbconnect.php
を作成しましょう。
dbconnect.phpにDBと接続する処理を書いていきます。
dbconnect.phpにDBと接続する処理を書いておけば、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;
}
}
?>
そしてindex.php(DBの値を使いたいファイル)に
・dbconnect.phpファイルを読み込む処理
・dbconnect.php内にある、dbconnection()関数を実行する処理
を書いていきます。
<?php
require_once( "./commons/dbconnect.php" );
//require_once関数で外部ファイルを読み込みます。
dbconnection();
//関数を実行
?>
上記のように記述することで、dbconnect.phpに記述した、dbconnection()関数を実行することが出来ます。
では実際にデータを取得しましょう。
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です!
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です!
タロウさんの情報のみが取得できていますね。
ぜひ、変数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です!
$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です!
このように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です!
このように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です!
送信フォームが完成したので、受け取る処理を作成しましょう。
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.html
とrecieve.php
、commons
フォルダがあり、commons
フォルダ配下にdbconnect.php
が配置されている構造になっています。
実際に動かして確認してみましょう!
http://localhost:8888/search/ または、http://localhost/search/ にアクセスしましょう!
アクセスし、今回はidが2のレコードを検索してみましょう!
画像のようにinput要素に2
を入力して検索ボタンをクリックしてください。
画像のように、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です!
今回学んだハッシュ化と、次に学ぶ暗号化をうまく使って、ユーザーのデータが不正利用されないようにしてあげましょう!
データの暗号化
フォルダ名:「encrypted」
暗号化
とは
元のデータに対して処理を行い、別データに変換する処理のことです。
それに対して暗号化されたデータを元のデータに戻す処理のことを復号化
と言います。
暗号化や復号化の処理にはアルゴリズムに応じた鍵
が必要になります。
同じ暗号アルゴリズムを採用しても、鍵
が違っていると、処理の結果が変わります。
暗号アルゴリズムについて簡単に説明すると、どのような方法で暗号化を行うかということです。
今回の暗号化にはopensslを使います。
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です!
復号化
復号化
とは、暗号化されているデータをもとの形に戻すことです。
先程も少し触れましたが、暗号化は復号化(もとに戻す)ことが出来ます!
もとに戻すには、暗号化した際に使用したパスワードを使用するので、それを知っている必要があります。
では早速、先程暗号化したデータを復号化してみましょう!
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です!
ハッシュ化と暗号化の違い
ハッシュ化と暗号化の使い方について学んだところで、ハッシュ化と暗号化はどのような違いがあるのかについて学んでいきましょう!
ハッシュ化は一度変換してしまうと元に戻せませんが、暗号化は鍵
があれば元に戻すことが出来ます。
以下のようなイメージで使い分けます。
・メールアドレスは 個人情報であるが、サイトから案内メールを送信する際に必要となるので暗号化
する
・パスワードは ユーザーのみが知っていればよいのでハッシュ化
する
というように使い分けます。
メールアドレスは暗号化、パスワードはハッシュ化というように覚えてしまって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文を実行することになります。
画像のようにフォームに2 or true
が入力できたら、検索ボタンをクリックしましょう!
画像のように、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を見てみましょう。
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