zoukankan      html  css  js  c++  java
  • thinkphp执行流程

    1. 入口文件index.php
    用户对url的访问首先被定位到http://<serverIp>/<appName>/index.php, 这里的入口文件index.php做三件事情:1.1, 1.2, 1.3
    1.1 定义或载入全局变量
    常见的有APP_NAME(项目名称), APP_PATH(项目路径), THINK_PATH(ThinkPHP框架路径);
    我研究的是ThinkSNS1.6,它除了用ThinkPHP的全局变量比如THINK_MODE, 又加入了自己定义的一些全局变量,如SITE_PATH, SITE_URL,
    注意到ThinkSNS定义了自己的模式ThinkSNS,


    define('THINK_MODE','ThinkSNS');


    关于ThinkPHP的模式扩展,在ThinkPHP2.0完全开发手册6.10模式扩展章节中有介绍,总的思想是通过模式扩展使得开发者可以定制自己需要使用的ThinkPHP底层框架核心,不必拘泥于ThinkPHP默认的标准模式。

    1.2 加载框架入口文件ThinkPHP.php
    入口文件通常是ThinkPHP.php,


    require(THINK_PATH."/ThinkPHP.php");


    而ThinkSNS定义了自己的入口文件ThinkSNS.php,不过总体的思想是一样的。
    在这个框架入口文件,做下面的事情:

    1.2.1 记录开始运行时间
    $GLOBALS['_beginTime'] = microtime(TRUE);


    1.2.2 检测THINK_PATH,APP_NAME, APP_PATH
    // ThinkPHP系统目录定义
    if(!defined('THINK_PATH')) define('THINK_PATH', dirname(__FILE__));
    if(!defined('APP_NAME')) define('APP_NAME', basename(dirname($_SERVER['SCRIPT_FILENAME'])));
    if(!defined('APP_PATH')) define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']));


    1.2.3 检测项目编译缓存目录定义,没有则取项目的Temp目录
    1.2.4 加载常量定义文件defines.php和公共函数文件functions.php
    require THINK_PATH.'/Common/defines.php';

    ...

    $runtime[] = THINK_PATH.'/Common/functions.php'; // 系统函数


    1.2.5 加载核心基类
    // 核心基类必须加载
    $runtime[] = THINK_PATH.'/Lib/Think/Core/Think.class.php';


    1.2.6 加载核心编译文件
    核心编译文件列表由文件core.php给出;可以自定制,放在CONFIG_PATH下;或者可以根据扩展模式放在THINK_MODE下;或者使用默认的THINK_PATH.'/Common/core.php'
    // 读取核心编译文件列表
    if(is_file(CONFIG_PATH.'core.php')) {

    // 加载项目自定义的核心编译文件列表
    $list = include CONFIG_PATH.'core.php';
    }else{
    if(defined('THINK_MODE')) {
    // 根据设置的运行模式加载不同的核心编译文件
    $list = include

    THINK_PATH.'/Mode/'.strtolower(THINK_MODE).'.php';
    }else{
    // 默认核心
    $list = include THINK_PATH.'/Common/core.php';
    }
    }


    默认的THINK_PATH.'/Common/core.php'的内容为

    // 系统默认的核心列表文件
    return array(
    THINK_PATH.'/Lib/Think/Exception/ThinkException.class.php', // 异常处理类
    THINK_PATH.'/Lib/Think/Core/Log.class.php', // 日志处理类
    THINK_PATH.'/Lib/Think/Core/App.class.php', // 应用程序类
    THINK_PATH.'/Lib/Think/Core/Action.class.php', // 控制器类
    //THINK_PATH.'/Lib/Think/Core/Model.class.php', // 模型类
    THINK_PATH.'/Lib/Think/Core/View.class.php', // 视图类
    THINK_PATH.'/Common/alias.php', // 加载别名
    );


    这样就加载了系统核心类库(包括App、Action、Model、View、ThinkException、Log)
    1.2.7 生成核心编译缓存~runtime.php
    如果没有定义NO_CACHE_RUNTIME, 则把上面步骤中加载的文件统一写到~runtime.php中,下次就可以直接调用核心编译缓存~runtime.php,无需再一一加载


    // 生成核心编译缓存 去掉文件空白以减少大小
    if(!defined('NO_CACHE_RUNTIME')) {
    $compile = defined('RUNTIME_ALLINONE');
    $content = compile(THINK_PATH.'/Common/defines.php',$compile);
    $content .= compile(defined('PATH_DEFINE_FILE')? PATH_DEFINE_FILE : THINK_PATH.'/Common/paths.php',$compile);
    foreach ($runtime as $file){
    $content .= compile($file,$compile);
    }
    if(defined('STRIP_RUNTIME_SPACE') && STRIP_RUNTIME_SPACE == false ) {
    file_put_contents(RUNTIME_PATH.'~runtime.php','<?php'.$content);
    }else{ file_put_contents(RUNTIME_PATH.'~runtime.php',strip_whitespace('<?php'.$content));
    }
    unset($content);

    }


    1.2.8 记录加载文件时间 $GLOBALS['_loadTime']
    // 记录加载文件时间
    $GLOBALS['_loadTime'] = microtime(TRUE);


    1.3 执行应用,实例化App类
    //实例化一个网站应用实例
    $App = new App();
    $App->run();


    在调用$App->run()时,具体做的事情,可看ThinkPHPLibThinkCoreApp.class.php里的public function run(),

    /**
    +----------------------------------------------------------
    * 运行应用实例 入口文件使用的快捷方法
    +----------------------------------------------------------
    * @access public
    +----------------------------------------------------------
    * @return void
    +----------------------------------------------------------
    */
    public function run() {
    $this->init();
    // 记录应用初始化时间
    if(C('SHOW_RUN_TIME'))
    $GLOBALS['_initTime'] = microtime(TRUE);
    $this->exec();
    $GLOBALS['_endTime'] = microtime(TRUE);
    // 保存日志记录
    if(C('WEB_LOG_RECORD'))
    Log::save();
    return ;
    }


    那么接着看$this->init()做什么事情,根据下面的代码,看到
    首先如果编译后的项目文件~app.php存在则直接加载它,如果不存在则调用build函数来生成~app.php;
    之后通过define('MODULE_NAME',$this->getModule())和define('ACTION_NAME', $this->getAction())将模块和动作的名字放入全局变量

    /**
    +----------------------------------------------------------
    * 应用程序初始化
    +----------------------------------------------------------
    * @access public
    +----------------------------------------------------------
    * @return void
    +----------------------------------------------------------
    */
    public function init()
    {
    // 设定错误和异常处理
    set_error_handler(array(&$this,"appError"));
    set_exception_handler(array(&$this,"appException"));
    // 检查项目是否编译过
    // 在部署模式下会自动在第一次执行的时候编译项目
    if(is_file(RUNTIME_PATH.'~app.php') && (!is_file(CONFIG_PATH.'config.php') || filemtime(RUNTIME_PATH.'~app.php')>filemtime(CONFIG_PATH.'config.php'))) {
    // 直接读取编译后的项目文件
    C(include RUNTIME_PATH.'~app.php');
    }else{
    // 预编译项目
    $this->build();
    }
    // 项目开始标签
    if(C('TAG_PLUGIN_ON')) tag('app_begin');

    // 设置系统时区 PHP5支持
    if(function_exists('date_default_timezone_set'))
    date_default_timezone_set(C('TIME_ZONE'));

    if(C('SESSION_AUTO_START'))
    // Session初始化
    session_start();

    // 应用调度过滤器
    // 如果没有加载任何URL调度器
    // 默认只支持 QUERY_STRING 方式
    // 例如 ?m=user&a=add
    if(C('DISPATCH_ON')) {
    import('Dispatcher');
    Dispatcher::dispatch();
    }

    if(!defined('PHP_FILE'))
    // PHP_FILE 由内置的Dispacher定义
    // 如果不使用该插件,需要重新定义
    define('PHP_FILE',_PHP_FILE_);

    // 取得模块和操作名称
    // 可以在Dispatcher中定义获取规则
    if(!defined('MODULE_NAME')) define('MODULE_NAME', $this->getModule()); // Module名称
    if(!defined('ACTION_NAME')) define('ACTION_NAME', $this->getAction()); // Action操作

    // 加载模块配置文件
    if(is_file(CONFIG_PATH.strtolower(MODULE_NAME).'_config.php'))
    C(include CONFIG_PATH.strtolower(MODULE_NAME).'_config.php');

    // 系统检查
    $this->checkLanguage(); //语言检查
    $this->checkTemplate(); //模板检查

    if(C('HTML_CACHE_ON')) { // 开启静态缓存
    import('HtmlCache');
    HtmlCache::readHTMLCache();
    }

    // 项目初始化标签
    if(C('TAG_PLUGIN_ON')) tag('app_init');

    return ;
    }


    $this->init()执行完后,就完成了定义MODULE_NAME和ACTION_NAME,接着执行
    $this->exec(),


    /**
    +----------------------------------------------------------
    * 执行应用程序
    +----------------------------------------------------------
    * @access public
    +----------------------------------------------------------
    * @return void
    +----------------------------------------------------------
    * @throws ThinkExecption
    +----------------------------------------------------------
    */
    public function exec()
    {
    // 是否开启标签扩展
    $tagOn = C('TAG_PLUGIN_ON');
    // 项目运行标签
    if($tagOn) tag('app_run');

    //创建Action控制器实例
    $module = A(MODULE_NAME);
    if(!$module) {
    // 是否存在扩展模块
    $_module = C('_modules_.'.MODULE_NAME);
    if($_module) {
    // 'module'=>array('classImportPath'[,'className'])
    import($_module[0]);
    $class = isset($_module[1])?$_module[1]:MODULE_NAME.'Action';
    $module = new $class;
    }else{
    // 是否定义Empty模块
    $module = A("Empty");
    }
    if(!$module) {
    // 模块不存在 抛出异常
    throw_exception(L('_MODULE_NOT_EXIST_').MODULE_NAME);
    }
    }

    //获取当前操作名
    $action = ACTION_NAME;
    if(strpos($action,':')) {
    // 执行操作链 最多只能有一个输出
    $actionList = explode(':',$action);
    foreach ($actionList as $action){
    $module->$action();
    }
    }else{
    if (method_exists($module,'_before_'.$action)) {
    // 执行前置操作
    call_user_func(array(&$module,'_before_'.$action));
    }else{
    // 操作前置标签
    if($tagOn) tag('action_before');
    }
    //执行当前操作
    call_user_func(array(&$module,$action));
    if (method_exists($module,'_after_'.$action)) {
    // 执行后缀操作
    call_user_func(array(&$module,'_after_'.$action));
    }else{
    // 操作后置标签
    if($tagOn) tag('action_after');
    }
    }
    // 项目结束标签
    if($tagOn) tag('app_end');
    return ;
    }


    根据上面代码,
    首先创建Action控制器实例$module = A(MODULE_NAME),
    其中function A()是在文件functions.php里的,它负责实例化对应的Action的class,它的部分代码如下,它根据MODULE_NAME来加载对应的Ation Class的文件,之后通过$action = new $className()进行实例化.

    if('@'===$appName) {
    require_cache(LIB_PATH.'Action/'.$className.'.class.php');
    }else{
    import($appName.'.Action.'.$className);
    }
    if(class_exists($className)) {
    $action = new $className();
    $_action[$appName.$OriClassName] = $action;
    return $action;
    }else {
    return false;
    }


    后记:由于看得文档时ThinkPHP2.0的,而所有的代码都是ThinkSNS1.6(使用的是ThinkPHP1.6)的,所以有些地方并不是很准确,但大体思想和步骤是一致的。
     
  • 相关阅读:
    windows下使用curl命令,以及常用curl命令
    使用 C# 下载文件的十八般武艺
    初闻不知曲中意,再听已是曲中人
    从线性回归走进机器学习
    自定义Vue&Element组件,实现用户选择和显示
    ARP协议原理——地址解析协议, 用于实现从 IP 地址到 MAC 地址的映射,即询问目标IP对应的MAC地址,ARP整个完整交互过程仅需要两个包,一问一答即可搞定
    SSH加密隧道流量攻击与检测技术——这玩意和思科加密流量检测没有本质区别啊,可借鉴CNN图像
    bt2——基于telegram的C2
    通过gmail进行C2控制——看了下源码,本质上和dropbox c2架构一样,都是去轮训邮件,将c2攻击的东西以邮件形式发送,结果也发到邮箱里
    DropboxC2 工具原理总结——就是通过dropbox文件来间接做c2控制和交互。
  • 原文地址:https://www.cnblogs.com/moqiang02/p/4061630.html
Copyright © 2011-2022 走看看