DISCUZ原始碼分析流程詳細介紹【admin.php入口】

weixin_30588675發表於2020-04-05

開啟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等。 

 

轉載於:https://www.cnblogs.com/alleyonline/p/8371630.html

相關文章