PHP-DB - 15. エミュレート機能

引き続きプリペアドステートメントについて学習します。ここではプリペアドステートメントの内部的な振る舞いについて解説します。

PHPでは、プリペアドステートメント機能を持たないデータベースをサポートするためにエミュレート機能が搭載されています。エミュレート機能を有効にするとデータベースのプリペアドステートメント機能を使わずに、PHP側でプリペアドステートメントを実現できます。

しかし過去にはPHPのエミュレート機能の脆弱性をつく攻撃も報告されています。そのため開発の現場ではエミュレート機能を無効にするケースも多いです。一方で、エミュレート機能を使うことで不要なデータベースアクセスを減らすことができるので処理速度の向上が期待できます。

PDOのエミュレート機能は必要に応じて有効/無効を設定できます。本講座では以降、エミュレート機能を無効にして開発を進めるようにします。

エミュレート機能の有効/無効設定は、SQLiteなどPDOドライバの実装によってはサポートされていないものもあります。MySQLやPostgreSQLなどのPDOドライバではこれらの設定変更は機能しますのでここで解説しておきます。

ここでは次のプログラム( pdo13.php )を作成します。

<?php
try {
    $dsn = "sqlite:eldb.sqlite3";
    $username = null;
    $passwd = null;
    $pdo = new PDO($dsn, $username, $passwd);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    $sql = "select * from categories where title = ?";
    $ps = $pdo->prepare($sql);

    $title = 'Photo';
    $ps->bindValue(1, $title, PDO::PARAM_STR);
    $ps->execute();

    $rows = $ps->fetchAll();
    var_dump($rows);
} catch (PDOException $e) {
    echo $e->getMessage() . PHP_EOL;
}

このプログラムでは PDO クラスの setAttribute メソッドを呼び出すことで、PDOのエミュレート機能を無効にしています。

    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

上記のように PDO::ATTR_EMULATE_PREPARES 属性の値に false を指定することで、PDOのエミュレート機能を無効にできます。

上記の図に示すように PDOのエミュレート機能を無効にすることで PDO クラスの prepare メソッドを呼び出すときに、データベース上でSQLの構文解析が実行されるようになります。

それではコマンドラインからプログラムを実行してみましょう。

$ php pdo13.php
array(1) {
  [0]=>
  array(4) {
    ["id"]=>
    int(4)
    [0]=>
    int(4)
    ["title"]=>
    string(5) "Photo"
    [1]=>
    string(5) "Photo"
  }
}

実行結果からこれまでとおりSQLを実行できている様子を確認できます。

まとめ

  • PHPではプリペアドステートメント機構を持たないデータベースをサポートするためにエミュレート機能を備えている
  • エミュレート機能を有効にするとデータベースを使わずにPHP側でプリペアドステートメントを実現する
  • PHP5.2以降ではエミュレート機能はデフォルトで有効となっているので、必要に応じて無効にできる