ThinkPHP開發博客系統筆記之一

1.先後臺搭建javascript

開發的第一步是搭建先後臺系統。搭建前臺系統的時候新建了LoginController控制器和登陸界面View/Login/index.tpl。模板文件中須要引入js和css文件,這裏想經過在配置文件中建立模板變量的方式簡化腳本文件的引入,但在建立的過程當中遇到了問題。php

Home/Conf/config.php
<?php return array( 'TMPL_PARSE_STRING' => array( '__CSS__' => '__PUBLIC__/Home/css', '__JS__' => '__PUBLIC__/Home/js', '__IMG__' => '__PUBLIC__/Home/img', ), );
View/Login/index.tpl
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>微博系統——登陸界面</title> <script type="text/javascript" src="__JS__/jquery.js"></script> <script type="text/javascript" src="__JS__/jquery.ui.js"></script> <script type="text/javascript" src="__JS__/login.js"></script> <link rel="stylesheet" href="__CSS__/jquery.ui.css"> <link rel="stylesheet" href="__CSS__/login.css"> </head> <body> </body> </html>

結果__JS__等幾個變量在模板文件中沒法正確解析。緣由是__PUBLIC__是模板替換變量,只有出如今模板文件中時纔會被替換爲對應的字符串。而__ROOT__、__APP__、__MODULE__、__CONTROLLER__、__ACTION__、__SELF__既是模板替換變量,也是系統常量,它們能夠應用在模板文件和配置文件中,因此這裏能夠用__ROOT__css

Home/Conf/config.php
<?php
return array(
    'TMPL_PARSE_STRING'    => array(
        '__CSS__'    =>    __ROOT__.'/Public/Home/css',
        '__JS__'    =>    __ROOT__.'/Public/Home/js',
        '__IMG__'    =>    __ROOT__.'/Public/Home/img',
    ),
);

這裏還能夠用系統常量MODULE_NAME代替模塊名稱Home,改進後的版本以下:html

 

Home/Conf/config.php

<?php
return array(
    'TMPL_PARSE_STRING'    => array(
        '__CSS__'    =>    __ROOT__.'/Public/'.MODULE_NAME.'/css',
        '__JS__'    =>    __ROOT__.'/Public/'.MODULE_NAME.'/js',
        '__IMG__'    =>    __ROOT__.'/Public/'.MODULE_NAME.'/img',
    ),
);

 

2. 登陸頁設計前端

 登陸頁的功能之一就是自動縮放和隨機變換的背景,前一個功能是經過CSS3的新屬性background-size實現的。java

body {
    margin: 0;
    padding: 0;
    height: 100%;
    background: url(../img/background.jpg) no-repeat;
    background-size: 100%;
}

由於我用的圖片寬度太小,沒法填充整個頁面,我試圖經過設置width: 100%來填充整個頁面,結果固然是失敗的,由於heightwidth屬性是控制content的,與background無關。jquery

後一個功能是經過js實現的。最初的測試腳本以下:web

$(function(){
    
    //登陸頁背景隨機
    var rand = Math.floor(Math.random() * 5) + 1;
    $("body").css("background", "url(../img/login_bg1.jpg)");
});

刷新瀏覽器頁面報錯:ajax

注意,這裏查找login_bg1.jpg的路徑是相對於index.php的,由於index.php已位於網站根目錄www,因此它的上級目錄仍是www。數組

這裏的url路徑是否可使用__PUBLIC__呢?答案是否認的。由於模板替換隻會發生在模板文件中,在js腳本中沒法替換。但咱們能夠在模板文件中定義js變量,這樣在引用該腳本中就可使用這些變量了。

Home/View/Login/index.tpl

<script type="text/javascript">
    var ThinkPHP = {
        "IMG" : "__PUBLIC__/{:MODULE_NAME}/img",
    };
</script>
login.js

$(function(){
    
    //登陸頁背景隨機
    var rand = Math.floor(Math.random() * 5) + 1;
    $("body")
.css("background", "url(" + ThinkPHP['IMG']+ "/login_bg" + rand +".jpg) no-repeat")
.css("background-size" , "100%"); });

