discuz是国内著名的论坛系统,今天大象有空看看源码,顺便理下流程,跟哥交流请发邮件到576272452@qq.com

一、首先必须知道的目录结构

(一)uc_client Ucentent客户端程序

(二)uc_server Ucentent服务端程序

(三)static 静态文件

(四)install 安装目录

(五)config 站点配置

(六)api 外部接口

(七)templets 模板目录

(八)source 代码主目录

(九)data 数据缓存及附件

(十) archive 论坛静态化

有图有真相

二、流程结构(随便找个地址来分析下,比如 设置 -> 个人资料 -> 联系方式;地址是:home.php?mod=spacecp&ac=profile&op=contact)

(一)首先打开home.php文件 看到第17行

1
require_once './source/class/class_core.php';

我同时打开了多个入口的文件都有这么一个引入,因此可以肯定这是个入口配置文件,负责文件引入及初始化需要的组件,下面来看下这个文件

第10行 error_reporting(E_ALL); 报告所有错误

第12-15行四个常量定义

1
2
3
4
define('IN_DISCUZ', true);
define('DISCUZ_ROOT', substr(dirname(__FILE__), 0, -12));
define('DISCUZ_CORE_DEBUG', false);
define('DISCUZ_TABLE_EXTENDABLE', TRUE);

第17-22行设置异常处理函数

1
2
3
4
5
6
set_exception_handler(array('core', 'handleException'));
if(DISCUZ_CORE_DEBUG) {
    set_error_handler(array('core', 'handleError'));
    register_shutdown_function(array('core', 'handleShutdown'));
}

第24-30行设置类自动引入的处理函数(这里看仔细,很重要)

1
2
3
4
5
6
7
if(function_exists('spl_autoload_register')) {
    spl_autoload_register(array('core', 'autoload'));
} else {
    function __autoload($class) {
        return core::autoload($class);
    }
}

第32行 初始化core类

1
C::creatapp();

这个C是core类的映射,证据是第208行

1
class C extends core {}

来看静态方法creatapp()

1
2
3
4
5
6
public static function creatapp() {
        if(!is_object(self::$_app)) {
            self::$_app = discuz_application::instance();
        }
        return self::$_app;
    }

我们看到是返回了一个属性,这个属性_app 是discuz_application::instance()的返回值,我们来看discuz_application类,从上面的自动引入中我们看到这个类的地址是 ./source/class/discdz/discdz_application.php,

来看刚才执行的静态方法 discuz_application::instance() 的返回值是个啥?

1
2
3
4
5
6
7
static function &instance() {
        static $object;
        if(empty($object)) {
            $object = new self();
        }
        return $object;
    }

原来是按址引用的,并且是实理化自身了,这个类继承自抽象类discuz_base,这个应该是个基类,来看看构造函数。

1
2
3
4
5
6
public function __construct() {
        $this->_init_env(); //274-316行;初始化环境变量。定义了些常量,引入了公共函数库,在./source/function/function_core.php,设置最小内存128M。并设置了允许的全局变量(_GET,_POST,_REQUEST,_COOKIE,_SERVER,_ENV,_FILES),定义了一个全局变量$_G,变将这个全局变量按址传递给了$this->var,看来在模板中可以直接使用这些变量的。
        $this->_init_config();  //274-316行;初始化配置变量。引入了配置,在./config/config_global.php,将配置变量全部压入到$this->var['config']中,在全局都可以使用配置啦
        $this->_init_input();//224-272行;初始化输入。过滤了下全局变量($_GET['GLOBALS'],$_POST['GLOBALS']……),如果开启了get_magic_quotes_gpc(),就给$_GET,$_POST,$_COOKIE变量stripslashes一下,设置合法的cookie的键名必须 $this->config['cookie']['cookiepre']这个开头的,在配置文件中有。这样做应该是防止非法cookie变量,243行把$_POST的值合并到$_GET变量中去。把rawurlencode($_GET['page'])编码下,过滤了下$_GET['handlekey'],过滤$_GET变量,foreach($_GET as $k => $v) {$this->var['gp_'.$k] = daddslashes($v);}使用的是stripslashes函数。另外设置了几个全局变量 $this->var['XXX']自己瞅瞅。
        $this->_init_output();//318-345行;初始化输出。过滤URL$this->_xss_check();<"CONTENT-TRANSFER-ENCODING都是非法的。如果控制器为'seccode', 'secqaa', 'swfupload'则进行这个过滤,有时间看看./source/include/misc/misc_security.php;开启ob_start(),设置charset;
    }

