DISCUZ源码分析流程详细介绍【admin.php入口】

Stella981
• 阅读 828

打开admin.php

define('IN_ADMINCP', TRUE);

//定义常量IN_ADMINCP为true 这样在后面的每个页面都会判断

if(!defined('IN_DISCUZ') || !defined('IN_ADMINCP')) {
 exit('Access Denied');
}

//防止外面直接访问后台文件,必须通过admin.php包含才可以访问其他文件,IN_DISCUZ在/sorce/class/class_core.php里定义的常量,后面几行马上包含该文件

define('NOROBOT', TRUE);

//定义常量NOROBOT为true,用于阻止搜索引擎爬虫抓取。

define('ADMINSCRIPT', basename(__FILE__));//admin.php

//__FILE__是获取文件磁盘位置详细路径,比如:D:\DedeAMPZ\web2013\discuz_video\upload\admin.php

//basename(__FILE__)就是取文件名 也就是admin.php

define('CURSCRIPT', 'admin');

//定义常量CURSCRIPT为admin,当前脚本为admin
define('HOOKTYPE', 'hookscript');

//定义常量HOOKTYPE 为 hookscript
define('APPTYPEID', 0);

//定义APPTYPEID 为 0

require './source/class/class_core.php';

包含核心类class_core.php

程序进入class_core.php内

error_reporting(E_ALL);

//定义错误报告为E_ALL

define('IN_DISCUZ', true);

//定义常量IN_DISCUZ为true 后续判读,防止外界直接访问内部页面
define('DISCUZ_ROOT', substr(dirname(__FILE__), 0, -12));

//定义DISCUZ_ROOT为DISCUZ的根目录也就是upload目录的磁盘位置,这个常量后续会很常用到
define('DISCUZ_CORE_DEBUG', false);

//定义调试模式为 false后续可以修改为true进行调试
define('DISCUZ_TABLE_EXTENDABLE', TRUE);

//定义常量'DISCUZ_TABLE_EXTENDABLE' 为true

set_exception_handler(array('core', 'handleException'));

//PHP自带函数 使用 core::handleException 来执行异常处理可以是单个函数名为参数,也可以是类和函数组成的数组

if(DISCUZ_CORE_DEBUG) {
 set_error_handler(array('core', 'handleError'));//设置错误处理函数 core::handleError 来执行
 register_shutdown_function(array('core', 'handleShutdown'));//致命错误处理函数 core::handleShutdown 来执行
}

//如果是调试模式的话设置错误处理函数为core::handleError,设置致命错误处理函数为core::handleShutdown

if(function_exists('spl_autoload_register')) {
 spl_autoload_register(array('core', 'autoload'));
} else {
 function __autoload($class) {
  return core::autoload($class);
 }
}

//自动加载类,执行 以下autoload函数 PHP5之后如果试图调用没有加载的类就会自动调用__autoload()函数或者执行spl_autoload_register()指定的函数

//直接调用类时会先调用core::autoload($class)函数,在这个函数里会包含该类文件

C::creatapp();

//执行C::createapp()函数,双冒号是调用类的静态函数。DISCUZ里大多都用的是静态函数

在类名的最下方有C的定义

class C extends core {}
class DB extends discuz_database {}

类名C是继承于core的,执行C::createapp()就是执行core::createapp()

再看core::createapp()函数如下:

public static function creatapp() {
  if(!is_object(self::$_app)) {
   //discuz_application主要定义了mem session misic mobile setting等数组
   //在这里直接调用discuz_application类,会触发core::autoload('discuz_application')执行,因为spl_autoload_register()函数设置了
   self::$_app = discuz_application::instance();//由于执行了spl_autoload_register自动加载类
   //instance执行了$object = new self();这样就执行了__construct函数
  }
  return self::$_app;
 }

该函数直接返回core::$_app , core::$_app 开始为空,所以调用discuz_application::instance();

由于上面设置了类自动加载,所以调用discuz_application的时候,会先调用

core::autoload()函数,

函数执行到 core::autoload()里,代码如下:

