就以这个小实例来将核心包里的知识串一下,并且学习thinkphp3的三大自动,以及拓展包文件上传、验证码、Ajax的简单实用。不具体去做前端的样式,仅仅简单实现一下功能。

功能分析

登录模块,加图片

  • 登录
  • 退出

注册模块,加图片

  • 注册用户

留言模块,加图片

  • 提交留言信息
  • 显示留言信息

数据库设计

根据下表建立数据库

to_user (用户表)
字段 类型 notnull 默认值 备注
id int notnull 主键 自增
username varchar(30) ‘’ 用户名
password char(32) 密码
sex tyint notnull 1 性别:1代表男 0 代表女
tp_message
字段 类型 notnull 默认值 备注
id int notnull 主键 自增
title varchar(60) ‘’ 题目
content text 内容
filename varchar(30) notnull 1 附件名
time int 时间:时间戳格式
uid int 外键:用户表中的id

创建项目

将thinkphp文件夹复制到新建的Message文件夹中,并且创建主入口文件index.php

1
2
3
4
5
6
7
8
9
10
//index.php
<?php
//应用名称
define('APP_NAME','Home');
//应用路径
define('APP_PATH','./Home/');
//是否选择开启debug模式。
//define('APP_DEBUG',true);
require './ThinkPHP/ThinkPHP.php';
?>

保存文件后。访问http://localhost/Message/index.php就可以看到文件里自动生成了项目文件

首页功能

一个留言板的首页是怎样的呢?这里将首页切割成三份,一部分显示系统名称留言板,第二部分显示留言内容,第三部分提交留言内容。并且建立好相应的前端模板文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//IndexAction.class.php
<?php
class IndexAction extends Action {
public function index(){
//通过session来判断是否登陆
if(isset($_SESSION['username'])&&$_SESSION['username']!=''){
$this->display();
}else{
$this->redirect('Login/login');
}
//如果没有登陆则跳转到登陆页面
//否则显示index页面
}

//top部分的显示
public function top(){
$this->display();
}
//left部分的显示
public function left(){
$this->display();
}
//right部分的显示
public function right(){
$this->display();
}
}

以上方式需要在每个需要判断session的地方加上上述代码。因此,我们可以建立一个公共的中间类,在初始化阶段就完成权限判断,不仅如此,还可以将一些公共部分添加进来。

1
2
3
4
5
6
7
8
9
10
11
// CommconAction.class.php
<?php
class CommonAction extends Action{
Public function _initialize(){
// 初始化的时候检查用户权限
if(!isset($_SESSION['username']) || $_SESSION['username']==''){
$this->redirect('Login/login');
}
}
}
?>

这样就需要将Index模块改写,继承Commcon

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//IndexAction.class.php
<?php
// 本类由系统自动生成,仅供测试用途
class IndexAction extends CommonAction {
public function index(){
$this->display();
}
public function top(){
//$this->assign('name',$_SESSION['username']);
$this->display();
}
public function left(){
$this->display();
}
public function right(){
$this->display();
}
}

模板部分如下,需要先建好top.html,left.html,right.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 // Tpl\Index\index.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Index</title>
</head>
<frameset rows='20%,*'>
<frame src='__URL__/top' name='top'/>
<frameset cols='50%,50%'>
<frame src='__URL__/left' name='left'/>
<frame src='__URL__/right' name='right'/>
</frameset>
</frameset>
</html>

登陆功能

登陆功能首先需要一个登陆页面,还要相应的模块进行登陆的验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php

