Thinkphp权限认证(2)-Auth权限控制器

根据上一节内容 Auth权限认证规则与管理组创建  我们创建好了相关的规则和管理组。下面介绍下如何在其他控制器中进行权限认证:

在控制器Controller目录中创建以下控制器。

1.创建登录控制器 LoginController.class.php

namespace Admin\Controller;
use Think\Controller;

class LoginController extends Controller{
	
	public function index(){
		if(IS_POST){
			$_POST['password'] = md5($_POST['password']);
			$user = M('user');
			if($user->create()){
				if($data = $user->where(I())->find()){
					$_SESSION['user'] = $data;
					$this->success("登录成功!",U("Index/index"));
				}else{
					$this->error("登录失败");
				}	
				
			}else{
				$this->error("登录失败");
			}
			exit;
		}
		$this->display();
	}
	public function logout(){
		$_SESSION['user'] = array();
		$this->redirect("Login/index");
	}
}

2.创建公共控制器 PublicController.class.php

namespace Admin\Controller;
use Think\Controller;

class PublicController extends Controller{
	
	public function _initialize(){
               //判断登录
		$uid = $_SESSION['user']['id'];
		if(!$uid){
			$this->error("请先登录!",U("Login/index"));
		}
		//判断超级管理员
		if($uid == 6){
			return true;
		}
		//权限认证
		$auth = new \Think\Auth();
		$rule = CONTROLLER_NAME.'/'.ACTION_NAME;
		if(!$auth->check($rule,$uid)){
			$this->error("没有权限");
		}
	}
}

3.在其他控制器继承 PublicController.class.php

namespace Admin\Controller;

class IndexController extends PublicController {
    public function index(){
        
		$this->display();
    }
}

完成以上即可实现Auth权限认证控制。

 

Thinkphp权限认证(1)- Auth权限认证规则与管理组创建

Auth权限简介

Thinkphp系统提供了完善的权限控制方法-Auth权限认证,可以对用户的管理权限进行很好的控制。

Auth权限认证的基本原理是由四张表进行逻辑关联达到权限控制。这四张表分别是:

1.用户表 user 存放用户的信息

2.规则表 auth_rule 存放具体规则,每条规则是由规则名对应控制器方法,比如 新增文章 – Article/add

3.用户组表auth_group 存放权限管理组,每条管理组对应多个规则

4.用户组明细表 auth_group_access 存放用户与管理组的关联。

通过以上四张表之间的相互关联,就可以对每个用户的具体访问权限进行控制。

如何创建Auth权限认证规则与管理组:

在ThinkPHP/Library/Think目录的 Auth.class.php 文件中,可以详细看到Auth的介绍。下面的表的创建方法就是摘取此文件。

1.创建规则表、用户组表及用户组明细表

//数据库
-- ----------------------------
-- think_auth_rule,规则表,
-- id:主键,name:规则唯一标识, title:规则中文名称 status 状态:为1正常,为0禁用,condition:规则表达式,为空表示存在就验证,不为空表示按照条件验证
-- ----------------------------
 DROP TABLE IF EXISTS `tp_auth_rule`;
