続、PHPとH2OをfastCGIでつなぐ話、暗黒道
前回のあらすじ
- H2Oという速いhttpdがfastCGIをサポート
- PHPはfastCGIをサポート
- PHPerはつなぎたい
- 実際つながった!やったー!
- しかし、設定がよくわからん
- ぼやいたら作者のkazuhoさんにアンサーエントリを頂けた
- やった!試すぞ!
Kazuho's Weblog: H2OとPHPを組み合わせるの、超簡単です(もしくはmod_rewriteが不要な理由)
今回の話
ちゃんとルーターをつかうようなPHPアプリが繋がるのか、PATH_INFO周辺はどうなるのか。こんなシンプルなconfigで本当に動くのか。
そして、kazuhoさんの説明を見た時、ふと気になったのが「PHPのアプリの相乗りはどうなるのか?」である。
(後、実際の設定ファイルからディレクトリ名などをちょっとばかり修正してるので、もしかしたら、つじつまが合ってないところがあったらすみません)
今回、まずこの様に設定した
listen: 8080 file.custom-handler: extension: .php fastcgi.connect: host: 127.0.0.1 port: 9000 type: tcp hosts: "127.0.0.1:8080": paths: /: file.dir: /var/www/app/htdocs redirect: url: /index.php/ internal: YES status: 307 access-log: /dev/stdout
(これはconfig全体である、短い!)
/var/www/app/(htdocs)には、Slim frameworkでつくったPHPのアプリがおいてある。
説明は作者のkazuhoさんのエントリにゆずるが、
Kazuho's Weblog: H2OとPHPを組み合わせるの、超簡単です(もしくはmod_rewriteが不要な理由)
fileが存在しなかったら内部リダイレクトでredirect節に行く、なるほどである。nginxよりも数倍すっきりしている。
結論からいえば、この設定をするだけで、拍子抜けするほど何の問題もなく期待通りに動いた。やったね!!
PHPerにはH2Oが光り輝いてみえたのだった!
皆さんも具体的に気になるであろう所
前述の設定で
$app->get('/path/phpinfo', function () use ($app){ phpinfo(); exit; });
みたいにルーターにルートが登録されていたとして、
http://localhost:8080/path/phpinfo?hoge=fuge
みたいなURLでアクセスしたとき、PHPerなら間違いなく気になる$_SERVERの一部がこちら。
$_SERVER['SERVER_SOFTWARE'] h2o/1.3.0 $_SERVER['SERVER_PROTOCOL'] HTTP/1.1 $_SERVER['SERVER_NAME'] 127.0.0.1 $_SERVER['SERVER_PORT'] 8080 $_SERVER['SERVER_ADDR'] ::1 $_SERVER['REQUEST_URI'] /path/phpinfo?hoge=fuge $_SERVER['HTTP_HOST'] localhost:8080 $_SERVER['REQUEST_METHOD'] GET $_SERVER['REMOTE_PORT'] 59195 $_SERVER['REMOTE_ADDR'] ::1 $_SERVER['QUERY_STRING'] hoge=fuge $_SERVER['PATH_INFO'] /path/phpinfo $_SERVER['SCRIPT_NAME'] /index.php $_SERVER['SCRIPT_FILENAME'] /var/www/app/htdocs/index.php $_SERVER['PHP_SELF'] /index.php/path/phpinfo $_SERVER['argv'] Array ( [0] => hoge=fuge ) $_SERVER['argc'] 1
これを知りたい人には説明いらないだろう。
PHP_INFO、SCRIPT_NAME、PHP_SELF、REQUEST_URI、このあたりの食い合わせが悪いと死ぬ系のフレームワークは結構ある。まあ俺は好きなSlimが問題なさげなので問題はない。
ここまでで止めておけば、H2OとPHPは最強タッグ!みたいな事が言えそうである。
しかし、PHPerはドンドンと闇に潜っていくしかないのだ…。
アプリの相乗りの話
このアプリは以下のような設定になっているのは上述した通りだが、
/: file.dir: /var/www/app/htdocs redirect: url: /index.php/ internal: YES status: 307
これは
- /path/phpinfoにアクセスがあり
- ファイルがなかったからredirect節にいき
- 内部リダイレクトでindex.phpのURLになり
- 勿論それは存在し
- そのファイルの拡張子がphpなので「file.custom-handler:\n extension: .php」が発火し
- fastCGIへ、SCRIPT_FILENAMEに/var/www/app/htdocs/index.php指定でもろもろコールされる
んだと思う。(長い)
では気になるのが、同様の記述を並べ、複数の仮想パスは扱えるのか?(アプリの相乗りはできるのか?)
コスト削減が叫ばれる現代、エンジニアのちんぎんのみならず*1、当然ながらサーバー台数もできれば効率的に削減したい、つまり、各種アプリを相乗りさせたい。
/index.php一つにすべてのアプリを統合してはいられないのだ!*2
テスト1
ここでまずhtdocs以下に phpinfo.php をおいて、そのURLを開いてみる。
http://localhost:8080/phpinfo.php
これは動く。Apache的な挙動でわかりやすく、好感が持てる!
では、仮想パスをあててみたい、
http://localhost:8080/info/asdf
としたときに、phpinfo.phpを呼べるのか?
以下のようにしてみたら見事にうごいた!よさそうである。
/info: file.dir: /var/www/app/htdocs redirect: url: /phpinfo.php/ internal: YES status: 307
( /info:は/: の前にかいても、後にかいても大丈夫っぽい、どういうマッチ順判定になるのかよくわからない、最長かな? )
テスト2
では、世間では余り見ないが、自分がしばしばやりたくて、nginxだと設定が長くなって難儀な設定をやってみる。*3
htdocsを共にしない別のappを、接ぎ木(マウント)してみたい。
/app2: file.dir: /var/www/app2/htdocs redirect: url: /index.php/ internal: YES status: 307
これも上手くいくだろ…とおもったら残念、上手くいかなかった。
http://localhost:8080/app2/index.php
はうまくapp2/htdocs/index.phpが読み込まれるのだが、
を指定すると、どうやら/:の方の、/var/www/app/htdocs/index.phpが読み込まれる模様。
私の設定がダメな気もするが、フーム?
(仮想パスとurl:の兼ね合い?)
テスト3
気をとりなおして、こちらはしばしばよく見る構成。
/form/index.php を /form/test でよびだしたい。こちらはhtdocsを共有である。
/form: file.dir: /var/www/app/htdocs redirect: url: /form/index.php/ internal: YES status: 307
意外なことにダメだった。(追記:エントリ冒頭の通り、解決しました!)
さらにいえば、
http://localhost:8080/form/index.php
をひらいたら、/と同じ画面になってしまった。
ちなみに以下のようにしてもダメである。
ただし、直接ファイル名まで指定したら、今度は目的のphpが開けた。
/form: file.dir: /var/www/app/htdocs/form redirect: url: /index.php/ internal: YES status: 307
フーム?
どうも思い通りにならない。h2oの仕様なのかなと思っておりますが、どうなんでしょうか。
テスト2については、こんなよくわかんないアプリの載せ方する奴は滅多に居ないし、俺が悪い気もする。(ただ、これができるとすごい嬉しい)
ただ、テスト3については、ごたまぜなPHPのサイトではたまに使われる構成なので、是非動いて欲しい。
追記:エントリ冒頭の通り、解決しました!
まとめ
H2Oはnginxとくらべて、fastcgiとpath(location)の主従が逆転しているのが面白い。拡張子を見て特定のfastcgiの繋ぎ先(ここではphp)を特定するし、Apache likeな感覚であり、楽だ。
かたや、nginxは書こうとおもえばトコトン書けるので、path毎にPHP(のバージョンや設定を)を変えたりできるのが良いかもしれない。ただまあ、そんな闇深いのは地獄ですが、proxyとして多用されるのを考えると*4、あれはあれで。
(まあ、php5とかそういう拡張子を用意すれば(これまたApache的だ!)H2Oでも似たような事ができそうですが)
ところで、kazuhoさんの「コンフィグをシンプルにかけるようにしたいんだ!」というすごい良い考えを、ドンドンよごしていってる感じがする。とにかくPHPerの迷惑さがある…。
もう諦めて、h2o+phpを重ねていけば(proxyしていけば)ええんちゃうか?と思った(…だが…しかし…我々は…)。
後、h2oと完全に関係ないが、.htaccessはやっぱり便利だと再認識する。
複雑怪奇で誰も適切に理解できないmod_rewrite+.htaccessだが、とにかく外にゴミがあふれ出さず、そのディレクトリの中で封がされているのはPHP的だ。
そういう場当たり的な便利ツールは個人的には無くても良いが、なんだかんだで現実の運用で複数のアプリが乗り始めると、h2oでもconfigは伸びていきそうであった。でもまあ、nginx+php-fpmより断然読みやすいですけどね!
h2oがもっと正しく扱われる世界にあこがれる深夜のPHPerであった。
こちらからは以上です。よろしければ続報をお待ちください。