// 登陆模块
class LoginAction extends Action{
public function login(){
//显示出登陆页面
$this->display();
}
// doLogin 用于验证是否登陆成功
public function doLogin(){

//接受前端传来的参数
$username=$_POST['username'];
$password=$_POST['password'];
$code=$_POST['code'];
//验证验证码是否正确
if(md5($code)!=$_SESSION['code']){
$this->error('验证码不正确');
exit();
}
$where['username']=$username;
$where['password']=$password;
$user=M('User');
$count=$user->where($where)->count();
if($count>0){
//登陆成功
$_SESSION['username']=$username;
$_SESSION['id']=$id;
$this->success('登陆成功',U('Index/index'));
}else{
$this->error("用户或密码错误",U('Login/login'));
}
//数据库查询,是否有该条记录
//如果有登陆成功,给SESSION写值,并且跳转回首页
//否则登陆失败,跳转回登陆页面

}
}

?>

验证码的使用

先下载拓展包解压会得到一个Extend文件,替换掉ThinkPHP文件里的Extend。然后再创建一个公共的验证码的模块控制器。代码如下

1
2
3
4
5
6
7
8
9
//PublicAction.class.php
<?php
class PublicAction extends Action{
public function code(){
import('ORG.Util.Image');
Image::buildImageVerify(4,1,'png',30,30,'code');
}
}
?>

会生产一个图片,只要在前端引用这个图片就好了。

1
验证码: <input type='text' name='code'/><img src='__APP__/Public/code' onclick="this.src=this.src+'?'+Math.random()"/><br/>

完整的Login.html代码如下,省略了图片和Css,Js文件。此处使用js来进行表单的提交。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Login</title>
<load href="__PUBLIC__/Css/basic.css" />
<load href="__PUBLIC__/Css/Home/reg.css" />
<load href="__PUBLIC__/Js/jquery.js"/>
<script>
$(function(){
$('img[title="register"]').click(function(){

window.location.href="__APP__/Register/reg";

});
var error = new Array();
$('input[name="code"]').blur(function(){

var code = document.forms['myForm']['code'].value;

$.post('__APP__/Public/Yzcode',{'code':code},function(data){
if(data=='error'){
error['code']=1;
$('#code').remove();
$('img[name="code"]').after('<p id="code" style="color:red">验证码错误</p>');
}else if(data=='correct'){
error['code']=0;
$('#code').remove();
}
});

});

$('img[title="login"]').click(function(){
if(error['code']==0){
$('form[name="myForm"]').submit();
}else{
return false;
}
});
});
</script>
</head>
<body>
<form action='__URL__/doLogin' method='post' name='myForm'>
用户名:<input type='text' name='username'/></br>
密 码:<input type='password' name='password'/><br/>

验证码: <input type='text' name='code'/><img src='__APP__/Public/code' onclick="this.src=this.src+'?'+Math.random()" name='code'/><br/>
<img src='__PUBLIC__/Images/login.gif' title='login' class='submit'/>
<img src='__PUBLIC__/Images/register.gif' title ='register'/>
</form>
</body>
</html>

账号退出

利用thinkphp3提供的对session进行操作的方法,实现账号的退出。

1
2
3
4
5
6
7
8
9
10
11
12
13
//LoginAction.class.php
public function doLogout(){
//这样就可以清除session
/*$_SESSION=array();
if(isset($_COOKIE[session_name()])){
setcookie(session_name(),'',time()-1,'/');
}
session_destroy();
*/
//Thinkphp提供了销毁当前session的机制
session('[destroy]');
$this->redirect('Index/index');
}

注册功能

注册功能和登录功能差不太多,运用Ajax来实现用户名是否已经被注册了。首先先创建好注册功能的模板文件.

为了能顺利理解和使用Ajax。。狂补了一波JS语法。。