這個地方還有一個小問題,就是url不能寫成以下形式:

$(function(){
    
    //登陸頁背景隨機
    var rand = Math.floor(Math.random() * 5) + 1;
    $("body").css("background", "url(ThinkPHP['IMG']/login_bg1.jpg)");    
});

由於Javascript中引號中的都是字符串常量,將ThinkPHP['IMG']放在引號中就不會轉換爲它所表明的變量了。

登陸頁面中不可或缺的元素就是登錄表單。登錄form的各元素在頁面上佈置好以後,先用jquery ui將type=submit的input元素轉換爲按鈕:

login.js

$(function(){
    
    //登陸頁按鈕
    $("#login input[type='submit']").button();
});

設置好各元素的css以後我發現submit按鈕的位置有點兒靠上,須要經過定位讓它的位置下移一些,並用:hover實現鼠標移動到它上面時的動畫效果:

login.css

#login input[type="submit"] {
    position: relative;
    top: -4px;
    
    width: 150px;
    height: 50px;
    
    font-family: 黑體;
    font-size: 24px;
    
    background-color: #c3c3c3;
}

#login input[type="submit"]:hover {
    background-color: #3c3c3c;
}

 上面的main部門又加了一個註冊和找回密碼連接後就開始設計頁面的底部,也就是footer部門。這裏footer要實現一個透明的功能,我直接在footer上進行CSS的設計,結果footer裏的文字也變透明瞭,這不是我想要的結果。因此我把裏面的文字移出來,放到一個class=「footer_text」的p標籤中。

Login/index.tpl

<div id="footer"></div>
<p class="footer_text">Juedi's blog</p>
login.css

#footer {
    position: absolute;
    bottom: 0;
    
    width: 100%;
    height: 40px;
        
    opacity: 0.4;
    background: #000;
}

.footer_text {
    position: absolute;
    bottom: 0;
    
    width: 100%;
    
    text-align: center;
    font-size: 13px;
    color: #000;
}

 下面就開始設計新用戶註冊界面了,最初的版本以下:

<div id="register">
            <form>
                <p>
                    <label for="user">帳號:</label>
                    <input type="text" name="user" class="text" id="user" placeholder="暱稱,不小於兩位!">
                    <span class="star">*</span>
                    <label for="password">密碼:</label>
                    <input type="password" name="password" class="text" id="password" placeholder="密碼,不小於6位!">
                    <span class="star">*</span>
                    <label for="email">郵箱:</label>
                    <input type="email" name="email" class="text" id="email" placeholder="郵箱,用於找回密碼!">
                    <span class="star">*</span>
                </p>
            </form>
        </div>

結果界面以下:

很顯然是哪裏出了問題。問題就在於label、span和input都是行內元素,它們不會自動換行,因此須要就它們放在一個塊元素裏面,這裏咱們用的是p,而後就正常了。

<div id="register">
            <form>
                <p>
                    <label for="user">帳號:</label>
                    <input type="text" name="user" class="text" id="user" placeholder="暱稱,不小於兩位!">
                    <span class="star">*</span>
                </p>
                <p>
                    <label for="password">密碼:</label>
                    <input type="password" name="password" class="text" id="password" placeholder="密碼,不小於6位!">
                    <span class="star">*</span>
                </p>
                <p>
                    <label for="email">郵箱:</label>
                    <input type="email" name="email" class="text" id="email" placeholder="郵箱,用於找回密碼!">
                    <span class="star">*</span>
                </p>
            </form>
        </div>

 

3. 建立用戶表

如今開始建立用戶表,第一個版本的表結構以下:

這個表有幾個須要改進的地方。首先,create能夠改成int類型,方便在web程序裏操做。其次,這個表裏有的字段是char類型,有的字段是varchar類型。char類型是固定長度的,可能會浪費一些空間,但查詢速度快,varchar正好相反。因此,咱們考慮把常常須要查詢到的username、email改成char類型。若是一個表裏既有char也有varchar,那麼它的查詢速度就會收到影響,因此咱們這裏把intro單獨拿出來放到一個新表裏,兩個表經過外鍵關聯,而且在username、email和uid上都創建unique索引。最終兩個表以下:

 

