学习thinkphp的一些总结:
数据库跨库操作 :如果没有定义模型的话 可以这样 $User = M('user.User','other_'); //表示实例化User模型,连接的是user数据库的other_user表。
获取数据库的字段信息:$fields=$user->getDbField(); // 即可获得数据库表user中的字段信息 字段缓存保存在Runtime/Data/_fields/ 目录下面 (如果新增的字段无法存入数据库,可以尝试清空缓存)
首先,要了解好thinkphp的各个目录。
左边的目录为,thinkphp下载下来时的目录。而右边的目录是使用入口文件之后生成的目录。
二、使用入口文件。
首先要新建好前台和后台的首页。
①前台的是index.php 项目目录是home。
②后台的是admin.php 项目目录是admin。
之后把入口文件thinkphp.php文件引入进去即可。
下面就以前台的index.php 为例:
一个网站分为前台和后台。而后台的话,就只需把home 改成admin(home和admin用户可以自定义)。当你在网址中输入localhost/index.php
就会看到thinkphp的欢迎界面。同时在index的同级目录下会生成home文件夹(而后台admin也是同样的),且里面有使用了入口文件之后生成的相关目录。
控制器
在home的目录下有个lib目录下有个action目录,里面会生成IndexAction.class.php。文件如下:
在这里面你可以自定义方法。之后通过url来访问:localhost/index.php/Index/index。
index.php是入口文件 Index是控制器 index则是方法名。
通过这个方法同样还是可以访问到欢迎界面。如果你想自己在IndexAction 中添加自己的方法只需改localhost/index.php/Index/'自己定义的方法'。(注意:方法必须是public的
,不给的话,默认是public)。
url的四种模式
在home/conf/config.php中设置url的模式。(若想让url中的控制器不区分大小写,则可配置'URL_CASE_INSENSITIVE'=>TRUE)
第一种: -->'URL_MODEL'=>0,(普通模式模式) 访问方式:localhost/index.php/?m=Index&a=index。m代表控制器,a代表方法。
第二种 -->'URL_MODEL'=>1,(PATHINFO模式) 访问方式:localhost/index.php/model/action/key/val key是要传的参数键值,val是值。而/是区位符,相当于是?。
第三种 -->'URL_MODEL'=>2,(rewrite模式) 修改apache的配置文件,启用rewrite模块,同时allowoverride all。并在入口文件同级目录下新建.htaccess文件。内容可以复制thinkphp手册中的url重写中的内容。这样就可以隐藏掉url中入口文件了(localhost/Index/index)。
第四种 -->'URL_MODEL'=>3,(兼容种模式) 就是普通模式和PATHINFO 模式的集合。
调试工具
-----在系统目录下的conf目录下找到debug.php 文件并打开,添加 'SHOW_PAGE_TRACE' => true。 这样则会在页面中的右下角图标中显示的信息(点击图标)。
------若在项目的conf.php 中添加'APP_STATUS'=>'debug'他首先会去当前同级目录下寻找debug.php。若不存在,则会去系统目录(thinkphp下载后放置的目录)下去找到debug。
------空模块是把EmptAction.class.php 放置在IndexAction.class.php同一个目录下(若没有模块,则访问Empt控制器)。而空方法则是,在Index控制器中添加_empt方法(同模块)。
模板引擎
-----这个跟smarty模板有很大的相同之处。若调用项目目录下tpl目录下Index(对应控制器名)目录下的index.html(对应方法名)模板 则只需在Index控制器中的index方法中使用$this->display(); 在localhost/index.php/Index/index访问是会加载index.html模板。而给模板分配参数跟smarty是一样的($this->assign('php100',$arr))即可。
-------若是模板跳转的话,需要使用如下方法display('./home/tpl/Index/test')跳转。还有一种跳转方法:$this->dispaly('Index:test') Index是 tpl/Index目录,而test是tpl/Index目录下的test模板。
--------模板中使用到的常量(比较常用的)。
__APP__ 代表 入口文件
__TMPL__ 代表 模板文件目录
__ACTION__ 代表 控制器中的方法
__URL__ 代表 控制器
__SELF__ 代表 输入的url
模板布局方式
前置和后置(控制器下的各个方法页面都加上头部和页脚部)
①在系统文件中的lib/Core/APP.class.php(注意要备份) 中找到before和after方法并把传参中的4个.$action 去掉。
②只需在控制器中加上如下内容。
// 前置
function _before_(){
$this->display('Public:head'); // public 是项目tpl目录下的一个公共目录,用来存放错误页面和公共头和公共页脚部的。
}
//后置
function _after_(){
$this->display('Public:footer');
}
这样就可以达到同一个控制器使用一个公共的头部。
include:
----------相对于模板文件来做的设定。
在模板文件中使用include方法来加载公共头和页脚:
① <include file="完整模板文件路径"/> 路径是基于入口文件的,而且要跟上后缀名。
②<include file="模块名:方法名"/> eg:<include file="Public:footer"/> Public 是tpl目录下的文件夹,footer是public下面的一个文件。
③<include file="文件名"/> 文件名无需后缀名,文件是跟当前模板同一级目录下的文件。
④<include file="file1,file2....."/> 可以引入多个文件。
layout(先制作一个模板,再把相应的文件放到模板文件中去,这样多个器控中都是用同一个头部和页脚)
①先在项目的conf中设定'LAYOUT_ON'=>TRUE,//启动layout。同时设置模板文件名'LAYOUT_NAME'=>'tmpls'//会到项目的tpl目录下去找tmpls.html文件。
②之后再tmpls.html 中写上头部和页脚部的代码,放入content只需在tmpls的相应位置加上{__CONTENT__},同时在方法中加上$this->display();,就会把方法模板(列如:index.html)加载进去。若不需要加载tmpls,只需在方法模板中加上{__NOLAYOUT__}即可。
不同的方法页面显示不同的内容,在方法中传入方法模板(eg:$this->assign('file','index'))就会把index.html传到方法对应的模板中去。在方法模板中用
<include file='head'/>
<include file="$file"/>
<include file="footer"/> //注意这三个不能合并成一个include。
另外也可以不启用conf中的LAYOUT_ON,而直接在方法模板(index.html)中使用<layout name="tmpls"/>并在tmpls.html中加上{__CONTENT__}也可以达到同样的加载头和页脚的效果。
模板引擎函数的使用
------在控制器中定义了字符串,对象或者数组的话,可以在模板文件中接受。
eg:(在控制器中定义如下)
$str='this is thinkphp!'; // 字符串
// 数组
$arr=array(
'name'=>'zhikai',
'age'=>'35',
)
// 在模板文件中通过如下方式直接接收。
// 对象的使用如下图(使用系统的M方法来实例化对象)
{$str}
{$arr['name']}和{$arr.name}一样的效果。但是推荐第一种使用方法。如果是三维数组:{$arr['name']['nikename']}
修改模板文件的左右标示符
注意:在模板文件中如果使用js代码的话需要用<literal></literal>将js代码包括起来,避免混淆。而php代码的话则可以直接使用。
在模板文件中使用系统函数
{$str | md5 | strtoupper | substr=0,3}// 列如substr的用法是substr($变量,截取长度)变量在前面无需##
{$str | md5 | strtoupper | function=0,4,###} // function(操作符,变量)变量在后面需要##
注意:{和$之间不能有空格或者是任何符号。函数间用|来分隔,函数从左到右的顺序执行的。
在模板中执行函数并输出:{:function()....}。 在手册的模板引擎中的系统变量是无需控制器传的。直接在模板中就可以使用了的。
Model 的操作:
model在项目中lib目录下,命名方式:数据库表名(不包含数据库表名前缀)+Model.class.php。但是需要实例化而且必须是在控制器中进行实例化。
$user = new Model('User'); // 实例化模块,User是数据库的表后缀。
$info = $user->select(); 查询数据库中user表的信息。
还有一种实例化的方法:
$user = M();
$info = $user->query("select * from 'cms_user' where 1");
注意:D和M的区别
D函数实例化的是 你当前项目的Lib/Model下面的模块
如果该模块不存在的话 直接返回实例化Model的对象(意义就与M()函数相同)
而M 只返回 实例化 Model的对象..它的$name参数 作为数据库的表名来处理对数据库的操作
通俗点说,D就是实例化一个基于Model文件的Model,而M则是通过直接实例化Model方法(ThinkPHP基类)来动态的实例化一个Model对象,即使这个对应的Model文件不存在。
再通俗一点说就是,m实例化参数是数据库的表名.
d实例化的是你自己在model文件夹下面建立的模型文件.
thinkphp中实现验证码:
①首先下载ORG完整的扩展包:
放入系统目录下ThinkPHP/Extend/Library/ORG/Util/(如果没有请手动创建)目录下面
在thinkphp中内置了验证码的方法,可以直接调用使用,前提是你必须导入扩展类库中的 ORG.Util.Image 类库和 ORG.Util.String 类库
最简单的例子
Publicfunctionverify(){
// 导入Image类库
import("ORG.Util.Image");
Image::buildImageVerify();
}
import 方法是 ThinkPHP 内置的类库和文件导入方法,上例导入的文件为 ThinkPHP 系统目录下 Lib/ORG/Util/Image.class.php 文件。如果已经将 Image 类库拷贝到了当前项目下,如 Lib/ORG 下,则可以以:
import("@.ORG.Util.Image");import 方法是 ThinkPHP 内置的类库和文件导入方法,上例导入的文件为 ThinkPHP 系统目录下 Lib/ORG/Util/Image.class.php 文件。
在表单中调用验证码方法
在表单页面中使用验证码,是以html img 标签来调用:
有两种方法:
①:
<img src="./code.php" οnclick="this.src='code.php?a='+Math.random()"/>
②:
<inputtype="text"name="verify">
<imgid="verifyImg"src="__URL__/verify"onClick="changeVerify()"title="点击刷新验证码"/>
刷新验证码需要特定的函数
当点击验证码图片时,触发 JavaScript changeVerify() 函数重新读取验证码,从而实现验证码刷新。该函数参考如下:
<scriptlanguage="JavaScript">
functionchangeVerify(){
vartimenow =newDate().getTime();
document.getElementById('verifyImg').src='__URL__/verify/'+timenow;
}
</script>
对数据库表的操作需要到相应项目中的conf.php中进行分配。具体如下:
'DB_TYPE' => 'mysql',
'DB_HOST' => 'localhost',
'DB_NAME' => 'tpcms', // 数据库名
'DB_USER' => 'root',
'DB_PWD' => '',
'DB_PREFIX' => 'cms_', //表前缀
'DB_PORT' => '3306',
'DB_CHARSET' => 'utf8',
注意:以上的实例化的同时,就都对数据库进行了操作,小的项目可以。但是遇到对密码和用户名的验证的话。还是需要用到model。这时需要自己在项目目录下lib/model/下自己定义一个model(UserModel.class.php)
<?php
class UserModel extends Model{
内容区.............
}
模型的操作(curd)(操作前要配置文件中配置好对数据库的连接等。)
首先在控制器中添加方法:
eg:
// 添加
public function add(){
$user=M('User'); // user 是数据库表后缀名 实例化user
$data=array(
'user'=>'super',
'password'=>'hello',
)
$user->add($data); // 添加方法,只能添加一条
/*
addAll可以是多条数据但是要是二维数组
二位数组定义:
$data=array(
array('user'=>'shfi','password'=>'djifjdif'),
array('user'=>'shfi','password'=>'sdifdjfi'),
)
$user->addAll($data); // 使用addAll来添加。
*/
}
// 查询
public function select(){
$list=M('User');
$list->where('id=10')->order('id')->limit(10)->select();
$list->find();// 只能读取一条,如果find中加参数(find(10)这样就会查询出ID等于10的)
$list->where('id=2')->getField('password');//查询出 id=2中password的值。查询出某个字段的值。
}
//更新
同上,使用的是save方法,注意要给主键:where('id=1')->save($data);
thinkphp中实现数据库的关联方法:(很实用)
$list = $photo->table( 'cms_photo a,cms_title b')->where( 'a.bid = b.id')->field ( 'a.*,b.classify' )->order('id')->page($nowPage.','.$page->listRows)->select();
说明:cms_photo a,给表区别名 classify是表中的字段 nowpage是控制器中前面定义了的($nowPage = $_GET['p']?$_GET['p']:1;),$listRows 每页显示记录数(不用传参);
this->redirect(‘User/index’,array(‘cate_id’=>2),5,’页面跳转中….’);
此方法有四个参数,
第一个是需要重定向的URL,可以用模块/操作的方式来写,意思就是跳到哪个模块的哪个操作方法中,比如小编写的User/index表示的是跳到User模块的index操作方法,
第二个参数是数组,代表URL传递的GET参数,可以传递很多个参数,像小编上面写的传递参数cate_id=2,如果要传递很多参数可以这样写,array(‘cate_id’=>3,’cate_name’=>’admin’,'cate_time’=>’10-26′)
第三个参数是需要停留几秒后跳转,
第四个参数是在停留期间在页面显示出来的内容,支持HTML标签。
验证码的生成:
首先在控制器中引入验证码类库
- Public function verify(){
- import('ORG.Util.Image');
- Image::buildImageVerify();
- }
buildmageVerify()的使用方法如下:buildImageVerify($length,$mode,$type,$width,$height,$verifyName)(具体看手册)
在要显示的页面中
- <img src='__APP__/Public/verify/' /> 即可
①项目部署:
index.php
define('APP_NAME','App');
define('APP_PATH','./App/');
define('APP_DEBUG',true);
require'引入框架入口文件';
运行index.phpapp项目的建立好了。
之后在配置文件中开启分组:
'APP_GROUP_LIST'=>'Index, Admin', index 是前台 admin是后台。可以自定义的。
'DEFAULT_GROUP'=>'Index' //默认分组
这样就实现了分组了。分组中目录基本都是公用的,如果后台单独定义的话,需要再目录下新建一个Admin目录之后在新建一个文件来存放eg(Common/Admin/function.php 这就是专属于后台的函数文件)
②如果想让自己的网站结构跟简单一点的话,可以配置成独立分组的形式。
首先建好APP项目 之后在公共的配置文件中开启独立分组:
'APP_GROUP_MODE'=>1,
'APP_GROUP_PATH'=>'Modules', // 独立文件夹名称
具体结构如下:
APP|---Modules|--Index -- |--Action //所需的Model,Conf,Common都可以再这个目录中建
| | |--Tpl // Index目录下的是前台的,Admin目录下的都是后台独立的
| | |--Model
| |--Admin //后台的因为空间问题我就不举例了(原理都一样的)
|
|--Common //公共函数 里面是common.php
|--Conf //公共的配置文件
|--Lib|--Action //公用的方法和模块
|--Model
这样设置了目录结构之后有个麻烦一点的就是访问模板的时候Tpl/Index/index 这样每个方法都要新建一个文件夹很麻烦。解决方法:在公共的配置文件中配置 ' TMPL_FILE_DEFR'=>'_', 这样,就直接新建Tpl/Index_index.html这样就方便多。
隐 藏index.php的方法:①在apache中启动 Allowoverride=on 同时引入rewrite模块 ②在index.php同级目录下创建 .htaccess文件 ③在配置文件中定义 'URL_MODEL'=>2
③自定义public 目录
例如:我们配置后台的public目录:首先我们在后台的配置文件中定义:
'TMPL_PARSE_STRING'=>array(
'__PUBLIC__'=>__ROOT__. '/' .APP_NAME . '/Modules/'.GROUP_NAME. '/Tpl/Public', //Modules是独立分组中的独立文件夹名称 可以根据自己实际的目录来给路径。
),
注意:在独立分组中包含公共文件的时候使用<include file="Rbac:role"/>这种格式的时候,特别要注意,在方法中echo是没用的。而且要必须有控制器,同时也要有模板文件,才能看到结果(这问题纠结了我老半天)。
thinkphp中隐藏index.php 方法:
①:确定引入了apache的rewrite模块,并设定allowoverride=on,
②:在index.php同级目录中新建.htaccess文件
<IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] </IfModule>
③:在配置文件中启动url模块二‘URL_MODEL'=>2,
常用两种关联模型:
---多对多的关联模型:在项目model目录中定义新建一个UserRelationModel.class.php文件。内容如下图:
protected $_link=array(
'role'=>array( // 副表, 这就是模型名(UserRelationModel)
'mapping_type'=>MANY_TO_MANY, //关联类型
'relation_table'=>'think_role_user',// 两表关联(中间表)
'foregin_key'=>'user_id', // 主表关联外键
'relation_key'=>'role_id', // 副表关联外键
),
);
在控制器中使用如下:
$user=D('User')->relation(true)->select(); 查询到两表数据
一对多的关联模型
protected $_link=array(
'Node'=>array( // 关联附表
'mapping_type'=>HAS_MANY, // 关联方式
'mapping_name'=>'child', // 附表关联在主表的字段值
'mapping_name'=>'sort' // 关联排序方式
'parent_key'=>'pid', // 关联的字段
),
);
④配置函数扩展
配置了独立分组的话,公共函数中的函数文件名是common.php,前后台单独的文件名是function.php
配置函数文件名的方法:(在配置文件中)
'LOAD_EXT_FILE'=>'function',
或者:
<?php
$config=array(
'LOAD_EXT_FILE'=>'function',
);
return array_merge(include './conf/config.php',$config);
?>
在函数中配置p函数(打印)
function p($arr){
dump($arr,1,'<pre>',0);
}
无限极分类函数:
/*
**无限极分类函数
*/
function merge($data,$access=null,$pid=0){
$arr=array();
foreach ($data as $value) {
if($value['pid']==$pid){
/*$value是每次都在循环而不至于被覆盖。
* 如果是$arr[]的话,还要避免每次都要被覆盖
*/
if(is_array($access)){ // 如果是数组则说明分配的有权限
$value['access']=in_array($value['id'], $access)?1:0;
}
$value['child']=merge($data,$access,$value['id']);
$arr[]=$value; // 给$key 是为了第二次循环时被覆盖
}
}
return $arr;
}
⑤Rbac 用户权限配置(在think中还是蛮重要的)
数据库自己建好,表的话可以到系统文件目录中的Extend/Library/ORG/Util/RBAC.class.php中找到。注意:用户表要自己建。
同时相关的页面自己写好。之后配置文件
配置文件中配置:
'USER_AUTH_ON' => true, // 开启验证 'RBAR_SUPERADMIN'=>'admin', // 超级管理员 'ADMIN_AUTH_KEY' =>'administrator', // 管理员识别 'USER_AUTH_KEY' =>'uid', // 用户的id(登陆时存入session中的) 'USER_AUTH_TYPE' => 1, // 1 权限分配后,登录之后才验证,2 是实时验证 'NOT_AUTH_MODULE' =>'', //无需验证的模块 'NOT_AUTH_ACTION' =>'', //无需验证的方法 'GUEST_AUTH_ON' => false, //是否开启游客授权访问 'GUEST_AUTH_ID' => 0, //游客标记
'RBAC_ROLE_TABLE' =>'think_role', // 角色表(也就是用户所属组) 'RBAC_USER_TABLE' =>'think_role_user', //角色 用户表 'RBAC_ACCESS_TABLE' =>'think_access', //权限表 'RBAC_NODE_TABLE' =>'think_node', // 节点表
在配置文件中配置好之后,首先在用户登陆验证成功之后导入RBAC类库。调用saveAccessList方法(读取用户的权限并保存到session中的)
之后新建一个Common类,让所有需要判断权限的模块都继承。而Common类就是初始化判断用户是否登录了,和该用户是否有相关的权限来访问(可以使用显示和隐藏的方式--下面专门讲解)。
实现不同用户登陆显示不同的左侧权限导航:(本来想自己实现的,结果在数据读取上面没有到自关联,最后还是看了视频的。官网的视频还是给力的)
实现的思路:
判断保存在session中的用户是否是admin 如果是,则取出所有的用户节点(注意,只取出level=2 的下面的所有节点[前后台的等级是1,模块是2,方法的等级是3])。如果不是admin,则取出先取出登陆时候保存的模块节点和方法节点的id(在用户登陆时候用户的拥有的模块权限和方法权限是保存在session中的_ACCESS_LIST中的)。 下面在取出所有level=2的节点。循环取出模块节点和节点id,在循环时,判断取出的节点是否存在session中的,如果不存在则删除节点(删除模块节点和方法节点有不同之处。具体要看取出的数据结构)。最后分配给模板循环显示就是了。
/******************************** 常用易错think用法:***********************************/
U函数在error中的用法:$this->error('用户权限不足', U('Login/index'));一般都是{:U('Login/index')}
thinkphp 关联模型依然使用的两条sql语句,如果是一对多的话
加入是一个用户(user)有多条评论(comment)
可以先查询出用户的数据,再根据用户的id(外键)来查询相关的评论。
$db = M('User');
$list = $db->select();
foreach($list as $k=>$v){
$rst = M('Comment')->where("uid = ".$v['id'])->select();
$list[$k]['username'] = $v['username'];
$list[$k]['nickname'] = $v['nickname'];
$list[$k]['child']=$rst;
}。