PHPを実行する環境として、FPMも有用です。ただし、FPM内から環境変数を参照するには、いくつもの壁が立ちはだかっています。
環境変数の使い方
データベースのアクセスキーやAPIのキーなどのような、Gitに残すのが適当でない情報や、データベースサーバの位置や環境設定の切り替え用のフラグなど、環境ごとに変更が必要な情報は、環境変数に入れておいてアクセスする、というのがサーバサイドでの定石のようになっています。
そういうわけで、システム側で環境変数を用意してPHPから読み取らせようとしたのですが、見事に失敗してしまいました。
PHP-FPMとは
Webサーバで動的なページを供給しようとする場合、いくつかの手段があります。
- Webサーバから別プロセスを呼び出す
- Webサーバにプログラムを組み込む
- 動的なページを処理するアプリケーションサーバを用意して、Webサーバがそちらに投げる
いちばん最初のがもともとのCGIですが、これではプロセスの生成コストがかさんでしまうので、高速化を追求する中では下火となっていきました。そして、PHPでは2番めのように、Apacheにmod_php
を追加して動かす、という形態もよく取られます。
ただ、ご存知のようにApacheへPHPを組み込むと、両者がからみ合って動作設定が複雑化する、片方だけ取り替えることができないなど、密結合にしたことによる問題が生じてきます。ということで、「アプリだけ動くサーバ⇔フロントエンドのHTTPサーバ」という2つに分ける方法も取られるようになってきました。
RailsなどRuby系でよく使われるUnicornやNode.jsのように、アプリケーションサーバ自体がHTTPで結果を返してももちろん構わないのですが、バックエンドアプリ用に開発されたFastCGIという専用のプロトコルもあります。そして、FastCGIで結果を返すPHP用のアプリケーションサーバ(PHP純正)がPHP-FPMです。
第一の壁…FPM自体
まずは、PHP-FPMのマニュアルを確認してみましたが、その中にclear_env
という項目がありました。PHP 5.6以上や、PHP 5.4/5.5系でもリビジョンによっては、特に設定しないと環境変数がクリアされてしまうようです。
選択肢としては、「同じPHP-FPMの設定ファイルで環境変数も設定する」という方法と、「clear_env = false
として、外からの環境変数を通す」という2つの手段があります。ここで設定するほうが楽かもしれませんが、あとあとcronなどFPMを経由しないでPHPを実行する際に同じ値を使えなくて煩雑になる、ということを考えて、clear_env = false
とすることで、第一の壁を外すことにしました(後述の事情により、むやみやたらな環境変数が来る心配はありません)。
第二の壁…systemd
Webサーバとして動かすには、FPMも常駐が必要なので、ふつうは何かしらのデーモン管理システムから起動することになります。そういうわけで、たとえばRHEL7系列であればsystemd
経由で動かすことになるのですが、こちらも環境変数をクリアします。
もちろん、「第三者が適当に設定した環境変数で動作が影響すべきでない」ということを考えれば、その動作は適切なのですが、今回は「あえて環境変数を設定している」ので、それは通してほしいものです。
で、調べてみると、EnvironmentFile
としてNAME=val
形式の行を連ねたファイルを指定できるということだったので、ここで指定することでPHP-FPMにも環境変数が伝わるようにしておきます。そして、きちんと書いておけば同じファイルをシェルスクリプトとして読むこともできますので、シェルスクリプトでその設定ファイルをsource
してexport
すれば、1ファイルの設定でFPMにもシェルにも同じ環境変数を設定可能です。
第2.5の壁…PHP自体
順序としてはいちばん手前に来る壁のはずなのですが、これは迂回できるので最後に回しました。
これだけ設定して環境変数がPHP-FPMから見えるようになっても、$_ENV
に値が入らないことがあります。php.ini
の設定にvariables_order
というのがあって、よくGPCS
と、$_ENV
を生成しないような設定となっているのです。
設定を変更してももちろん構わないのですが、「警告」にあるように、FastCGI環境では$_SERVER
にも環境変数が設定されるようになっていますので、確実にFPMで実行するのであれば$_SERVER
から取ってしまうことができます。また、getenv()
関数で取得しても構いません。