Route.class.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <?php
  2. namespace KIF;
  3. use KIF\Core\Request;
  4. use KIF\Core\Config;
  5. use KIF\String\String;
  6. use KIF\Math\Math;
  7. /**
  8. *
  9. * 路由类
  10. * @author gaoxiaogang
  11. *
  12. */
  13. class Route {
  14. /**
  15. *
  16. * Enter description here ...
  17. * @var array 格式:array(
  18. * $route_file => array(
  19. * 'instance' => (Route),
  20. * 'rules' => array(
  21. * (string) $rewrite_pattern => (array) $rule,
  22. * ... ,
  23. * ),
  24. * 'reverse_rules' => array(
  25. * (string)$fingerprint => (string)$rewrite_pattern,
  26. * ... ,
  27. * ),
  28. * ),
  29. * );
  30. */
  31. static private $structs;
  32. protected $struct;
  33. # 禁止被外部new
  34. private function __construct($route_file) {
  35. if (!file_exists($route_file) || !is_file($route_file)) {
  36. $route_rules = array();
  37. } else {
  38. $route_rules = include($route_file);
  39. }
  40. $rules = array();
  41. $reverse_rules = array();
  42. if (!$route_rules || !is_array($route_rules)) {
  43. self::$structs[$route_file]['rules'] = $rules;
  44. self::$structs[$route_file]['reverse_rules'] = $reverse_rules;
  45. return;
  46. }
  47. foreach ($route_rules as $rewrite_pattern => $rule) {
  48. if (!isset($rule['a']) || !$rule['a']) {
  49. $rule['a'] = 'default';
  50. }
  51. $fingerprint = $this->generateFingerprint($rule);
  52. $rules[$rewrite_pattern] = $rule;
  53. $reverse_rules[$fingerprint] = $rewrite_pattern;
  54. }
  55. self::$structs[$route_file]['rules'] = $rules;
  56. self::$structs[$route_file]['reverse_rules'] = $reverse_rules;
  57. }
  58. /**
  59. *
  60. * 生成指纹,方便反向rewrite时高效查找。
  61. * @param array $args
  62. * @return string
  63. */
  64. private function generateFingerprint($args) {
  65. if (!isset($args['a'])) {
  66. $args['a'] = 'default';
  67. }
  68. $arg_eles = array_combine(array_keys($args), array_fill(0, count($args), null));
  69. if (isset($args['a']))
  70. $arg_eles['a'] = $args['a'];
  71. if (isset($args['c']))
  72. $arg_eles['c'] = $args['c'];
  73. ksort($arg_eles);
  74. return Math::md5_16(print_r($arg_eles, true));
  75. }
  76. /**
  77. *
  78. * @return KIF\Route
  79. */
  80. static public function getInstance() {
  81. $route_file = Config::getInstance()->get('route_file');
  82. $route_file = realpath($route_file);
  83. if (!isset(self::$structs[$route_file])) {
  84. self::$structs[$route_file]['instance'] = new self($route_file);
  85. }
  86. self::$structs[$route_file]['instance']->struct = & self::$structs[$route_file];
  87. return self::$structs[$route_file]['instance'];
  88. }
  89. /**
  90. *
  91. * 实现细节:
  92. * 根据当前app的路由配置,查找到指定条目,并将当前path里携带的参数存放进 $_GET和$_REQUEST变量里
  93. * 对当前请求路由
  94. *
  95. */
  96. public function rewrite() {
  97. $path = Request::getInstance()->path();
  98. $rules = $this->struct['rules'];
  99. foreach ($rules as $pattern => $rule) {
  100. $pattern = "#^{$pattern}$#";
  101. if (preg_match($pattern, $path, $matches)) {
  102. foreach ($rule as $param => $paramVal) {
  103. if ($paramVal{0} != '$') {
  104. $_GET[$param] = $paramVal;
  105. $_REQUEST[$param] = $paramVal;
  106. } else {
  107. $match_pos = substr($paramVal, 1);
  108. if (Verify::naturalNumber($match_pos)) {
  109. $_GET[$param] = $matches[$match_pos];
  110. $_REQUEST[$param] = $matches[$match_pos];
  111. }
  112. }
  113. }
  114. break;
  115. }
  116. }
  117. }
  118. /**
  119. *
  120. * 获取经过路由后得到的请求参数。目前该方法被 Request::pageUrlTpl使用
  121. * @return array 如果没有对应的路由,返回空数组
  122. */
  123. public function getsRouteParams() {
  124. $route_params = array();
  125. $path = Request::getInstance()->path();
  126. $rules = $this->struct['rules'];
  127. foreach ($rules as $pattern => $rule) {
  128. $pattern = "#^{$pattern}$#";
  129. if (preg_match($pattern, $path, $matches)) {
  130. foreach ($rule as $param => $paramVal) {
  131. if ($paramVal{0} != '$') {
  132. $route_params[$param] = $paramVal;
  133. } else {
  134. $match_pos = substr($paramVal, 1);
  135. if (Verify::naturalNumber($match_pos)) {
  136. $route_params[$param] = $matches[$match_pos];
  137. }
  138. }
  139. }
  140. break;
  141. }
  142. }
  143. return $route_params;
  144. }
  145. /**
  146. *
  147. * 反向rewrite。通过 $args 给定的参数,逆向rewrite规则,获取rewrite的url
  148. * @param array $args 给定的参数值
  149. * @return String
  150. */
  151. public function reverse(array $args) {
  152. if (!$args) {
  153. return false;
  154. }
  155. if (!isset($args['a'])) {
  156. $args['a'] = 'default';
  157. }
  158. $arg_fingerprint = $this->generateFingerprint($args);
  159. if (isset($this->struct['reverse_rules'][$arg_fingerprint])) {
  160. $rewrite_pattern = $this->struct['reverse_rules'][$arg_fingerprint];
  161. if (strpos($rewrite_pattern, '(') === false) {
  162. return $rewrite_pattern;
  163. }
  164. $rule = $this->struct['rules'][$rewrite_pattern];
  165. $rule = array_filter($rule, function ($tmpV) {
  166. if ($tmpV{0} != '$') {
  167. return false;
  168. }
  169. return $tmpV;
  170. });
  171. $match_times = 0;
  172. $url = preg_replace_callback('#\([^)]+\)#', function ($matches) use (& $match_times, $rule, $args) {
  173. $match_times++;
  174. $key = array_search("\${$match_times}", $rule);
  175. if (!$key) {
  176. return false;
  177. }
  178. if (!isset($args[$key])) {
  179. return false;
  180. }
  181. return $args[$key];
  182. }, $rewrite_pattern);
  183. if (is_null($url)) {//说明发生错误了。
  184. return String::jointUrl('', $args);
  185. }
  186. return $url;
  187. }
  188. return String::jointUrl('', $args);
  189. }
  190. }