注册页面的代码。实现了ajax判断是否注册,已经确认密码操作。应该考虑一下把js代码封装起来?之后再完善吧.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>注册</title>
<load href="__PUBLIC__/Css/basic.css" />
<load href="__PUBLIC__/Css/Home/reg.css" />
<load href="__PUBLIC__/Js/jquery.js"/>
<script>
$(function(){
var error=new Array();
$('input[name="username"]').blur(function(){
var username = document.forms['myForm']['username'].value;
$.post('__URL__/ajax',{'username':username},function(data){
if(data=='已注册'){
error['username']=1;
$('#umessage').remove();
$('input[name="username"]').after('<p id="umessage" style="color:red">该用户名已经注册</p>');
}else if(data=="可以注册"){
error['username']=0;
$('#umessage').remove();
}
});
});

$('input[name="repassword"]').blur(function(){
var password1=document.forms['myForm']['password'].value;
var password2=document.forms['myForm']['repassword'].value;
if(password1==password2&&password1!=''&&password2!=''){
error['password']=0;
$('#pmessage').remove();
}else{
error['password']=1;
$('#pmessage').remove();
$('input[name="password"]').after('<p id="pmessage" style="color:red">两次输入的密码不一样</p>');
}

});

$('input[name="code"]').blur(function(){
var code = document.forms['myForm']['code'].value;
$.post('__APP__/Public/Yzcode',{'code':code},function(data){
if(data=='error'){
error['code']=1;
$('#code').remove();
$('img[name="code"]').after('<p id="code" style="color:red">验证码错误</p>');
}else{
error['code']=0;
$('#code').remove();
}
});
});

$("img.register").click(function(){

if(error['username']==1){
return false;
}else if(error['password']==1){
return false;
}else if(error['code']==1){
return false;
}else{
$("form[name='myForm']").submit();
}
});
});
</script>
</head>
<body>
<form action='__URL__/doReg' method='post' name='myForm'>
用 户 名:<input type='text' name='username'/><br/>
密  码:<input type='password' name='password'/><br/>
确认密码:<input type='password' name='repassword'/><br/>
性  别:<input type='radio' name='sex' value='1' class='radio'/>
<input type='radio' name='sex' value='0' class='radio'/><br/>
验 证 码:<input type='text' name='code'/> <img src='__APP__/Public/code' onclick="this.src=this.src+'?'+Math.random()" name='code'/>
<br/>
<img src='__PUBLIC__/Images/register.gif' class='register'/>
<img src='__PUBLIC__/Images/reset.gif' class='reset'/>
</form>
</body>
</html>

自动创建

在实际的注册功能这,首先想到的是定义一个doReg函数来接受参数之后再进行add()插入数据。Thinkphp3提供了自动创建的功能,能够自动将传来的POST值自动创建数据对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php

class RegisterAction extends Action{

public function reg(){
$this->display();
}
public function doReg(){

/*
随便称这种为基本方式的注册。
完成注册,
先接受传参
*/
$username=$_POST['username'];
$password=$_POST['password'];
$sex = $_POST['sex'];
$User = M('User');
$User->username=$username;
$User->password=$password;
$User->sex=$sex;
if($User->add()>0){
$this->success("注册成功",U('Login/login'));
}else{
$this->error("注册失败");
}
}
public function doReg2(){
/*
自动创建方式
*/
$User=D('User');
if(!$User->create()){
$this->error($User->getError());//自动验证能够自动判断数据是否符合要求
}
if($User->add()>0){
$this->success("注册成功",U('Login/login'));
}else{
$this->error("注册失败");
}
}
}
?>

自动验证

既然可以自动创建出数据模型,那如何对他们的数据符不符合数据库里定义的标准该如何判断?thinkphp3提供自动验证的机制,需要在模型类中定义好规则。注意上文创建模型是用D方法,D(‘User’)是将UserModel.class.php进行实例化,和M方法是完全不一样的,在实际开发,自带的Model是不足以满足业务需求,因此需要定义自己的模型类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Model/UserModel.class.php
//和Action类似,需要继承Model类
<?php
class UserModel extends Model{
protected $_validate=array(
//array(验证字段,验证规则,错误提示,[验证条件,附加规则,验证时间])
array('code','require','验证码必须填写!'),
array('code','checkCode','验证码错误!',0,'callback',1), //checkCode函数必须写成protect
array('username','require','用户必须填写!'),
array('username','','用户已经存在',0,'unique',1),
array('username','/^\w{6,}$/','用户名必须6个字母以上',0,'regex',1),//正则必须以/开头和结尾
array('repassword','password','确认密码不正确',0,'confirm'),
);
}
protected function checkCode($code){
if(md5($code)!=$_SESSION['code']){
return false;
}else{
return true;
}
}

