天天看點

ECMALL的登入過程機制解析

在ecmall.php檔案中執行個體化控制器類,每一個控制器類,必須繼承(extends)upload\admin\app\backend.base.php檔案。在繼承中調用方法是誰先被繼承誰的方法被先調用。

以default為例,首先在公共入口檔案index.php檔案中包含eccore/ecmall.php檔案,調用startup方法并把includes/global.lib.php,includes/libraries/time.lib.php,includes/ecapp.base.php,includes/plugin.base.php,app/backend.base.php,以資料方式傳遞。在ECMAall類中的startup()方法中包含了eccore/controller/app.base.php和eccore/model/model.base.php檔案。

獲得控制器預設為[upload\admin\app\default.app.php檔案,并繼承BackendApp(app/backend.base.php)類,并繼承ECBaseApp(includes/ecapp.base.ph)類,并繼承BaseApp(eccore/controller/app.base.php),并繼承Object(eccore/ecmall.php)]。然後調用ECBaseApp中的do_action()方法在調用其實父類BaseApp中的do_action()并判斷$act(index)方法在預設控制器中是否存在,如果存在并符合條件,調用本對像是最早繼承檔案(app/backend.base.php)他中的_run_action()方法。

/**
 *    背景的需要權限驗證機制
 *
 *    @author    Garbin
 *    @return    void
 */
function _run_action()
{
    /* 先判斷是否登入 */
    if (!$this->visitor->has_login)
    {
        $this->login();
        return;
    }
    /* 登入後判斷是否有權限 */
    if (!$this->visitor->i_can('do_action', $this->visitor->get('privs')))
    {
        $this->show_warning('no_permission');
        return;
    }
    /* 運作 */
    parent::_run_action();
}
           

在此要判斷目前使用者是否登入。

如果沒有登入,調用(app/backend.base.php)他中的login()方法。

function login()
{
    if ($this->visitor->has_login)
    {
        $this->show_warning('has_login');
        return;
    }
    if (!IS_POST)
    {
        if (Conf::get('captcha_status.backend'))
        {
            $this->assign('captcha', 1);
        }
        $this->display('login.html');
    }
    else
    {
        if (Conf::get('captcha_status.backend') && base64_decode($_SESSION['captcha']) != strtolower($_POST['captcha']))
        {
            $this->show_warning('captcha_faild');
            return;
        }
        $user_name = trim($_POST['user_name']);
        $password  = $_POST['password'];
        $ms =& ms();
        $user_id = $ms->user->auth($user_name, $password);
        if (!$user_id)
        {
            /* 未通過驗證,提示錯誤資訊 */
            $this->show_warning($ms->user->get_error());
            return;
        }
        /* 通過驗證,執行登陸操作 */
        if (!$this->_do_login($user_id))
        {
            return;
        }
        $this->show_message('login_successed',
            'go_to_admin', 'index.php');
    }
}
           

然後調用includes/ecapp.base.php檔案中的display()方法加載頁面模闆,在加載過程中需要給視圖傳遞變量,調用eccore/controller/app.base.php中的assign()方法,在這個方法中還需要調用eccore/controller/app.base.php中的_init_view()方法,在這個過程中很重要因為他要引用傳回eccore/ecmall.php檔案中的& v()方法所引用的變量(引用eccore/view/template.php)檔案,類似于加載,然後在eccore/controller/app.base.php中的assign()方法調用(eccore/view/template.php)檔案assign()方法,以,鍵·值,形式指派給_var數組中。

display()函數:

function display($f)
{
    if ($this->_hook('on_display', array('display_file' => & $f)))
    {
        return;
    }
    $this->assign('site_url', SITE_URL);
    $this->assign('ecmall_version', VERSION);
    $this->assign('random_number', rand());
    /* 語言項 */
    $this->assign('lang', Lang::get());
    /* 使用者資訊 */
    $this->assign('visitor', isset($this->visitor) ? $this->visitor->info : array());
    /* 新消息 */
    $this->assign('new_message', isset($this->visitor) ? $this->_get_new_message() : '');
    $this->assign('charset', CHARSET);
    $this->assign('price_format', Conf::get('price_format'));
    $this->assign('async_sendmail', $this->_async_sendmail());
    $this->_assign_query_info();
    parent::display($f);
    if ($this->_hook('end_display', array('display_file' => & $f)))
    {
        return;
    }
}
           

assign()函數:

/**
 *    給視圖傳遞變量
 *
 *    @author    Garbin
 *    @param     string $k
 *    @param     mixed  $v
 *    @return    void
 */
