uzullaがブログ

uzullaがブログです。

続、PHPとH2OをfastCGIでつなぐ話、暗黒道

追記

uzulla.hateblo.jp

本エントリのテスト3ができない件は、解決されました!

前回のあらすじ

uzulla.hateblo.jp

  • H2Oという速いhttpdfastCGIをサポート
  • PHPfastCGIをサポート
  • 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が読み込まれるのだが、

http://localhost:8080/app2/

を指定すると、どうやら/:の方の、/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のサイトではたまに使われる構成なので、是非動いて欲しい。

追記:エントリ冒頭の通り、解決しました!

まとめ

  • 普通のPHPアプリはすんなり動く!シンプル!
  • ごった煮の、Apacheべったりなアプリはまだ難しいかも


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であった。

こちらからは以上です。よろしければ続報をお待ちください。

続報できました。

uzulla.hateblo.jp

*1:日記だが、今日まさにある客先よりコストカットを宣告されてかなしい気分になっている、つらい。

*2:PHPの利点であり、忌み嫌われる欠点でもある

*3:これがnginx+fastcgiだと、assetまで含めて考えると異常に面倒な…んだが、すごくやりたいんだ!俺は!!

*4:事例と、設計どちらが先かわからないが