123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- <?php
- namespace Qii\Router\Parse;
- /**
- * Route规则文件
- * 兼容以前版本的匹配规则
- *
- * @author Jinhui Zhu<jinhui.zhu@live.cn>2015-10-24 23:11
- * @version 1.2
- */
- class Normal
- {
- const VERSION = '1.2';
- private $config;
- public function __construct()
- {
- }
- /**
- * 设置路由规则
- * @param Array $config 路由规则
- */
- public function setConfig($config)
- {
- $this->config = $config;
- }
- /**
- * 路由转发, 转发对应的规则中xx不能为*
- *
- * @param string $url url链接
- * @param String $controller
- * @param String $action
- * @return Array ($controller, $action);
- *
- * $rules = [
- * 'api:*' => 'api\client\*:*',
- * 'api:client:admin:*' => 'api\client\{2}:*',
- * 'api:admin:*' => 'api\admin\{2}:*',
- * 'admin:*' => 'admin\{1}:*',
- * 'udp:*' => 'udp\{1}:*',
- * 's:*' => 's:index',
- * 'index:*' => 'ip:*',
- * 'shortURL:*:*' => '\shortURL\*:*'
- * ];
- *
- * $urls = [
- * '/api/client/admin' => ['controller' => 'api\client\client', 'action' => 'index'],
- * '/api/client/admin/remove' => ['controller' => 'api\client', 'action' => 'remove'],
- * '/api/url/add' => ['controller' => 'api\url', 'action' => 'add'],
- * '/api/admin/free/add' => ['controller' => 'api\admin\free', 'action' => 'add'],
- * '/admin/index' => ['controller' => 'admin\index', 'action' => 'index'],
- * '/admin/dir/add' => ['controller' => 'admin\dir', 'action' => 'add'],
- * '/udp/index' => ['controller' => 'udp', 'action' => 'index'],
- * '/udp/add' => ['controller' => 'udp', 'action' => 'index'],
- * '/s/for' => ['controller' => 's', 'action' =>'index'],
- * '/index/for' => ['controller' => 'ip', 'action' =>'for'],
- * '/usr/login/check' => ['controller' => 'usr\login', 'action' => 'check'],
- * '/shortURL/free/sss' => ['controller' => '\shortURL\free', 'action' => 'sss'],
- * ];
- */
- public function parse($url, $controller, $action)
- {
- if (!$this->config) {
- return array('controller' => $controller, 'action' => $action);
- }
- if($url == '' || $url == '/') $url = 'index/index.html';
- $url = ltrim($url, '/');
- $dirName = pathinfo($url, PATHINFO_DIRNAME);
- $dirInfo = explode('/', $dirName);
- $fileName = pathinfo(ltrim($url, '/'), PATHINFO_FILENAME);
- if ($dirName == '.') {
- $dirInfo = array();
- }
- $dirInfo[] = $fileName;
- //补全路径
- if(count($dirInfo) == 1)
- {
- $dirInfo[] = 'index';
- }
- $dir = [];
- $match = ['url' => $url, 'controller' => $controller, 'action' => $action, 'dirInfo' => $dirInfo];
- if(isset($this->config['*:*'])) {
- list($controller, $action) = $arr = explode(':', $this->config['*:*']);
- preg_match_all("/\{[\d]{1,}\}|[\*]{1}/", $this->config['*:*'], $rules);
- if(!$rules) {
- $match['match'] = '*:*';
- $match['controller'] = $controller ? $controller : 'index';
- $match['action'] = $action ? $action : 'index';
- }
- return $this->matchVal($this->config['*:*'], $dirInfo);
- }
- $lastFound = [];
- //将内容和规则做匹配
- foreach ($dirInfo AS $key => $path) {
- $dir[] = $path;
- $register = [];
- $matchLen = 0;
- foreach($this->config as $config => $val) {
- //匹配规则
- $configArr = explode(':', $config);
- $interSet = array_intersect_assoc($configArr, $dir);
- if($interSet) {
- $countInterSet = count($interSet);
- if($configArr[$countInterSet] == '*' || $configArr[$countInterSet] == $dirInfo[$dirInfo[$key]]) {
- if($matchLen < $countInterSet) {
- $register = ['rule' => $config, 'val' => $val, 'interSet' => $interSet];
- }else{
- $matchLen = $countInterSet;
- }
- }
- }
- }
- }
- if(!empty($register)){
- $lastFound = $register;
- }
- $match['match'] = $lastFound;
- //没有匹配到就直接使用/url做匹配
- if(!$match['match']) {
- $info = $this->getInfoFromDirInfo($dirInfo);
- $match['controller'] = $info['controller'];
- $match['action'] = $info['action'];
- return $match;
- }
- //解析规则
- return $this->matchVal($match['match']['val'], $dirInfo);
- /*
- preg_match_all("/\{[\d]{1,}\}|[\*]{1}/", $rulesVal, $rules);
- if(empty($rules) || empty($rules[0])) {
- $info = $this->getInfoFromDirInfo($dirInfo);
- $match['controller'] = $info['controller'];
- $match['action'] = $info['action'];
- }
- $maxIndex = 0;
- //获取*位置最大值索引值
- if(preg_match("/[\*]{1}/", $rulesVal)) {
- foreach($rules[0] as $val) {
- $val = intval(str_replace(array('{', '}'), '', $val));
- if($val > $maxIndex) $maxIndex = $val;
- }
- $maxIndex++;
- }
- $replacements = $rules[0];
- foreach($rules[0] as $key => $val)
- {
- if(preg_match("/\{[\d]{1,}\}/", $val)) {
- $index = str_replace(array('{', '}'), '', $val);
- $replacements[$key] = $dirInfo[$index] ?? 'index';
- $rulesVal = preg_replace("/\{[\d]{1,}\}/", $replacements[$key], $rulesVal, 1);
- }else if($val == '*'){
- $replacements[$key] = $dirInfo[$maxIndex] ?? 'index';
- //一次只替换一个,用于匹配多次
- $rulesVal = preg_replace("/[\*]{1}/", $replacements[$key], $rulesVal, 1);
- $maxIndex++;
- }
- }
- list($controller, $action) = explode(":", $rulesVal);
- $match['controller'] = $controller;
- $match['action'] = $action ?? 'index';
- $match['replacements'] = $replacements;
- $match['rulesVal'] = $rulesVal;
- return $match;*/
- }
- /**
- * 从路径中获取controller和action
- *
- * @param array $dirInfo 目录路径
- * @return array
- */
- protected function getInfoFromDirInfo($dirInfo)
- {
- if(count($dirInfo) >= 2) {
- $action = array_pop($dirInfo);
- $controller = join("\\", $dirInfo);
- }else{
- $controller = join("\\", $dirInfo);
- $action = 'index';
- }
- return ['controller' => $controller, 'action' => $action];
- }
- protected function matchVal($rulesVal, $dirInfo) {
- if(!$rulesVal) return [];
- preg_match_all("/\{[\d]{1,}\}|[\*]{1}/", $rulesVal, $rules);
- $maxIndex = 0;
- //获取*位置最大值索引值
- if(preg_match("/[\*]{1}/", $rulesVal)) {
- foreach($rules[0] as $val) {
- $val = intval(str_replace(array('{', '}'), '', $val));
- if($val > $maxIndex) $maxIndex = $val;
- }
- $maxIndex++;
- }
- $replacements = $rules[0];
- foreach($rules[0] as $key => $val)
- {
- if(preg_match("/\{[\d]{1,}\}/", $val)) {
- $index = str_replace(array('{', '}'), '', $val);
- $replacements[$key] = $dirInfo[$index] ?? 'index';
- $rulesVal = preg_replace("/\{[\d]{1,}\}/", $replacements[$key], $rulesVal, 1);
- }else if($val == '*'){
- $replacements[$key] = $dirInfo[$maxIndex] ?? 'index';
- //一次只替换一个,用于匹配多次
- $rulesVal = preg_replace("/[\*]{1}/", $replacements[$key], $rulesVal, 1);
- $maxIndex++;
- }
- }
- list($controller, $action) = explode(":", $rulesVal);
- $match['controller'] = $controller;
- $match['action'] = $action ?? 'index';
- $match['replacements'] = $replacements;
- $match['rulesVal'] = $rulesVal;
- return $match;
- }
- }
|