//自动加载类
 public static function autoload($class) {
  $class = strtolower($class);//变为小写
  if(strpos($class, '_') !== false) {
   list($folder) = explode('_', $class);
   $file = 'class/'.$folder.'/'.substr($class, strlen($folder) + 1);
  } else {
   $file = 'class/'.$class;
  }

  try {

   self::import($file);
   return true;

  } catch (Exception $exc) {

   $trace = $exc->getTrace();
   foreach ($trace as $log) {
    if(empty($log['class']) && $log['function'] == 'class_exists') {
     return false;
    }
   }
   discuz_error::exception_error($exc);
  }
 }

//此时传递给autoload的变量$class是discuz_application,由于文件名中含有_,所以$file是class/discuz/discuz_application.php,如果没有_的类,则在class/类名.php,然后执行

self::import($file);

函数进入core::import()内代码如下:

public static function import($name, $folder = '', $force = true) {
  $key = $folder.$name;
  if(!isset(self::$_imports[$key])) {
   $path = DISCUZ_ROOT.'/source/'.$folder;
   if(strpos($name, '/') !== false) {
    $pre = basename(dirname($name));
    $filename = dirname($name).'/'.$pre.'_'.basename($name).'.php';
   } else {
    $filename = $name.'.php';
   }

   if(is_file($path.'/'.$filename)) {
    self::$_imports[$key] = true;
    $rt = include $path.'/'.$filename;
    return $rt;
   } elseif(!$force) {
    return false;
   } else {
    throw new Exception('Oops! System file lost: '.$filename);
   }
  }
  return true;
 }

//此时传递给core::import()的参数为class/discuz/discuz_application.php,第2,3个参数为默认的

