Real Blog

レジェンド鈴木が日々感じたことを哲学するブログ。書評、エッセイ、ポエムも書いてます。

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/actionhttp://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がレンダリングされます。