Discuz!X 系列的內核是使用面向對象模式開發的,所以每一次頁面訪問其實都有一個內核實例化的過程,下文將簡單介紹一下內核的實現,以及提供的相關功能。
一、實例化操做
一般只有經過 Discuz 入口文件對站點進行訪問纔會正常進行內核實例化,這些入口文件位於 Dz 根目錄下,如:forum.php、home.php、plugin.php 等等。想繞過這些入口文件而直接訪問 Dz 目錄中的文件則會被拒絕,一般咱們會看到 「Access Denied」 的提示。緣由是,除了入口文件和一些專用 API 接口文件外全部源碼文件的開頭都有以下代碼:php
而 IN_DISCUZ 這個常量只有實例化的時候纔會被定義,任何繞過入口文件而直接執行代碼由於 IN_DISCUZ 未被賦值而顯示 「Access Denied」 提示。
要實例化內核對象只須要三條語句,代碼以下:數據庫
初始化完成之後,Dz 內核所集成的功能就可使用了,好比包含整個內核信息的全局變量 $_G,各類緩存接口,模塊實例化接口,數據庫操做接口等等。
二、實例化過程
經過閱讀源碼,咱們能夠知道:class_core.php 中首先建立實例數組
大寫 C 其實只是內核對象的一個簡寫形式瀏覽器
所以 C 就表明內核,同時內核還封裝了一個很重要的成員函數,即:t(),在 Dz 源碼中隨處可見相似 C::t('forum_post')->fetch 之類的調用,這實際上是數據庫操做函數,相關的數據庫操做,後文再詳述。
靜態成員函數 creatapp 用於建立內核實例,而內核的核心實際上是定義在 discuz_application 類中,參考代碼以下:緩存
實例化首先會調用構造函數,構造函數會對基本的運行環境、系統配置文件、輸入輸出作基本的初始化,參考代碼以下:安全
_init_env() 函數主要用於檢測服務器軟件環境,並作相應設置;加載 function_core.php,Dz 內置的經常使用函數都在此文件中;判斷來訪者是不是機器人,經過 checkrobot() 實現;初始化全局變量 $_G;
_init_config() 函數主要用於讀取 Dz 配置文件,Dz 的配置文件位於根目錄下的 config 文件夾中,config_global.php 用於 Dz 系統,config_ucenter.php 用於 UCenter 系統;Dz 的配置文件包含了比較多的內容,主要有這麼幾個部分:數據庫訪問參數、內存緩存接口參數、頁面輸出參數、Cookie參數、安全相關參數等等;經過配置文件的合理配置能夠實現 Dz 的分佈式部署以及對 MySQL 讀寫分離功能的支持。
_init_input() 函數主要用於對輸入內核的數據進行相關處理,好比對 $_GET、$_POST、$_COOKIE 中的數據進行相關處理,將 $_GET 與 $_POST 合併,所以在 Dz 源碼中,能夠統一使用 $_GET 來處理用戶的輸入;
_init_output() 則是用於頁面輸出,即展現給瀏覽器的部分,根據配置文件的設定,能夠實現頁面編碼,好比 UTF-8 或者 GBK,以及頁面是否使用 Gzip 壓縮後傳輸;
構造函數執行完畢後,還須要繼續業務系統的初始化,這些工做則是經過 $discuz->init() 來完成, 其中的 init 成員函數實際上是 discuz_application 中提供的,代碼以下:服務器
咱們能夠看到,初始化內核一共調用了 7 個子模塊,分別用於:數據庫、系統設置、用戶數據、SESSION數據、移動端適配、計劃任務、其餘附加功能。
_init_db() 用於初始化數據庫,Dz 系統會自動檢測適合的數據庫驅動,也就是接口函數,最終的初始化經過 DB::inti() 完成;
_init_setting() 用於加載系統設置、默認風格參數、自動化任務等等數據;
_init_user() 與 _init_session() 一塊兒完成了用戶登陸相關的一些初始化工做,好比若是用戶以前已經登陸,那麼在 session 過時前能夠直接訪問網站而無需再次登陸;
_init_mobile() 用於識別用戶使用的瀏覽器是不是移動端,若是是則還要進一步分析是新型觸摸屏移動設備仍是老式移動設備,並經過設置常量 IN_MOBILE 來標示用戶的瀏覽器屬性;
_init_cron() 用於自動任務的初始化,Dz 的自動化任務能夠在後臺控制面板中看到,好比天天定時清理論壇數據(用戶數、帖子訪問量等等),須要指出的是 Dz 的自動化任務執行不一樣於操做系統提供的自動化任務,好比 Linux 系統的 crontab,區別在於:操做系統的自動化任務嚴格按照時間設定執行,而 Dz 的自動化任務須要用戶訪問來觸發,也就是說,只有在每次內核實例化而且執行 _init_cron() 函數的時候纔會執行,這時 Dz 內置的相關模塊會逐個檢測設定好的自動化任務,若是知足執行條件,就會自動調用;
_init_misc() 用於一些雜項的設置,包括一些安全設置,好比進行 xss 攻擊檢測、表單 FORMHASH 常量設置用於防止非法訪問、用戶狀態檢測(好比用戶id,ip地址是否被封等等)。
到此,整個實例化過程完成,每一個部分的具體細節,有興趣的同窗就須要仔細去研究源碼才能獲得答案。
三、內核數據庫操做接口
前面講過 Dz 內核封裝了對數據庫的操做,經過內核接口,咱們能夠很是方便的操做對應的數據表,同時由於內核的面向對象特性,使得咱們能夠很容易的擴展接口的功能。在 Dz source/class/table 目錄下有不少以 table_ 前綴開頭的 php 源碼文件,這些文件就是 C::t() 函數加載的對象,例如:C::t('forum_post') 會自動加載 source/class/table/talbe_forum_post.php 文件中的同名類,而這些類均繼承自相同的父類 discuz_table;
對數據表經常使用的操做好比 插入、更新、讀取等等 都在 discuz_table 類中進行了封裝,這裏簡單介紹下這些函數的使用。
插入操做:session
$data:要插入的數據,必須是 key => value 結構的數組,且 key 應該和對應數據表的相關字段名對應;
$return_insert_id:是否返回插入記錄的ID號,若是設置爲 true,則插入成功後會返回新記錄的主鍵值,好比用戶表就是 uid;
後面兩個參數用於 REPLACE INTO 模式或者 靜默模式,具體請參考相關數據庫知識;
記錄跟新操做:app
$val:用於更新數據表的主鍵值,若是是用戶表, $val = 2 表示更新 uid = 2 的用戶數據;
$data:要更新的數據字段的值,必須是 key => value 結構的數組,且 key 應該和對應數據表的相關字段名對應;
後面兩個參數我也不多用,有興趣的同窗能夠自行研究:)
取數據操做:xss
$id:要取的數據的主鍵,好比要獲取用戶2的數據,那麼就是 C::t('common_member')->fetch(2);
$force_from_db:用於設置是否強制從數據庫中獲取數據,默認容許直接從緩存取數據;
其餘還有不少內置接口,同窗們能夠自行研究源碼,若是內置接口沒法知足要求,則徹底能夠自行對以上接口進行從新封裝。
插件數據表的操做方法:插件根目錄下建立 table 目錄,對應的表名必須是 table_ + 表名的結構,須要注意的是在數據庫中手動建立插件數據表時,須要與系統數據表保持相同的前綴,Dz 默認安裝時的表前綴都是 pre_ ,所以若是是默認安裝,則須要先在數據庫中建立表名爲 pre_yourtable 的數據表,而後在插件 table 目錄下建立對應的數據庫操做類,文件名爲 table_yourtable.php,最後在插件代碼中就能夠經過 C::t("#插件ID#yourtable") 加在插件數據表操做類,並同時繼承了父類提供的 insert、update、fetch 等操做。
本節完