アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

variables_orderの設定とgetenv()推進キャンペーン

こんにちは、亀本です。

先日、私用がてらにふらりと遊びに来てくださっていたid:rskyさんと共に、アシアルの何名かでウノウさんへちょびっと遊びに行ってきました。
そこで自分は使えなキャラだったことが判明し、軽くションボリ中です(´・ω・`)

さて、今回はスーパーグローバル変数周りのお話です。
知ってる人は知っている事だと思うので恐縮ですが、ちょっとした小ネタです。


普段わりと忘れられがちなのですが、スーパーグローバル変数の値はどんな時でも必ず取得できるわけではありません。
スーパーグローバル変数の値のうち、$_GET、$_POST、$_COOKIE、$_SERVE、$_ENVの5つは、php.iniの中のvariables_orderというディレクティブによって、値のパースを行うかどうかが規定されています。

ソースからコンパイルした場合、php.ini-distであれば


variables_order = "EGPCS"

となっており、php.ini-recommendでは


variables_order = "GPCS"

が初期設定です。
ディストリビューションでも多くの場合はphp.ini-distと同じです。(ただ、ここは未確認の部分も多いです。)

E、G、P、C、SはそれぞれENV、GET、POST、COOKIE、SERVERの指定で、これらがそれぞれ指定されているかどうかで、各変数がパースされるかどうかが決まります。
つまり、上記の例でいえばphp.ini-recommendをシステムで使用した場合、$_ENVの中身は空っぽ、ということになります。

G、P、C、SはWebアプリケーションではほぼ必須なのでOFFになっていることは少ないですが、$_ENVはあまり使う機会が多くないので、Eの指定がOFFになっていることが忘れられがちですし、ONにする要件もあまりありません。
むしろ、phpinfo()の情報が誤って漏洩した時のリスクを高めるだけなので、あえて変更することは考えにくいでしょう。


余談ですが、この指定をすべて消して


variables_order = ""

とした場合、マニュアルには「"" に設定すると、一切 superglobals を設定しません。」との記述がありますがこれは誤りです。
PHPバージョンで確認したわけではありませんが、実際には空文字列にしてしまうと全てのスーパーグローバル変数が設定されます。つまり"EGPCS"と指定したのと同じことになります。
まぁ、このような指定は通常考えられないので、問題はないのですが。。。


さて、本題に戻ります。
最近はPHPの設定ベースとしてphp.ini-recommendが推奨されていることも多く、上記のような設定になっている状況は間々あります。
そのため、気をつけておかないと、php.ini-distベースで運用していたテストサーバで組んだCLIバッチがphp.ini-recommendベースで運用している本番上では$_ENVが設定されていないためにエラーになる、という罠にはまることもあります。
また、ライブラリで$_ENVを使っていると、php.ini-recommendベースのシステムでは毎回こういった問題に当たることになります。


この問題を起こさないようにする為に、ライブラリやバッチを作成する場合には$_ENVではなくgetenv()関数を用いるとよいでしょう。
PHPのgetenv()関数はC言語のgetenv()関数の単純なラッパーになっており、上記の設定に依存することなく指定した環境変数の値を取得します。
そのため、$_ENVに値が設定されていない場合でも、getenv()関数を用いれば(環境変数に値が存在する限り)取得が可能です。

ということで、現在getenv()推進キャンペーン展開中です(`・ω・´)
(※別にアシアルで推奨、って意味じゃないですよ。個人的な話です。)


なお、補足ですが、この件に関して/halt/snapshotにて


if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {
    return $var;
}

といった処理が紹介されています。
特にライブラリで使用する場合には、取得してくる値がグローバルであることの明示という意味合いからも、このような処理の方が望ましいかもしれませんね。