博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CI3设置子目录控制器为默认控制器的解决办法
阅读量:6222 次
发布时间:2019-06-21

本文共 6566 字,大约阅读时间需要 21 分钟。

codeigniter


    在框架中配置文件多目录前后台应该是个很常见的事情。像一般的php框架(CITp等)采用都是模式,或许有人会直接在框架根目录新建文件admin.php,然后改变框架app结构,以达到访问不同入口文件名获得不同资源的效果。那么在CI中一样可以这样做,不过个人觉得这种方法太浪费资源(占用了几十k的资源吧)。于是在‘求学问道’的途中,终于得到了比较完美的解决方法。

业务需求

环境:

需求:在CI3中实现前后台的效果。例:

地址栏输入xxx.com默认访问前台主页,输入xxx.com/admin访问后台

所遇问题

依照惯例,我们会在框架中的config/route.php路由配置文件中配置我们的前后台访问路径:

// path => application/config/route.php$route['admin'] = 'admin/admin'; //后台路径$route['default_controller'] = 'home/home'; // 默认前台路径$route['404_override'] = '';$route['translate_uri_dashes'] = FALSE;

一般来说,我们这样配置是没问题的,但是有一个条件就是在CI3以下的版本中是没任何问题。但是目前的框架版本CI3,所以就会出现找不到资源文件的情况,空口无凭不算,下面是两张CI2CI3的route的配置图,和浏览器效果图:

CI2和CI3相同路由配置对比图:

CI2和CI3路由配置对

CI2和CI3相同路由配置运行网页对比图:

CI2和CI3网页展示对比

由上述两图可以看到,相同的路由配置下,但是结果却是不一样。因为CI3已经不支持设置子目录下的控制器为默认控制器的功能。但是要完成需求描述,这样的效果该如何实现呢?接下来看我们追踪CI3源码;

源码追踪core/Route.php

通过上面的结论,我们应该可以联想到出现404这样的报错,应该是解析default_controller的时候出现的问题,于是我在sublime中利用全文检索查询哪里有用到default_controller,搜索的范围可以假定为在CI核心目录中,因为路由的解析一般是由核心目录里的路由类完成的,于是查询范围锁定在system目录,得出下面的结果:

查询结果

锁定_set_default_controller方法

Route类中_set_default_controller方法

于是我一步一步排查,最终发现是这一段代码的问题:

// Is the method being specified?if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2){    $method = 'index';}if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php')){    // This will trigger 404 later    return;}

上面的代码第一段if里面拆分我们在config/route.php里配置好的default_controller值得到控制器名并赋值给变量class方法名并赋值给method,如果method为空则默认为index,很显然这与我们的初衷不相符,因为我们的计划是default_controller里的值home/home,第一个home是目录名(floder_name),第二个home才是控制器名字(controller_name)

而第二段if的意思是判断控制器文件是否存在,排查也发现控制器名竟然不存在,打印

APPPATH . 'controllers/' . $this->directory . ucfirst($class) . '.php'

得到:E:\WWW\ci3\application\controllers/Home.php,这显然与我们的实际目录不相符,我们的实际目录应该是E:\WWW\ci3\application\controllers/home/Home.php,锁定这两个问题之后,就可以思考如何修正这里了,刚开始对这个地方的改动想法是这样的:

  1. 假定设置默认的控制器值为Home/home/index(目录名/控制器名/方法名)的形式
  2. 修改core/Route.php源码中的_set_default_controller方法,截取default_controller的值进行处理

修改_set_default_controller方法如下:

protected function _set_default_controller(){    if (empty($this->default_controller))    {        show_error('Unable to determine what should be displayed. A default route has not been specified in the routing file.');    }    /**     * if里为自己修改的部分     * 1.截取default_controller为数组     * 2.如果default_controller_arr大于3 表示是默认控制器过来的     * 3.赋值相应的变量     */    $default_controller_arr = explode('/', $this->default_controller);    if(count($default_controller_arr) == 3) {        // 赋值控制器所在目录        $this->directory = trim($default_controller_arr[0], '/') . '/';        // 赋值控制器名        $class = $default_controller_arr[1];        // 因为这里计划约定默认控制器输入完整uri 即目录名/控制器名/方法名的形式        // 所以方法名这里一定不为空        $method = $default_controller_arr[2];    }else {        // Is the method being specified?        if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2)        {            $method = 'index';        }    }    if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php'))    {        // This will trigger 404 later        return;    }    $this->set_class($class);    $this->set_method($method);    // Assign routed segments, index starting from 1    $this->uri->rsegments = array(        1 => $class,        2 => $method    );    log_message('debug', 'No URI present. Default controller set.');}

虽说这样修改测试成功了,但是觉得并不是最好的解决办法(修改源码一般是最后的解决手段),于是求助codeigniter中国的官方微信群的小伙伴,在群里和Hex(手动@Hex)老大讨论了一下这个功能的解决方案,最终在他的帮助下得到了比较完美的解决方法,就是要在application/core里新建一个自己的扩展路由类MY_Router.php,然后定义自己的_set_default_controller方法,代码如下,顺便贴上自己上面设想的解决方法:

default_controller)) { show_error('Unable to determine what should be displayed. A default route has not been specified in the routing file.'); } if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2) { $method = 'index'; } /** * 1.判断目录是否存在 * 2.如果存在 调用设置控制器目录方法 详细参考system/core/Route.php set_directory方法 * 3.接着再把method拆分 赋值给$class $method $method为空则设置为index */ if( is_dir(APPPATH.'controllers/'.$class) ) { // Set the class as the directory $this->set_directory($class); // $method is the class $class = $method; // Re check for slash if method has been set if (sscanf($method, '%[^/]/%s', $class, $method) !== 2) { $method = 'index'; } } if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php')) { // This will trigger 404 later return; } $this->set_class($class); $this->set_method($method); // Assign routed segments, index starting from 1 $this->uri->rsegments = array( 1 => $class, 2 => $method ); log_message('debug', 'No URI present. Default controller set.'); } /** * @author 命中水、 * @date(2017-8-7) * * 使用这个方法时 把这个方法名和上面的方法名调换一下 * application/config/route.php default_controller的值写uri全称(目录名/控制器名/方法名) 即可 * 因为最终Route.php路由类库调用的还是_set_default_controller方法 */ protected function _set_default_controller_me() { if (empty($this->default_controller)) { show_error('Unable to determine what should be displayed. A default route has not been specified in the routing file.'); } /** * if里为自己修改的部分 * 1.截取default_controller为数组 * 2.如果default_controller_arr大于3 表示是默认控制器过来的 * 3.赋值相应的变量 */ $default_controller_arr = explode('/', $this->default_controller); if(count($default_controller_arr) == 3) { // 赋值控制器目录 $this->directory = trim($default_controller_arr[0], '/') . '/'; // 赋值控制器名 $class = $default_controller_arr[1]; // 因为这里计划约定默认控制器输入完整uri 即目录名/控制器名/方法名的形式 // 所以方法名这里一定不为空 $method = $default_controller_arr[2]; }else { if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2) { $method = 'index'; } } if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php')) { // This will trigger 404 later return; } $this->set_class($class); $this->set_method($method); // Assign routed segments, index starting from 1 $this->uri->rsegments = array( 1 => $class, 2 => $method ); log_message('debug', 'No URI present. Default controller set.'); }}

以上代码比较完美的那个,亲测有效!!!(自己的这个简单测试了一下,也可以使用)

资源

参考文章

资源

转载地址:http://mzgja.baihongyu.com/

你可能感兴趣的文章
Android通讯录查询篇--ContactsContract.Data
查看>>
去掉TabActivity底部默认白线
查看>>
ISS配置的错误
查看>>
jq倾斜的动画导航菜单
查看>>
[AaronYang原创] 大话ASP.NET MVC3+ (C#与DOM与JS页面上的很炫的技巧)
查看>>
有感20131009
查看>>
Python: 拷贝函数签名
查看>>
C# DataTable 转 List(大家进来讨论讨论)
查看>>
Database Management System 基础01:管理自己的任何事
查看>>
Android 显示网络图片
查看>>
SQL 存储过程入门(事务)(四)
查看>>
秒杀多线程第四篇 一个经典的多线程同步问题
查看>>
[SQL Server优化]善用系统监视器,确定系统瓶颈
查看>>
Wireshark数据抓包教程之Wireshark捕获数据
查看>>
jquery发送异步请求
查看>>
I2S音频总线学习(一)数字音频技术
查看>>
怎么解决VMware“该虚拟机似乎正在使用中”问题
查看>>
C语言复合字面量的使用
查看>>
[积累]C++复习 海大2014硕士生面试题微信系统总结
查看>>
Python初学笔记
查看>>