ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 控制器方法钩子(hook) ## 原理 程序访问控制器方法的时候,检查是否存在相应的hook,如果有对应的hook,那么就先执行hook,再继续执行当前方法,当然,如果hook里面执行中断继续执行,那后面就不会执行,而同一个方法可能有多个hook,那么就依次执行(安装hook表的ID正序)。 ## 举例 **需要实现的功能** 如果我要在用户进入首页的时候检测用户的IP,并显示在首页上显示出用户的访问IP **分析** 首页相关的控制器是`Home/c/HomeController.php`,相关的方法是`index()` 那么我要做的是在这个控制器+方法上面加个hook,即`new Home/c/HomeController()->index()` **实现** 1. 先在前台Home/plugins文件夹下面写一个`控制器+方法`实现这个检测IP的功能 ~~~ <?php namespace Home\plugins; //定义本文件空间 use Home\c\HomeController; //使用HomeController控制器 use FrPHP\Extend\Page; use FrPHP\Extend\ArrayPage; //直接继承原Home/c下面的HomeController控制器 class IpTestController extends HomeController { //直接复制HomeController的index方法,再修改 function index(){ //插入获取用户IP的方法 $ip = GetIP(); //系统内置的方法,无需考虑如何实现 //赋值到模板中输出,这一步不能缺少,否则无法输出 $this->ip = $ip; /**以上为新增内容**/ //检查缓存 $url = current_url(); $cache_file = APP_PATH.'cache/data/'.md5(frencode($url)); $this->cache_file = $cache_file; $this->start_cache($cache_file); $this->display($this->template.'/index'); $this->end_cache($this->cache_file); //此方法最后写了exit中断继续执行 } } ?> ~~~ > 注意:这个`index`方法自带`exit`中断继续执行下去,而如果你要写继续执行下去的话,就不要写`exit`,程序会继续执行下去。 > 从制作思路上考虑,直接继续原控制器,然后复制对应的方法,进修改的比较方便的,但也仅仅只能在这个方法上添加一个hook,多个则不行,因为中断执行了。 2. 加入系统中hook表 > 该章节涉及到后台安装插件制作,不熟悉的朋友,先看下个章节的插件文件介绍和说明 在`PluginsController.php`的`install`方法里添加进数据库 ~~~ //执行SQL语句在此处处理,或者移动文件也可以在此处理 public function install(){ //下面是新增test表的SQL操作 //检测是否已安装前台插件 $filepath = APP_PATH.'Home/plugins/IpTestController.php'; if(file_exists($filepath)){ JsonReturn(array('code'=>1,'msg'=>'前台Home下面已存在相应的Banip控制器!')); } //注册到hook里面 $w['module'] = 'Home'; //所在的模块 $w['namespace'] = 'Home'; //hook所在的空间命名(v1.6.4已废弃) $w['controller'] = 'Home'; //hook所在的控制器名(缩写) $w['action'] = 'index'; //hook所在的方法 $w['all_action'] = 0;//是否该控制器所有方法都执行此hook $w['hook_namespace'] = 'Home'; //插件控制器所在的空间命名(v1.6.4已废弃) $w['hook_controller'] = 'IpTest'; //插件控制器名 $w['hook_action'] = 'index'; //插件所执行的方法 $w['plugins_name'] = 'iptest';//插件文件夹 $w['addtime'] = time(); M('hook')->add($w); return true; } ~~~ 同样,你注册了插件,就要卸载插件,删除对应的hook数据 ~~~ //卸载程序,对新增字段、表等进行删除SQL操作,或者其他操作 public function uninstall(){ //下面是删除test表的SQL操作 M('hook')->delete(['plugins_name'=>'iptest']); return true; } ~~~ 3. 完善插件安装文档 4. 测试插件是否能够成功安装并实现功能 > hook确实有些复杂,但是其强大之处在于做小功能,检测类,比如检测验证码,获取数据做其他处理等等,可以多个hook,不只基于一个控制器。