下載解壓 ThinkPHP 3.2.3,在默認的應用 Application(./Application) 中,包含一個默認的模塊 Home(./Application/Home)。javascript
須要在該默認應用中建立一個用於後臺管理的 Admin 模塊,能夠經過在應用入口文件(./index.php)中綁定 Admin 模塊來 自動生成 Admin 模塊:php
define('BIND_MODULE','Admin');
此時訪問 http://serverName/index.php 便會自動在 ./Application 下建立 Admin 目錄(要記得把上面的定義 刪掉,不然經過入口文件訪問網站首頁就會默認訪問 Admin 模塊)。css
不須要修改入口文件。html
此時訪問 http://serverName/index.php/Admin 就能夠訪問後臺的 Index 控制器的 index 方法了。java
目錄結構以下:mysql
應用配置(公共配置文件)位於 ./Application/Common/Conf/config.php ,在 ThinkPHP 調用全部的模塊以前加載。jquery
在這裏沒有作特別的配置,只開啓了 Trace 追蹤信息:redis
<?php return array( //'配置項'=>'配置值' //顯示頁面 Trace 信息 'SHOW_PAGE_TRACE' => true, );
Admin 模塊的模塊配置位於 ./Application/Admin/Common/Conf/config.phpsql
該項目開啓的配置包括:數據庫
① 數據庫
//數據庫配置信息 'DB_TYPE' => 'mysql', // 數據庫類型 'DB_HOST' => '127.0.0.1', // 服務器地址 'DB_NAME' => 'tptest', // 數據庫名 'DB_USER' => 'root', // 用戶名 'DB_PWD' => '', // 密碼 'DB_PORT' => 3306, // 端口 'DB_PARAMS' => array(), // 數據庫鏈接參數 'DB_PREFIX' => 'crm_', // 數據庫表前綴 'DB_CHARSET'=> 'utf8', // 字符集 'DB_DEBUG' => TRUE, // 數據庫調試模式 開啓後能夠記錄SQL日誌
② 配置後臺公共文件
因爲該項目同時包含 Home、Admin 模塊,因此公共文件必須分開,所以能夠把 Admin 模塊的公共文件放在 ./Application/Public/Admin 下,在 Admin 的模塊配置文件中配置:
//後臺公共文件路徑 'TMPL_PARSE_STRING' => array( '__PUBLIC__' => __ROOT__.'/Public/Admin' ),
③ 定義異常頁面
//異常頁面 'TMPL_EXCEPTION_FILE' => './Public/Admin/error.html',
異常頁面 error.html 中錯誤信息能夠用 $e['message'] 表示
若是須要有倒計時跳轉的功能,能夠參考 ./ThinkPHP/Tpl/dispatch_jump.tpl 文件
error.html:
<!DOCTYPE html> <html> <head> <title>error</title> <meta charset="UTF-8"> </head> <body> <?php echo $e['message'];?><br /> <b id="wait">5</b>秒後跳轉回首頁 或 點擊<a id="href" href="/Admin/Index/index">返回首頁</a> <script> (function(){ var wait = document.getElementById('wait'),href = document.getElementById('href').href; var interval = setInterval(function(){ var time = --wait.innerHTML; if(time <= 0) { location.href = href; clearInterval(interval); }; }, 1000); })(); </script> </body> </html>
例如訪問了不存在的方法,頁面會輸出:
沒法加載控制器:Login2
3秒後跳轉回首頁 或 點擊返回首頁
而後跳轉回後臺主頁。
注:該頁面中不能使用 ThinkPHP 的標籤,只能使用原生的 PHP 語句。
用於登錄的文件是 Admin 模塊下的 LoginController.class.php
<?php namespace Admin\Controller; use Think\Controller; class LoginController extends Controller{ public function index() { $this->display(); } //驗證碼 public function verify() { $conf = array( //'useZh'=>true,//使用中文 'fontSize'=>20, 'length'=>1, 'imageW'=>100,//驗證碼寬度 ); $Verify = new \Think\Verify($conf); $Verify->entry(); } public function login() { if(!IS_POST) { e('非法登錄'); } //檢驗驗證碼 if(!check_verify(I('post.code'))) { $this->error('驗證碼錯誤'); } $username = I('post.username', ''); $user = M('user')->where(array('username'=>$username))->find(); if(!$user || md5(I('post.password')) != $user['password']) { $this->error('用戶名或密碼錯誤'); } if($user['lock']) $this->error('用戶被鎖定'); //更新用戶表 $data = array( 'id'=>$user['id'], 'logintime'=>time(), 'loginip'=> get_client_ip() ); M('user')->save($data); //保存session session("user.uid", $user['id']); session("user.username", $user['username']); session("user.logintime", date('Y-m-d H:i:s', $user['logintime'])); session("user.loginip", $user['loginip']); //成功跳轉 $this->redirect('Admin/Index/index'); } }
幾點說明:
① IS_POST
位於 ./ThinkPHP/Library/Think/App.class.php(ThinkPHP 應用程序類 執行應用程序管理) 的 static public function init() 方法(應用程序初始化)內
定義當前請求的系統常量,源碼:
define('REQUEST_METHOD', $_SERVER['REQUEST_METHOD']); define('IS_POST', REQUEST_METHOD =='POST' ? true : false);
② e 方法
位於 ThinkPHP/Common/functions.php (Think 系統函數庫)
/** * 拋出異常處理 * @param string $msg 異常消息 * @param integer $code 異常代碼 默認爲0 * @throws Think\Exception * @return void */ function E($msg, $code=0) { throw new Think\Exception($msg, $code); }
③ 模板路徑
默認狀況下,Admin 模塊 Login 控制器的 index 方法對應的模板文件應該是 ./Application/Admin/View/Login/index.html
若是不但願目錄層級太多的話,能夠將該方法對應的模板文件設置爲 ./Application/Admin/View/Login_index.html,減小了一層目錄,在 Admin 模塊的模塊配置 config.php 中添加:
//模版路徑 'TMPL_FILE_DEPR' => '_',
登錄之後進入後臺首頁 http://serverName/Admin/Index/index
Admin 模塊的 Index 控制器 ./Application/Admin/Controller/IndexController.class.php:
<?php namespace Admin\Controller; class IndexController extends CommonController { public function index(){ $this->display(); } //推出登錄 public function loginout() { session_unset(); session_destroy(); $this->redirect('Admin/Login/index'); } }
注:要進入後臺首頁,必須通過登錄,所以在加載該控制器以前應該先檢查用戶是否登錄,檢查的方法能夠寫在 Admin 模塊的 Common 控制器中,而後 Index 控制器繼承 Common 控制。Common 控制器位於 ./Application/Admin/Controller/CommonController.class.php:
<?php namespace Admin\Controller; use Think\Controller; class CommonController extends Controller{ public function _initialize() { if(!isset($_SESSION['user']['uid']) || !isset($_SESSION['user']['username'])) { $this->redirect('Admin/Login/index'); } } }
注:在 ./ThinkPHP/Library/Think/Controller.class.php (ThinkPHP 控制器基類)定義了
/** * 架構函數 取得模板對象實例 * @access public */ public function __construct() { Hook::listen('action_begin',$this->config); //實例化視圖類 $this->view = Think::instance('Think\View'); //控制器初始化 if(method_exists($this,'_initialize')) $this->_initialize(); }
登錄模塊的視圖文件位於 ./Application/Admin/View/Login_index.html:
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="__PUBLIC__/Css/login.css" /> <meta charset="utf-8"> <script src="__PUBLIC__/Js/jquery-1.7.2.min.js"></script> <script src="__PUBLIC__/Js/login.js"></script> </head> <body> <div id="top"> </div> <div class="login"> <form action="{:U('Admin/Login/login')}" method="post" id="login"> <div class="title"> 登陸後臺 </div> <table border="1" width="100%"> <tr> <th>管理員賬號:</th> <td> <input type="username" name="username" class="len250"/> </td> </tr> <tr> <th>密碼:</th> <td> <input type="password" class="len250" name="password"/> </td> </tr> <tr> <th>驗證碼:</th> <td> <input type="code" class="len250" name="code"/> <img src="{:U('Admin/Login/verify','','')}" id="code"/> <a href="javascript:void(change_code(this));">看不清</a> </td> </tr> <tr> <td colspan="2" style="padding-left:160px;"> <input type="submit" class="submit" value="登陸"/></td> </tr> </table> </form> </div> </body> </html>
注:
① U 方法
在控制器使用 U 方法的格式是 U(模塊/控制器/方法, array('參數1'=>'參數1的值','參數2'=>'參數2的值', '僞靜態後綴'))
在模板中使用 U 方法的格式是 {:U(模塊/控制器/方法, array('參數1'=>'參數1的值','參數2'=>'參數2的值', '僞靜態後綴'))}
② 僞靜態後綴
能夠在模塊配置文件 config.php 中配置僞靜態後綴,默認爲 .html,即 URL 多是 http://serverName/Admin/Index/index.html。能夠設置爲空,即 URL 可能爲 http://serverName/Admin/Index/index
//僞靜態後綴 'URL_HTML_SUFFIX'=>'',
Admin 模塊的文件目錄:
crm_user 表:
CREATE TABLE `crm_user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `username` char(20) NOT NULL DEFAULT '', `password` char(32) NOT NULL DEFAULT '', `logintime` int(10) unsigned NOT NULL, `loginip` varchar(30) NOT NULL, `lock` tinyint(1) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
① 把 Session 存儲在 MySQL 數據庫中
ThinkPHP 3.2.3 自帶了 Db 類型的 Session 驅動,Db 類位於 ./ThinkPHP/Library/Think/Session/Driver/Db.class.php
框架已經準備好了 session 表:
CREATE TABLE think_session ( session_id varchar(255) NOT NULL, session_expire int(11) NOT NULL, session_data blob, UNIQUE KEY `session_id` (`session_id`) );
修改模塊配置 ./Application/Admin/Common/Conf/config.php,增長如下配置便可:
'SESSION_TYPE'=>'Db',
② 把 Session 存儲在 Redeis 中
ThinkPHP 3.2.3 自帶了 Memcache 驅動,能夠參考該驅動來開發 Redis 驅動,新建 Redis.class.php,放在 ./ThinkPHP/Library/Think/Session/Driver 下:
<?php // +--------------------------------------------------------------------- // | Date:2016/01/09 // +---------------------------------------------------------------------- namespace Think\Session\Driver; class Redis { //保存Redis鏈接對象 protected $redis; //Session有效時間 private $expire; /** * 打開Session * @access public * @param string $savePath * @param mixed $sessName */ public function open($savePath, $sessName) { $this->expire = C('SESSION_EXPIRE') ? C('SESSION_EXPIRE') : ini_get('session.gc_maxlifetime'); $this->redis = new Redis(); return $this->redis->connect(C('REDIS_HOST'), C('REDIS_PORT')); } /** * 關閉Session * @access public */ public function close() { return $this->redis->close(); } /** * 讀取Session * @access public * @param string $sessID */ public function read($sessID) { $sessID = C('SESSION_PREFIX').$sessID; $sessData = $this->redis->get($sessID); return $sessID ? $sessID : ''; } /** * 寫入Session * @access public * @param string $sessID * @param String $sessData */ public function write($sessID, $sessData) { $sessID = C('SESSION_PREFIX').$sessID; return $this->redis->set($sessID, $sessData, $this->expire); } /** * 刪除Session * @access public * @param string $sessID */ public function destroy($sessID) { $sessID = C('SESSION_PREFIX').$sessID; return $this->redis->delete($sessID); } /** * Session 垃圾回收 * @access public * @param string $sessMaxLifeTime */ public function gc($sessMaxLifeTime) { return true; } }
而後修改模塊配置文件 config.php:
'SESSION_TYPE'=>'Redis', //Redeis服務器地址 'REDIS_HOST'=>'127.0.0.1', //Redis端口號 'REDIS_PORT'=>'6379', //Session前綴 'SESSION_PREFIX'=>'session_', //Session有效時間 'SESSION_EXPIRE'=>3600
文章管理的控制器 ArticleManageController.class.php:
<?php /* * 文章管理類 * date:2016/01/10 */ namespace Admin\Controller; use Think\Page; class ArticleManageController extends CommonController{ public function index() { $count = M('article')->count(); $page = new Page($count, 3); $limit = $page->firstRow.','.$page->listRows; $show = $page->show(); $list = M('article')->limit($limit)->select(); $this->assign('list', $list); $this->assign('show', $show); $this->display(); } }
注:ThinkPHP 3.2.3 的分頁類位於 ./ThinkPHP/Library/Think/Page.class.php,所以除了使用 use 關鍵字引入命名空間爲 Think 的 Page類,而後直接實例化 Page類外,還能夠在須要實例化 Page 類的時候 new \Think\Page(); Think 前面的 \ 表明根命名空間。
在使用分頁類的時候只須要把總條數和每頁分配的條數做爲參數傳給 Page 類以獲取 limit 參數。
文章管理的視圖文件位於 ./Application/Admin/View/ArticleManage_index.html:
<!DOCTYPE html> <html> <head> <title>TODO supply a title</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <css file='__PUBLIC__/Css/public.css'/> </head> <body> <table class='table'> <tr> <th>序號</th> <th>標題</th> <th>發佈人</th> <th>內容概述</th> <th>發佈時間</th> <th>操做</th> </tr> <volist name='list' id='vo'> <tr> <td>{$vo.id}</td> <td>{$vo.title}</td> <td>{$vo.creat_id}</td> <td>{$vo.content}</td> <td>{$vo.addtime|date="Y-m-d H:i", ###}</td> <td> <a href="#">刪除</a> </td> </tr> </volist> <tr> <td colspan="6" align="center">{$show}</td> </tr> </table> </body> </html>
注:模板中使用了點語法解析數組,點語法在模板中除了解析數組外,還能夠解析對象。能夠在模塊配置中設置點語法只解析數組,可使模板解析速度更快:
//點語法默認解析
'TMPL_VAR_IDENTIFY' => 'array',