如何实现一个php框架系列文章【4】url路由管理,直接通过url参数访问业务模块($app)中控制器($ctl)里的函数($act) 我们支持3种路由模式 普通模式 _a=$app, _u=$ctl.$act 最简单的方式,专注实现业务$act函数,不需要再写额外代码 为什么参数名前面要加下划线就不解释了 easy模式 _easy=$app.$tpl.$ctl.$act _easy=$app.$ctl.$act 在web开发中,通常我们在$act中输出一个前端页面, easy模式下,如果未实现$act处理函数,会自动寻找并显示对应的前端模板文件。 对于简单的展示页面适合使用这种路由模式 url重写模式(需要nginx或apache配置) apache: ^rewrite[\.\/](.*)$ /index.php?_rewrite=$1 [R,QSA] nginx: rewrite ^/rewrite[\.\/](.*)$ /index.php?_rewrite=$1 last; rewrite.{$app}.{$ctl}.{$act}.{$params}.html 或更加优雅的目录式访问方式 rewrite/{$app}/{$ctl}/{$act}/{$params}.html 其中$params为选填参数部分.格式为urlencode后的参数列表 如果想传递sp_uid=1&d=1.2&p=sb, 那么$params = sp_uid%3D1%26d%3D1.2%26p%3Ds%2Fb 或sp_uid/1/d/1.2/p/sb 在某些要求url中不能带?&特殊字符的场景下可以使用这种模式 1. 为了能通过qq oauth2登陆验证,需要配置重写规则 rewrite.thirdlogin.index.qqcallback.sp_uid%3D1.php 2. 资源静态化 rewrite.upload.index.out.uidm%3D310ef4b.png 3. 支付回调 rewrite.pay.weixin.native2_notify.php 4. 微信开放平台授权回调 rewrite/web/component/message/_app_id/xxxxxxx.php 部分实现代码12345678910111213 $a = (!empty($_REQUEST['_a']) && is_string($_REQUEST['_a'])) ? $_REQUEST['_a'] : 'web'; if (!preg_match('/^[\w\.]+$/', $a)) { exit('invalid _app name! ' . htmlspecialchars($a)); } $GLOBALS['_UCT']['APP'] = !empty($a) ? strtolower($a) : 'web'; $u = (!empty($_REQUEST['_u']) && is_string($_REQUEST['_u'])) ? $_REQUEST['_u'] : 'index.index'; if (!preg_match('/^[\w\.]+$/', $u)) { exit('invalid _url name! ' . htmlspecialchars($u)); } $u = explode('.', $u, 2); $GLOBALS['_UCT']['CTL'] = !empty($u['0']) ? strtolower($u['0']) : 'index'; $GLOBALS['_UCT']['ACT'] = !empty($u['1']) ? strtolower($u['1']) : 'index'; easy模式1234567891011121314151617181920212223242526 //easy 模式直接访问模板tpl if (!empty($_REQUEST['_easy']) && is_string($_REQUEST['_easy'])) { $easy = explode('.', $_REQUEST['_easy']); switch (count($easy)) { case 4: $_GET['_u'] = $_REQUEST['_u'] = $easy[2] . '.' . $easy[3]; if (preg_match('/^[\w\.]+$/', $easy[1])) { $GLOBALS['_UCT']['TPL'] = $easy[1]; } $_GET['_a'] = $_REQUEST['_a'] = $easy[0]; break; case 3: $_GET['_u'] = $_REQUEST['_u'] = $easy[1] . '.' . $easy[2]; $_GET['_a'] = $_REQUEST['_a'] = $easy[0]; break; case 2: $_GET['_u'] = $_REQUEST['_u'] = $easy[1]; $_GET['_a'] = $_REQUEST['_a'] = $easy[0]; break; case 1: $_GET['_a'] = $_REQUEST['_a'] = $easy[0]; break; default: exit('invalid _easy param! ' . htmlspecialchars($_REQUEST['_easy'])); } } rewrite模式123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051 //url重写模式 if (!empty($_REQUEST['_rewrite']) && is_string($_REQUEST['_rewrite'])) { //1.支持apache 重写模式下?后的参数缺失的情况 if(stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') === false) { $_REQUEST['_rewrite'] = urldecode(substr($_SERVER['QUERY_STRING'], strlen('_rewrite='))); } //2. 丢弃_rewrite中的后缀名 $rewrite = substr($_REQUEST['_rewrite'], 0, strrpos($_REQUEST['_rewrite'], '.')); //3. 支持/作为分隔符 $sp = '.'; for($i = 0; $i strlen($rewrite); $i++) { if(in_array($rewrite[$i], array('.', '/'))) { $sp = $rewrite[$i]; break; } } $rewrite = explode($sp, $rewrite, 4); //最后1段是必填后缀名 switch(count($rewrite)) { case 3: case 4: { $_GET['_a'] = $_REQUEST['_a'] = $rewrite[0]; $_GET['_u'] = $_REQUEST['_u'] = $rewrite[1].'.'.$rewrite[2]; if(!empty($rewrite[3])) { if(strpos($rewrite[3], '/')) { $params = explode('/', $rewrite[3]); for($i=0; $i+1count($params); $i+=2) { $_REQUEST[urldecode($params[$i])] = urldecode($params[$i+1]); } } else { foreach(explode('&', $rewrite[3]) as $p) { list($k, $v) = explode('=', $p, 2); $_REQUEST[urldecode($k)] = urldecode($v); } } } break; } case 2: $_GET['_a'] = $_REQUEST['_a'] = $rewrite[0]; $_GET['_u'] = $_REQUEST['_u'] = $rewrite[1]; break; case 1: $_GET['_a'] = $_REQUEST['_a'] = $rewrite[0]; break; default: break; } }
09-19 00:37