読者です 読者をやめる 読者になる 読者になる

localdisk

PHP とか Java とか Web とか好きなことを書きます。

PHPフレームワークはどのようにリクエストされたURLを取得しているか?

自分でフレームワークを作ろうとか思うと、こういった素朴な疑問がでてきたり。昨今のフレームワークRails以来、URLを解析してコントローラ及びメソッドをコールするというのが主流になってるんじゃないかと思う。そこで各フレームワークの実装を調べてみた。
調べたのは以下のフレームワーク

Ztend Framework

<?php
// Zend_Controller_Request_Http#setRequestUri
if ($requestUri === null) {
    if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch
        $requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
    } elseif (isset($_SERVER['REQUEST_URI'])) {
        $requestUri = $_SERVER['REQUEST_URI'];
        // Http proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path
        $schemeAndHttpHost = $this->getScheme() . '://' . $this->getHttpHost();
        if (strpos($requestUri, $schemeAndHttpHost) === 0) {
            $requestUri = substr($requestUri, strlen($schemeAndHttpHost));
        }
    } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI
        $requestUri = $_SERVER['ORIG_PATH_INFO'];
        if (!empty($_SERVER['QUERY_STRING'])) {
            $requestUri .= '?' . $_SERVER['QUERY_STRING'];
        }
    } else {
        return $this;
    }
} elseif (!is_string($requestUri)) {
    return $this;
} else {
    // Set GET items, if available
    if (false !== ($pos = strpos($requestUri, '?'))) {
        // Get key => value pairs and set $_GET
        $query = substr($requestUri, $pos + 1);
        parse_str($query, $vars);
        $this->setQuery($vars);
    }
}

Zend Framework は「HTTP_X_REWRITE_URL」→「REQUEST_URI」→「ORIG_PATH_INFO」の順番で取得している。おそらくIISApache他→CGIみたいな流れだろうか? 書かれているコメントもそうっぽい。

kohana

<?php
// Router_Core#find_uri
elseif (isset($_SERVER['PATH_INFO']) AND $_SERVER['PATH_INFO'])
{
    Router::$current_uri = $_SERVER['PATH_INFO'];
}
elseif (isset($_SERVER['ORIG_PATH_INFO']) AND $_SERVER['ORIG_PATH_INFO'])
{
    Router::$current_uri = $_SERVER['ORIG_PATH_INFO'];
}
elseif (isset($_SERVER['PHP_SELF']) AND $_SERVER['PHP_SELF'])
{
    Router::$current_uri = $_SERVER['PHP_SELF'];
}

kohanaはかなりシンプル。「PATH_INFO」→「ORIG_PATH_INFO」→「PHP_SELF」の順番に取得しようとしている。IISとかこれで大丈夫なのだろうか? と思ったがkohanaのサイトには

An HTTP server. Kohana is known to work with: Apache 1.3+, Apache 2.0+, lighttpd, and MS IIS

installation:requirements [Kohana User Guide]

と書いてあったりするので大丈夫なのだろう。多分。

CakePHP

<?php
// dispatcher.php uri
foreach (array('HTTP_X_REWRITE_URL', 'REQUEST_URI', 'argv') as $var) {
    if ($uri = env($var)) {
        if ($var == 'argv') {
            $uri = $uri[0];
        }
        break;
    }
}

kohanaに輪をかけてシンプル。「HTTP_X_REWRITE_URL」→「REQUEST_URI」という感じ。argvはCLIなのでここでは省略。IISを気にしなければREQUEST_URIだけとればOKということだろうか?

結論

サーバとPHPの組み合わせでどのようにスーパーグローバル変数が変化するのか、というドキュメントを上手く見つけることができなかったのでどれが正解なのかよくわからない。むむむ…。自分がやるんだったら、REQUEST_URI→PATH_INFO→ORIG_PATH_INFOかなぁ。IISはどうでもいいし。