?>

留言模块

留言模块实质就是将留言内容插入到数据库,以及将上传的附件名字存入数据库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php

class MessageAction extends Action{
public function doMessage(){

$title = $_POST['title'];
$content = $_POST['content'];
$message = new Model('Message');
$message->time=time();
$message->tittle=$title;
$message->content=$content;
if(!empty($_FILES['filename']['name'])&&$_FILES['filename']['name']!="")
{
import('ORG.Net.UploadFile');
$upload = new UploadFile();// 实例化上传类
$upload->savePath = './Public/Uploads/';// 设置附件上传目录
$upload->allowExts = array('jpg', 'gif', 'png', 'jpeg');//设置文件上传后缀的白名单
if(!$upload->upload()) {// 上传错误提示错误信息
$this->error($upload->getErrorMsg());
}else{// 上传成功 获取上传文件信息
$info = $upload->getUploadFileInfo();
$message->filename=$info[0]['savename'];
}
}
//获取上传以后的文件名
$message->uid=$_SESSION['id'];
if($message->add()){
$this->success('成功留言');
}else{
$this->error('留言失败');
}

}
}

?>

包含了文件上传的组件的最基本利用,还可以设置文件上传的后缀等安全措施。

显示留言

关联模型

关联模型可以非常方便的将两个有相互关系的表关联起来,此时自定义的模型类需要继承的是RelationModel而不是Model 详细信息参看手册。

自动完成

自动完成是三大自动之一,可以自动完成一些操作,例如将密码进行md5加密,赋值等操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php

class MessageModel extends RelationModel{

//设置自动填充
protected $_auto=array(
array('time','time',1,'function'),
array('uid','getId',1,'callback'),
);

//设置关联数组,Message和其他表的所有关联关系都写在这
protected $_link = array(
//设置message表和user表的关联
'User'=> array(
'mapping_type'=>BELONGS_TO,
'class_name'=>'User',
'foreign_key'=>'uid',
'mapping_name'=>'user',
'as_fields'=>'username',
),


);

protected function getId(){
echo $_SESSION['id'];
return $_SESSION['id'];
}

}

?>

数据分页

在IndexAction.class.php中将数据库的值查询出,再利用分页操作,将数据分页。并且数据传递交由给模板显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
class IndexAction extends Action {
public function index(){
//通过session来判断是否登陆
if(isset($_SESSION['username'])&&$_SESSION['username']!=''){
$this->display();
}else{
$this->redirect('Login/login');
}
//如果没有登陆则跳转到登陆页面
//否则显示index页面
}

//top部分的显示
public function top(){
$this->display();
}
//left部分的显示
public function left(){

//首先获得message表中的所有数据
$message=D('Message'); //MessageAction.class.php
//////////////////////////分页操作
import('ORG.Util.Page');
$count=$message->count();
//多少条数据一页
$page = new Page($count,2);

$page->setConfig('header','条留言');
$show = $page->show();//返回分页的字符串。
//////////////////////////

///////////////关联操作 relation(true);
$arr = $message->relation(true)->limit($page->firstRow.','.$page->listRows)->select();
$this->assign('list',$arr);
$this->assign('show',$show);
$this->display();

}
//right部分的显示
public function right(){
$this->display();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
left.html
<html>
<h1>留言板</h1>
<body>
<foreach name='list' item='vo'>

<p>留言标题:{$vo.tittle}</p>
<p>留言内容:{$vo.content}</p>
<p>留言用户:{$vo.uname}</p>
<p>留言时间:{$vo.time|date='Y/m/d H:i:s',###}</p>
<p>附  件:{$vo.filename}</p>
<hr/>
</foreach>
{$show}
</body>
</html>