thinkphp 路由規則終極詳解(附僞靜態)

<?php 
//thinkphp 路由定義規則		
$route = array(
		'news/:action/:year\d/:month/:day'=>'news/read?year=:2&month=:3&day=:4',
				'news/:action^delete|update|insert/:year\d/:month/:day'=>array(                'news/read?extra=:2&status=1','year=:2&month=:3&day=:4'),
	    );

$url  = 'http://www.test.com/index.php/news/read/2012/2/21/extraparam/test.html';



//後綴名
$extension = 'html';



//根據pathinfo定義  詳情: http://my.oschina.net/u/1178986/blog/201206
//可知: $_SERVER['PATH_INFO'] = 'news/read/2012/2/21/extraparam/test.html';
$regx = 'news/read/2012/2/21/extraparam/test.html';

//循環匹配路由規則
foreach($route as $key=>$value){
		//若是匹配成功,則不繼續匹配
		if(parseUrlRule($key,$value,$regx,$extension))
			break;
}

//運行結果: 打印$_GET
//Array
// 	(
// 	    [actionName] => read
// 	    [moduleName] => news
// 	    [extra] => 2012
// 	    [status] => 1
// 	    [extraparam] => test
// 	    [year] => 2012
// 	    [month] => 2
// 	    [day] => 21
// 	    [finalUrl] => news/read?extra=2012&status=1&extraparam=test&year=2012&month=2&day=21
// 	)
// 	[Finished in 0.6s]

//至關於訪問: http://www.test.com/news/read?extra=2012&status=1&extraparam=test&year=2012&month=2&day=21

//在部署時會把index.php隱藏,開啓apache的重寫模塊
//重寫規則 : RewriteRule  ^(.+)$  /index.php/$1 
//詳細配置: http://lamp.linux.gov.cn/Apache/ApacheMenu/rewrite/
//開啓後,apache會自動把 http:/www.test.com/news/read/2012/2/21/extraparam/test.html轉換爲 http:/www.test.com/index.php/news/read/2012/2/21/extraparam/test.html

/**
 *  @$rule  string    路由規則   
 *  @$route string    規則映射的新地址
 *  @$regx  string    地址欄pathinfo字符串
 *  @$extension stirng  僞靜態拓展名
 *  return  bool 
 */
function parseUrlRule($rule,$route,$regx,$extension=null){
		 //去掉後綴名
		 !is_null($extension) && $regx = str_replace('.'.$extension,'',$regx);

		 //把路由規則和地址,分割到數組中,而後逐項匹配
		 $ruleArr = explode('/',$rule);
		 $regxArr = explode('/',$regx);

		 //$route以數組的格式傳遞,則取第一個
		 $url = is_array($route) ? $route[0] : $route;
		 $match =true;

		 //匹配檢測
		 foreach($ruleArr as $key=>$value){
		 		if(strpos($value,':')===0){
		 			if(substr($value,-2)=='\\d' && !is_numeric($regxArr[$key])){
		 				$match = false;
		 				break;
		 			}elseif(strpos($value,'^')){
		 				$stripArr = explode('|',trim(strstr($value,'^'),'^'));
		 				if(in_array($regxArr[$key],$stripArr)){
		 					$match = false;
		 					break;
		 				}
		 			}
		 		//靜態項不區分大小寫
		 		}elseif(strcasecmp($value, $regxArr[$key])!==0)	{
		 			$match = false;
		 			break;
		 		}
		 }

		 //匹配成功
		 if($match){
		 		//把動態變量寫入到數組$matches 中,同時去除靜態匹配項
		 		foreach($ruleArr as $key=>$value){
		 				if(strpos($value,':')===0){
		 					//獲取動態變量,做爲數組下標
		 					if(substr($value,-2,1)=='\\')
		 						$matchKey = substr($value,1,-2);
		 					elseif($pos=strpos($value,'^'))
		 						$matchKey =substr($value,1,$pos-1); 
		 					else
		 						$matchKey = substr($value,1);

		 					$matches[$matchKey] = array_shift($regxArr);
		 				}else
		 					array_shift($regxArr);   //去除靜態匹配項
		 		}


		 		//獲取數組中的值,目的是配合子模式進行替換
		 		$values = array_values($matches);
		 		//正則匹配替換,正則須要用'e'做爲修飾符
		 		$url = preg_replace('/:(\d+)/e','$values[\\1-1]',$url);

		 		//解析url    格式:  分組/模塊/操做?key1=value1&key2=value2
		 		if(strpos($url,'?')!==false){   
		 			 // 分組/模塊/操做?key1=value1&key2=value2
		 				$arr = parse_url($url);
		 				$paths = explode('/',$arr['path']);
		 				parse_str($arr['query'],$queryArr);
		 		}elseif(strpos($url,'/')!==false)  //分組/模塊/操做)
		 				$paths = explode('/',$url);
		 		else 							// key1=value1&key2=value2
		 				parse_str($url,$queryArr);


		 		//獲取 分組 模塊 操做
		 		if(!empty($paths)){
		 				$var['actionName'] = array_pop($paths);
		 				$var['moduleName'] = array_pop($paths);
		 				if(!empty($paths)){
		 					$groupList = 'Home,Admin';
		 					$temp = array_pop($paths);
		 					if(in_array($temp,explode(',',$groupList)))
		 						$var['groupName'] = $temp;
		 				}
		 		}
		 		//合併的到GET數組中,方便全局調用
		 		$_GET = array_merge($_GET,$var);

		 		//合併參數
		 		if(isset($queryArr))
		 			$_GET = array_merge($_GET,$queryArr);

		 		//匹配url中剩餘的參數
		 		preg_replace('/(\w+)\/([^,\/]+)/e','$tempArr[\'\\1\']=\'\\2\'',implode('/',$regxArr));
		 		if(!empty($tempArr))
		 			$_GET = array_merge($_GET,$tempArr);


		 		//route是數組的話
		 		if(is_array($route)){
		 				$route[1]=preg_replace('/:(\d+)/e','$values[\\1-1]',$route[1]);
		 				parse_str($route[1],$var);
		 				$_GET = array_merge($_GET,$var);
		 				strpos($url,'?')!==false ? $der ='&' : $der='?';
		 				//最終寫入到$_GET中的參數,包括三個部分
		 				//1.地址欄剩餘參數
		 				//2.路由地址中的參數
		 				//3.$route是數組時的第二個參數
		 				if(!empty($tempArr))
		 					$var = array_merge($tempArr,$var);
		 				$url .=$der.http_build_query($var);
		 		}
		 		$_GET['finalUrl'] = $url;
		 		//保證$_REQUEST 也能訪問
		 		$_REQUEST = array_merge($_REQUEST,$_GET);
		 		//結果
		 		print_r($_GET);
		 		return true;
		 }
		 return $match;
}


