PHPでのSQLインジェクション対策 - プレースホルダ編: pg_****

PHPでのSQLインジェクション対策 - プレースホルダ編: pg_****

pg_query_params

PHPはバージョン5.1.0から、pg_query_params関数が使えます。データベース接続時はクライアントの文字エンコーディングを、optionで設定するか、あるいは直後にpg_set_client_encoding関数を使って設定してください。

$dbconn = pg_connect('host=localhost port=5432 dbname=testdb'
. ' user=user password=pass');
$ret = pg_set_client_encoding('utf8');
// または
$dbconn = pg_connect('host=localhost port=5432 dbname=testdb'
. ' user=user password=pass options=\'--client_encoding=utf8\'');

それでは例をみていきましょう。

$res = pg_query_params(
  $dbconn,
  'SELECT userid, username, profile FROM users WHERE username = $1',
  array($_REQUEST['username'])
);
$res = pg_query_params(
  $dbconn,
  'UPDATE users SET profile = $1 WHERE userid = $2',
  array($_REQUEST['profile'], $_SESSION['me']['userid'])
);

まずは、pg_query_params使用した場合です。1つめの引数にデータベース接続リソースを、2つめに「$1」「$2」という表記のプレースホルダを含んだSQLを、3つめにプレースホルダを置き換えるパラメータを配列の形式で指定します。当然ですが、$1、$2…の順番や個数は、パラメータのそれらと合致していなければなりません。

すぐに実行されるのであまり意識されませんが、PostgreSQLのログを参照すると、実際には無名のプリペアドステートメントが使用されているようです。

 

pg_prepare および pg_execute

これらの組み合わせも、PHPはバージョン5.1.0から使えます。pg_query_paramsと同様、最初にクライアントの文字エンコーディングを設定してください。

$res = pg_prepare(
  $dbconn,
  'users_select_by_username',
  'SELECT userid, username, profile FROM users WHERE username = $1'
);
$res = pg_execute(
  $dbconn,
  'users_select_by_username',
  array($_REQUEST['username'])
);
$res = pg_prepare(
  $dbconn,
  'user_prpfile2update_by_userid',
  'UPDATE users SET profile = $1 WHERE userid = $2'
);
$res = pg_execute(
  $dbconn,
  'user_prpfile2update_by_userid',
  array($_REQUEST['profile'], $_SESSION['me']['userid'])
);

pg_prepare関数は、1つめの引数にデータベース接続リソースを、2つめにステートメント名、3つめにプレースホルダを含んだSQLを指定します。pg_execute関数も、1・2つめの引数はpg_prepareと同じです。ただし3つめにはプレースホルダを置き換えるパラメータを配列の形式で指定します。

複数のステートメントを並行して動かしたい場合、準備する時点で名前をつけ、実行するときにはその名前を指定します。ステートメント名に空の文字列('')を設定することで、無名のステートメントを指定したことになりますが、とうぜん後の無名ステートメントに上書きされてしまいます。できるだけprepareの直後にexecuteを発行するか、システムの中でなるべくユニークになるようなステートメント名をつけましょう。