好了,现在我们明白了,我们现在得到了一个对象C,并且它有一个属性叫_app,这个属性是discuz_application对象,再在回到入口配置文件class_core.php,下面执行到了第209行,我们看到一个映射

1
class DB extends discuz_database {}

DB代表了discuz_database对象,我们去看看这个对象。从上面的自动引入类机制中我们得到了这个类位于 ./source/class/discdz/discdz_application.php。打开看看,原来是数据库操作的;静态方法 init($driver, $config)应该是初始化这个类的方法,从字面意思看,传两个参数进来,第一个参数是数据库驱动,第二个参数是数据库连接参数,以后的数据库操作应该都是DB::update()  DB::delete这样的方法了。

好了,跟着程序运行顺序走,我们现在返回到入口文件home.php第18行

1
require_once './source/function/function_home.php';

进去看看,原来是一组函数,这是个函数库,瞄了两眼,现在回到home.php第20行

1
$discuz = C::app();

原来是把discuz_application对象赋值给变量$discuz。

到第22-24行

1
2
3
$cachelist = array('magic','userapp','usergroups', 'diytemplatenamehome');
$discuz->cachelist = $cachelist;
$discuz->init();

哇靠,$discuz->init();这一行才是核心中的核心,具体功能是初始化整个discuz应用。discuz_application类是整个discuz的应用初始化类,相当于织梦的 /include/common.inc.php的功能

1
2
3
4
5
6
7
8
9
10
11
12
public function init() {
        if(!$this->initated) {
            $this->_init_db();//初始化数据库
            $this->_init_setting();//系统设置初始化
            $this->_init_user();//用户信息初始化
            $this->_init_session();//session操作初始化
            $this->_init_mobile();//手机功能初始化
            $this->_init_cron();//计划任务初始化
            $this->_init_misc();//其他功能初始化
        }
        $this->initated = true;//设置完成标志
    }

核心代码第一句 $this->_init_db();

1
2
3
4
5
6
7
8
9
private function _init_db() {
        if($this->init_db) {
            $driver = 'db_driver_mysql';
            if(getglobal('config/db/slave')) {//在设置里修改slave可以修改数据库驱动类,默认为db_dirver_mysql
                $driver = 'db_driver_mysql_slave';
            }
            DB::init($driver, $this->config['db']);//DB类位于:./source/class/discuz/discuz_database.php
        }
    }

DB::init方法是在discuz_database类中实例化了数据库驱动类db_driver_mysql驱动类,并将其赋值给DB::db属性,根据自动引入规则驱动类的位置在:./source/class/db/db_driver_mysql.php;

核心代码第二句 $this->_init_setting(),

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private function _init_setting() {
        if($this->init_setting) {
            if(empty($this->var['setting'])) {
                $this->cachelist[] = 'setting';
            }
            if(empty($this->var['style'])) {
                $this->cachelist[] = 'style_default';
            }
            if(!isset($this->var['cache']['cronnextrun'])) {
                $this->cachelist[] = 'cronnextrun';
            }
        }
        !empty($this->cachelist) && loadcache($this->cachelist);//主要是这句,加载缓存,实现的过程可以看function_core.php中的第687-716行,实际是把缓存赋值给$_G变量($_G['setting'],$_G['cache'],$_G['grouplevels']),处理缓存的其实是在第700行 C::t('common_syscache')->fetch_all($caches);,这块是重点。可以研究一下,DZ的缓存部分,这里我略讲一下,用C::t('common_syscache')->fetch_all($caches) 实例化了一个对象common_syscache 位置:./source/class/table/table_common_syscache.php,挺绕得,我看了半天代码才找出来,其实这个完整的对象是discuz_container。common_syscache对象只是discuz_container的一个属性obj;在class_core.php的第76-90行可以看出这种关系来,table_common_syscache.php第38行,$data = memory('get', $cachenames);这个是最后得到的缓存数据,我们来追下memory函数,第一个参数是get,那么会执行function_core.php中的第1687行 case 'get': return C::memory()->get($key, $value); 其中C::memory()是实例化了discuz_memory对象,在./source/class/discuz/discuz_memory.php ;看get方法在第70-102行,它有两个参数,get($key, $prefix = '')。get方法第97行$ret = $this->memory->get($this->_key($key));使用了memory_driver_eaccelerator类的get方法,位置./source/class/memory/memory_driver_eaccelerator.php第22行,return eaccelerator_get($key);,缓存就是依靠eaccelerator_get函数获取的
        if(!is_array($this->var['setting'])) {
            $this->var['setting'] = array();
        }
    }