function assign($k, $v = null)
{
    $this->_init_view();
    if (is_array($k))
    {
        $args  = func_get_args();
        foreach ($args as $arg)     //周遊參數
        {
            foreach ($arg as $key => $value)    //周遊資料并傳給視圖
            {
                $this->_view->assign($key, $value);
            }
        }
    }
    else
    {
        $this->_view->assign($k, $v);
    }
}
           

_init_view()函數:

/**
 *    初始化視圖連接配接
 *
 *    @author    Garbin
 *    @param    none
 *    @return    void
 */
function _init_view()
{
    if ($this->_view === null)
    {
        $this->_view =& v();
        $this->_config_view();  //配置
    }
}
           

在includes/ecapp.base.php檔案中的display()中調用其父類eccore/controller/app.base.php中的display()方法,在display()方法中引用變量調用(eccore/view/template.php)檔案中的display()方法,在display()方法中首先要判斷目前的頁面檔案(upload\admin\templates)是否被修改如果有被修改重新緩存(upload\temp\compiled\admin),在模闆緩存的時候首先要用strpos()方法判斷編碼頭部(\xEF\xBB\xBF)是否出現過,如果出現在用我們最常用的str_replace()方法把其替換為空。

在頁面送出中用到define('IS_POST', (strtoupper($_SERVER['REQUEST_METHOD']) == 'POST'))來判斷是否送出,因為在頁面送出的時候,$_SERVER['REQUEST_METHOD']預設為GET。

在登入頁面中用method="post"方法送出表單是以得到IS_POST定義值為TRUE,進入到執行SQL語句中,判斷是否登入成功。

在這個過程中要引用includes/global.lib.php檔案中的&ms()方法(此方法中包含/includes/passport.base.php,/includes/passports/' . MEMBER_TYPE . '.passport.php,MEMBER_TYPE在data/config.inc.php中定義預設為default),把變量值位址引用到/includes/passports/default.passport.php檔案中DefaultPassport類,DefaultPassport(/includes/passports/default.passport.ph)繼承了BasePassport(/includes/passport.base.php)

/**
 *    連接配接會員系統
 *
 *    @author    Garbin
 *    @return    Passport 會員系統連接配接接口
 */
function &ms()
{
    static $ms = null;
    if ($ms === null)
    {
        include(ROOT_PATH . '/includes/passport.base.php');
        include(ROOT_PATH . '/includes/passports/' . MEMBER_TYPE . '.passport.php');
        $class_name  = ucfirst(MEMBER_TYPE) . 'Passport';
        $ms = new $class_name();
    }
    return $ms;
}
           

在這個過程中,把若幹類執行個體化,是以調用auth(&username,&password)判斷使用者是不是存在正确,如果正确獲得使用者ID執行登陸操作調用_do_login方法,在這裡我們的回到剛加載檔案時候的初始化中因為在includes/ecapp.base.php檔案初始化的時候執行了$this->_init_visitor();方法引用了AdminVisitor他類并繼承了BaseVisitor類,是以可以在_do_login()方法中應用$this->visitor->assign()方法,其實就是BaseVisitor類中的

function assign($user_info)
{
	$_SESSION[$this->_info_key]   =   $user_info;
}
           

這樣就把使用者資訊用SESSION儲存,在執行操作的時候就可以對$this->has_login進行改變了。

好了這就是登入了。

其實他應用到"引用"和"繼承"比較多是以會讓初學者都感覺到很亂,沒有頭緒。引用就是不同的名字通路同一個變量内容,引用作為函數參數可以避免參數對象的額外拷貝。

如果程式比較大,引用同一個對象的變量比較多,并且希望用完該對象後手工清除它,個人建議用 "&" 方式,然後用$var=null的方式清除.另外, php5中對于大數組的傳遞,建議用 "&" 方式, 畢竟節省記憶體空間使用。

function qev(&$array)
{
     Var_export($array);
}
$array_qev = array(
'1'=>'a','2'=>'b'
)
Qev($array_qev);
           

繼承其實結果就是為增加代碼的可重用性,也就是你定義一個方法如果他有一定的共性可以被多個新增加的效果所調用。

如果登入,在(app/backend.base.php)他檔案_run_action()他方法中調其父類includes/ecapp.base.php檔案中的_run_action()方法,在調用其父類eccore/controller/app.base.php他檔案中的_run_action()方法,在此方法中調用自己所在的控制器(預設default)也就是(upload\admin\app\default.app.php)檔案中的方法(預設index)index();

這些隻是一點程式走向結構,具體内容結構還沒有研究。程式結構給人感覺似乎挺亂的,但是如果細心研究執行效果非常的好。

---------------------------------------------------

文章來源:http://www.nowamagic.net/librarys/veda/detail/1078