4. AJAX註冊及自動完成

這裏主要應用了jquery validate插件來實現註冊信息的ajax方式提交

$("#register").dialog({
        width: 430,
        height: 330,
        modal: true,
        resizable: false,
        autoOpen: false,
        title: "註冊新用戶",
        closeText: "關閉",
        buttons: [{
            text: "提交",
            click: function(e) {
                $(this).submit();
            },
        }],
        
    }).validate({
        submitHandler: function(form) {
            $(form).ajaxSubmit({
                url: ThinkPHP["MODULE"] + "/User/register",
                type: "POST",
            });
        },
    });

爲了訪問User/register,咱們定義了ThinkPHP["MODULE"]變量

index.tpl

<script type="text/javascript">
    var ThinkPHP = {
        "IMG" : "__PUBLIC__/{:MODULE_NAME}/img",
        "MODULE" : "__MODULE__"
    };
</script>

最開始咱們把用戶註冊邏輯放在了UserController中,可是這樣程序的結構不夠清晰,應該將其放到UserModel中,由Model來處理業務邏輯,Controller的做用主要是處理用戶提交的數據,這裏注意不要忘記在UserController.class.php中use Home\Model\UserModel。

UserModel.class.php

<?php
namespace Home\Model;
use Think\Model;

class UserModel extends Model {
    
    protected $_auto = array(
            array("password", "sha1", self::MODEL_BOTH, "function"),
            array("create", "time", self::MODEL_INSERT, "function"),
        );
        
    //註冊一個用戶
    public function register($username, $password, $email) {
        $data = array(
            'username' => $username,
            'password' => sha1($password),
            'email'       => $email,
            'create'   => time(),
        );
        
        if ($this->create($data)) {
            $uid = $this->add($data);
            return $uid? $uid : 0;
        }
    }
}

 

5. 服務器端驗證

服務器端的驗證應用了ThinkPHP框架中模型的自動驗證功能:

UserModel.class.php

//用戶表自動驗證
protected $_validate = array(
    array('username', '2, 20', '用戶名長度不合法', self::EXISTS_VALIDATE, 'length'),
    array('password', '6, 30', '密碼長度不合法', self::EXISTS_VALIDATE, 'length'),    
);
......

if ($this->create($data)) {
$uid = $this->add($data);
return $uid? $uid : 0;
} else {
return $this->getError();
}

 

驗證錯誤信息(如上面的"用戶名長度不合法")能夠經過模型的getError()方法獲得,可是getError只會返回第一個驗證的錯誤信息,由於驗證到第一個不符合條件的項目後就再也不繼續驗證了。能夠經過打開批量驗證功能,是全部表項都獲得驗證,此時getError返回的是一個數組:

UserModel.class.php

//打開批量驗證功能
protected $patchValidate = true;

......

if ($this->create($data)) {
    $uid = $this->add($data);
    return $uid? $uid : 0;
} else {
    print_r($this->getError());
}

設置好以上自動驗證後,輸入用戶名和密碼的時候測試老是報錯:

緣由是咱們在自動完成裏設置了對密碼進行hash,因此hash後的密碼長度都是40,超過了自動驗證裏的長度限制30。可是,經過閱讀《ThinkPHP3.2.2徹底開發手冊》,我發現自動驗證是在自動完成以前,應該不會出現上面的問題纔對啊?!

今天終於找到了緣由:

UserModel.class.php

//
註冊一個用戶 public function register($username, $password, $email) { $data = array( 'username' => $username, 'password' => sha1($password), 'email' => $email, 'create' => time(), ); if ($this->create($data)) { $uid = $this->add($data); return $uid? $uid : 0; } else { print_r($this->getError()); } }

上面對password執行了sha1,致使了長度爲40,去掉sha1就正常了。

前面的自動驗證的錯誤信息返回的都是字符串,其實這個錯誤最終要返回給客戶端,因此最好用數字代替字符串,這樣還須要關閉批量驗證功能:

UserModel.class.php