核心代码第三句$this->_init_user();discuz_application.php 428-493行

$auth = getglobal('auth', 'cookie') 得到cookie中的auth的值,加密过的值

$auth = daddslashes(explode("\t", authcode($auth, 'DECODE'))); 利用authcode函数解密,得到一个数组

list($discuz_pw, $discuz_uid) = empty($auth) || count($auth) < 2 ? array('', '') : $auth; 从这句看数组第一个元素为密码,第二个元素是会员登陆的ID。存在common_member表中。

$user = getuserbyuid($discuz_uid, 1);利用getuserbyuid得到会员信息,第二个参数如果是1并且在common_member中没有该会员就去common_member_archive表中去寻找,否则直接去common_member表中查找

1
2
3
4
5
6
7
8
9
if(!empty($user) && $user['password'] == $discuz_pw) {如果查出的密码是对的
    if(isset($user['_inarchive'])) {
        C::t('common_member_archive')->move_to_master($discuz_uid);如果数组中有_inarchive元素就将当前查到的用户信息插入到用户表common_member表中
    }
    $this->var['member'] = $user;将用户信息压入模板变量中
} else {
    $user = array();
    $this->_init_guest();//设置没登陆的访客的信息
}
1
2
3
if($user && $user['groupexpiry'] > 0 && $user['groupexpiry'] < TIMESTAMP && (getgpc('mod') != 'spacecp' || CURSCRIPT != 'home')) {
   dheader('location: home.php?mod=spacecp&ac=usergroup&do=expiry');//如果登陆时间过期了,或者访问的是home.php下的内容时跳转到登陆页面
}

这里作用是检查登陆了没有。

462行;!empty($this->cachelist) && loadcache($this->cachelist);装载缓存, 使用缓存可以参照我另一篇文章中关于缓存的应用

477行;$this->var['member']['lastvisit'] = TIMESTAMP - 3600;dsetcookie('lastvisit', TIMESTAMP - 3600, 86400 * 30);设置最后浏览的时间

464-490行,设置了cookie、全局变量、增加var属性变量

核心代码第四句 $this->_init_session();discuz_application.php 386-426行

设置session类,更新用户状态

1
2
3
4
5
<?php
$sessionclose = !empty($this->var['setting']['sessionclose']);//设置中sessionclose是否为真
$this->session = $sessionclose ? new discuz_session_close() : new discuz_session();//如果为真就实例化discuz_session_close类 应该是关闭session后的解决方案,否则实例化discuz_session类,位置在source/class/discuz/discuz_session.php

if($this->session->get('groupid') == 6)判断session中的groupid合法性

$this->session->set('lastactivity', TIMESTAMP);设置最后访问时间为当前时间

dsetcookie('lip', $this->var['member']['lastip'].','.$this->var['member']['lastvisit']);第一次访问的话设置访问IP的session

C::t('common_member_status')->update($this->var['uid'], array('lastip' => $this->var['clientip'], 'lastvisit' => TIMESTAMP));//更新用户的状态

?>

核心代码第五句 $this->_init_mobile();discuz_application.php 680-789行

大概看了下,都是设置手机访问的一些变量,全局变量,cookie,session,跳转,常量等,有空细看下

核心代码第六句$this->_init_cron();discuz_application.php 508-515行

计划任务初始化 。配置文件中  $_config['remote']['cron'] = 1;设置后;远程调用: 开启外部 cron 任务. 系统内部不再执行cron, cron任务由外部程序激活

1
2
3
4
5
6
$ext = empty($this->config['remote']['on']) || empty($this->config['remote']['cron']) || APPTYPEID == 200;
if($this->init_cron && $this->init_setting && $ext) {//如果远程调用: 开启外部 cron 任务后调用discuz_cron::run();类
    if($this->var['cache']['cronnextrun'] <= TIMESTAMP) {
            discuz_cron::run();
    }
}

至此我们看到了一个完整的初始化过程

1
2
3
4
5
6
7
require_once './source/class/class_core.php'; //引入核心类文件,作用为:自动引入类规则,错误和异常处理,单例创建discuz_application类实例,引入默认函数库function.core.php
require_once './source/function/function_home.php';//项目函数库
$discuz = C::app();//实例化desiuz_application类
$cachelist = array('magic','userapp','usergroups', 'diytemplatenamehome');
$discuz->cachelist = $cachelist;//设置缓存列表
$discuz->init();//初始化整个应用

下一章将讲到discuz控制器和模板

转载自:http://hi.baidu.com/tong_jh/item/9980dd3d0115e583c2cf293a

