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をベースに、もっと使いやすいルータを実装してみる。