├─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 | 用于数据过滤 | 字符串 |
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句