$key = $folder.$name;
  if(!isset(self::$_imports[$key])) {

如果包含了文件则不重复包含,包含过后都会把类名保存在$_imports[]数组内,所以开始判断下这个键值是否已经存在,不存在执行下一步,然后下面的代码也就是包含对应的PHP文件了,不详细多说。

包含了文件后,程序继续执行,因为此时discuz_application已经包含进来,可以继续执行以下函数。

self::$_app = discuz_application::instance();

执行discuz_application::instance()函数

----------------------------------------程序即将跳转----------------------------------------

static function &instance() {
  static $object;

  if(empty($object)) {
   $object = new self();//初始化一个类,如此便开始执行__construct()函数
  }
  return $object;
 }

初始化一个类,$object=new self(),初始化后必然执行__construct()函数

----------------------------------------程序即将跳转----------------------------------------

代码如下

public function __construct() {
  
  $this->_init_env();//环境设置
  $this->_init_config();//配置
  $this->_init_input();//设置GET,POST ,COOKIE
  $this->_init_output();//rss charset GZIP等。
 }

----------------------------------------程序即将跳转----------------------------------------

 $this->_init_env();//环境设置

 代码如下:

private function _init_env() {
  
  error_reporting(E_ERROR);
  if(PHP_VERSION < '5.3.0') {
   set_magic_quotes_runtime(0);
  }

  define('MAGIC_QUOTES_GPC', function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc());
  define('ICONV_ENABLE', function_exists('iconv'));
  define('MB_ENABLE', function_exists('mb_convert_encoding'));
  define('EXT_OBGZIP', function_exists('ob_gzhandler'));

  define('TIMESTAMP', time());//记录开始时间,没刷新页面都会执行
  $this->timezone_set();//设置时区
  //包含核心函数库
  if(!defined('DISCUZ_CORE_FUNCTION') && !@include(DISCUZ_ROOT.'./source/function/function_core.php')) {
   exit('function_core.php is missing');
  }
  //内存设置为128M
  if(function_exists('ini_get')) {
   $memorylimit = @ini_get('memory_limit');
   if($memorylimit && return_bytes($memorylimit) < 33554432 && function_exists('ini_set')) {
    ini_set('memory_limit', '128m');
   }
  }

  define('IS_ROBOT', checkrobot());
  //$GLOBALS为全局变量数组,比如外部定义了$f00="123",在这里通过$GLOBALS['foo']='123';
  foreach ($GLOBALS as $key => $value) {
   if (!isset($this->superglobal[$key])) {
    $GLOBALS[$key] = null; unset($GLOBALS[$key]);//不明白为何要清空$GLOBALS,似乎是用自己的一套变量清空系统变量
   }
  }
  
  global $_G;//超级大数组
  $_G = array(
   'uid' => 0,
   'username' => '',
   'adminid' => 0,
   'groupid' => 1,
   'sid' => '',
   'formhash' => '',
   'connectguest' => 0,
   'timestamp' => TIMESTAMP,
   'starttime' => microtime(true),
   'clientip' => $this->_get_client_ip(),//获取客户端IP地址
   'referer' => '',
   'charset' => '',
   'gzipcompress' => '',
   'authkey' => '',
   'timenow' => array(),
   'widthauto' => 0,
   'disabledwidthauto' => 0,

   'PHP_SELF' => '',
   'siteurl' => '',
   'siteroot' => '',
   'siteport' => '',

   'pluginrunlist' => !defined('PLUGINRUNLIST') ? array() : explode(',', PLUGINRUNLIST),

   'config' => array(),
   'setting' => array(),
   'member' => array(),
   'group' => array(),
   'cookie' => array(),
   'style' => array(),
   'cache' => array(),
   'session' => array(),
   'lang' => array(),
   'my_app' => array(),
   'my_userapp' => array(),

   'fid' => 0,
   'tid' => 0,
   'forum' => array(),
   'thread' => array(),
   'rssauth' => '',

   'home' => array(),
   'space' => array(),

   'block' => array(),
   'article' => array(),

   'action' => array(
    'action' => APPTYPEID,
    'fid' => 0,
    'tid' => 0,
   ),

   'mobile' => '',
   'notice_structure' => array(
    'mypost' => array('post','pcomment','activity','reward','goods','at'),
    'interactive' => array('poke','friend','wall','comment','click','sharenotice'),
    'system' => array('system','myapp','credit','group','verify','magic','task','show','group','pusearticle','mod_member','blog','article'),
    'manage' => array('mod_member','report','pmreport'),
    'app' => array(),
   ),
   'mobiletpl' => array('1' => 'mobile', '2' => 'touch', '3' => 'wml','yes' => 'mobile'),
  );
  //dhtmlspecialchars 在function_core.php里
  $_G['PHP_SELF'] = dhtmlspecialchars($this->_get_script_url());
  $_G['basescript'] = CURSCRIPT;//在运行首个PHP文件里定义了,比如member.php里定义了member
  $_G['basefilename'] = basename($_G['PHP_SELF']);
  $sitepath = substr($_G['PHP_SELF'], 0, strrpos($_G['PHP_SELF'], '/'));
  if(defined('IN_API')) {
   $sitepath = preg_replace("/\/api\/?.*?$/i", '', $sitepath);
  } elseif(defined('IN_ARCHIVER')) {
   $sitepath = preg_replace("/\/archiver/i", '', $sitepath);
  }
  
  $_G['isHTTPS'] = ($_SERVER['HTTPS'] && strtolower($_SERVER['HTTPS']) != 'off') ? true : false;
  $_G['siteurl'] = dhtmlspecialchars('http'.($_G['isHTTPS'] ? 's' : '').'://'.$_SERVER['HTTP_HOST'].$sitepath.'/');

  $url = parse_url($_G['siteurl']);
  $_G['siteroot'] = isset($url['path']) ? $url['path'] : '';
  $_G['siteport'] = empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' || $_SERVER['SERVER_PORT'] == '443' ? '' : ':'.$_SERVER['SERVER_PORT'];

  if(defined('SUB_DIR')) {
   $_G['siteurl'] = str_replace(SUB_DIR, '/', $_G['siteurl']);
   $_G['siteroot'] = str_replace(SUB_DIR, '/', $_G['siteroot']);
  }
  
  $this->var = & $_G;

 }

----------------------------------------程序即将跳转----------------------------------------

 $this->_init_env();//环境设置

$this->_init_config();//配置
  $this->_init_input();//设置GET,POST ,COOKIE
  $this->_init_output();//rss charset GZIP等。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Discuz X3.2源码解析 discuz_application类(转自百度)
1.discuz\_application在/source/class/discuz/discuz\_application.php中。!DiscuzX3.2源码解析discuz_application类(https://oscimg.oschina.net/oscnet/99b35d79caf70b7c74ad0838d6
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这