↑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) †
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) †
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) †
INSERT とほぼ同様なので、説明は割愛します。
PDO を使用して SQL文を発行 (DELETE) †
INSERT とほぼ同様なので、説明は割愛します。
SQLインジェクション †
冒頭で PHP で MySQL を扱うための方法を幾つか挙げました。
その中の mysql 関数を例として、SQLインジェクションについて説明します。
mysql 関数を使用して INSERT を実行する場合、次のように記述します。
8行目の mysql_query 関数で第一引数の SQL文を実行します。
ここでクエリの一部を変数 (この場合は $name) とした場合、変数の内容によって問題が起こることがあります。
例えば、上記のプログラムで $name を $evil_name と置き換えると次のような SQL文が実行されます。
DELETE FROM members WHERE name = 'xxx' OR '' = ''
このクエリが実行されてしまうと、members テーブル中の全てのレコードが削除されてしまいます。
SQLインジェクションの対策方法は二つあります。
- バインド機構を利用する (SQLの雛形にプレースホルダを埋めておき、後にバインド値を割り当てる方式)
- SQL中の特殊な文字列 (「'」や「/」など) をエスケープする
PDO はバインド機構を利用した例の一つです。
宿題 †
第五週の宿題として作成した、BMIを計算するウェブアプリに次の機能を追加してください。
- 計算したBMIデータをデータベースに記録する機能
- 計算したBMIデータをデータベースから取得(して表示)する機能
機能追加したものは、次のURLで参照できる場所に置いてください("y-mahata"は自分のIDに置き換えてください)。
参考資料 †