10週間ウェブ開発講座

第七週

PHP から MySQL を操作する方法について扱います。

概要

PHP から MySQL を操作する方法は多数存在します。
代表的なものを次に例示します。

  • PHP の MySQL 関数を使う
  • PHP の MySQL 改良版拡張モジュール (mysqli) を使う
  • PEAR の データベースライブラリ (「PEAR DB」など) を使う
  • PDO を使う

それぞれの方法に、それぞれ固有の特徴が存在します。
本講座では PDO について解説します。

PDO

PDO は 「PHP 5.1」以降のバージョンに標準で含まれている、データベースアクセスのためのライブラリです。
PDO を使うことで、使用しているデータベースの種類を意識せずにプログラムを記述することができます。
この特徴は「移植性の高いプログラム」を書くのに役立ちます。

なお、次からの記述は前週の「members」テーブルと「departments」テーブルが作成されていることを前提としています。

PDO を使用して SQL文を発行 (SELECT)

  1. <?php
  2.  
  3. // SQL を実行する (SELECT : すべての行を取得する)
  4. $db_handle = new PDO('mysql:host=localhost;dbname=y_mahata_db', 'y_mahata', 'password'); // PDOオブジェクトを生成し、$db_handle に代入する
  5. $sample_sql = 'SELECT * FROM members';
  6. $st_handle = $db_handle->prepare($sample_sql); // SQL実行用のオブジェクトを生成し、$st_handle に代入する
  7. $st_handle->execute();
  8.  
  9. // SELECT 文の実行結果を出力する
  10. while ($row = $st_handle->fetch(PDO::FETCH_ASSOC)) {
  11.     echo $row['id'] . ', ' . $row['name'] . "\n";
  12. }
  13.  
  14. ?>

4行目の「$db_handle = new PDO(xxx, yyy, zzz);」という記述で、$db_handle にPDOオブジェクトを代入しています。
「オブジェクト」についての説明は第九週に譲りますが、ここでは「オブジェクトとは特殊な変数である」と考えてください。
xxx にはDSN*1が、yyyにはDBユーザ名が、zzzにはDBパスワードが入ります。

PDOオブジェクトは「prepare」という関数を使用することができます。
「prepare」という関数で、引数に与えられた SQL 文を実行するための文オブジェクト*2を生成します。
6行目の「$st_handle = $db_handle->prepare($sample_sql)」という記述で $sample_sql を実行するための文オブジェクトを生成し、$st_handle に代入します。

7行目で文オブジェクトが SQL 文を実行します。

10行目の while で SELECT 文の結果を出力するループに入ります。
文オブジェクトの fetch 関数で SELECT 文の実行結果から 1行分のデータを取得します。
fetch 関数の引数に PDO::FETCH_ASSOC を指定したとき、データは連想配列の形式で返されます。
その連想配列のキーはカラム名になります (この例では 'id' や 'name')

fetch 関数は、データの取得に失敗したときに false を返します。
したがって、 10行目から始まるループは、 SELECT 文で取得した行数分だけ実行されます。

PDO を使用して SQL文を発行 (INSERT)

  1. <?php
  2.  
  3. // SQL を実行する (INSERT : 'f-mita' を追加する)
  4. $db_handle = new PDO('mysql:host=localhost;dbname=y_mahata_db', 'y_mahata', 'password'); // PDOオブジェクトを生成し、$db_handle に代入する
  5. $sample_sql = 'INSERT INTO members (name, department_id) VALUES (?, ?)';
  6. $st_handle = $db_handle->prepare($sample_sql); // SQL実行用のオブジェクトを生成し、$st_handle に代入する
  7. $st_handle->execute(array('f-mita', 1));
  8.  
  9. ?>

5行目で $sample_sql に SQL 文が代入されています。
この SQL 文には 「?」 が二箇所含まれています。
この「?」のことをプレースホルダと呼びます。

