URLルーティングを作る – part zero : mod_rewrite
PHPでwebアプリケーションを作るときよくあるのが、リクエストラインにパラメータを乗せて機能名やパラメータを載せる方法。
http://hoge.example.com/some_content/some_control.php?action=view&hoge=0&piyo=1
それに対して、リクエストパラメータを解析し共通のコントローラに渡すのがURLルーティング。前述のURLはこんな感じになるだろうか。
http://hoge.example.com/some_content/some_control/view/0/1/
実際に処理するのはフロントコントローラとかルータと呼ばれるクラスで、各種パラメータを解析して適切なコントローラを呼び出す(dispatch)のが仕事である。
kwappa開発室初の連載記事。まずは「Url Routing with PHP」(英語)という記事を元に、もっとも基本的なURLルータを設計してみる。
●mod_rewriteでリクエストをURLルータに集める
まずはapacheもしくは.htaccessでmod_rewriteの設定をする。
<Directory "/path/to/docroot/app_dir/"> RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule (.*) /app_dir/router.php/$1 [L] </Directory>
オプションは…
-f : ファイルが存在すればtrue
-d : ディレクトリが存在すればtrue
つまり上記オプションでは「ファイルもディレクトリも存在しなければリクエストをルータに向ける」という設定になる。
mod_rewriteは他にもいろいろ凝ったことができる。リファレンスはこちらが使いやすい。
Apache : mod_rewriteリファレンス – Flash/Web Application Weblog Directory
http://blog.dawgsdk.org/weblog/archives/411011
●REQUEST_URIからパラメータを切り出す
http://kwappa.example.com/app_dir/obj/method/arg0/arg1/
このURLをrewriteし、呼び出されたrouter.phpでURLからパラメータを取り出す。
<?php $requestUri = explode("/",$_SERVER['REQUEST_URI']) ; $scriptName = explode("/",$_SERVER['SCRIPT_NAME']) ; var_dump($requestUri) ; /* array(6) { [0]=> string(0) "" [1]=> string(7) "app_dir" [2]=> string(3) "obj" [3]=> string(6) "method" [4]=> string(4) "arg0" [5]=> string(4) "arg1" } */ var_dump($scriptName) ; /* array(3) { [0]=> string(0) "" [1]=> string(7) "app_dir" [2]=> string(10) "router.php" } */ // 共通する要素(=routerまでのpath)を取り除いた配列を作る。 foreach ($scriptName as $key => $value) { if ($value == $requestUri[$key]) { unset($requestUri[$key]) ; } } $requestArgs = array_values($requestUri) ; var_dump($requestArgs) ; /* array(5) { [0]=> string(3) "obj" [1]=> string(6) "method" [2]=> string(4) "arg0" [3]=> string(4) "arg1" [4]=> string(0) "" } */ ?>
この辺までが「Url Routing with PHP – Part One」第1回の内容。このままPart Two / Part Threeを参考にobj(コントローラ名)とmethod(コマンド名)でdispatch(呼び出すコントローラ / コマンドを解決)するクラスを実装すると基本的なURLルーティングができるようになる。
だが、それでは機能的に物足りない点が多いだろう。足りない点を「俺実装」してもいいのだが、既存ライブラリに十分なものがあれば、あえて「再発明しない勇気」を持つのも大事(かもしれない)。
ということで次回(URLルーティングを作る – part one : PEAR::Net_URL_Mapper)はPEAR::Net_URL_Mapperをベースに、もっと使いやすいルータを実装してみる。