在了解了項目的結(jié)構(gòu)之后,接下來就該實戰(zhàn)操作了晋修。對大多數(shù)網(wǎng)站而言六水,登錄注冊的功能是不可或缺的俺孙,這也是許多網(wǎng)站開始的第一步。今天就做一個簡單版的登錄功能掷贾,來了解一下PHP與Web是如何實現(xiàn)交互的睛榄。
在開始之前,我們需要先理一下思路想帅。一個登錄的邏輯大概是這樣:用戶輸入用戶名與密碼->網(wǎng)頁校驗數(shù)據(jù)->把數(shù)據(jù)發(fā)給后端->后端從數(shù)據(jù)庫中查詢后給出響應(yīng)场靴,成功則跳轉(zhuǎn),失敗給出失敗原因港准。
關(guān)聯(lián)Controller與View
根據(jù)以上分析旨剥,我們在寫具體登錄的邏輯前,需要一個靜態(tài)的網(wǎng)頁浅缸,還需要一份數(shù)據(jù)庫轨帜,用以承載數(shù)據(jù)。靜態(tài)的網(wǎng)頁是必須的衩椒,但是不屬于討論的范疇蚌父,所以可以從網(wǎng)上尋找模板,這個網(wǎng)上有很多毛萌,當(dāng)然如果自己會寫html苟弛,手打自然是最好不過了。
不管是從網(wǎng)上下載的模板阁将,還是自己寫的HTML膏秫,其結(jié)構(gòu)都與下圖類似:
按照上文說的,我們最好應(yīng)該把 css冀痕、js荔睹、images等文件放到\Public\Home\相應(yīng)的文件夾下狸演,那么HTML文件應(yīng)該放在哪里呢言蛇?這里就需要掌握一下TP框架是如何把我們的代碼與所請求的鏈接對應(yīng)起來的。在TP中(至少在TP3.2.3版本中)宵距,TP通過訪問 http://域名:端口號/模塊名/控制器名/方法名 的規(guī)則建立了請求鏈接與實際代碼的對應(yīng)關(guān)系腊尚。例如,在第一篇文章中满哪,我們曾經(jīng)在\Application\Home\Controller\IndexController.class.php中婿斥,將框架自動生成的代碼替換成了:
echo 'Hello PHP劝篷!';
在瀏覽器中輸入http://localhost/thinkphp_3.2.3_full/就看到了這句輸出。而在瀏覽器中輸入http://localhost/thinkphp_3.2.3_full/民宿,TP框架實際上做的是:試圖尋找跟隨在域名和端口號后的模塊名娇妓、控制器名與方法名。而在這個請求中沒有找到這些活鹰,TP就會用默認的控制器名和方法名來解析這個請求哈恰,所以實際上我們輸入http://localhost/thinkphp_3.2.3_full/時,TP就會解析成http://localhost/thinkphp_3.2.3_full/Home/Index/index志群,也就是它會去尋找項目中位于Home模塊下名稱為Index的控制器下的定義為index的那個方法着绷,也就是執(zhí)行了我們替換的那句:
echo 'Hello PHP!';
那么锌云,到底HTML文件應(yīng)該放在哪里呢荠医?要知道,在TP中桑涎,是用MVC模式組織代碼的彬向。剛剛的IndexController屬于控制器層,而HTML顯然應(yīng)該屬于View層石洗,所以我們應(yīng)該把它放在View文件夾下幢泼,并要注意把引用的css、js讲衫、images等的相對路徑指定到\Public\Home\下對應(yīng)的路徑缕棵,修改后類似于下圖:
現(xiàn)在,還有另外一個問題涉兽,HTML代碼被放在了View層里招驴,那么我們應(yīng)該怎么去訪問它呢?剛剛說了枷畏,鏈接里包含的是控制器名别厘,并沒有包含View,所以只能是由Controller來調(diào)用View拥诡。這里直接給出代碼:
class IndexController extends Controller {
public function index(){
$this->display();
}
}
就是把剛剛那句打印触趴,換成:
$this->display();
IndexController就會去尋找位于\View\Index\下的index.html文件。display()方法是在TP框架內(nèi)部定義的渴肉,它有幾個默認的參數(shù)冗懦,可以直接看框架中的定義:
/**
* 模板顯示 調(diào)用內(nèi)置的模板引擎顯示方法,
* @access protected
* @param string $templateFile 指定要調(diào)用的模板文件
* 默認為空 由系統(tǒng)自動定位模板文件
* @param string $charset 輸出編碼
* @param string $contentType 輸出類型
* @param string $content 輸出內(nèi)容
* @param string $prefix 模板緩存前綴
* @return void
*/
protected function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') {
$this->view->display($templateFile,$charset,$contentType,$content,$prefix);
}
這些參數(shù)都可以靈活選用仇祭,默認情況下披蕉,如果HTML文件的名稱與控制器對應(yīng)(和控制器名稱相同但全部小寫),我們可以不傳遞任何參數(shù)。例如我們把HTML文件的名稱改為'index1.html'没讲,就把
$this->display();
替換成
$this->display('index1');
就可以正常工作了眯娱。
然而,做完這些工作后爬凑,當(dāng)我們嘗試在瀏覽器中去訪問時徙缴,就出現(xiàn)了下面的問題:
稍微了解一點前端,都能看出來是css等文件沒有加載出來嘁信,而僅僅在HTML文件中定義的其他代碼顯示出來了娜搂,這是在初學(xué)時常見的事情。
那么吱抚,原因是什么呢百宇?由于我們使用的是Apache服務(wù)器,Apache服務(wù)器的根路徑實際上是www秘豹,而我們寫相對路徑時想當(dāng)然的把項目的根目錄作為根路徑了携御,所以Apache服務(wù)器自然找不到我們指定的代碼。知道了這點之后既绕,我們就可以想到兩種解決方案:給每個路徑都增加一個層級啄刹,讓它相對于www開始;另一種就是凄贩,想辦法讓Apache服務(wù)器的根路徑和項目的一致誓军。
給每個路徑增加層級,把路徑寫的死死的這種做法是不推薦的疲扎,這為我們以后修改或遷移造成了很大的麻煩昵时,所以這里優(yōu)先采用第二種方法。要實現(xiàn)這種方案椒丧,就需要配置vhost壹甥,并建立域名映射。具體步驟是:打開wamp安裝目錄下的\bin\apache\apache2.4.23\conf\extra\httpd-vhosts.conf文件壶熏,默認內(nèi)容如下:
其中的ServerName就是我們訪問的地址句柠,DocumentRoot就是指定的根目錄。這也是訪問http://localhost/時將使用的路徑“艏伲現(xiàn)在我們把這段代碼復(fù)制一份溯职,把信息改成自己的項目,如下所示:
這里的DocumentRoot就是我們項目的目錄帽哑,因為我要把項目同步到git谜酒,所以路徑改了一下名字,相當(dāng)于之前的/www/thinkphp_3.2.3_full祝拯。
除此之外绣否,還需要在C:\Windows\System32\drivers\etc\hosts文件中,為剛剛配置的域名添加本地映射了牛,內(nèi)容如下:
然后重啟Apache服務(wù)器注竿,再打開瀏覽器就可以看到正確的頁面了:
關(guān)聯(lián)數(shù)據(jù)庫
頁面顯示正常后,開始寫業(yè)務(wù)邏輯了康嘉。我們需要在MySQL中建立數(shù)據(jù)庫碉输、數(shù)據(jù)表,并插入幾條數(shù)據(jù)(由于做的功能是登錄亭珍,必須先有賬號才行)敷钾,并且把建立的數(shù)據(jù)庫和項目關(guān)聯(lián)起來。
首先肄梨,可以通過點擊wamp運行起來的圖標(biāo)阻荒,選擇MySQL->MySQL console,打開mysql控制臺众羡,在顯示Enter password時直接按回車侨赡。或者通過Windows的命令行粱侣,進入到wamp安裝目錄下的\bin\mysql\mysql5.7.14\bin目錄羊壹,然后輸入:
mysql -hlocalhost -uroot -p
按回車,也可以進入到mysql的控制臺齐婴。其中-h表示服務(wù)器名油猫,localhost表示本地;-u為數(shù)據(jù)庫用戶名柠偶,root是mysql默認用戶名情妖;-p為密碼,如果設(shè)置了密碼诱担,可直接在-p后鏈接輸入鲫售,如:-p123456,用戶沒有設(shè)置密碼该肴,顯示Enter password時情竹,直接回車即可。默認情況下是沒有設(shè)置密碼的匀哄,所以直接按回車秦效,就會進入下圖的頁面,等待輸入:
接下來需要掌握一些MySQL的命令才能繼續(xù)下去涎嚼。首先阱州,可以通過
show databases;
顯示現(xiàn)在已有的數(shù)據(jù)庫,如圖所示:
然后通過命令創(chuàng)建一個名為tplearn的數(shù)據(jù)庫:
create database tplearn;
要使用創(chuàng)建的數(shù)據(jù)庫法梯,需要使用命令:
use tplearn;
現(xiàn)在苔货,我們就有了項目需要的數(shù)據(jù)庫犀概,然后需要建一張名為user的表,用來存儲賬號信息夜惭。在控制臺輸入以下代碼:
create table if not exists user(
id int unsigned auto_increment,
user_name varchar(50) not null,
user_pass varchar(50) not null,
user_phone varchar(20) not null,
user_email varchar(50) not null,
user_sex tinyint unsigned not null default 0 comment '0 男 1 女',
create_time int unsigned not null default 0,
primary key (id)
)engine=InnoDB default charset=utf8;
這段代碼創(chuàng)建了一張名為user的表姻灶,字段有id,姓名诈茧、密碼产喉、手機號、郵箱敢会、性別曾沈,還有創(chuàng)建時間等字段,其中id是主鍵鸥昏,comment是給字段添加注釋塞俱。創(chuàng)建好后,可以用
show create table user;
或
desc user;
來顯示創(chuàng)建的表結(jié)構(gòu)吏垮,示意圖如下:
然后敛腌,創(chuàng)建幾個測試用的賬號,添加到數(shù)據(jù)表中惫皱,執(zhí)行以下兩條語句:
insert into user (user_name,user_pass,user_phone,user_email,user_sex,create_time)
values ('test1','123456','13122223333','test1@qq.com',0,0);
insert into user (user_name,user_pass,user_phone,user_email,user_sex,create_time)
values ('test2','654321','13133334444','test2@qq.com',1,0);
完成后像樊,可以通過
select * from user;
查看數(shù)據(jù)庫中所有的數(shù)據(jù):
現(xiàn)在,就要把數(shù)據(jù)庫與項目關(guān)聯(lián)在一起旅敷。在TP中生棍,這步操作十分簡單。只需要從\ThinkPHP\Conf\convention.php中找到注釋為“數(shù)據(jù)庫設(shè)置”的一段代碼媳谁,復(fù)制到\Application\Common\Conf\config.php中涂滴,然后配置一些字段即可,配置后代碼如下:
/* 數(shù)據(jù)庫設(shè)置 */
'DB_TYPE' => 'mysql', // 數(shù)據(jù)庫類型
'DB_HOST' => '127.0.0.1', // 服務(wù)器地址
'DB_NAME' => 'tplearn', // 數(shù)據(jù)庫名
'DB_USER' => 'root', // 用戶名
'DB_PWD' => '', // 密碼
'DB_PORT' => '3306', // 端口
'DB_PREFIX' => '', // 數(shù)據(jù)庫表前綴
'DB_PARAMS' => array(), // 數(shù)據(jù)庫連接參數(shù)
'DB_DEBUG' => TRUE, // 數(shù)據(jù)庫調(diào)試模式 開啟后可以記錄SQL日志
'DB_FIELDS_CACHE' => true, // 啟用字段緩存
'DB_CHARSET' => 'utf8', // 數(shù)據(jù)庫編碼默認采用utf8
'DB_DEPLOY_TYPE' => 0, // 數(shù)據(jù)庫部署方式:0 集中式(單一服務(wù)器),1 分布式(主從服務(wù)器)
'DB_RW_SEPARATE' => false, // 數(shù)據(jù)庫讀寫是否分離 主從式有效
'DB_MASTER_NUM' => 1, // 讀寫分離后 主服務(wù)器數(shù)量
'DB_SLAVE_NO' => '', // 指定從服務(wù)器序號
在當(dāng)前階段晴音,只需要配置前7項即可柔纵,其中數(shù)據(jù)庫表前綴指的是創(chuàng)建數(shù)據(jù)表時,名稱前加的前綴锤躁,比如創(chuàng)建的數(shù)據(jù)表為lp_user搁料,前綴就是'lp_',這里沒有前綴系羞,保持空即可」疲現(xiàn)在,數(shù)據(jù)庫就和當(dāng)前的項目關(guān)聯(lián)在一起了椒振。
關(guān)聯(lián)在一起后昭伸,又怎樣寫SQL語句,來實現(xiàn)業(yè)務(wù)呢澎迎?在TP中庐杨,有兩種方式來操作數(shù)據(jù)庫选调,一種是創(chuàng)建一個與數(shù)據(jù)表對應(yīng)的Model,Model的名稱是數(shù)據(jù)表名去掉前綴灵份,比如數(shù)據(jù)表為tp_user仁堪,Model名稱就定義為UserModel,在Model中就可以進行增刪改查等操作了各吨。另外一種,則是通過M()方法直接操作數(shù)據(jù)表袁铐。同時揭蜒,TP中還定義了一系列函數(shù),用以支持MySQL使用時的連貫操作剔桨,這些在手冊中都有詳細介紹屉更。
第一種方法需要創(chuàng)建Model類,在\Application\Home\Model下新建一個名為UserModel.class.php的php文件洒缀,內(nèi)容如下:
<?php
namespace Home\Model;
use Think\Model;
class UserModel extends Model{
}
namespace為命名空間瑰谜,定義Model或Controller時都需要指定命名空間,在自動生成的IndexController中也有這個字段树绩。然后在UserModel中寫一個測試方法萨脑,獲取數(shù)據(jù)庫中所有的賬號。
public function getUsers(){
return $this->select();
}
這個方法的效果饺饭,就等同于"select * from user;"渤早。然后在Controller中就可以這樣引用它:
$User = D("User");
$res = $User->getUsers();
D()方法等同于 new UserModel();它是用來簡化實例化類的操作的。通過獲取UserModel的實例再調(diào)用方法就可以得到結(jié)果了瘫俊。
這種方法由于需要實例化類鹊杖,會消耗部分性能,也因為要實例化類扛芽,所以要多寫很多代碼骂蓖,適合用于操作比較頻繁、語句比較復(fù)雜的情況川尖。當(dāng)僅需要對數(shù)據(jù)表進行基本的CURD(增刪改查)時登下,還可以使用第二種方法,就是使用M()方法與建立數(shù)據(jù)表的關(guān)聯(lián)叮喳。M()方法和D()方法功能類似庐船,只是它不實例化類,性能較好嘲更,所有的CURD操作都需要直接進行筐钟,即使定義了UserModel類,M()方法也不會使用它赋朦。使用M()方法實現(xiàn)剛才的實例篓冲,如下所示:
$User = M("User");
$res = $User->select();
可以想象李破,當(dāng)數(shù)據(jù)操作較為復(fù)雜時,使用M()方法會使得Controller類比較臃腫壹将,因此具體使用哪種方法需要權(quán)衡考慮嗤攻。
完成這些工作后,終于可以寫具體的邏輯了诽俯。由于最初接觸妇菱,有許多東西需要了解,所以從零到一顯得比較復(fù)雜暴区,但是掌握了之后闯团,寫起代碼來還是蠻輕松的。剩余的內(nèi)容仙粱,請參考《ThinkPHP初學(xué)者:寫一個簡單登錄頁面(二)》房交。