Normal.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <?php
  2. namespace Qii\Router\Parse;
  3. use Qii\Config\Register;
  4. /**
  5. * Route规则文件
  6. * 兼容以前版本的匹配规则
  7. *
  8. * @author Jinhui Zhu<jinhui.zhu@live.cn>2015-10-24 23:11
  9. * @version 1.2
  10. */
  11. class Normal
  12. {
  13. const VERSION = '1.2';
  14. private $config;
  15. public function __construct()
  16. {
  17. }
  18. /**
  19. * 设置路由规则
  20. * @param Array $config 路由规则
  21. */
  22. public function setConfig($config)
  23. {
  24. $this->config = $config;
  25. }
  26. /**
  27. * 路由转发, 转发对应的规则中xx不能为*
  28. *
  29. * @param string $url url链接
  30. * @param String $controller
  31. * @param String $action
  32. * @return Array ($controller, $action);
  33. *
  34. * $rules = [
  35. * 'api:*' => 'api\client\*:*',
  36. * 'api:client:admin:*' => 'api\client\{2}:*',
  37. * 'api:admin:*' => 'api\admin\{2}:*',
  38. * 'admin:*' => 'admin\{1}:*',
  39. * 'udp:*' => 'udp\{1}:*',
  40. * 's:*' => 's:index',
  41. * 'index:*' => 'ip:*',
  42. * 'shortURL:*:*' => '\shortURL\*:*'
  43. * ];
  44. *
  45. * $urls = [
  46. * '/api/client/admin' => ['controller' => 'api\client\client', 'action' => 'index'],
  47. * '/api/client/admin/remove' => ['controller' => 'api\client', 'action' => 'remove'],
  48. * '/api/url/add' => ['controller' => 'api\url', 'action' => 'add'],
  49. * '/api/admin/free/add' => ['controller' => 'api\admin\free', 'action' => 'add'],
  50. * '/admin/index' => ['controller' => 'admin\index', 'action' => 'index'],
  51. * '/admin/dir/add' => ['controller' => 'admin\dir', 'action' => 'add'],
  52. * '/udp/index' => ['controller' => 'udp', 'action' => 'index'],
  53. * '/udp/add' => ['controller' => 'udp', 'action' => 'index'],
  54. * '/s/for' => ['controller' => 's', 'action' =>'index'],
  55. * '/index/for' => ['controller' => 'ip', 'action' =>'for'],
  56. * '/usr/login/check' => ['controller' => 'usr\login', 'action' => 'check'],
  57. * '/shortURL/free/sss' => ['controller' => '\shortURL\free', 'action' => 'sss'],
  58. * ];
  59. */
  60. public function parse($url, $controller, $action)
  61. {
  62. if (!$this->config) {
  63. return array('controller' => $controller, 'action' => $action);
  64. }
  65. if($url == '' || $url == '/') $url = 'index/index.html';
  66. $url = ltrim($url, '/');
  67. $dirName = pathinfo($url, PATHINFO_DIRNAME);
  68. $dirInfo = explode('/', $dirName);
  69. $fileName = pathinfo(ltrim($url, '/'), PATHINFO_FILENAME);
  70. if ($dirName == '.') {
  71. $dirInfo = array();
  72. }
  73. $dirInfo[] = $fileName;
  74. //补全路径
  75. if(count($dirInfo) == 1)
  76. {
  77. $dirInfo[] = 'index';
  78. }
  79. $dir = [];
  80. $match = ['url' => $url, 'controller' => $controller, 'action' => $action, 'dirInfo' => $dirInfo];
  81. if(isset($this->config['*:*'])) {
  82. list($controller, $action) = $arr = explode(':', $this->config['*:*']);
  83. preg_match_all("/\{[\d]{1,}\}|[\*]{1}/", $this->config['*:*'], $rules);
  84. if(!$rules) {
  85. $match['match'] = '*:*';
  86. $match['controller'] = $controller ? $controller : 'index';
  87. $match['action'] = $action ? $action : 'index';
  88. }
  89. return $this->matchVal($this->config['*:*'], $dirInfo);
  90. }
  91. $lastFound = [];
  92. //将内容和规则做匹配
  93. foreach ($dirInfo AS $key => $path) {
  94. $dir[] = $path;
  95. $register = [];
  96. $matchLen = 0;
  97. foreach($this->config as $config => $val) {
  98. //匹配规则
  99. $configArr = explode(':', $config);
  100. $interSet = array_intersect_assoc($configArr, $dir);
  101. if($interSet) {
  102. if($configArr == $interSet) {
  103. $register = ['rule' => $config, 'val' => $val, 'interSet' => $interSet];
  104. break;
  105. }
  106. $countInterSet = count($interSet);
  107. if(isset($configArr[$countInterSet]) && ($configArr[$countInterSet] == '*' || (isset($dirInfo[$dirInfo[$key]]) && $configArr[$countInterSet] == $dirInfo[$dirInfo[$key]]))) {
  108. if($matchLen < $countInterSet) {
  109. $register = ['rule' => $config, 'val' => $val, 'interSet' => $interSet];
  110. }else{
  111. $matchLen = $countInterSet;
  112. }
  113. }
  114. }
  115. }
  116. }
  117. if(!empty($register)){
  118. $lastFound = $register;
  119. }
  120. $match['match'] = $lastFound;
  121. //没有匹配到就直接使用/url做匹配
  122. if(!$match['match']) {
  123. $info = $this->getInfoFromDirInfo($dirInfo);
  124. $match['controller'] = $info['controller'];
  125. $match['action'] = $info['action'];
  126. return $match;
  127. }
  128. //解析规则
  129. return $this->matchVal($match['match']['val'], $dirInfo);
  130. }
  131. /**
  132. * 从路径中获取controller和action
  133. *
  134. * @param array $dirInfo 目录路径
  135. * @return array
  136. */
  137. protected function getInfoFromDirInfo($dirInfo)
  138. {
  139. if(count($dirInfo) >= 2) {
  140. $action = array_pop($dirInfo);
  141. $controller = join("\\", $dirInfo);
  142. }else{
  143. $controller = join("\\", $dirInfo);
  144. $action = 'index';
  145. }
  146. return ['controller' => $controller, 'action' => $action];
  147. }
  148. protected function matchVal($rulesVal, $dirInfo) {
  149. if(!$rulesVal) return [];
  150. preg_match_all("/\{[\d]{1,}\}|[\*]{1}/", $rulesVal, $rules);
  151. $maxIndex = 0;
  152. //获取*位置最大值索引值
  153. if(preg_match("/[\*]{1}/", $rulesVal)) {
  154. foreach($rules[0] as $val) {
  155. $val = intval(str_replace(array('{', '}'), '', $val));
  156. if($val > $maxIndex) $maxIndex = $val;
  157. }
  158. $maxIndex++;
  159. }
  160. $replacements = $rules[0];
  161. foreach($rules[0] as $key => $val)
  162. {
  163. if(preg_match("/\{[\d]{1,}\}/", $val)) {
  164. $index = str_replace(array('{', '}'), '', $val);
  165. $replacements[$key] = isset($dirInfo[$index]) && $dirInfo[$index] != '' ? $dirInfo[$index] : Register::get("APP_DEFAULT_ACTION");
  166. $rulesVal = preg_replace("/\{[\d]{1,}\}/", $replacements[$key], $rulesVal, 1);
  167. }else if($val == '*'){
  168. $replacements[$key] = isset($dirInfo[$maxIndex]) ? $dirInfo[$maxIndex] : 'index';
  169. //一次只替换一个,用于匹配多次
  170. $rulesVal = preg_replace("/[\*]{1}/", $replacements[$key], $rulesVal, 1);
  171. $maxIndex++;
  172. }
  173. }
  174. list($controller, $action) = explode(":", $rulesVal);
  175. $match['controller'] = $controller;
  176. $match['action'] = $action ? $action: Register::get("APP_DEFAULT_ACTION");
  177. $match['replacements'] = $replacements;
  178. $match['rulesVal'] = $rulesVal;
  179. return $match;
  180. }
  181. }