PHP簡單的偽靜態URL機制實現

PHP雖然是一門新語言,但是如果程式語言寫的好容易上手。以下是本站小編精心為大家整理的PHP教程,希望對大家有所幫助!更多內容請關注應屆畢業生網!

PHP簡單的偽靜態URL機制實現

曾幾何時,我們公司準備開發一套新的建站系統,決定將以前的框架給KO掉,重新開發一套新的框架來適應新的系統功能。領導們不希望使用外面已有的框架,號稱要開發有自己特色的框架(不懂開發的領導害死人)。於是我們又投入到了新的開發當中。

由於我們的系統支援偽靜態,以前的系統是直接使用伺服器apache或IIS自帶的rewrite檔案定義規則,而框架中沒有任何路由機制,於是這次框架準備使用新的策略,由PHP實現路由機制。於是我開始了功能實現的探索之路。

開發之前,我先了解‘路由機制’要做什麼,它主要做兩件事。

1.路由機制就是把某一個特定形式的URL結構中提煉出來系統對應的引數。舉個例子,如: 其中:/article/1 -> ?_m=article&id=1。

2.其次,是將擁有對應引數的URL轉換成特定形式的URL結構,是上面的過程的逆向過程。由於路由機制隔離了URL結構和引數的轉換關係,使的.日後結構的變化不會影響下面程式碼的執行。

 通過上面的瞭解,可以得出要編寫一個路由機制要一下幾步:

1.編寫伺服器apache或IIS自帶的rewrite檔案,將URL結構匯入。

2.一個路由規則配置檔案。

3.一個路由解析器,用來解析規則,匹配和轉換URL。

於是,我們一一實現其中的每一個部分。

ite檔案編寫,以Apache為例:

1234567<IfModulemod_rewrite.c>RewriteEngineOnRewriteRule^index$-[L]RewriteCond%{REQUEST_FILENAME}!-fRewriteCond%{REQUEST_FILENAME}!-dRewriteRule(.+)$1[L]</IfModule>

上面的程式碼就是將URL結構匯入中,具體的rewrite細節就不贅述了。

2.在PHP中設定一個路由規則配置檔案,我簡單的使用了一個hash陣列編寫規則:

123456789101112131415161718192021222324/***路由配置檔案編寫說明:*路由配置在一個array陣列中,一條記錄代表一個規則*其中陣列key的資料代表匹配的路徑格式:使用特定的字串標識如:'/{id}'*字串中可以包含特定的變數,所有變數使用大括號{}包裹起來*陣列value裡是一個array陣列,是對key中路徑中變數進行特定處理*變數寫在陣列的key中,規範寫在陣列的value裡,如:array('id'=>'/d+/','_m'=>'frontpage','_a'=>'index')*規範分成兩類:*1.格式判斷:比如'/{id}'=>array('id'=>'/d+/','_m'=>'frontpage','_a'=>'index')為例,其中'id'=>'/d+/'就是一個格式判斷,*表示id變數只能是數字,格式判斷後面只能使用正則表示式,由於PHP沒有正則類,所以我指定'/XXX/'和'#XXX#'格式的字串為正則表示式*2.預設引數:比如'/{id}'=>array('id'=>'/d+/','_m'=>'frontpage','_a'=>'index')為例,其中'_m'=>'frontpage'就是一個預設引數,*因為前面的路徑沒有_m和_a資訊,所以後面會使用預設引數作為_m和_a的值**所以對於規則'/{id}'=>array('id'=>'/d+/','_m'=>'frontpage','_a'=>'index')。我傳入/3系統會轉換成_a=index&id=3**規則匹配是按照$routes陣列的順序逐一匹配,一旦匹配上了就不往下匹配了。所以一些特定的匹配規則要放在前面,通用的放在後面。*否則可能導致不執行特定的匹配規則了*/$routes=array('/'=>array('_m'=>'wp_frontpage','_a'=>'index'),'/{id}'=>array('id'=>'/d+/','_m'=>'wp_frontpage','_a'=>'index'),'/{_m}/{_a}/{id}'=>array('id'=>'/d+/'),'/{_m}/{_a}'=>array());

  3.路由機制中最複雜也是最重要的一部分,就是解析器。

解析器有兩個類組成(名字可能起的不佳)。

一個是Route,作為整個解析器對外的介面,用於解析規則,匹配和轉換URL,然而它只是一個代理,實際操作不是直接由它直接做的。

一個是RoutePattern,每個RoutePattern例項對應規則陣列中的一條記錄,一個Route例項包含多個RoutePattern,而Route中的所有操作都會呼叫內部所有RoutePattern例項操作,並進行整合。

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162classRoute{privatestatic$instance=null;private$routepatterns=array();privatefunction__construct(){$routes=array();includeROOT."/";foreach($routesas$key=>$value){$this->routepatterns[]=newRoutePattern($key,$value);}if(!isset($_SERVER['PATH_INFO']))returnfalse;$urlpath=$_SERVER['PATH_INFO'];$ismatch=$this->match_url($urlpath);$strip_urlpath=str_replace('/','',$urlpath);if(!$ismatch&&!empty($strip_urlpath)){Content::redirect(PAGE_404);}}/***用路由規則匹配對應的url地址,匹配成功將對應url引數放入$_GET中*@paramstringurl地址*@returnbool是否匹配成功*/publicfunctionmatch_url($urlpath){foreach($this->routepatternsas$router){$urlargs=$router->match_url($urlpath);if($urlargs!==false){$_GET=array_merge($urlargs,$_GET);returntrue;}}returnfalse;}publicfunctionrewrite_url($urlparams){foreach($this->routepatternsas$router){$urlstr=$router->rewrite_url($urlparams);if($urlstr!==false){return$urlstr;}}$actualparams=array();foreach($urlparamsas$arg=>$val){$actualparams[]=$arg."="ncode($val);}$actualparamstr=implode('&',$actualparams);$rewriteurl="/";if(!empty($rewriteurl))$rewriteurl.="?{$actualparamstr}";return$rewriteurl;}publicstaticfunctioninit(){if(null==self::$instance){self::$instance=newRoute();}returnself::$instance;}}classRoutePattern{//......}