//打開批量驗證功能
//protected $patchValidate = true;
    
//用戶表自動驗證
protected $_validate = array(
    //-1, 用戶名長度不合法
    array('username', '2, 20', -1, self::EXISTS_VALIDATE, 'length'),
    //-2, 密碼長度不合法
    array('password', '6, 30', -2, self::EXISTS_VALIDATE, 'length'),
    //-3, 密碼和密碼確認不一致
    array('repassword', 'password', -3, self::EXISTS_VALIDATE, 'confirm'),
    //-4, 郵箱格式不正確
    array('email', 'email', -4, self::EXISTS_VALIDATE),
    //-5, 用戶名被佔用
    array('username', '', -5, self::EXISTS_VALIDATE, 'unique', self::MODEL_INSERT),
    //-6, 郵箱被佔用
    array('email', '', -6, self::EXISTS_VALIDATE, 'unique', self::MODEL_INSERT),
    );

......

if ($this->create($data)) {
    $uid = $this->add($data);
    return $uid? $uid : 0;
} else {
    return $this->getError();
    }

 

6. 客戶端驗證

客戶端驗證利用了jquery validate插件:

validate({
        submitHandler: function(form) {
            $(form).ajaxSubmit({
                url: ThinkPHP["MODULE"] + "/User/register",
                type: "POST",
            });
        },
        
        rules: {
            username: {
                required: true,
                minlength: 2,
                maxlength: 20,
            },
            password: {
                required: true,
                minlength: 6,
                maxlength: 30,
            },
            repassword: {
                required: true,
                equalTo: '#password',
            },
            email: {
                required: true,
                email: true,
            },
        },
        
        messages: {
            username: {
                required: '帳號不得爲空',
                minlength: $.format('帳號不得小於{0}位!'),
                maxlength: $.format('帳號不得大於{0}位!'),
            },
            password: {
                required: '密碼不得爲空',
                minlength: $.format('密碼不得小於{0}位!'),
                maxlength: $.format('密碼不得大於{0}位!'),
            },
            repassword: {
                required: '密碼確認不得爲空',
                equalTo: '密碼和密碼確認必須一致!',
            },
            email: {
                required: '郵箱不得爲空',
                email: '郵箱格式不正確',
            },
        },
        
    });

效果以下圖所示:

如今全部的錯誤提示信息都顯示在了表單項的後面,這樣很不美觀,咱們想把它們放到註冊窗口的最上方,並重寫錯誤信息的顯示方式。

首先咱們在註冊表單中添加一個無序列表:

index.tpl

<
form id="register" action="123.html"> <ol class="register_errors"></ol> <p> <label for="user">帳號:</label> <input type="text" name="username" class="text" id="user" placeholder="暱稱,不小於兩位!"> <span class="star">*</span>
</p>
......
login.js

showErrors: function(errorMap, errorList) {
    this.defaultShowErrors();
},
        
errorLabelContainer: 'ol.register_errors',

如今錯誤顯示以下:

咱們應該把每條信息放到一個單獨的列表項中,添加以下代碼:

showErrors: function(errorMap, errorList) {
    this.defaultShowErrors();
},
        
errorLabelContainer: 'ol.register_errors',
        
wrapper: 'li',

如今的顯示效果以下:

 咱們看到註冊表框右邊出現了一個scrollbar,錯誤信息的顏色也不夠顯眼,咱們如今想把它去掉,同時讓錯誤信息和出現錯誤的表單項的邊框變爲紅色:

login.css

#register ol.register_errors
{ margin: 0; padding: 0 0 0 20px; color: red; } #register ol.register_errors li { height: 20px; }
login.js

showErrors: function(errorMap, errorList) { var errors = this.numberOfInvalids(); if (errors > 0){ $("#register").dialog('option', 'height', errors * 20 + 370); } else { $("#register").dialog('option', 'height', 370); }; this.defaultShowErrors(); }, hightlight: function(element, errorClass) { $(element).css('border', '1px solid red'); }, unhightlight: function(element, errorClass) { $(element).css('border', '1px solid #ccc'); },

 如今咱們想實現另外一個效果,當輸入項正確的時候,表單項後面出現一個對號,錯誤的時候出現一個叉號,以下所示:

首先咱們設計兩個CSS樣式:

login.css

#register span.succ {
    display: inline-block;
    
    padding: 5px;
    width: 28px;
    height: 28px;
    
    background: url(../img/success.png) no-repeat top;
}

#register span.failure {
    display: inline-block;
    
    padding: 5px;
    width: 28px;
    height: 28px;
    
    background: url(../img/failure.png) no-repeat top;
}

而後在login.js中添加以下代碼:

login.js

highlight: function(element, errorClass) {
    $(element).css('border', '1px solid red');
    $(element).parent().find('span').html('&nbsp;').removeClass('succ').addClass('failure');
},

unhighlight: function(element, errorClass) {
    $(element).css('border', '1px solid #ccc');
    $(element).parent().find('span').html('&nbsp;').removeClass('star').addClass('succ');
},

 

7. Ajax驗證數據

這裏也是應用的validate插件的功能,基本思路以下:經過remote將數據Ajax提交給服務器,服務器調用相應的方法檢查字段,返回'true'或'false'給remote。注意,remote只接受字符串true或false做爲返回值,因此checkUserName和checkEmail都返回true或false。

login.js

rules: { username: { required:
true, minlength: 2, maxlength: 20, remote: { url: ThinkPHP['MODULE'] + '/User/checkUserName', type: 'POST', /* beforeSend: function() { $('#username').next().html('&nbsp;').removeClass('succ').addClass('loading'); }, complete: function(jqXHR) { if (jqXHR.responseText == 'true') { $('#username').next().html('&nbsp;').removeClass('loading').addClass('succ'); } else { $('#username').next().html('&nbsp;').removeClass('loading').addClass('failure'); } } */ }, }, password: { required: true, minlength: 6, maxlength: 30, }, repassword: { required: true, equalTo: '#password', }, email: { required: true, email: true, remote: { url: ThinkPHP['MODULE'] + '/User/CheckEmail', type: 'POST', /* beforeSend: function() { $('#email').next().html('&nbsp;').removeClass('succ').addClass('loading'); }, complete: function(jqXHR) { if (jqXHR.responseText == 'true') { $('#email').next().html('&nbsp;').removeClass('loading').addClass('succ'); } else { $('#email').next().html('&nbsp;').removeClass('loading').addClass('failure'); } } */ }, }, },
UserModel.class.php

//
驗證佔用字段 public function checkField($field, $type) { $data = array(); switch ($type) { case 'username': $data['username'] = $field; break; case 'email': $data['email'] = $field; break; default: return 0; } return $this->create($data)? 1 : $this->getError(); }
UserController.class.php

//
Ajax驗證數據,帳號返回給Ajax public function checkUserName() { if (IS_AJAX) { $user = new UserModel(); $uid = $user->checkField(I('username'), 'username'); echo $uid > 0? 'true' : 'false'; } } //Ajax驗證數據,郵箱返回給Ajax public function checkEmail() { if (IS_AJAX) { $user = new UserModel(); $uid = $user->checkField(I('email'), 'email'); echo $uid > 0? 'true' : 'false'; } }

 

8. 完善及郵箱補全

到這一步,登錄界面已經快完成了,但還有幾個須要完善的地方。首先咱們但願在用戶提交了註冊信息到服務器返回這段時間能有一個提示信息,用戶註冊成功後也有一個提示信息,像下面這樣:

這兩個提示框實際上是兩個沒有titlebar的dialog,其中第一個dialog咱們是寫在模板文件中的,第二個dialog是經過javascript替換第一個的圖標和文字內容實現的:

index.tpl

<div id="loading">數據交互中...</div>

它的CSS代碼以下:

login.css

