Thursday, June 18, 2015

H2OとPHPを組み合わせるの、超簡単です(もしくはmod_rewriteが不要な理由)

FastCGI対応機能がH2Oにマージされたことを受けて、uzullaさんが「H2OでPHP(がちょっとだけ動くまで)」という記事を書いてくださっています。

ありがたやありがたや。

その中で、
http://hoge/entry/1 みたいなのをphpにマップする方法はまだよくわかってません。その内しらべます

github.comを読む限り
FastCGI (or PHP) applications should be as easily configurable as it is for the Apache HTTP server
ということで、やったぜ!ってなるんですけど、nginxはもとより、Apacheにおいても現状ルーターをつかっているようなアプリだとhtaccessをいちいちかかないといけないので、Apacheみたいなスタイルが楽なのか?というとちょっと疑問があります。

(たとえば以下みたいなの)
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
ここらへんがスッっとかけないと、まあApache、nginx同様にH2Oの設定のタレが必要になるかなあ、という感じはあります。
いやはや、まったくそのとおりなわけです。

ちなみにこの手のことをNginxでやろうとするともっと難しくて、以下のようにtry_filesfastcgi_split_path_infoを使わないと脆弱性が発生するなんて話があるそうです(参照: Setting up PHP-FastCGI and nginx? Don’t trust the tutorials: check your configuration! » Neal Poole)。これ、みんなちゃんとできてるんですかね?
# Pass all .php files onto a php-fpm/php-fcgi server.
location ~ \.php$ {
   try_files $uri =404;

   fastcgi_split_path_info ^(.+\.php)(/.+)$;
   include fastcgi_params;
   fastcgi_index index.php;
   fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
   fastcgi_pass php;
}

こんな難しい設定、書けるわけないだろうが!!!!!!!

というわけで、H2Oの場合はもっと簡単に設定できるようになっています。以下のような感じ。
paths:
  "/":
    # /path/to/doc-root以下の静的ファイルを返す(存在した場合)
    file.dir: /path/to/doc-root
    # 存在しなければ、/index.php/ に内部転送
    redirect:                     
      url: /index.php/
      internal: YES
      status: 307

単純ですね。どうなってるかはコメントを見れば自明かとも思いますが、以下解説します。

実は、H2Oの設定ファイルにおいては、1つのパスに複数のハンドラを設定することができるのです。

複数のハンドラが設定されている場合、H2O は有効なレスポンスが生成できるまで、ハンドラを順次実行していきます。つまり、コメントにあるように、ファイルが存在すればそれを返すし、存在しなければ /index.php/ 以下にリクエストを内部的に転送し、その転送した結果の応答をクライアントに返すわけです。

わかりやすいですね。簡単ですね。


少し理屈っぽい話をすると、mod_rewriteのようなリクエストを書き換える黒魔術は、おおむね3種類の目的に使われてきました。第1の目的は、複数のローカルのディレクトリツリーを重ね合わせてひとつのhttpサイトとして表示すること。第2の目的は、uzullaさんが指摘したような、特定の条件をもつ以外のURLの処理を、FastCGIやアプリケーションサーバに委譲すること。第3の目的は、User-Agentや言語設定によって異なる応答を返すこと。

ですが、前2者を実現するためだけならば、正規表現を用いてURLを書き換えるような手法は過剰にすぎて管理がしづらかったわけです。H2OにおけるPHP対応においては、この点を意識し、複数のハンドラの連鎖を可能にすることで、設定が安全簡潔にできるようにしたのでした。

ちなみに、uzullaさんの例ではphp-fpmを使っていますが、H2Oはphp-cgiを自分で管理することができるので、小規模なウェブサイトにおいては、
file.custom-handler:          
  extension: .php
  fastcgi.spawn: "PHP_FCGI_CHILDREN=10 exec /usr/bin/php-cgi"
のように書くと、別途FastCGIデーモンを管理する必要がなくなって、より幸せになれるでしょう(名前はphp-cgiでも、この設定においてはFastCGIとして動作します)。


最後になりますが、ここで説明したFastCGI対応機能を盛り込んだH2Oバージョン1.3は今朝方リリースされたので、PHPerの皆様もそれ以外の皆様も、お試しいただければ幸甚に存じます。

リンク先のリリース告知エントリにも書いてあるけど、他のウェブサーバより表示速度(first-paint time)が、かなり速いですよ!

3 comments: