├─ThinkPHP.php 框架入口文件
├─Common 框架公共文件
├─Conf 框架配置文件
├─Extend 框架扩展目录
├─Lang 核心语言包目录
├─Lib 核心类库目录
│ ├─Behavior 核心行为类库
│ ├─Core 核心基类库
│ ├─Driver 内置驱动
│ │ ├─Cache 内置缓存驱动
│ │ ├─Db 内置数据库驱动
│ │ ├─TagLib 内置标签驱动
│ │ └─Template 内置模板引擎驱动
│ └─Template 内置模板引擎
└─Tpl 系统模板目录
app
目录的外面修改入口文件index.php
的内容为
<?php
define('APP_NAME','app'); //定义项目名
define('APP_PATH','./app/'); //项目目录
require '/ThinkPHP框架所在目录/ThinkPHP.php';
├─index.php 项目入口文件
├─Common 项目公共文件目录
├─Conf 项目配置目录
├─Lang 项目语言目录
├─Lib 项目类库目录
│ ├─Action Action类库目录
│ ├─Behavior 行为类库目录
│ ├─Model 模型类库目录
│ └─Widget Widget类库目录
├─Runtime 项目运行时目录
│ ├─Cache 模板缓存目录
│ ├─Data 数据缓存目录
│ ├─Logs 日志文件目录
│ └─Temp 临时缓存目录
└─Tpl 项目模板目录
每个项目都有一个独立的配置文件(位于项目目录的Conf/config.php
),配置文件的定义格式均采用PHP返回数组的方式,例如:
// 项目配置文件
return array(
'配置参数' => '配置值',
// 更多配置参数
//...
);
一旦有需要,我们就可以在项目配置文件中添加相关配置项目。通常我们提到的添加配置项目,就是指在项目配置文件中添加:
'配置参数' => '配置值',
需要为每个模块定义一个控制器类,控制器类的命名规范是:
模块名+Action.class.php
(模块名采用驼峰法并且首字母大写)
系统的默认模块是Index,对应的控制器就是项目目录下面的Lib/Action/IndexAction.class.php
,类名和文件名一致。默认操作是index,也就是控制器的一个public方法。初次生成项目目录结构的时候,系统已经默认生成了一个默认控制器(就是之前看到的欢迎页面),我们把index方法改成下面的代码:
class IndexAction extends Action {
public function index(){
echo 'hello,world!';
}
}
入口文件是项目的单一入口,对项目的所有请求都定向到项目的入口文件,系统会从URL参数中解析当前请求的模块和操作,我们之前访问的URL地址中没有任何参数,因此系统会访问默认模块(Index)的默认操作(index),因此下面的访问和之前是等效的:
http://localhost/app/index.php/Index/index
这种URL模式就是系统默认的PATHINFO模式,不同的URL模式获取模块和操作的方法不同,ThinkPHP支持的URL模式有四种:普通模式、PATHINFO、REWRITE和兼容模式。
也就是传统的GET传参方式来指定当前访问的模块和操作,例如:
http://localhost/app/?m=module&a=action&var=value
ThinkPHP内置了一个编译型模板引擎,也支持原生的PHP模板,并且还提供了包括Smarty在内的模板引擎驱动。和Smarty不同,ThinkPHP在渲染模板的时候如果不指定模板,则会采用系统默认的定位规则,其定义规范是 Tpl/模块名/操作名.html,所以,Index模块的index操作的默认模板文件位于项目目录下面的Tpl/Index/index.html。
<html>
<head>
<title>hello {$name}</title>
</head>
<body>
hello, {$name}!
</body>
</html>
要输出视图,必须在控制器方法中进行模板渲染输出操作,例如:
class IndexAction extends Action {
public function index(){
$this->name = 'thinkphp'; // 进行模板变量赋值
$this->display();
}
}
display方法中我们没有指定任何模板,所以按照系统默认的规则输出了Index/index.html模板文件。
$id = $_GET['id']; // 获取get变量
$name = $_POST['name']; // 获取post变量
$value = $_SESSION['var']; // 获取session变量
$name = $_COOKIE['name']; // 获取cookie变量
$file = $_SERVER['PHP_SELF']; // 获取server变量
系统的Action类提供了对系统变量的增强获取方法,包括对GET、POST、PUT、REQUEST、SESSION、COOKIE、SERVER和GLOBALS参数,除了获取变量值外,还提供变量过滤和默认值支持,用法很简单,只需要在Action中调用下面方法:
$id = $this->_get('id'); // 获取get变量
$name = $this->_post('name'); // 获取post变量
$value = $this->_session('var'); // 获取session变量
$name = $this->_cookie('name'); // 获取cookie变量
$file = $this->_server('PHP_SELF'); // 获取server变量
调用格式为:
$this->方法名("变量名",["过滤方法"],["默认值"])
方法名可支持:
方法名 | 含义 |
---|---|
_get | 获取GET参数 |
_post | 获取POST参数 |
_param | 自动判断请求类型获取GET、POST或者PUT参数 |
_request | 获取REQUEST参数 |
_put | 获取PUT参数 |
_session | 获取$_SESSION参数 |
_cookie | 获取$_COOKIE参数 |
_server | 获取$_SERVER参数 |
_globals | 获取$GLOBALS参数 |
在某些情况下面,我们还有一种获取URL参数的特殊需求,一般来说,获取URL参数是采用get变量的方式就够用了,但是对于我们定制过的URL,或者采用了路由的情况下面,URL的参数可能会没有规律,这个时候,我们可以采用另外一种方式来获取。 例如,当前的URL地址是:
http://localhost/index.php/news/hello_world/thinkphp
要获取其中的参数,可以用:
$this->_param(0); // 获取news
$this->_param(1); // 获取hello_world
$this->_param(2); // 获取thinkphp
在控制器中给模板变量赋值:
$name = 'ThinkPHP';
$this->assign('name',$name);
$this->display();
在模板中使用该变量:
Hello,{$name}!
普通的模板变量需要首先赋值后才能在模板中输出,但是系统变量则不需要,可以直接在模板中输出,系统变量的输出通常以{$Think 打头,例如:
{$Think.server.script_name} // 输出$_SERVER['SCRIPT_NAME']变量
{$Think.session.user_id} // 输出$_SESSION['user_id']变量
{$Think.get.pageNumber} // 输出$_GET['pageNumber']变量
{$Think.cookie.name} // 输出$_COOKIE['name']变量
支持输出_SERVER、_ENV、 _POST、 _GET、 _REQUEST、_SESSION和
{$data.name|md5}
编译后:
<?php echo (md5($data['name'])); ?>
{$create_time|date="y-m-d",###}
表示date函数传入两个参数,每个参数用逗号分割,这里第一个参数是y-m-d,第二个参数是前面要输出的create_time变量,因为该变量是第二个参数,因此需要用###标识变量位置,编译后的结果是:
<?php echo (date("y-m-d",$create_time)); ?>
{$user.nickname|default="这家伙很懒,什么也没留下"}
Action参数绑定的原理是把URL中的参数(不包括分组、模块和操作名)和控制器的操作方法中的参数(按变量名)进行绑定。
例如,我们给Blog模块定义了两个操作方法read和archive方法,并且给read操作需要指定一个id参数,archive方法指定年份(year)和月份(month)两个参数。为了演示方便,我们省去了具体操作方法的业务代码,仅仅用echo 输出当前的参数。
class BlogAction extends Action{
public function read($id){
echo 'id='.$id;
}
public function archive($year='2012',$month='01'){
echo 'year='.$year.'&month='.$month;
}
}
URL的访问地址分别是
http://serverName/index.php/Blog/read/id/5
http://serverName/index.php/Blog/archive/year/2012/month/03
输出的结果
id=5
year=2012&month=03
UploadFile.class.php
位于ThinkPHP/Extend/Library/ORG/Net/
<form id="upload" method='post' action="!-URL-!/upload/" enctype="multipart/form-data">
<input name="image" type="file" />
<input type="submit" value="提交" >
</form>
注意,表单必须添加enctype="multipart/form-data"
属性才能支持文件上传功能。
在Action控制器中添加upload操作方法如下
// 文件上传
public function upload() {
import('ORG.Net.UploadFile');
$upload = new UploadFile();// 实例化上传类
$upload->maxSize = 3145728 ;// 设置附件上传大小
$upload->allowExts = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
$upload->savePath = './Public/Uploads/';// 设置附件上传目录
if(!$upload->upload()) {// 上传错误提示错误信息
$this->error($upload->getErrorMsg());
}else{// 上传成功
$this->success('上传成功!');
}
}
import('ORG.Net.UploadFile');
$upload = new UploadFile();// 实例化上传类
maxSize | 文件上传的最大文件大小(以字节为单位)默认为-1 不限大小 |
---|---|
savePath | 文件保存路径(必须) |
saveRule | 上传文件的保存规则,必须是一个无需任何参数的函数名,例如可以是 time、 uniqid com_create_guid 等,但必须能保证生成的文件名是唯一的,默认是uniqid |
hashType | 上传文件的哈希验证方法,默认是md5_file |
autoCheck | 是否自动检测附件,默认为自动检测 |
uploadReplace | 存在同名文件是否是覆盖 |
allowExts | 允许上传的文件后缀(留空为不限制),使用数组设置,默认为空数组 |
allowTypes | 允许上传的文件类型(留空为不限制),使用数组设置,默认为空数组 |
thumb | 是否需要对图片文件进行缩略图处理,默认为false |
thumbMaxWidth | 缩略图的最大宽度,多个使用逗号分隔 |
thumbMaxHeight | 缩略图的最大高度,多个使用逗号分隔 |
thumbPrefix | 缩略图的文件前缀,默认为thumb_ |
thumbSuffix | 缩略图的文件后缀,默认为空 |
thumbPath | 缩略图的保存路径,留空的话取文件上传目录本身 |
thumbFile | 指定缩略图的文件名 |
thumbExt | 指定缩略图的扩展名 |
thumbRemoveOrigin | 生成缩略图后是否删除原图 |
autoSub | 是否使用子目录保存上传文件 |
subType | 子目录创建方式,默认为hash,可以设置为hash、date或者custom |
subDir | 子目录名称 subType为custom方式后有效 |
dateFormat | 子目录方式为date的时候指定日期格式 |
hashLevel | 子目录保存的层次,默认为一层 |
//设置附件上传目录
$upload->savePath = './Uploads/';
//设置需要生成缩略图,仅对图像文件有效
$upload->thumb = true;
//设置需要生成缩略图的文件后缀
$upload->thumbPrefix = 'm_,s_'; //生产2张缩略图
//设置缩略图最大宽度
$upload->thumbMaxWidth = '200,50';
//设置缩略图最大高度
$upload->thumbMaxHeight = '200,50';
或者在实例化的同时传入上传参数,例如:
import('ORG.Net.UploadFile');
$config['savePath'] = './Uploads/';
$config['thumb'] = true;
$config['thumbPrefix'] = 'm_,s_';
$config['thumbMaxWidth'] = '200,50';
$config['thumbMaxHeight'] = '200,50';
$upload = new UploadFile($config);// 实例化上传类并传入参数
uploadOne方法表示每次执行只上传指定的一个文件,并且如果上传成功的话uploadOne方法的返回值就是成功上传的文件信息,和getUploadFileInfo方法不同的是,这个文件信息是一个仅包含单个文件信息的一维数组。如果发生错误,依然是通过getErrorMsg方法获取错误信息。
import("ORG.Net.UploadFile");
$upload = new UploadFile();
foreach ($_FILES as $key=>$file){
if(!empty($file['name'])) {
$upload->autoSub = true;
$upload->subType = 'date';
$info = $upload->uploadOne($file);
if($info){ // 保存附件信息
M('Photo')->add($info);
}else{ // 上传错误
$this->error($upload->getErrorMsg());
}
}
}
上传类默认就支持多文件上传,只需要修改表单页面: 如果需要使用多个文件上传,只需要修改表单,把
<input type='file' name='image'>
改为
<input type='file' name='image1'>
<input type='file' name='image2'>
<input type='file' name='image3'>
首先在数据库thinkphp中创建一个think_data数据表(以mysql数据库为例):
CREATE TABLE IF NOT EXISTS `think_data` (
`id` int(8) unsigned NOT NULL AUTO_INCREMENT,
`data` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
INSERT INTO `think_data` (`id`, `data`) VALUES
(1, 'thinkphp'),
(2, 'php'),
(3, 'framework');
如果我们需要读取数据库中的数据,就需要在项目配置文件中(App/home/conf/config.php
)添加数据库连接信息如下:
// 添加数据库配置信息
'DB_TYPE' => 'mysql', // 数据库类型
'DB_HOST' => 'localhost', // 服务器地址
'DB_NAME' => 'thinkphp', // 数据库名
'DB_USER' => 'root', // 用户名
'DB_PWD' => '', // 密码
'DB_PORT' => 3306, // 端口
'DB_PREFIX' => 'think_', // 数据库表前缀
或者:
'DB_DSN' => 'mysql://root@localhost:3306/thinkphp'
修改控制器方法,添加读取数据的代码:
class IndexAction extends Action {
public function index(){
$Data = M('Data'); // 实例化Data数据模型
$this->data = $Data->select();
$this->display();
}
}
M('Data')
实例化后,就可以对think_data数据表(think_ 是我们在项目配置文件中定义的数据表前缀)进行操作(包括CURD)了
定义好控制器后,我们修改模板文件,添加数据输出标签如下:
<html>
<head>
<title>Select Data</title>
</head>
<body>
<volist name="data" id="vo">
{$vo.id}--{$vo.data}<br/>
</volist>
</body>
</html>
volist标签是内置模板引擎用于输出数据集的标签。{vo.id} 和 {vo.data}的用法和Smarty类似,就是用于输出数据的字段,这里就表示输出think_data表的id和data字段的值。我们访问
http://localhost/app/
输出:
1--thinkphp
2--php
3--framework
即数据库的Create.Update.Read.Delete,与ThinkPHP中的 add.save.select.delete一致。
Create操作通常会通过表单来提交数据,首先,我们在项目的Tpl/Form 目录下面创建一个add.html 模板文件,内容为
<FORM method="post" action="__URL__/insert">
标题:<INPUT type="text" name="title"><br/>
内容:<TEXTAREA name="content" rows="5" cols="45"></TEXTAREA><br/>
<INPUT type="submit" value="提交">
</FORM>
然后再项目中Action目录下创建FormAction.class.php
文件,
class FormAction extends Action{
public function insert(){
$Form = D('Form');
if($Form->create()) {
$result = $Form->add();
if($result) {
$this->success('操作成功!');
}else{
$this->error('写入错误!');
}
}else{
$this->error($Form->getError());
}
}
}
}
如果主键是自增类型的话,add方法的返回值就是该主键的值。不是自增主键的话,返回值表示插入数据的个数。如果返回false则表示写入出错。
public function read($id=0){
$Form = M('Form');
// 读取数据
$data = $Form->find($id);
if($data) {
$this->data = $data;// 模板变量赋值
}else{
$this->error('数据错误');
}
$this->display();
}
数据的更新操作在ThinkPHP使用save方法,可以看到,我们同样可以使用create方法创建表单提交的数据,而save方法则会自动把当前的数据对象更新到数据库,而更新的条件其实就是表的主键,这就是我们在编辑页面要把主键的值作为隐藏字段一起提交的原因。 如果更新操作不依赖表单的提交的话,就可以写成:
$Form = M("Form");
// 要修改的数据对象属性赋值
$data['id'] = 5;
$data['title'] = 'ThinkPHP';
$data['content'] = 'ThinkPHP3.1版本发布';
$Form->save($data); // 根据条件保存修改的数据
$User = M("User"); // 实例化User对象
$User->where('id=5')->delete(); // 删除id为5的用户数据
$User->delete('1,2,5'); // 删除主键为1,2和5的用户数据
$User->where('status=0')->delete(); // 删除所有状态为0的用户数据
不够安全
$User = M("User"); // 实例化User对象
$User->where('type=1 AND status=1')->select();
//SELECT * FROM think_user WHERE type=1 AND status=1
较为常用
$User = M("User"); // 实例化User对象
$condition['name'] = 'thinkphp';
$condition['status'] = 1;
// 把查询条件传入查询方法
$User->where($condition)->select();
//SELECT * FROM think_user WHERE `name`='thinkphp' AND status=1
以stdClass内置对象为例
$User = M("User"); // 实例化User对象
// 定义查询条件
$condition = new stdClass();
$condition->name = 'thinkphp';
$condition->status= 1;
$User->where($condition)->select();
//SELECT * FROM think_user WHERE `name`='thinkphp' AND status=1
$User = M("User"); // 实例化User对象
$map['name|title'] = 'thinkphp';
// 把查询条件传入查询方法
$User->where($map)->select();
$User = M("User"); // 实例化User对象
$map['name|title'] = 'thinkphp';
// 把查询条件传入查询方法
$User->where($map)->select();
内置的ORM和ActiveRecord模式实现了方便的数据存取操作,而且新版增加的连贯操作功能更是让这个数据操作更加清晰,但是ThinkPHP仍然保留了原生的SQL查询和执行操作支持,为了满足复杂查询的需要和一些特殊的数据操作,SQL查询的返回值因为是直接返回的Db类的查询结果,没有做任何的处理。主要包括下面两个方法:
query($sql,$parse=false)
sql
:要查询的SQL语句
parse
:是否需要解析SQL
$Model = new Model() // 实例化一个model对象 没有对应任何数据表
$Model->query("select * from think_user where status=1");
execute($sql,$parse=false)
sql
:要查询的SQL语句
parse
:是否需要解析SQL
$Model = new Model() // 实例化一个model对象 没有对应任何数据表
$Model->execute("update think_user set name='thinkPHP' where status=1");
例如$User->where('status=1')->order('create_time')->limit(10)->select();
where 用于查询或者更新条件的定义
用法 | where($where) |
---|---|
参数 | where(必须):查询或者操作条件,支持字符串、数组和对象 |
返回值 | 当前模型实例 |
备注 | 如果不调用where方法,默认不会执行更新和删除操作 |
table 定义要操作的数据表名称,动态改变当前操作的数据表名称,需要写数据表的全名,包含前缀,可以使用别名和跨库操作
用法 | table($table) |
---|---|
参数 | table(必须):数据表名称,支持操作多个表,支持字符串、数组和对象 |
返回值 | 当前模型实例 |
备注 | 如果不调用table方法,会自动获取模型对应或者定义的数据表 |
data 可以用于新增或者保存数据之前的数据对象赋值
用法 | data($data) |
---|---|
参数 | data(必须):数据,支持数组和对象 |
返回值 | 当前模型实例 |
备注 | 如果不调用data方法,则会取当前的数据对象或者传入add和save的数据 |
field 用于定义要查询的字段
用法 | field($field,$except=false) |
---|---|
参数 | field(必须):字段名,支持字符串和数组,支持指定字段别名;如果为true则表示显式或者数据表的所有字段。 except(可选):是否排除,默认为false,如果为true表示定义的字段为数据表中排除field参数定义之外的所有字段。 |
返回值 | 当前模型实例 |
备注 | 如果不调用field方法,则默认返回所有字段,和field(’*’)等效 |
order 用于对操作结果排序
用法 | order($order) |
---|---|
参数 | order(必须):排序的字段名,支持字符串和数组,支持多个字段排序 |
返回值 | 当前模型实例 |
备注 | 如果不调用order方法,按照数据库的默认规则 |
\app\common\entity\Article::where('category', $category)->order('sort', 'asc')->select();
limit 用于定义要查询的结果限制(支持所有的数据库类型)
用法 | limit($limit) |
---|---|
参数 | limit(必须):限制数量,支持字符串 |
返回值 | 当前模型实例 |
备注 | 如果不调用limit方法,则表示没有限制 |
group 用于数据库的group查询支持
用法 | group($group) |
---|---|
参数 | group(必须):group的字段名,支持字符串 |
返回值 | 当前模型实例 |
备注 | 无 |
union 用于数据库的union查询支持
用法 | union($union,$all=false) |
---|---|
参数 | union(必须):union操作,支持字符串、数组和对象 all(可选):是否采用UNION ALL 操作,默认为false |
返回值 | 当前模型实例 |
备注 | Union方法支持多次调用 |
方法 | 作用 | 支持的参数类型 |
---|---|---|
where | 用于查询或者更新条件的定义 | 字符串、数组和对象 |
table | 用于定义要操作的数据表名称 | 字符串和数组 |
alias | 用于给当前数据表定义别名 | 字符串 |
data | 用于新增或者更新数据之前的数据对象赋值 | 数组和对象 |
field | 用于定义要查询的字段(支持字段排除) | 字符串和数组 |
order | 用于对结果排序 | 字符串和数组 |
limit | 用于限制查询结果数量 | 字符串和数字 |
group | 用于对查询的group支持 | 字符串 |
filter | 用于数据过滤 | 字符串 |