alleyonline

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

打开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等。 

 

分类:

技术点:

相关文章: