http_build_queryのワナ

string http_build_query ( array $formdata [, string $numeric_prefix [, string $arg_separator ]] )

PHP: http_build_query - Manual

PHPのhttp_build_query関数は配列を渡すとURLパラメータ形式の文字列にシリアライズしてくれる、とても便利な関数なのですが、実はこの関数にはワナが潜んでいるのです。

http_build_query関数には第3引数($arg_separator)を設定できて、例えばこれを@@@にした場合、

$ php -r "var_dump(http_build_query(array('a' => 'foo', 'b' => 'bar'), null, '@@@'));"
string(13) "a=foo@@@b=bar"

このように区切り文字を変更することができます。この引数はいつも省略していたのですが、省略した場合は何が入るでしょう。「&」が入ると普通は思いますよね。ですがそうとは限りません。マニュアルには次のようにあります。

arg_separator.output が区分のためのセパレータとして使用されます。ただし、 このパラメータが指定されていた場合は それが使用されます。

PHP: http_build_query - Manual

第3引数を省略した場合、php.iniのarg_separator.outputに設定されている値が入るようになっています。んで問題はこのarg_separator.outputの設定です。

手元にあるUbuntu 9.10に入っているPHP 5.2.10では次のようになっていました。

; The separator used in PHP generated URLs to separate arguments.
; Default is "&".
;arg_separator.output = "&"

コメントアウトされている状態です。iniの方で未設定の場合ですが、手元のPHP 5.3.0のソースのext/standard/http.cを見たら

#define URL_DEFAULT_ARG_SEP "&"

デフォルトは「&」になっていたので、コメントアウトされた状態であれば特に問題はないと思います。が、しかし。

先日XAMPPで作業する必要があってそこで色々やっていたところ、XAMPPのphp.iniのデフォルト設定ではarg_separator.outputの設定のコメントアウトが外されており、この値が「&」になっていました。。。

それでhttp_build_query使って生成したパラメータを元にfile_get_contentsで開こうとしたらおかしい結果になってしまい、、、

Linux上で開発しているときには一切はまらなかったのでそもそも引数の存在すら知らなかったのですが、環境に依存しないコードを書くためにはきちんと第3引数を指定してあげる必要がありそうです。

しかし、なんでXAMPPがこのコメントアウトを外しているのか理解できません。。。