COLUMN

cakephpがなぜ動作するのか

cakephpで作成したシステムのURLは一般的に http://example.com/cakephp設置ディレクトリ/コントローラー名/アクション名  のような形式になります。
しかしwebサーバー上には上記のようなファイルはありません。
それなのに何故、コントローラー、アクションで設定したhtmlにアクセスできるかを見ていきたいと思います。

cakephp設置ディレクトリ直下の.htaccessファイル

まず設置ディレクトリ直下にある.htaccessファイルによって、設置ディレクトリ/app/webroot/ へurlが書きかえれます。

RewriteEngine on
RewriteRule    ^$ app/webroot/    [L]
RewriteRule    (.*) app/webroot/$1 [L]

上記の表記によって、 http://example.com/cakephp_dir/controllers/action は http://example.com/cakephp_dir/app/webroot/controllers/action となります。

webrootディレクトリの.htaccessファイル

webrootにある.htaccessファイルでは次のような処理が行われます。

1. urlに実際にファイルがある場合は何もしない。
2. ファイルがない場合、次のようにurlを書き換える。
http://example.com/cakephp_dir/app/webroot/controllers/action => http://example.com/cakephp_dir/app/webroot/index.php?url=controllers/action

webroot以下のcssや画像ファイルにちゃんとアクセスできるのは上記の1の処理のおかげということになります。
実際にファイルがない場合はすべて、GETパラメーターにurl情報が渡された形でhttp://example.com/cakephp_dir/app/webroot/index.phpが起動します。


RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]


index.phpでの処理

index.phpでは基盤のファイル読み込み、各種設定後に、渡されたurl情報を解析してコントローラーとアクションを特定します。
//index.php内でDispatchオブジェクトが生成され、dispatchメソッドが実行される。
//index.php内
if (isset($_GET['url']) && $_GET['url'] === 'favicon.ico') {
return;
} else {
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch();
}
//dispatch内でurlが解析される
・・・
} else {
if ($url) {
$_GET['url'] = $url;
}
$url = $this->getUrl();
$this->params = array_merge($this->parseParams($url), $additionalParams);
}
$this->here = $this->base . '/' . $url;
・・・
//コントローラーに各種パラメーターが設定される
$controller =& $this->__getController();
・・・
$controller->base = $this->base;
$controller->here = $this->here;
$controller->webroot = $this->webroot;
$controller->plugin = isset($this->params['plugin']) ? $this->params['plugin'] : null;
$controller->params =& $this->params;
$controller->action =& $this->params['action'];
$controller->passedArgs = array_merge($this->params['pass'], $this->params['named']);
if (!empty($this->params['data'])) {
$controller->data =& $this->params['data'];
} else {
$controller->data = null;
}
・・・
// _invokeにコントローラーとパラメーターを渡す。
return $this->_invoke($controller, $this->params);
//_invoke内で controller->render() を実行し、実行結果を出力
//コントローラーで設定した処理が実行される
$output = call_user_func_array(array(&$controller, $params['action']), $params['pass']);
if ($controller->autoRender) {
$controller->output = $controller->render();
} elseif (empty($controller->output)) {
$controller->output = $output;
}
・・・
echo($controller->output);
上記のような流れでコントローラーに設定した処理が実行され、htmlがレンダリングされます。