#loading
{ font-size: 14px; font-weight: bold; color: #666; line-height: 25px; text-indent: 40px; background: url(../img/loading.gif) no-repeat 20px center; }
login.js

submitHandler: function(form) {
    $(form).ajaxSubmit({
        url: ThinkPHP["MODULE"] + "/User/register",
        type: "POST",
        beforeSubmit: function() {
            $('#loading').dialog('open');
        },
        success: function(responseText) {
            if (responseText) {
                $('#loading').css('background', 'url(' + ThinkPHP['IMG'] + '/reg_success.png) no-repeat 20px center').html('數據新增成功...');
                
            }
        },
    });
},

 如今當用戶註冊成功的時候會有提示信息,可是如今該信息和註冊界面都不會消失,因此咱們還得加上讓它們消失的代碼。此外,若是提示信息消失的太快會顯得很突兀,因此咱們給它加上一秒的延時:

login.js

success: function(responseText) { if (responseText) { $('#loading').css('background', 'url(' + ThinkPHP['IMG'] + '/reg_success.png) no-repeat 20px center').html('數據新增成功...'); setTimeout(function() { $('#register').dialog('close'); //關閉註冊界面 $('#loading').dialog('close'); //關閉提示界面 $('#register').resetForm(); //還原註冊表單 $('#register span.star').html('*').removeClass('succ'); //恢復*去掉對號 }, 1000); } },

對於郵箱補全功能,我直接copy了網上現成的代碼:

$("#email").autocomplete({  
    delay: 0, //默認爲300 毫秒,延遲顯示設置。  
    autoFocus:true, //設置爲true 時,第一個項目會自動被選定。  
    source: function (request, response) {  

        var hosts = ["qq.com", "163.com", "263.com", "sina.com.cn", "gmail.com", "hotmail.com"];//郵箱域名集合  

        var term = request.term; //獲取用戶輸入的內容;  
        var name = term;  //郵箱的用戶名  
        var host = "";   //郵箱的域名 例如qq.com  
        var ix = term.indexOf('@'); //@的位置  
        var result = []; //最終呈現的郵箱列表  
          
        //當用戶輸入的數據(email)裏存在@的時候,就從新給用戶名和域名賦值  
        if (ix > -1) { //若是@符號存在,就表示用戶已經輸入用戶名了。  
            name = term.slice(0, ix);  
            host = term.slice(ix + 1);  
        }  

        if (name) { //若是name有值 即:不爲空  

            var getHosts = []; //根據用戶名填寫的域名咱們在hosts裏面找到對應的域名集合  
              
            getHosts=  host ? ($.grep(hosts, function (val) { return val.indexOf(host) > -1 })) : hosts;  

            result = $.map(getHosts, function (val) { //這個val就是getHosts裏的每一個域名元素。  
                return name + "@" + val;  
            });                  
        }            
        result.unshift(term); // unshift方法的做用是:將一個或多個新元素添加到數組開始,數組中的元素自動後移,返回數組新長度 

        response(result);  

    }  
});  

這裏有一個問題就是dialog阻止了溢出(overflow),致使自動提示的內容顯示不全:

咱們須要設置dialog顯示溢出:

login.css

.ui-dialog {
    border: none;
    overflow: visible;
}

 

9. 彈出驗證碼

爲了防止機器註冊,咱們給註冊頁面添加一個彈出驗證碼的功能。這裏須要一個新的dialog,我在模板文件裏新添加一個form:

index.tpl

<
form id="verify_register"> <ol class="ver_error"></ol> <p> <label for="verify">驗證碼:</label> <input type="text" name="verify" class="text" id="verify"> <span class="star">*</span> <a href="javascript:void(0)" class="changeimg">換一換</a> </p> <p> <img src='{:U("Login/verify",'','')}' class="changeimg verifyimg"> </p> </form>

而後咱們在LoginController.class.php中添加一個verify方法,就是上面img的src中的方法:

LoginController.class.php

<?php
namespace Home\Controller;
use Think\Controller;

class LoginController extends Controller {
    public function index() {
        $this->display();
    }
    
    public function verify() {
        $verify = new \Think\Verify();
        $verify->entry(1);
    }
}

在javascript中將form變爲dialog:

login.js

$("#verify_register").dialog({ width: 290, height: 300, modal: true, resizable: false, autoOpen: true, title: "請輸入驗證碼", closeText: "關閉", buttons: [{ text: "完成", click: function(e) { $(this).submit(); }, }], });

最後爲這個驗證碼彈出頁面添加樣式:

login.css
i
#verify_register input.text {
    padding: 5px;
    border: 1px solid #ccc;
    border-radius: 3px;
    width: 85px; 
    height: 25px;
    
    background: #fff;    
}

咱們還須要驗證碼刷新的功能,這樣是經過javascript實現的:

login.js

//點擊更換驗證碼
var verifyimg = $('.verifyimg').attr('src');
$('.changeimg').click(function(){
    $('.verifyimg').attr('src', verifyimg + '?random=' + Math.random());
});

上週日添加了驗證碼功能後,註冊表單的提交按鈕忽然很差用了,詳細檢查了login.js,依然無果。今天又查看了一下其它文件,終於找到了問題的緣由,原來是UserController.class.php裏一個函數寫錯了:

UserController.class.php

//
Ajax驗證數據,郵箱返回給Ajax public function checkEmail() { if (IS_AJAX) { $user = new UserModel(); $uid = $user->checkField(I('email'), 'email'); echo $uid > 0? 'true' : 'false'; } } //Ajax驗證數據,驗證碼返回給Ajax public function checkEmail() { //應該是checkVerify if (IS_AJAX) { if (check_verify(I('verify'))) { echo "驗證碼正確"; } else { echo "驗證碼錯誤"; } } }

 

10. 登錄驗證

當用戶登錄的時候,既可使用用戶名,也能夠用郵箱,由於用戶名和郵箱都是惟一的。可是這裏有一個問題,那就是若是用戶用郵箱做爲用戶名來註冊,這就可能出現一個用戶有兩個帳號的問題,因此咱們須要在註冊的用戶名上作一些限制,使郵箱沒法做爲用戶名來註冊。方法也很簡單,就是限制用戶名不能包含@符號。

咱們須要同時在客戶端和服務器端進行檢測。

客戶端代碼:

login.js

//
自定義驗證,不得包含@符號 $.validator.addMethod('inAt', function(value, element) { var text = /^[^@]+$/i; //注意不要加引號!!! return this.optional(element) || (text.test(value)); }, '存在@符號');
login.js

rules: {
    username: {
        required: true,
        inAt: true,
        minlength: 2,
        maxlength: 20,
        remote: {
            url: ThinkPHP['MODULE']  + '/User/checkUserName',
            type: 'POST',
login.js

messages: {
    username: {
        required: '帳號不得爲空',
        inAt: '帳號不得包含@符號',
        minlength: $.format('帳號不得小於{0}位!'),
        maxlength: $.format('帳號不得大於{0}位!'),
        remote: '帳號被佔用',
    },

如今當用戶登錄的時候可使用用戶名也可使用郵箱名,固然登錄方式仍是採用ajax方式:

login.js

$('#login').validate({
    submitHandler: function(form){
        $(form).ajaxSubmit({
            url: ThinkPHP['MODULE']  + '/User/login',
            type: 'POST',
        });
    },
});

後臺的登錄處理程序是UserController.class.php中的login方法:

Usercontroller.class.php

//Ajax驗證數據,帳號返回給Ajax
public function login() {
    if (IS_AJAX) {
        $user = new UserModel();
        $uid = $user->login(I('username'), I('password'));
        echo $uid;
    } else {
        $this->error('非法訪問');
    }
}

它又調用了UserModel.class.php中的login方法:

UserModel.class.php

//登錄驗證
public function login($username, $password) {
    $data = array(
        'login_username' => $username,
        'password' => $password,
    );
    
    //where條件
    $map = array();
    
    if ($this->create($data)) {
        //這裏採用郵箱登錄
        $map['email'] = $username;
        $user = $this->field('id, password')->where($map)->find();
            if ($user['password'] == $password) {
                return $user['id'];
            } else {
                return -9;    //用戶密碼錯誤
            }
            
    } else {
        if($this->getError() == 'noemail') {
            //這裏採用用戶名登錄
            $map['username'] = $username;
            $user = $this->field('id, password')->where($map)->find();
            if ($user['password'] == $password) {
                return $user['id'];
            } else {
                return -9;    //用戶密碼錯誤
            }
            
        } else {
            echo $this->getError();
        }
    }
    
}

咱們能夠看到這裏在處理用戶名登錄和郵箱名登錄時有一部分代碼是相同的,咱們能夠把這部分代碼拿出來:

UserModel.class.php

//登錄驗證
public function login($username, $password) {
    $data = array(
        'login_username' => $username,
        'password' => $password,
    );
    
    //where條件
    $map = array();
    
    if ($this->create($data)) {
        //這裏採用郵箱登錄
        $map['email'] = $username;                
    } else {
        if($this->getError() == 'noemail') {
            //這裏採用用戶名登錄
            $map['username'] = $username;
        } else {
            echo $this->getError();
        }
    }
    
    $user = $this->field('id, password')->where($map)->find();
    if ($user['password'] == $password) {
        return $user['id'];
    } else {
        return -9;    //用戶密碼錯誤
    }
    
}

 當用戶登陸的時候若是登陸信息不合法,咱們須要顯示錯誤信息,這裏咱們把信息顯示在相應的input中,以下圖所示:

首先咱們須要改造模板頁面,把username和password放到span標籤中:

index.tpl

<div id="main">
    <form id="login">
        <div class="top">
            <span class="username">
                <input type="text" name="username" placeholder="用戶名/郵箱">
            </span>
            <span class="password">
                <input type="password" name="password" placeholder="密碼">
            </span>
            <input type="submit" name="submit" value="登陸">
        </div>
        <div class="bottom">
            <a href="javascript:void(0)" id="reg_link">註冊新用戶</a>
            <a href="javascript:void(0)">忘記密碼?</a>
        </div>
    </form>
</div>

接着設計CSS:

login.css

#login span.username, #login span.password {
    position: relative;
}

#login span.username label.error, #login span.password label.error {
    position: absolute;
    right: 20px;
    bottom: 0px;
    
    color: #f90;
}

前端驗證代碼以下:

login.js

$('#login').validate({
    submitHandler: function(form){
        $(form).ajaxSubmit({
            url: ThinkPHP['MODULE']  + '/User/login',
            type: 'POST',
        });
    },
    rules: {
        username: {
            required: true,
            minlength: 2,
            maxlength: 50,
        },
        password: {
            required: true,
            minlength: 6,
            maxlength: 30,
        },
    },
    messages: {
        username: {
            required: '帳號不得爲空',
            minlength: $.format('帳號不得小於{0}位!'),
            maxlength: $.format('帳號不得大於{0}位!'),
        },
        password: {
            required: '密碼不得爲空',
            minlength: $.format('密碼不得小於{0}位!'),
            maxlength: $.format('密碼不得大於{0}位!'),
        },
    },
});

 當用戶點擊登陸按鈕以後,咱們須要根據ajax返回數據作出反應,這主要是經過javascript實現的:

login.js

$('#login').validate({
    submitHandler: function(form){
        $(form).ajaxSubmit({
            url: ThinkPHP['MODULE']  + '/User/login',
            type: 'POST',
            beforeSubmit: function() {
                $('#loading').dialog('open');
            },
            success: function(responseText) {
                if (responseText == -9) {
                    $('#loading').dialog('option', 'width', 200).css('background', 'url(' + ThinkPHP['IMG'] + '/warning.png) no-repeat 20px center').html('帳號或密碼不正確...');
                    setTimeout(function(){
                        $('#loading').dialog('close');
                        $('#loading').dialog('option', 'width', 180).css('background', 'url(' + ThinkPHP['IMG'] + '/loading.gif) no-repeat 20px center').html('數據交互中...');
                    }, 2000);
                } else {
                    $('#loading').dialog('option', 'width', 220).css('background', 'url(' + ThinkPHP['IMG'] + '/reg_success.png) no-repeat 20px center').html('登陸成功,跳轉中...');
                    setTimeout(function(){
                        location.href = 'http://www.baidu.com';
                    }, 1000);
                }
            },
        });
相關文章
相關標籤/搜索