//如下是正則路由代碼: 
$rule = '/news\/read\/(\d+)\/(\d+)\/(\d+)/';
$route ='news/read?year=:1&month=:2&day=:3';
$regx = 'news/read/2012/2/21/extraparam/test.html';
$extension = 'html';
parseUrlRuleRegx($rule,$route,$regx,$extension);


/**
 *  @$rule  string    路由規則   
 *  @$route string    規則映射的新地址
 *  @$regx  string    地址欄pathinfo字符串
 *  @$extension stirng  僞靜態拓展名
 *  return  bool 
 */
function parseUrlRuleRegx($rule,$route,$regx,$extension=null){
		 !is_null($extension) && $regx = str_replace('.'.$extension,'',$regx);
		 $url = is_array($route) ? $route[0] : $route;
		 if(preg_match($rule,$regx,$matches)){
		 		$url = preg_replace('/:(\d+)/e','$matches[\\1]',$url);
		 }else
		     return false;
 		//解析url    格式:  分組/模塊/操做?key1=value1&key2=value2
 		if(strpos($url,'?')!==false){   
 			 // 分組/模塊/操做?key1=value1&key2=value2
 				$arr = parse_url($url);
 				$paths = explode('/',$arr['path']);
 				parse_str($arr['query'],$queryArr);
 		}elseif(strpos($url,'/')!==false)  //分組/模塊/操做)
 				$paths = explode('/',$url);
 		else 							// key1=value1&key2=value2
 				parse_str($url,$queryArr);


 		//獲取 分組 模塊 操做
 		if(!empty($paths)){
 				$var['actionName'] = array_pop($paths);
 				$var['moduleName'] = array_pop($paths);
 				if(!empty($paths)){
 					$groupList = 'Home,Admin';
 					$temp = array_pop($paths);
 					if(in_array($temp,explode(',',$groupList)))
 						$var['groupName'] = $temp;
 				}
 		}
 		//合併的到GET數組中,方便全局調用
 		$_GET = array_merge($_GET,$var);
 		if(isset($queryArr))
 			$_GET = array_merge($_GET,$queryArr);

 		//匹配剩餘的參數
 		$regx = str_replace($matches[0],'',$regx);
 		preg_replace('/(\w+)\/([^,\/]+)/e','$tempArr[\'\\1\']=\'\\2\'',$regx);
 		if(!empty($tempArr)){
 			$_GET = array_merge($_GET,$tempArr);
 			strpos($url,'?')!==false ? $der='&':$der='?';
 			$url .=$der.http_build_query($tempArr);
 		}
 		if(is_array($route)){
 				$route[1] = preg_replace('/:(\d+)/e','$matches[\\1]',$route[1]);
 				parse_str($route[1],$var);
 				if(!empty($var)){
 					!empty($queryArr) && $var =array_merge($queryArr,$var);
 					$_GET= array_merge($_GET,$var);
 				}
 				strpos($url,'?')!==false ? $der='&':$der='?';
 				$url .=$der.http_build_query($var);
 		}



 		$_GET['finalUrl'] = $url;
 		print_r($_GET);
 		$_REQUEST = array_merge($_GET,$_REQUEST);
 		return true;
}

//運行結果: 
//Array
// (
//     [actionName] => read
//     [moduleName] => news
//     [year] => 2012
//     [month] => 2
//     [day] => 21
//     [extraparam] => test
//     [finalUrl] => news/read?year=2012&month=2&day=21&extraparam=test
// )
// [Finished in 0.1s]
相關文章
相關標籤/搜索