匿名質問者

PHP + PostgreSQLでクエリを実行する際に使用するpg_query_params()メソッドのプレースホルダの仕組みは、動的プレースホルダですか?それとも静的プレースホルダですか?

PHP + PostgreSQLで静的プレースホルダを利用する方法も教えて頂けますと助かります。

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2015/08/19 21:25:06

ベストアンサー

匿名回答1号 No.1

http://php.net/manual/ja/function.pg-query-params.php

pg_query_params() は PostgreSQL 7.4 以降の接続でのみ サポートされます。

http://www.postgresql.org/docs/7.4/interactive/release-7-4.html

New client-to-server protocol
The new protocol adds ..., parameter values separated from SQL commands, prepared statements available at the protocol level, and ....

また、
https://github.com/php/php-src/blob/master/ext/pgsql/pgsql.c#L1992
http://www.postgresql.org/docs/9.4/static/libpq-exec.html

PQexecParams is supported only in protocol 3.0 and later connections; it will fail when using protocol 2.0.

などからpg_query_params()はプロトコルの静的プレースホルダ対応に依存している事が推察出来き、静的プレースホルダしか対応しないと推察出来る。
したがって、7.4以降を使えば静的プレースホルダを利用出来るはず。

他5件のコメントを見る
匿名質問者

http://lets.postgresql.jp/documents/tutorial/with_php/against_sql_injection/placeholder/pg_xxxx

まずは、pg_query_params使用した場合です。1つめの引数にデータベース接続リソースを、2つめに「$1」「$2」という表記のプレースホルダを含んだSQLを、3つめにプレースホルダを置き換えるパラメータを配列の形式で指定します。当然ですが、$1、$2…の順番や個数は、パラメータのそれらと合致していなければなりません。
すぐに実行されるのであまり意識されませんが、PostgreSQLのログを参照すると、実際には無名のプリペアドステートメントが使用されているようです。


たしかに、pg_query_params実行時は無名のプリペアドステートメントが使用されている、と書かれているサイトもありました。だとすると

pg_query_params()は、プリペアドステートメントを構成するものではありませんが


という「安全なウェブサイトの作り方」の記載はなんなのでしょう。。

2015/08/28 21:01:49
匿名回答1号

ソースはC言語です。
phpもC言語で書かれていて、pg_query_params()とかphpのPostgreSQL関連の関数もC言語でpgsql.cに書かれてる。
https://github.com/php/php-src/blob/master/ext/pgsql/pgsql.c
で、このpgsql.cはPostgreSQLのライブラリのlibpq使ってます。そのソースのうち、クエリをサーバに送って実行する系の関数がfe-exec.cにあります。
http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/interfaces/libpq/fe-exec.c;hb=HEAD

プリペアドステートメントは文字通り、命令を事前に準備するって事です。
SQLでPREPARE命令って命令文に名前付けて後で呼び出せる命令あります。
これだとサーバに送るのはSQLだけです。パラメータも後でSQL(EXECUTE命令)として送ります。
これもプリペアドステートメントの一つなのですが、結局パラメータをSQLとして送る必要があるので、セキュリティ目的には利用出来ません。
PREPARE命令じゃなくてプロトコル、サーバとのやりとりの仕方で、名前付けて後で利用する方法もあります。
この場合、命令に名前付けたり、送るパラメータはSQLとしてではなく送る事が出来ます。
そのためには、サーバとのやりとりにSQL以外も送ることが可能なプロトコル/APIじゃないと出来ません。
逆に言えば、パラメータをSQLとしてではなく送ることが出来、SQLとして解釈される余地がなくなり、セキュリティ目的に利用出来ます。
これが出来るようになったのが7.4以降のようです。

さて、pg_query_params()で使ってるPQexecParams()はほとんどこのプリペアドステートメントと同じような事をしています。
まずSQL文を送ります。ただ、送った文に名前を付けません。名前がついていないので後で利用出来ません。利用する方法がありません。
その代わり、直ぐにパラメータを送り実行します。
プロトコル的、内部的には事前にサーバにSQL文を送り、直後でもその後にパラメータを送っているので、事前に準備された文ではあります。
ただ、PQexecParams()つまりAPIとしては連続で、1度切りで直ぐに実行しなければならないと言うのは、実質的な意味では事前に準備された文とは呼べないかもしれません。
しかし、値がSQL文としてではなく、プレースホルダを使用しプロトコルとして別々に送られて、サーバ側でバインドされているのでプレースホルダとしてはほぼ静的プレースホルダです。
ただ、ISO/JIS規格としての定義が(狭い意味での)プリペアドステートメントを用いるということなら定義としては静的プレースホルダではないかもしれません。
ただ、それらは字義/定義上での問題で、それがどちらになるにせよ、それで動作や安全性が変わるわけでもなく、サーバにはSQL文とパラメータが別々に送られているので、サーバにバグがない限りは安全でしょう。

と言う所でしょうか。

2015/08/29 01:16:01

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません