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呗