你现在的位置:首页 > PHP网站建设知识库 > Discuz > 正文

深入分析discuz的管理后台技术

discuz的后台拥有着非常变态的实现过程, 即没有html文件, 全部的实现都靠几个函数来完成,当然这种结构下就促使了它的后台单一化,及极其难修改. 整体来说过程是非常清晰的, 仅仅用了几个通用函数就解决了这一页页的后台管理.

   现在我们开始分析.

  admincp.php文件:

<?php

/*
        [Discuz!] (C)2001-2009 Comsenz Inc.
        This is NOT a freeware, use is subject to license terms

        $Id: admincp.php 16688 2008-11-14 06:41:07Z cnteacher $
*/

define('IN_ADMINCP', TRUE);
define('NOROBOT', TRUE);
require_once './include/common.inc.php';
//加载后台函数
require_once DISCUZ_ROOT.'./admin/global.func.php';
//加载管理员类库
require_once DISCUZ_ROOT.'./admin/cpanel.share.php';
//加载缓存系统.
require_once DISCUZ_ROOT.'./include/cache.func.php';
//加载语言模块
include language('admincp');

//设置当前动作
$discuz_action = 211;
//取得当前IP
$admincp['checkip'] && $onlineip = empty($_SERVER['REMOTE_ADDR']) ? getenv('REMOTE_ADDR') : $_SERVER['REMOTE_ADDR'];
//开始更新管理员记录
$adminsession = new AdminSession($discuz_uid, $groupid, $adminid, $onlineip);
//取得管理员记录.
$dactionarray = $adminsession->get('dactionarray');
//判断.
if($dactionarray ===  null) {
        $dactionarray = array();
        if($radminid != $groupid) {
                $tmp = unserialize($db->result_first("SELECT disabledactions FROM {$tablepre}adminactions WHERE admingid='$groupid'"));
                $dactionarray = $tmp ? $tmp : array();
        }
        $adminsession->set('dactionarray', $dactionarray, true);
}
//如果会员ID不是管理员,就为0, 如果是管理员, 就为1, 如果已经登录,就为2
$cpaccess = $adminsession->cpaccess;
//如果标识为0 即前台会员未登录,或者管理员ID不正确, 就进入登录页.
if($cpaccess == 0 || (!$discuz_secques && $admincp['forcesecques'])) {
        require_once DISCUZ_ROOT.'./admin/login.inc.php';
} elseif($cpaccess == 1) {
        //当$admin_password不为空, 就登录.
        if($admin_password != '') {
                require_once DISCUZ_ROOT.'./uc_client/client.php';
                $ucresult = uc_user_login($discuz_uid, $admin_password, 1, 1, $admin_questionid, $admin_answer);  //uc的接口.
                if($ucresult[0] > 0) {
                        $adminsession->errorcount = -1;
                        $adminsession->update();
                        dheader('Location: '.$BASESCRIPT.'?'.cpurl('url', array('sid')));  //直接用跳转.
                } else {
                        $adminsession->errorcount ++;
                        $adminsession->update();
                        writelog('cplog', dhtmlspecialchars("$timestamp/t$discuz_userss/t$adminid/t$onlineip/t$action/tAUTHENTIFICATION(PASSWORD)"));
                }
        }
        //如果上而代码没有跳转, 那又回到登录页.
        require_once DISCUZ_ROOT.'./admin/login.inc.php';
} else {
        //$cpaccess为2了.
        //处理管理员用户名
        $username = !empty($username) ? dhtmlspecialchars($username) : '';
        //处理GET
        $action = !empty($action) && is_string($action) ? trim($action) : '';
        $operation = !empty($operation) && is_string($operation) ? trim($operation) : '';
        $page = isset($page) ? intval((max(1, $page))) : 0;
        //处理两个动作.
        if(!empty($action) && !in_array($action, array('main', 'logs'))) {
                switch($cpaccess) {
                        case 1:
                                $extralog = 'AUTHENTIFICATION(ERROR #'.intval($adminsession['errorcount']).')';
                                break;
                        case 3:
                                $extralog = implodearray(array('GET' => $_GET, 'POST' => $_POST), array('formhash', 'submit', 'addsubmit', 'admin_password', 'sid', 'action'));
                                break;
                        default:
                                $extralog = '';
                }
                $extralog = trim(str_replace(array('GET={};', 'POST={};'), '', $extralog));
                $extralog = (($action == 'home' && isset($securyservice)) || ($action == 'insenz' && in_array($operation, array('register', 'binding')))) ? '' : $extralog;
                writelog('cplog', implode("/t", clearlogstring(array($timestamp,$discuz_userss,$adminid,$onlineip,$action,$extralog))));
                unset($extralog);
        }

        $isfounder = $adminsession->isfounder = isfounder();
        if(empty($action) || isset($frames)) {
                //管理页的首页.
                $extra = cpurl('url');
                $extra = $extra && $action ? $extra : (!empty($runwizard) ? 'action=runwizard' : 'action=home');
                require_once DISCUZ_ROOT.'./admin/main.inc.php';
        } elseif($action == 'logout') {
                //退出动作.
                $adminsession ->destroy();
                dheader("Location: $indexname");
        } else {
                //更新当前动作.
                checkacpaction($action, $operation);
                //这句有意思了, action来引入某个执行文件. 关键点.
                if(in_array($action, array('home', 'settings', 'members', 'profilefields', 'admingroups', 'usergroups', 'ranks', 'forums', 'threadtypes', 'threads', 'moderate', 'attach', 'smilies', 'recyclebin', 'prune', 'styles', 'plugins', 'tasks', 'magics', 'medals', 'google', 'qihoo', 'video', 'announce', 'faq', 'ec', 'tradelog', 'creditwizard', 'jswizard', 'project', 'counter', 'misc', 'adv', 'insenz', 'logs', 'tools', 'checktools', 'search', 'upgrade')) || ($isfounder && in_array($action, array('runwizard', 'templates', 'db')))) {
                        require_once DISCUZ_ROOT.'./admin/'.$action.'.inc.php';  // 引入.
                        $title = 'cplog_'.$action.($operation ? '_'.$operation : '');
                        if(!in_array($action, array('home', 'custommenu')) && lang($title, false)) {
                                (strtolower($_SERVER['REQUEST_METHOD']) == 'get') && admincustom($title, cpurl('url'));
                        }
                } else {
                        cpheader();
                        cpmsg('noaccess');
                }
                //结束函数.
                cpfooter();
        }
}

