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{//......}