7行目で文オブジェクトの execute 関数を実行します。
先ほどの SELECT の例とは違い、引数に配列を渡していることに注意してください。
execute 関数に与えられた配列は、プレースホルダに与えられます。
つまり、この例では、次の SQL 文と等価なものが実行されます。

INSERT INTO members (name, department_id) VALUES ('f-mita', 1)

プレースホルダは「SQLインジェクション」を回避する効果的な手段です。
SQLインジェクションについては後半で扱います。

PDO を使用して SQL文を発行 (UPDATE)

  1. <?php
  2.  
  3. // SQL を実行する (UPDATE : 'y-mahata' を 'mahata' に変更する)
  4. $db_handle = new PDO('mysql:host=localhost;dbname=y_mahata_db', 'y_mahata', 'password'); // PDOオブジェクトを生成し、$db_handle に代入する
  5. $sample_sql = 'UPDATE members SET name = ? WHERE name = ?';
  6. $st_handle = $db_handle->prepare($sample_sql); // SQL実行用のオブジェクトを生成し、$st_handle に代入する
  7. $st_handle->execute(array('mahata', 'y-mahata'));
  8.  
  9. ?>

INSERT とほぼ同様なので、説明は割愛します。

PDO を使用して SQL文を発行 (DELETE)

  1. <?php
  2.  
  3. // SQL を実行する (DELETE : 'f-mita' を削除する)
  4. $db_handle = new PDO('mysql:host=localhost;dbname=y_mahata_db', 'y_mahata', 'password'); // PDOオブジェクトを生成し、$db_handle に代入する
  5. $sample_sql = 'DELETE FROM members WHERE name = ?';
  6. $st_handle = $db_handle->prepare($sample_sql); // SQL実行用のオブジェクトを生成し、$st_handle に代入する
  7. $st_handle->execute(array('f-mita'));
  8.  
  9. ?>

INSERT とほぼ同様なので、説明は割愛します。

SQLインジェクション

冒頭で PHP で MySQL を扱うための方法を幾つか挙げました。
その中の mysql 関数を例として、SQLインジェクションについて説明します。

mysql 関数を使用して INSERT を実行する場合、次のように記述します。

  1. <?php
  2.  
  3. $db_link = mysql_connect('localhost', 'y_mahata', 'password');
  4. $db_handle = mysql_select_db('y_mahata_db', $db_link);
  5. $name = 'y_mahata';
  6. //$evil_name = "xxx' OR '' = '";
  7. $sample_query = "DELETE FROM members WHERE name = '{$name}'";
  8. mysql_query($sample_query, $db_link);
  9.  
  10. ?>

8行目の mysql_query 関数で第一引数の SQL文を実行します。
ここでクエリの一部を変数 (この場合は $name) とした場合、変数の内容によって問題が起こることがあります。

例えば、上記のプログラムで $name を $evil_name と置き換えると次のような SQL文が実行されます。

DELETE FROM members WHERE name = 'xxx' OR '' = ''

このクエリが実行されてしまうと、members テーブル中の全てのレコードが削除されてしまいます。

SQLインジェクションの対策方法は二つあります。

  1. バインド機構を利用する (SQLの雛形にプレースホルダを埋めておき、後にバインド値を割り当てる方式)
  2. SQL中の特殊な文字列 (「'」や「/」など) をエスケープする

PDO はバインド機構を利用した例の一つです。

宿題

第五週の宿題として作成した、BMIを計算するウェブアプリに次の機能を追加してください。

  • 計算したBMIデータをデータベースに記録する機能
  • 計算したBMIデータをデータベースから取得(して表示)する機能

機能追加したものは、次のURLで参照できる場所に置いてください("y-mahata"は自分のIDに置き換えてください)。

参考資料


*1 DSN は「Data Source Name」の略であり、データベースの接続に必要な情報を書式に沿って記述したもののことです。
*2 PDOStatement クラスのオブジェクトのことを「文オブジェクト」と呼んでいます。

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-05-08 (金) 23:50:49 (485d)