CREATE TABLE `tp_auth_rule` (  
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,  
    `name` char(80) NOT NULL DEFAULT '',  
    `title` char(20) NOT NULL DEFAULT '',  
    `type` tinyint(1) NOT NULL DEFAULT '1',    
    `status` tinyint(1) NOT NULL DEFAULT '1',  
    `condition` char(100) NOT NULL DEFAULT '',
    PRIMARY KEY (`id`),  
    UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-- ----------------------------
-- think_auth_group 用户组表, 
-- id:主键, title:用户组中文名称, rules:用户组拥有的规则id, 多个规则","隔开,status 状态:为1正常,为0禁用
-- ----------------------------
 DROP TABLE IF EXISTS `tp_auth_group`;
CREATE TABLE `tp_auth_group` ( 
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, 
    `title` char(100) NOT NULL DEFAULT '', 
    `status` tinyint(1) NOT NULL DEFAULT '1', 
    `rules` char(80) NOT NULL DEFAULT '', 
    PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-- ----------------------------
-- think_auth_group_access 用户组明细表
-- uid:用户id,group_id:用户组id
-- ----------------------------
DROP TABLE IF EXISTS `tp_auth_group_access`;
CREATE TABLE `tp_auth_group_access` (  
    `uid` mediumint(8) unsigned NOT NULL,  
    `group_id` mediumint(8) unsigned NOT NULL, 
    UNIQUE KEY `uid_group_id` (`uid`,`group_id`),  
    KEY `uid` (`uid`), 
    KEY `group_id` (`group_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

注意:表名前缀tp_改为自己的表前缀

2.修改Auth.class.php文件中关于用户表的两处内容

第一处是默认配置

//默认配置
protected $_config = array(
	'AUTH_ON'           => true,  
	'AUTH_TYPE'         => 1,
	'AUTH_GROUP'        => 'auth_group',
	'AUTH_GROUP_ACCESS' => 'auth_group_access',
	'AUTH_RULE'         => 'auth_rule',
	'AUTH_USER'         => 'user'  // 注意这里改为你的用户表名称,不含前缀
);

第二处是用户表的id

/**
 * 获得用户资料,根据自己的情况读取数据库
 */
protected function getUserInfo($uid) {
	static $userinfo=array();
	if(!isset($userinfo[$uid])){
                //下面'id'=>$uid,原来是'uid'=>$uid,这里要修改
		 $userinfo[$uid]=M()->where(array('id'=>$uid))->table($this->_config['AUTH_USER'])->find();
	}
	return $userinfo[$uid];
}

3.规则控制器与规则管理组控制器

规则表等创建完成以后,我们需要创建两个控制器及其方法,一个是RuleController.class.php用来增删改查规则,另一个是GroupController.class.php用来增删改查用户组(也就是规则管理组)。

完成以上表与规则创建,下一步就是对其他控制器进行权限认证 Auth权限控制器

 

Thinkphp文件上传

在Thinkphp中可以使用 \Think\Upload() 类实现上传功能。下面是具体文件上传步骤:

单文件上传

1.首先在模板中创建一个表单:

<form action="__CONTROLLER__/doAdd" method="POST" enctype="multipart/form-data">
	<input type="file" name="pic">
	<input type="submit" value="上传">
</form>

注意:一定要定义 enctype=”multipart/form-data”

2.在控制器中创建方法:

public function pic(){  //前端页面展示FORM表单
	$this->display();
}
public function doAdd(){  //表单提交的方法
	$this->upload($_FILES);		
}
private function upload($file){  //表单提交的文件处理
	$config = array(
		"maxSize" => 10240000,
		"exts" => array('jpg', 'gif', 'png', 'jpeg'),
		"rootPath" => "./Public/Upload/",
		"savaPath" => "",
	);
	$upload = new \Think\Upload($config);
	$info = $upload->uploadOne($file['pic']);
	if(!$info){
		$this->error($upload->getError());
	}else{
		dump($info);
	}
	
}

注意:\Thinkp\Upload类具体参数下面详细说明。

多文件上传:与单文件有两处不同

表单提交<input type=”file” name=”pic[]” multiple>

上传方法 $info = $upload->upload();

1.创建表单

<form action="__CONTROLLER__/doAdd" method="POST" enctype="multipart/form-data">
	<input type="file" name="pic[]" multiple>
	<input type="submit" value="上传">
</form>

2.控制器中创建方法

public function pic(){  //前端页面展示FORM表单
	$this->display();
}
public function doAdd(){  //表单提交的方法
	$this->upload($_FILES);		
}
private function upload($file){  //表单提交的文件处理
	$config = array(
		"maxSize" => 10240000,
		"exts" => array('jpg', 'gif', 'png', 'jpeg'),
		"rootPath" => "./Public/Upload/",
		"savaPath" => "",
	);
	$upload = new \Think\Upload($config);
	$info = $upload->upload();  //uploade()方法自动获取$_FILES
	if(!$info){
		$this->error($upload->getError());
	}else{
            foreach($info as $value){  //info是个三维数组,可以遍历每张图片的保存信息
               echo $value['savapath'].$value['savaname'];
            }		
	}
	
}

 

Thinkphp分页 搜索分页 定制分页样式

Thinkphp系统提供有分页功能,使用类 \Think\Page;

普通分页

$article = M("article");
$count = $article->count();  // 查询满足要求的总记录数
$page = new \Think\Page($count,25);  // 实例化分页类 传入总记录数和每页显示的记录数(25)
$show = $page->show();  // 分页显示输出
// 进行分页数据查询 注意limit方法的参数要使用Page类的属性
$list = $article->limit($page->firstRow.','.$page->listRows)->select();
$this->assign("show",$show);
$this->assign("list",$list);
$this->display();

注意: 实例化分页类 \Think\Page();

搜索分页

1.使用GET表单提交搜索

$article = M("article");
$title = urlencode($_GET['title']);
$map['title'] = array('LIKE',"%{$title}%");
$count = $article->where($map)->count();
$page = new \Think\Page($count,25);
$show = $page->show();
$list = $article->where($map)->limit($page->firstRow.','.$page->listRows)->select();
$this->assign("show",$show);
$this->assign("list",$list);
$this->display();

2.使用POST提交搜索表单

$article = M("article");
$title = urlencode($_REQUEST['title']);
$args['title'] = $title;		
$map['title'] = array('LIKE',"%{$title}%");
$count = $article->where($map)->count();
$page = new \Think\Page($count,25,$args);
$show = $page->show();
$list = $article->where($map)->limit($page->firstRow.','.$page->listRows)->select();
$this->assign("show",$show);
$this->assign("list",$list);
$this->display();

分页样式

我们可以对输出的分页样式进行定制,分页类Page提供了一个setConfig方法来修改默认的一些设置。例如:

$article = M("article");
$title = urlencode($_REQUEST['title']);
$args['title'] = $title;		
$map['title'] = array('LIKE',"%{$title}%");
$count = $article->where($map)->count();
$page = new \Think\Page($count,25,$args);
$page->setConfig("first","首页");
$page->setConfig("prev","上一页");
$page->setConfig("next","下一页");
$page->setConfig("last","末页");	//注意last不显示,此项是个bug
$page->setConfig("theme","%UP_PAGE% %LINK_PAGE% %DOWN_PAGE%");	//用theme自定义显示哪些内容
$show = $page->show();
$list = $article->where($map)->limit($page->firstRow.','.$page->listRows)->select();
$this->assign("show",$show);
$this->assign("list",$list);
$this->display();

setConfig方法支持的属性包括:

header:头部描述信息,默认值 “共 %TOTAL_ROW% 条记录

prev:上一页描述信息,默认值 “<<”

next:下一页描述信息,默认值 “>>”

first:第一页描述信息,默认值 “1…”

last:最后一页描述信息,默认值 “…%TOTAL_PAGE%”

theme :分页主题描述信息,包括了上面所有元素的组合 ,设置该属性可以改变分页的各个单元的显示位置,默认值是 “%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%”

其中,显示位置的对应的关系为:

位置 说明
%FIRST% 表示第一页的链接显示
%UP_PAGE% 表示上一页的链接显示
%LINK_PAGE% 表示分页的链接显示
%DOWN_PAGE% 表示下一页的链接显示
%END% 表示最后一页的链接显示

除了改变显示信息外,你还可以使用样式来定义分页的显示效果。这些样式class包括:first(第一页)、prev(上一页)、next(下一页)、end(最后一页)、num(其他页的数字)、current(当前页)。

 

Thinkphp自动验证 – 静态验证和动态验证

在我们将提交的表单数据插入或更新到数据库中时,一般都需要对表单数据进行验证,排除不符合我们要求的数据。

Thinkphp为我们提供很好的自动验证方法,在使用create()创建数据对象时会对提交的数据进行自动验证。

静态验证

静态验证是指在模型中预先定义好验证规则,然后在控制器中自动调用该模型进行数据验证。下面介绍下具体步骤:

1.在Model目录中创建model类,类文件名称有严格要求,必须跟数据库表名相关,如 UserModel.class.php (数据库表 user 的类)

namespace Home\Model;
use Think\Model;

class UserModel extends Model{
	protected $_validate = array(
		array("username","require","用户名必须填写"),
		array("username","6,18","用户名的长度必须在6到18个字节",0,"length",3),
		array("email","email","邮箱格式不正确"),
	);
}

注意:静态验证定义验证规则时,必须使用 protected $_validate = array(); (该成员属性必须用protected 且 属性名称必须是 $_validate)。数组里的验证规则可以参考下面的验证规则

2.在控制器中,使用create()创建数据对象时,直接默认调用

$user = D("user");
if(!$user->create()){
	$this->error($user->getError());
}else{
	echo 'success';
}

注意:必须使用 D 实例化数据库表,而不能使用M。例如,用D实例化数据库表 user 时,会同时调用模型类 user。(因此模型类文件名称必须是UserModel.class.php)。另外,用$user->getError() 是获取我们规则里设置的验证不成功的提示信息。

动态验证

使用动态验证比较灵活,不需要创建Model类。只需要在控制器中定义验证规则即可。缺点是动态验证规则只在当前方法中有效,无法重复使用。

//定义动态验证的变量名可以随意设置
$rules = array(
	array("username","require","用户名必须填写"),
	array("username","6,18","用户名长度必须在6到18位",1,"length",3),
	array("email","email","邮箱格式不正确"),
);
$user = M("user");
//创建数据对象前,使用validate()进行验证
if(!$user->validate($rules)->create()){
	$this->error($user->getError());
}else{
	echo 'success';
}

注意:动态验证用M实例化数据库表。

验证规则

验证规则是放在一个二位数组。格式如下

array(
  array(验证字段1,验证规则,错误提示[,验证条件,附加规则,验证时间]),
  array(验证字段2,验证规则,错误提示[,验证条件,附加规则,验证时间]),
  ......
)

1.验证字段(必须):就是提交表单的字段

2.验证规则(必须):验证规则需要跟附加规则一起使用,不过Thinkphp系统也内置几个验证规则,可以直接使用,包括 require(字段必须)、email(验证邮箱格式)、url(验证URL的格式)、currency(货币)、number(数字)

3.错误提示(必须):设置验证失败的提示信息

4.验证条件(可选):包含三种选择

  • self::EXISTS_VALIDATE 或者0 存在字段就验证(默认)
  • self::MUST_VALIDATE 或者1 必须验证
  • self::VALUE_VALIDATE或者2 值不为空的时候验证

5.附加规则(可选):配置验证规则一起使用,有一些的规则类型

规则 说明
regex 正则验证,定义的验证规则是一个正则表达式(默认)
function 函数验证,定义的验证规则是一个函数名
callback 方法验证,定义的验证规则是当前模型类的一个方法
confirm 验证表单中的两个字段是否相同,定义的验证规则是一个字段名
equal 验证是否等于某个值,该值由前面的验证规则定义
notequal 验证是否不等于某个值,该值由前面的验证规则定义(3.1.2版本新增)
in 验证是否在某个范围内,定义的验证规则可以是一个数组或者逗号分割的字符串
notin 验证是否不在某个范围内,定义的验证规则可以是一个数组或者逗号分割的字符串(3.1.2版本新增)
length 验证长度,定义的验证规则可以是一个数字(表示固定长度)或者数字范围(例如3,12 表示长度从3到12的范围)
between 验证范围,定义的验证规则表示范围,可以使用字符串或者数组,例如1,31或者array(1,31)
notbetween 验证不在某个范围,定义的验证规则表示范围,可以使用字符串或者数组(3.1.2版本新增)
expire 验证是否在有效期,定义的验证规则表示时间范围,可以到时间,例如可以使用 2012-1-15,2013-1-15 表示当前提交有效期在2012-1-15到2013-1-15之间,也可以使用时间戳定义
ip_allow 验证IP是否允许,定义的验证规则表示允许的IP地址列表,用逗号分隔,例如201.12.2.5,201.12.2.6
ip_deny 验证IP是否禁止,定义的验证规则表示禁止的ip地址列表,用逗号分隔,例如201.12.2.5,201.12.2.6
unique 验证是否唯一,系统会根据字段目前的值查询数据库来判断是否存在相同的值,当表单数据中包含主键字段时unique不可用于判断主键字段本身

6.验证时间(可选):确实是在什么情况下验证,系统默认有三种选择

  • self::MODEL_INSERT或者1新增数据时候验证
  • self::MODEL_UPDATE或者2编辑数据时候验证
  • self::MODEL_BOTH或者3全部情况下验证(默认)

 

 

 

 

 

 

Thinkphp扩展组件 – session与cookie支持

session支持

Thinkphp提供了一个函数 session() 用来管理SESSION的添加 删除等操作。Thinkphp系统已经设置了session初始化,不需要再初始化。

1.session赋值

session(“username”,”xiaoming”);

赋值给数组 session(“user.username”,”xiaoming”);

2.session取值

session(“username”);  这种方法只使用在控制器中使用且session是一维数组,在模板中有更方便的方法

3.session删除

session(“username”,NULL); 删除某个session值

session(NULL); 删除所有session值

cookie支持

Thinkphp也提供了cookie()函数用来操作cookie的相关设置。

1.cookie赋值

cookie(“username”,”小凡”);  这是最简单的设置方法

cookie(“username”,”小凡”,10); 其中的10是过期时间10秒

cookie(“user”,array(“username”=>”小凡”,”age”=>20),array(“expire”=>60,”prefix”=>”xf_”));  可以赋值数组,另外prefix是设置cookie前缀,防止与其他cookie值重复。

2.cookie取值

cookie(“username”);

cookie(“xf_user”);  如果设置了前缀,取值也要加前缀

3.cookie删除

cookie(“username”,null); 清除某个值

cookie(null); 清除全部值。

模板中取值

{$Think.session.username}  取值session

{$Think.cookie.username}  取值cookie

 

Thinkphp扩展组件 – Widget扩展

上一篇文章介绍过模板继承。我们在使用模板继承时会遇到一个问题:公共模板没有对应的控制器,如果公共模板局部的数据需要是动态的,比如顶部的菜单、底部的友情链接等等,这将无法实现。

为了解决这个问题,Thinkphp提供一个非常有用的功能:Widget扩展。它可以很好的解决上面的问题,下面介绍下具体操作步骤:

1.创建扩展类文件

在当前应用目录中创建 Widget 目录,然后在Widget目录中创建扩展文件,比如 CategoryWidget.class.php (注意文件名的格式 后面必须是Widget.class.php);编辑该文件,这里我们测试制作一个显示导航的扩展:

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

class CategoryWidget extends Controller{
	public function showCate(){
		$category = M("category");
		$categorys = $category->select();
		$this->assign("categorys",$categorys);
		$this->display("Public:nav");
	}
}

注意:$this->display(“Public:nav”); 这里是将内容传给扩展的模板文件,示例指的是View/Public/nav.html模板

2.创建扩展模板文件

在应用下 View目录下创建扩展目录 Public(名字个自定义),然后在扩展目录中创建扩展模板 nav.html。注意如果View目录中有多种主题,扩展目录应该放在相应的主题目录中。

创建好以后,编辑模板。这个模板只是为了显示扩展文件中传入的数据,因此只是一个片段,并不是完整的模板页面。如下面:

<foreach name="categorys" item="category">
	<div class="nav">{$category.title}</div>
</foreach>

以上就完成扩展的创建。

3.调用扩展

制作好的扩展,我们在模板文件的任何地方调用。

调用格式是 {:W(“Category/showCate”)}

其中的参数Category是扩展类名,showCate是方法名。

 

Thinkphp模板继承

在制作模板时,通常不同的页面模板都有共用的部分。为了提供开发效率和规范,我们可以把共用部分创建为公共模板,其他页面模板进行继承。以下是具体实施步骤:

1.在应用下的 View 目录创建公共模板目录,比如 Public。把公共模板放到这个目录中,公共模板是作为父级模板;

2.根目录的 Public 目录里的应用目录放入公共静态资源,css js image等;

3.调整公共模板的资源引用路径,可以用路径常量 __PUBLIC__

4.在其他页面模板中继承公共模板,比如在后台首页模板继承,模板文件中写入如下代码:

<extend name="Public:layout" />

以上代码意思是引用公共模板 Public/layout.html

5.继承模板肯定是有一些不同的地方,对于不同的模块,我们要用 <block>标签定义:

公共模板定义模块

<block name="main-content"></block>

其他子模板定义修改模块

<block name="main-content">
这里是放入子模板自定义的内容
</block>

以上就完成了模板继承的使用。

 

Thinkphp模板继承 – 路径常量

Thinkphp系统设置一些路径常量,常用的有:

__PUBLIC__ 根目录的Public目录路径  如 /tp/Pbulic  特别注意这个常量只能在模板中使用,不能在控制器中使用

__ROOT__ 根目录路径 如/tp 此常量可以在模板和控制器使用

__APP__ 当前应用路径 如/tp/admin.php 此变量可以在模板和控制器使用

__CONTROLLER__ 当前控制器路径 如 /tp/admin.php/Index  此常量可以在模板和控制器使用

__ACTION__  当前方法路径 如 /tp/admin.php/Index/index 此常量可以在模板和控制器使用

模板中使用方法如下

__PUBLIC__
<br>
__ROOT__
<br>
__CONTROLLER__
<br>
__ACTION__

 

Thinkphp内置标签 – 条件判断if标签

if 条件判断语句是很常用的语句,在Thinkphp模板中应该如何使用if判断呢?

与php原生的相似,只是形式不同。

<if condition=”条件判断”>…</if>

<if condition =”条件判断”>…<else />…</if>

<if condition=”条件判断”>…<elseif condition=””>…<else>…</if>

以下是示例:

<if condition="$num eq 5">
	num值等于5
</if>

<if condition="($num lt 0) OR ($num gt 10)">
	num值小于0或大于10
<elseif condition="$num eq 5" />
	num值等于5
<else />
	num值在0到10之间但不等于5
</if>

注意:condition条件中 判断大于 等于 小于 用 gt eq lt egt elt 不要用 > <等,其中唯有等于可以用 ==

如果表示两个条件,用 (条件1) OR (条件2) 形式。