discuz代码解析(一、初始化应用的过程)相关推荐

  1. JVM类加载、验证、准备、解析、初始化、卸载过程详解

    目录 0 使用类的准备工作 初始化(Init) 1 加载(Load) 1.1 详细过程 1.1.1 通过类全限定名获取该类的二进制字节流 1.1.2 静态存储结构=>运行时数据结构 1.1.3 ...

  2. 转载:discuz代码解析(一、初始化应用的过程)

    discuz是国内著名的论坛系统,今天大象有空看看源码,顺便理下流程 一.首先必须知道的目录结构 (一)uc_client Ucentent客户端程序 (二)uc_server Ucentent服务端 ...

  3. 29.类加载机制、类加载过程、加载、验证、准备、解析、初始化、总结

    29.类加载机制 29.1.类加载过程 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载.验证.准备.解析.初始化.使用和卸载七个阶段.它们开始的顺序如下图所示: 其中类加载 ...

  4. 类的加载过程详解:加载、验证、准备、解析、初始化

    想要弄明白的知识点: 类加载的过程,加载.验证.准备.解析.初始化.每个部分详细描述. 加载阶段读入.class文件,class文件时二进制吗,为什么需要使用二进制的方式? 验证过程是防止什么问题?验 ...

  5. 嵌入式linux的u-boot系统启动过程,嵌入式linux操作系统u-boot启动顺序以及代码解析...

    嵌入式linux操作系统u-boot启动顺序以及代码解析 (9页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 Bootloader/u-bo ...

  6. python批量处理csv_Python批量处理csv并保存过程代码解析

    本篇文章小编给大家分享一下Python批量处理csv并保存过程代码解析,代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看. 需求: 1.大量csv文件,以数字命 ...

  7. 【四足机器人--关节初始化时足端位置(速度、加速度)轨迹规划】(4.2)JPosInitializer(B样条曲线计算脚的摆动轨迹)代码解析

    系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录 前言 一.关节初始化构造函数(设置目标时间及间隔) 二.给定并B样条起始点 ...

  8. Discuz代码研究-编码规范

    来源:http://www.cnblogs.com/janas/archive/2013/08/20/3271408.html Discuz中的编码规范很值得PHP开发人员借鉴.里面既介绍了编码时代码 ...

  9. 视觉SLAM开源算法ORB-SLAM3 原理与代码解析

    来源:深蓝学院,文稿整理者:何常鑫,审核&修改:刘国庆 本文总结于上交感知与导航研究所科研助理--刘国庆关于[视觉SLAM开源算法ORB-SLAM3 原理与代码解析]的公开课. ORB-SLA ...

  10. mongoose框架示例代码解析(一)

    mongoose框架示例代码解析(一) 参考: Mongoose Networking Library Documentation(Server) Mongoose Networking Librar ...

最新文章

  1. JavaScript数据结构与算法——字典
  2. java getcolormodel_Java ColorModel.getTransparency方法代碼示例
  3. python游戏开发步骤_详解Python GUI版24点游戏制作过程
  4. Android之实现RTL的ViewPager
  5. Javascript基础(二)
  6. 提供写入的数据少于指定的数据_指定范围数据的汇总
  7. C语言中的“”和“”
  8. 图像分类模型的学习笔记
  9. 找规律 —— 英文篇
  10. 在网页上获取当前日期,数字时钟
  11. Asp.Net MVC Web应用程序中的安全向量
  12. QT实现低延迟的RTSP、RTMP播放器
  13. 项目启动阶段的主要工作
  14. Django安全认证机制CSRF
  15. 微信如何为好友设置特殊铃声提醒提示音
  16. “阿里云大数据技术实战训练营”江苏省大学生万人计划学术冬令营活动成功举行...
  17. CANopen总线的高级协议详解
  18. Android : TextView
  19. 【论文笔记】Image Manipulation Detection by Multi-View Multi-Scale Supervision
  20. MM买裤子杀价全过程

热门文章

  1. Matlab 函数文件简介
  2. 【千律】OpenCV基础:图像边缘检测 -- Roberts 算子
  3. 干货收藏|如何用chrom插件实现U校园自动刷课
  4. FPGA数字信号处理(十七)多级CIC滤波器Verilog设计
  5. javaScript编码爱心表白
  6. python避障小车_基于树莓派的超声波避障小车
  7. ActiveMQ下载和安装
  8. 详情页html源代码,仿新浪首页、主题、详情页,纯html静态页面
  9. 利用oc门或od门实现线与_TTL,CMOS,OC门,OD门的理解
  10. 利用matlab聚类分析,利用Matlab软件实现聚类分析