Dispatcher.class.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. // $Id$
  12. /**
  13. +------------------------------------------------------------------------------
  14. * ThinkPHP内置的Dispatcher类
  15. * 完成URL解析、路由和调度
  16. +------------------------------------------------------------------------------
  17. * @category Think
  18. * @package Think
  19. * @subpackage Util
  20. * @author liu21st <liu21st@gmail.com>
  21. * @version $Id$
  22. +------------------------------------------------------------------------------
  23. */
  24. class Dispatcher extends Think
  25. {//类定义开始
  26. /**
  27. +----------------------------------------------------------
  28. * URL映射到控制器
  29. +----------------------------------------------------------
  30. * @access public
  31. +----------------------------------------------------------
  32. * @return void
  33. +----------------------------------------------------------
  34. */
  35. static public function dispatch()
  36. {
  37. $urlMode = C('URL_MODEL');
  38. if($urlMode == URL_REWRITE ) {
  39. //当前项目地址
  40. $url = dirname(_PHP_FILE_);
  41. if($url == '/' || $url == '\\')
  42. $url = '';
  43. define('PHP_FILE',$url);
  44. }elseif($urlMode == URL_COMPAT){
  45. define('PHP_FILE',_PHP_FILE_.'?'.C('VAR_PATHINFO').'=');
  46. }else {
  47. //当前项目地址
  48. define('PHP_FILE',_PHP_FILE_);
  49. }
  50. if($urlMode) {
  51. // 获取PATHINFO信息
  52. self::getPathInfo();
  53. if (!empty($_GET) && !isset($_GET[C('VAR_ROUTER')])) {
  54. $_GET = array_merge (self :: parsePathInfo(),$_GET);
  55. $_varGroup = C('VAR_GROUP'); // 分组变量
  56. $_varModule = C('VAR_MODULE');
  57. $_varAction = C('VAR_ACTION');
  58. $_depr = C('URL_PATHINFO_DEPR');
  59. $_pathModel = C('URL_PATHINFO_MODEL');
  60. if (!C('APP_GROUP_LIST')) {
  61. $_GET[$_varGroup] = '';
  62. }
  63. // 设置默认模块和操作
  64. if(empty($_GET[$_varModule])) $_GET[$_varModule] = C('DEFAULT_MODULE');
  65. if(empty($_GET[$_varAction])) $_GET[$_varAction] = C('DEFAULT_ACTION');
  66. // 组装新的URL地址
  67. $_URL = '/';
  68. if($_pathModel==2) {
  69. // groupName/modelName/actionName/
  70. $_URL .= $_GET[$_varGroup].($_GET[$_varGroup]?$_depr:'').$_GET[$_varModule].$_depr.$_GET[$_varAction].$_depr;
  71. unset($_GET[$_varGroup],$_GET[$_varModule],$_GET[$_varAction]);
  72. }
  73. foreach ($_GET as $_VAR => $_VAL) {
  74. if('' != trim($_GET[$_VAR])) {
  75. if($_pathModel==2) {
  76. $_URL .= $_VAR.$_depr.rawurlencode($_VAL).$_depr;
  77. }else{
  78. $_URL .= $_VAR.'/'.rawurlencode($_VAL).'/';
  79. }
  80. }
  81. }
  82. if($_depr==',') $_URL = substr($_URL, 0, -1).'/';
  83. //重定向成规范的URL格式
  84. redirect(PHP_FILE.$_URL);
  85. }else{
  86. if(C('URL_ROUTER_ON')) self::routerCheck(); // 检测路由规则
  87. //给_GET赋值 以保证可以按照正常方式取_GET值
  88. $_GET = array_merge(self :: parsePathInfo(),$_GET);
  89. //保证$_REQUEST正常取值
  90. $_REQUEST = array_merge($_POST,$_GET);
  91. }
  92. }else{
  93. // 普通URL模式 检查路由规则
  94. if(isset($_GET[C('VAR_ROUTER')])) self::routerCheck();
  95. }
  96. }
  97. /**
  98. +----------------------------------------------------------
  99. * 分析PATH_INFO的参数
  100. +----------------------------------------------------------
  101. * @access private
  102. +----------------------------------------------------------
  103. * @return void
  104. +----------------------------------------------------------
  105. */
  106. private static function parsePathInfo()
  107. {
  108. $pathInfo = array();
  109. if(C('URL_PATHINFO_MODEL')==2){
  110. $paths = explode(C('URL_PATHINFO_DEPR'),trim($_SERVER['PATH_INFO'],'/'));
  111. $groupApp = C('APP_GROUP_LIST');
  112. if ($groupApp) {
  113. $arr = array_map('strtolower',explode(',',$groupApp));
  114. $pathInfo[C('VAR_GROUP')] = in_array(strtolower($paths[0]),$arr)? array_shift($paths) : '';
  115. }
  116. $pathInfo[C('VAR_MODULE')] = array_shift($paths);
  117. $pathInfo[C('VAR_ACTION')] = array_shift($paths);
  118. for($i = 0, $cnt = count($paths); $i <$cnt; $i++){
  119. if(isset($paths[$i+1])) {
  120. $pathInfo[$paths[$i]] = (string)$paths[++$i];
  121. }elseif($i==0) {
  122. $pathInfo[$pathInfo[C('VAR_ACTION')]] = (string)$paths[$i];
  123. }
  124. }
  125. }else {
  126. $res = preg_replace('@(\w+)'.C('URL_PATHINFO_DEPR').'([^,\/]+)@e', '$pathInfo[\'\\1\']="\\2";', $_SERVER['PATH_INFO']);
  127. }
  128. return $pathInfo;
  129. }
  130. /**
  131. +----------------------------------------------------------
  132. * 获得服务器的PATH_INFO信息
  133. +----------------------------------------------------------
  134. * @access public
  135. +----------------------------------------------------------
  136. * @return void
  137. +----------------------------------------------------------
  138. */
  139. public static function getPathInfo()
  140. {
  141. if(!empty($_GET[C('VAR_PATHINFO')])) {
  142. // 兼容PATHINFO 参数
  143. $path = $_GET[C('VAR_PATHINFO')];
  144. unset($_GET[C('VAR_PATHINFO')]);
  145. }elseif(!empty($_SERVER['PATH_INFO'])){
  146. $pathInfo = $_SERVER['PATH_INFO'];
  147. if(0 === strpos($pathInfo,$_SERVER['SCRIPT_NAME']))
  148. $path = substr($pathInfo, strlen($_SERVER['SCRIPT_NAME']));
  149. else
  150. $path = $pathInfo;
  151. }elseif(!empty($_SERVER['ORIG_PATH_INFO'])) {
  152. $pathInfo = $_SERVER['ORIG_PATH_INFO'];
  153. if(0 === strpos($pathInfo, $_SERVER['SCRIPT_NAME']))
  154. $path = substr($pathInfo, strlen($_SERVER['SCRIPT_NAME']));
  155. else
  156. $path = $pathInfo;
  157. }elseif (!empty($_SERVER['REDIRECT_PATH_INFO'])){
  158. $path = $_SERVER['REDIRECT_PATH_INFO'];
  159. }elseif(!empty($_SERVER["REDIRECT_Url"])){
  160. $path = $_SERVER["REDIRECT_Url"];
  161. if(empty($_SERVER['QUERY_STRING']) || $_SERVER['QUERY_STRING'] == $_SERVER["REDIRECT_QUERY_STRING"])
  162. {
  163. $parsedUrl = parse_url($_SERVER["REQUEST_URI"]);
  164. if(!empty($parsedUrl['query'])) {
  165. $_SERVER['QUERY_STRING'] = $parsedUrl['query'];
  166. parse_str($parsedUrl['query'], $GET);
  167. $_GET = array_merge($_GET, $GET);
  168. reset($_GET);
  169. }else {
  170. unset($_SERVER['QUERY_STRING']);
  171. }
  172. reset($_SERVER);
  173. }
  174. }
  175. if(C('URL_HTML_SUFFIX') && !empty($path)) {
  176. $suffix = substr(C('URL_HTML_SUFFIX'),1);
  177. $path = preg_replace('/\.'.$suffix.'$/','',$path);
  178. }
  179. $_SERVER['PATH_INFO'] = empty($path) ? '/' : $path;
  180. }
  181. /**
  182. +----------------------------------------------------------
  183. * 路由检测
  184. +----------------------------------------------------------
  185. * @access public
  186. +----------------------------------------------------------
  187. * @return void
  188. +----------------------------------------------------------
  189. */
  190. static public function routerCheck() {
  191. // 搜索路由映射 把路由名称解析为对应的模块和操作
  192. $routes = C('_routes_');
  193. if(!empty($routes)) {
  194. if(isset($_GET[C('VAR_ROUTER')])) {
  195. // 存在路由变量
  196. $routeName = $_GET[C('VAR_ROUTER')];
  197. unset($_GET[C('VAR_ROUTER')]);
  198. }else{
  199. $paths = explode(C('URL_PATHINFO_DEPR'),trim($_SERVER['PATH_INFO'],'/'));
  200. // 获取路由名称
  201. $routeName = array_shift($paths);
  202. }
  203. if(isset($routes[$routeName])) {
  204. // 读取当前路由名称的路由规则
  205. // 路由定义格式 routeName=>array(‘模块名称’,’操作名称’,’参数定义’,’额外参数’)
  206. $route = $routes[$routeName];
  207. if(strpos($route[0],C('APP_GROUP_DEPR'))) {
  208. $array = explode(C('APP_GROUP_DEPR'),$route[0]);
  209. $_GET[C('VAR_MODULE')] = array_pop($array);
  210. $_GET[C('VAR_GROUP')] = implode(C('APP_GROUP_DEPR'),$array);
  211. }else{
  212. $_GET[C('VAR_MODULE')] = $route[0];
  213. }
  214. $_GET[C('VAR_ACTION')] = $route[1];
  215. // 获取当前路由参数对应的变量
  216. if(!isset($_GET[C('VAR_ROUTER')])) {
  217. $vars = explode(',',$route[2]);
  218. for($i=0;$i<count($vars);$i++)
  219. $_GET[$vars[$i]] = array_shift($paths);
  220. // 解析剩余的URL参数
  221. $res = preg_replace('@(\w+)\/([^,\/]+)@e', '$_GET[\'\\1\']="\\2";', implode('/',$paths));
  222. }
  223. if(isset($route[3])) {
  224. // 路由里面本身包含固定参数 形式为 a=111&b=222
  225. parse_str($route[3],$params);
  226. $_GET = array_merge($_GET,$params);
  227. }
  228. //unset($_SERVER['PATH_INFO']);
  229. }elseif(isset($routes[$routeName.'@'])){
  230. // 存在泛路由
  231. // 路由定义格式 routeName@=>array(
  232. // array('路由正则1',‘模块名称’,’操作名称’,’参数定义’,’额外参数’),
  233. // array('路由正则2',‘模块名称’,’操作名称’,’参数定义’,’额外参数’),
  234. // ...)
  235. $routeItem = $routes[$routeName.'@'];
  236. $regx = str_replace($routeName,'',trim($_SERVER['PATH_INFO'],'/'));
  237. foreach ($routeItem as $route){
  238. $rule = $route[0];// 路由正则
  239. // 匹配路由定义
  240. if(preg_match($rule,$regx,$matches)) {
  241. // 检测是否存在分组 2009/06/23
  242. $temp = explode(C('APP_GROUP_DEPR'),$route[1]);
  243. if ($temp[1]) {
  244. $_GET[C('VAR_GROUP')] = $temp[0];
  245. $_GET[C('VAR_MODULE')] = $temp[1];
  246. }else {
  247. $_GET[C('VAR_MODULE')] = $temp[0];
  248. }
  249. $_GET[C('VAR_ACTION')] = $route[2];
  250. // 获取当前路由参数对应的变量
  251. if(!isset($_GET[C('VAR_ROUTER')])) {
  252. $vars = explode(',',$route[3]);
  253. for($i=0;$i<count($vars);$i++)
  254. $_GET[$vars[$i]] = $matches[$i+1];
  255. // 解析剩余的URL参数
  256. $res = preg_replace('@(\w+)\/([^,\/]+)@e', '$_GET[\'\\1\']="\\2";', str_replace($matches[0],'',$regx));
  257. }
  258. if(isset($route[4])) {
  259. // 路由里面本身包含固定参数 形式为 a=111&b=222
  260. parse_str($route[4],$params);
  261. $_GET = array_merge($_GET,$params);
  262. }
  263. break;
  264. }
  265. }
  266. }
  267. }
  268. }
  269. }//类定义结束
  270. ?>