ScarShow

< IS >

實作一個小型 Router use PHP (1)

2012-04-23  /  IT  /  PHP

之前有個開發Framework的經驗,在REST的設計風格中,HTTP Method是操作Resource的動作,而URL則是需要操作的Resource本身。所以我們必須讓HTTP Method及URL對應到要執行的程式上,實做Router的需求就這樣產生。那麼以下是不專業的範例教學。

首先建立一個PHP程式 server.php

<?php
// filename: server.php
print_r($_SERVER);

然後我們用curl來發送請求來觀察PHP到底收到了什麼訊息

curl -X GET "localhost/server.php/segement/input" -d "param=test" -G

底下是curl輸出之結果

Array
(
    [HTTP_USER_AGENT] => curl/7.21.6 (x86_64-pc-linux-gnu) libcurl/7.21.6 OpenSSL/1.0.0e zlib/1.2.3.4 libidn/1.22 librtmp/2.3
    [HTTP_HOST] => localhost
    [HTTP_ACCEPT] => */*
    [PATH] => /usr/local/bin:/usr/bin:/bin
    [SERVER_SIGNATURE] => <address>Apache/2.2.20 (Ubuntu) Server at localhost Port 80</address>

    [SERVER_SOFTWARE] => Apache/2.2.20 (Ubuntu)
    [SERVER_NAME] => localhost
    [SERVER_ADDR] => 127.0.0.1
    [SERVER_PORT] => 80
    [REMOTE_ADDR] => 127.0.0.1
    [DOCUMENT_ROOT] => /var/www/
    [SERVER_ADMIN] => webmaster@localhost
    [SCRIPT_FILENAME] => /var/www/server.php
    [REMOTE_PORT] => 58117
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_PROTOCOL] => HTTP/1.1
    [REQUEST_METHOD] => GET
    [QUERY_STRING] => param=test
    [REQUEST_URI] => /server.php/segement/input?param=test
    [SCRIPT_NAME] => /server.php
    [PATH_INFO] => /segement/input
    [PATH_TRANSLATED] => /var/www/segement/input
    [PHP_SELF] => /server.php/segement/input
    [REQUEST_TIME] => 1335154750
)

根據 $_SERVER 的內容中我們挑出能用的部份,REQUEST_METHOD 就是HTTP請求時的Method而 PATH_INFO 、PHP_SELF 及 REQUEST_URI 則可以用來當作比對用的URL。PATH_INFO的內容/segement/input完全符合需求,另外的 PHP_SELF 及 REQUEST_URI 要做額外的處理才能使用。

還有一件值得一提的事情,上面三個變數Apache都有、Nginx少 PATH_INFO 而IIS則少 REQUEST_URI。

接下來就開始實作了,實做一個Router我們需要上面提到的HTTP Method、URL以及Route Rule及Callback,原理很簡單當Method及URL與Route rule互相Match的時候就會去呼叫Callback執行相對應的動作。首先新增一個名為router的class把一些基本的架構制定出來

<?php
// filename: router.php
class router {
    public function __construct() {
        $this->method = $_SERVER['REQUEST_METHOD'];
        $this->url = $_SERVER['PATH_INFO'];
    }

    public function add($route, $callback) {
        // do something
    }

    public function run() {
        // compare
    }
}

以上的class提供一些基本的功能,當class被new時自動取得Method及URL,再用add加入Route Rule及Callback,接來下就可以用run讓Router 跑路 啟動了。

那麼比對怎樣做,直接用 == 字串比對就好啦 比較好的做好是使用正規表達式去比對字串。

待續...