?>

 

 

我们依后台管理的全局为例子, 来新建立一个管理页面..

 

 

if(in_array($action, array('home', 'settings', 'members', 'profilefields', 'admingroups', 'usergroups', 'ranks', 'forums', 'threadtypes', 'threads', 'moderate', 'attach', 'smilies', 'recyclebin', 'prune', 'styles', 'plugins', 'tasks', 'magics', 'medals', 'google', 'qihoo', 'video', 'announce', 'faq', 'ec', 'tradelog', 'creditwizard', 'jswizard', 'project', 'counter', 'misc', 'adv', 'insenz', 'logs', 'tools', 'checktools', 'search', 'upgrade')) || ($isfounder && in_array($action, array('runwizard', 'templates', 'db')))) {
                        require_once DISCUZ_ROOT.'./admin/'.$action.'.inc.php';  // 引入.
//全局的标识是: settings 所以我们会引入settings.inc.php文件. 此文件在admin目录中.

 

标识在哪里修改呢??  在admin目录中menu.inc.php文件中.
似乎里面写的全是代码,没有中文, 能够问这个问题, 你可以先看看templates/default/admincp.lang.php语言文件.

 

首先我们打开:menu.inc.php文件
查找:

 

showmenu('global', array(

 

在它的下一行增加:

 

        array('menu_settings_function, 'settings&operation=function'),

 

接着,我们需要修改一下语言文件admincp.menu.lang.php让它显示出我们想要的管理页名称.
查找:

'menu_settings_basic' => '站点信息',

 

在它的上一行增加:

'menu_settings_function' => '分享工作室',

现在刷新一下, 左边是不是显示了一个新的页链接? 分享工作室? 

接着, 我们需要定义一下链接显示页的标题:打开admincp.lang.php文件
查找:

'settings_basic' => '站点信息',

 

在它的上一行增加:

 

'settings_function'=>'新增加管理页',

 

似乎现在可以点击,但内容显示为未定义操作。, 那么我们要怎么让程序来运行新的动作呢? 接着我们打开 settings.inc.php,查找:

 

cpmsg('undefined_action');

 

这个函数位于动作判断的最后一个默认输出, 即前面没有符全项目, 就进入这个函数输出.为此,我们增加一个条件判断:写在else前面..

 

elseif ($operation === 'function'){
                echo '我是新符合条件的管理页';
}