0x1 目录结构
显示目录结构:tree -L 2 -C -d
├── _docs
├── admin //默认后台目录
│ ├── help
│ ├── images
│ ├── includes
│ ├── js
│ ├── styles
│ └── templates
├── api
│ └── notify
├── data //静态资源和系统缓存、配置目录
│ ├── assets //静态资源目录
│ ├── attached //附件目录
│ ├── backup //备份目录
│ ├── caches //缓存目录
│ ├── captcha //验证码图片
│ ├── certificate //验证
│ ├── codetable
│ ├── ipdata
│ ├── migrates
│ ├── session
│ ├── sqldata
│ └── template
├── include //核心目录
│ ├── apps //主程序(模块目录)
│ ├── base //基础程序
│ ├── classes //类文件
│ ├── config //配置文件
│ ├── helpers //助手函数
│ ├── languages //语言包
│ ├── libraries //主类库
│ ├── modules //模块
│ └── vendor //第三方扩展类
├── install //安装模块
│ ├── sqldata
│ └── templates
├── plugins //插件程序目录
│ ├── connect
│ ├── editor
│ ├── integrates
│ ├── payment
│ ├── shipping
└── themes //系统默认模版目录
└── ecmoban_zsxn
参考链接:
这样就可以确定重点是:include 文件夹
0x2 路由分析
入口文件index.php->引导文件bootstrap.php->urlRoute()路由解析->dispatc()路由调度
为了方便理解,我在这里分析下路由(这里有两种模式)
因为一般模式mvc都会用
/index.php?m=admin&c=index&a=index
所以在这里分析兼容模式下路由规则:
26-24 lines
$varPath = C('VAR_PATHINFO');//c函数是获取配置参数的值
$varModule = C('VAR_MODULE');
$varController = C('VAR_CONTROLLER');
$varAction = C('VAR_ACTION');
$urlCase = C('URL_CASE_INSENSITIVE');
if(isset($_GET[$varPath])) { // 判断URL里面是否有兼容模式参数
$_SERVER['PATH_INFO'] = $_GET[$varPath]; //获取r=xx的内容给$_SERVER['PATH_INFO']
unset($_GET[$varPath]); //释放变量
}
41-59 lines
$depr = C('URL_PATHINFO_DEPR'); //兼容模式分隔符 r
define('MODULE_PATHINFO_DEPR', $depr);
if(empty($_SERVER['PATH_INFO'])) {
$_SERVER['PATH_INFO'] = '';
define('__INFO__','');
define('__EXT__','');
}else{
define('__INFO__',trim($_SERVER['PATH_INFO'],'/')); //去除多余的/
// URL后缀
define('__EXT__', strtolower(pathinfo($_SERVER['PATH_INFO'],PATHINFO_EXTENSION))); //获取文件后缀之后的内容
$_SERVER['PATH_INFO'] = __INFO__;
if (__INFO__ && !defined('BIND_MODULE') && C('MULTI_MODULE')){ // 获取模块名
$paths = explode($depr,__INFO__,2);//切割__INFO__
$module = preg_replace('/.' . __EXT__ . '$/i', '',$paths[0]);//处理后缀
$_GET[$varModule] = $module;
$_SERVER['PATH_INFO'] = isset($paths[1])?$paths[1]:'';
}
}
62-67 lines
define('_PHP_FILE_', rtrim($_SERVER['SCRIPT_NAME'],'/'));//当前脚本文件目录
define('__SELF__',strip_tags($_SERVER[C('URL_REQUEST_URI')]));//URI(path+fragment)
// 获取模块名称
define('APP_NAME', defined('BIND_MODULE')? strtolower(BIND_MODULE) : self::getModule($varModule)); //getModule函数得到模块名 APP_NAME定义
C('_APP_NAME', APP_NAME);
为了方便理解我继续跟进getModule函数
*/
static private function getModule($var) {
$module = (!empty($_GET[$var])?$_GET[$var]:DEFAULT_APP); //前面处理的结果
unset($_GET[$var]);//释放变量
if($maps = C('URL_MODULE_MAP')) { //模块映射规则 默认跳过
if(isset($maps[strtolower($module)])) {
// 记录当前别名
define('MODULE_ALIAS',strtolower($module));
// 获取实际的模块名
return ucfirst($maps[MODULE_ALIAS]);
}elseif(array_search(strtolower($module),$maps)){
// 禁止访问原始模块
return '';
}
}
return strip_tags(strtolower($module)); //返回模块名
}
70-86 lines
if( APP_NAME && is_dir(APP_PATH.APP_NAME)){
// 定义当前模块路径
define('MODULE_PATH', APP_PATH.APP_NAME.'/');
// 加载模块配置文件
if(is_file(MODULE_PATH.'config/config.php'))
C(load_config(MODULE_PATH.'config/config.php'));
// 加载模块函数文件
if(is_file(MODULE_PATH.'helpers/function.php'))
include MODULE_PATH.'helpers/function.php';
// 加载模块的扩展配置文件
load_ext_file(MODULE_PATH);
}else{
E('模块不存在:'.APP_NAME);
}
这个作者的注释很明白 就是MODULE_PATH ->模块目录 + APP_NAME ->模块名
107-150 lines
if('' != $_SERVER['PATH_INFO'] && (!C('URL_ROUTER_ON') || !Route::check()) ){ // 检测路由规则 如果没有则按默认规则调度URL
// 去除URL后缀
$_SERVER['PATH_INFO'] = preg_replace(C('URL_HTML_SUFFIX')? '/.('.trim(C('URL_HTML_SUFFIX'),'.').')$/i' : '/.'.__EXT__.'$/i', '', $_SERVER['PATH_INFO']);
$depr = C('URL_PATHINFO_DEPR'); //'-'
$paths = explode($depr,trim($_SERVER['PATH_INFO'],$depr));
if(!defined('BIND_CONTROLLER')) {// 获取控制器
if(C('CONTROLLER_LEVEL')>1){// 控制器层次
$_GET[$varController] = implode('/',array_slice($paths,0,C('CONTROLLER_LEVEL')));
$paths = array_slice($paths, C('CONTROLLER_LEVEL'));
}else{
$_GET[$varController] = array_shift($paths); //取第一个作为控制器
}
}
// 获取操作
if(!defined('BIND_ACTION')){
$_GET[$varAction] = array_shift($paths); //数组第二个为操作
}
// 解析剩余的URL参数
$var = array(); //空
if(C('URL_PARAMS_BIND') && 1 == C('URL_PARAMS_BIND_TYPE')){
$var = $paths; // URL参数按顺序绑定变量
}else{
preg_replace_callback('/(w+)/([^/]+)/', function ($match) use (&$var) {
$var[$match[1]] = strip_tags($match[2]);
}, implode('/', $paths));
}
$_GET = array_merge($var,$_GET); //合并变量
}
// 获取控制器和操作名
define('CONTROLLER_NAME', defined('BIND_CONTROLLER')? BIND_CONTROLLER : self::getController($varController,$urlCase));
define('ACTION_NAME', defined('BIND_ACTION')? BIND_ACTION : self::getAction($varAction,$urlCase));
// 当前控制器的UR地址
$controllerName = defined('CONTROLLER_ALIAS')? CONTROLLER_ALIAS : CONTROLLER_NAME;
define('__CONTROLLER__',__MODULE__.$depr.(defined('BIND_CONTROLLER')? '': ( $urlCase ? parse_name($controllerName) : $controllerName )) );
// 当前操作的URL地址