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を発行するか、システムの中でなるべくユニークになるようなステートメント名をつけましょう。