CI源码分析
作者:bin- 一、index.php
- 二、CodeIgniter.php
- 1、定义ci版本:
- 2、引入全局函数:
- 3、引入常量:
- 4、判断php版本:
- 5、设置超时时间:
- 6、加载benchmark类,计算运行时间:
- 7、加载钩子类:
- 8、加载配置类:
- 9、加载URI类:
- 10、加载路由类:
- 11、加载输出类
- 12、判断是否有可用等缓存文件,有就输出后结束脚本
- 13、加载安全类,避免xss和csrf攻击
- 14、加载输入类
- 15、引入控制器基类
- 16、如果有自定义基类(继承上者),那么也引入
- 17、判断请求uri中的控制器是否存在:
- 18、引入uri中的控制器:
- 19、结束基础类加载计时:
- 20、判断请求uri中的类和方法是否合法:
- 21、启动钩子pre_controller:
- 22、启动pre_controller计时器:
- 23、示例化请求的控制器:
- 24、判断method是否存在:
- 25、执行方法:
- 26、结束controller的计时:
- 27、controller结束钩子方法执行:
- 28、输出结果到browser
- 29、执行system结束钩子:
- 30、关闭数据库连接:
楼主这里使用等ci版本为:2.2.0
一、index.php
定义开发环境:ENVIRONMENT
定义(define)文件路径:
SELF(当前文件名)、BASEPATH(system文件路径)、FCPATH(当前文件路径)、SYSDIR(框架文件路径)、APPPATH(应用目录)
引入核心文件:
require_once BASEPATH.’core/CodeIgniter.php’;
二、CodeIgniter.php
1、定义ci版本:
CI_VERSION
2、引入全局函数:
require(BASEPATH.’core/Common.php’);
Common中有几个相对重要的方法这里介绍以下:
load_class:类注册方法,这里遵循单例设计模式,会在APPPATH和BASEPATH以此查找文件,默认为libraries目录下,并且会压入is_loaded中
is_loaded :返回已加载的类
get_config:在APPPATH.’config/config.php’下查找配置文件,并且引入,判断$config是不是数组,之后遍历一遍,再返回$config
show_error: 打印错误并且exit
show_404:引入错误类,并且打印404错误;
log_message:引入日志类,并且打印日志;
3、引入常量:
根据环境引入常量config/constants.php,例如:
(defined)文件读写权限,图片目录,上传目录等;
4、判断php版本:
是否支持当前ci版本,如果小于5.2,关闭magic quotes
5、设置超时时间:
@set_time_limit(300);
6、加载benchmark类,计算运行时间:
$BM =& load_class('Benchmark', 'core');
开始全部计时
$BM->mark('total_execution_time_start');
开始基础类加载时间计时:
$BM->mark('loading_time:_base_classes_start');
7、加载钩子类:
$EXT =& load_class('Hooks', 'core');
运行pre_system钩子:
$EXT->_call_hook('pre_system');
8、加载配置类:
$CFG =& load_class('Config', 'core');
引入配置文件(get_config上文有提到):
$this->config =& get_config();
如何没有设置base_url,那么就设置$this->config[base_url]为当前文件url
9、加载URI类:
$URI =& load_class('URI', 'core');
10、加载路由类:
$RTR =& load_class('Router', 'core');
设置路由映射,根据URI请求确定应该提供什么服务:
$RTR->_set_routing(); _set_routing:
判断是否开启了enable_query_strings,开启了,就根据配置文件中的trigger,用$_GET去取controller、method等,并且设置,然后放入segments[]中。
然后引入用户配置文件中等Router.php,其中可以配置default_controller\404_override等页面
验证segments中等目录,文件,方法是否存在:
$this->_validate_request($segments);
设置默认控制器:
$this->_set_default_controller();
分解请求url:
$this->uri->_explode_segments();
将请求/home/index?id=1,分解成home/index?id=1,然后通过’/’炸成数组
explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string))
然后依次压入$segments中
$this->segments[] = $val;
解析url(⭐️)
$this->_parse_routes();
循环遍历
foreach ($this->routes as $key => $val)
循环自定义路由规则,看是否能命中当前uri地址
if (preg_match('#^'.$key.'$#', $uri))
设置请求:
$this->_set_request(explode('/', $val)); _set_request:
根据$segments中
如果count($segments) == 0 那么设置controller,否则设置class
如果!isset($segments[1])那么设置method=’index’,否则设置为method=$segments[1]
11、加载输出类
$OUT =& load_class('Output', 'core');
12、判断是否有可用等缓存文件,有就输出后结束脚本
if ($EXT->_call_hook('cache_override') === FALSE) if ($OUT->_display_cache($CFG, $URI) == TRUE)
判断缓存是否输出:
$filepath = $cache_path.md5($uri);
文件是否存在:
if ( ! @file_exists($filepath))
是否超时:
if (time() >= trim(str_replace('TS--->', '', $match['1'])))
13、加载安全类,避免xss和csrf攻击
$SEC =& load_class('Security', 'core');
xss:大量正则,过滤html标签
csrf:种cookie验证唯一请求
14、加载输入类
$IN =& load_class('Input', 'core');
重现遍历输入($_GET、$_POST、$_COOKIE),
期间通过_clean_input_keys,过滤掉$config[permitted_uri_chars]中的字符
如果开启了csrf,那么进行验证
if ($this->_enable_csrf == TRUE && ! $this->is_cli_request()) $this->security->csrf_verify();
15、引入控制器基类
require BASEPATH.'core/Controller.php';
16、如果有自定义基类(继承上者),那么也引入
if (file_exists(APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php')) { require APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'; }
17、判断请求uri中的控制器是否存在:
if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php'))
18、引入uri中的控制器:
include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php');
19、结束基础类加载计时:
$BM->mark('loading_time:_base_classes_end');
20、判断请求uri中的类和方法是否合法:
方法名不能以下划线开头
21、启动钩子pre_controller:
$EXT->_call_hook('pre_controller');
22、启动pre_controller计时器:
$BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start');
23、示例化请求的控制器:
$CI = new $class();
24、判断method是否存在:
if ( ! in_array(strtolower($method), array_map('strtolower', get_class_methods($CI))))
25、执行方法:
call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2));
26、结束controller的计时:
$BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end');
27、controller结束钩子方法执行:
$EXT->_call_hook('post_controller');
28、输出结果到browser
if ($EXT->_call_hook('display_override')
29、执行system结束钩子:
$EXT->_call_hook('post_system');
30、关闭数据库连接:
$CI->db->close();