php简单路由实现
需求
实现自定义url对应控制器及内部方法,友好url传参
服务器配置
- nginx
nginx.conf
location / {
rewrite ^/service/(.*)$ /index.php?_url=$1 last;
}
- apache
.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^$ index.php?_url= [QSA,PT,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?_url=$1 [QSA,L]
</IfModule>
以上配置文件是实现路由的关键,会将用户访问的 service/abc
在服务器转换成 service/index.php?_url=abc
,从而实现自定义路由
关键源码解析
$route=include "web.php";//在此处引入路由文件
class Router
{
private $route;//一个私有变量
public function __construct(array $route) //执行一个构造方法
{
$this->route = $route; //将路由赋值到类里
}
public function parse($url)
{
if(empty($url)) {//如果是空的,则访问默认的路由
list($controller, $action) = explode('@', $this->route['_DEFAULT_']);
return array(
'controller' => $controller,
'action' => $action,
'params' => array(),
);
}
//这里定义了实现 any 和num过滤的正则
$trans = array(
':any' => '[^/]+',
':num' => '[0-9]+'
);
//循环查找路由配置文件,匹配路由和控制器方法
foreach($this->route as $u => $d) {
$pattern = '#^' . strtr($u, $trans) . '$#';//过滤参数
if(preg_match($pattern, $url, $params)) {
list($controller, $action) = explode('@', $d);//将切割后的变量使用list赋值
array_shift($params);
return array(//这里返回即将执行的控制器、方法、参数
'controller' => $controller,
'action' => $action,
'params' => $params,
);
}
}
//如果找不到则返回404
header("HTTP/1.0 404 Not Found");
exit('<style>body{margin:0}</style><div style="padding:15px;font-size:20px;background: #B0413E;color: #fff;">Sorry, the page you are looking for could not be found.<br>This URL could not be found in the route.<br>Please check your request address or your defined route param.</div>');
}
}
$r = new Router($route);//启动执行路由类
$arr = $r->parse($_GET['_url']);//获取url上_url后的参数 也就是访问的路由,将其分割找出控制器和方法
require('Controller/'.$arr['controller'] . '.php');
//执行控制器的功能
$dispatcher = new $arr['controller'];//引入对应的控制器
call_user_func_array(array($dispatcher, $arr['action']), $arr['params']);//调用控制器方法并传入参数
源码结构
├── Controller # 控制权目录
├── index.php # 路由入口
├── web.php #路由配置文件
└── .htaccess apache服务器伪静态配置文件
使用方法
PHP环境配置(修改php.ini)
建议环境PHP7+
打开exif扩展
打开com_dotnet扩展
设置session.auto_start = 1
设置post_max_size = 500M
MYSQL环境配置(修改.ini)
#此处是设置mysql5.7允许使用group_by
在my.ini 的[mysqld]下添加sql_mode=STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
Apache环境配置(修改.http.conf)
打开LoadModule rewrite_module modules/mod_rewrite.so 如果前面有#去掉#
设置 Options Index FollowSymLinks Includes ExecCGI 为 Options FollowSymLinks Includes ExecCGI
项目内环境配置
修改service下server.php(socket服务)的$conf变量
修改service\Controller下ServerController.php(数据服务)的$conf变量
$conf=[
"HOST"=>"127.0.0.1", 为数据库所在地址
"PORT"=>"3306", 为数据库端口
"DATABASE"=>"db", 为数据库名
"USERNAME"=>"root", 为数据库用户名
"PASSWORD"=>"123456", 为数据库密码
"ADDRESS"=>"/abc/123" 为项目绝对路径地址(index.php文件所在地址)
];
路由配置
路由配置文件在service下的web.php
路由写法为 'xx/test/(:any)'=>'Controller@function',
xx/test为url部分后面对应控制器及控制器内的方法
(:any)为路由参数,对应方法所需参数,可带多个(:any)为任何字符,(:num)为数字
例如配置了 'aa/test/(:any)/(:any)'=>'Controller@test1'
,test1需要接受两个参数,test后的(:any)
则为传入test1方法的参数
在浏览器地址访问 http://domain.com/aa/test/123/666
在test1方法里输出 则会接收到 123
666
部署成功效果
此时的地址不应该出现index.php
访问你定义的路由
例如我定义了 'user/login' => 'UserController@login',
这个地址将会访问用户控制器里的登录方法,这里使用了post传参,所以路由没有参数
在浏览器访问http://domain.com/user/login
由于我返回了json,在浏览器看到的效果则是
这里经过转义后则是
[{
msg: "密码错误",
state: "error"
}]
不存在的路由或缺少参数
同样访问上面的http://domain.com/user/login/abc
不同的是在login后面多了/abc
那么浏览器将会显示
以上 便是一个路由系统简单的实现,下面是源码地址
源码
https://github.com/zjinh/php-route-service
觉得好用的话 留个star呗
原创不易,如果可以就打赏下吧~

