专栏首页宸机笔记PHP-ThinkPHP框架学习

PHP-ThinkPHP框架学习

结构

框架目录

├─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参数中解析当前请求的模块和操作,我们之前访问的URL地址中没有任何参数,因此系统会访问默认模块(Index)的默认操作(index),因此下面的访问和之前是等效的:

http://localhost/app/index.php/Index/index

这种URL模式就是系统默认的PATHINFO模式,不同的URL模式获取模块和操作的方法不同,ThinkPHP支持的URL模式有四种:普通模式PATHINFOREWRITE兼容模式

普通模式

也就是传统的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类动态获取

系统的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参数的特殊需求,一般来说,获取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/

功能

  • 基本上传功能
  • 支持批量上传
  • 支持生成图片缩略图
  • 自定义参数上传
  • 上传检测(包括大小、后缀和类型)
  • 支持覆盖方式上传
  • 支持上传类型、附件大小、上传路径定义
  • 支持哈希或者日期子目录保存上传文件
  • 支持动态定义子目录保存文件
  • 上传图片的安全性检测
  • 支持上传文件命名规则
  • 支持对上传文件的Hash验证

简单的上传

表单

<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

CURD

即数据库的Create.Update.Read.Delete,与ThinkPHP中的 add.save.select.delete一致。

创建数据(Create)

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();

SQL查询

内置的ORM和ActiveRecord模式实现了方便的数据存取操作,而且新版增加的连贯操作功能更是让这个数据操作更加清晰,但是ThinkPHP仍然保留了原生的SQL查询和执行操作支持,为了满足复杂查询的需要和一些特殊的数据操作,SQL查询的返回值因为是直接返回的Db类的查询结果,没有做任何的处理。主要包括下面两个方法:

query方法

query($sql,$parse=false)

sql:要查询的SQL语句

parse:是否需要解析SQL

$Model = new Model() // 实例化一个model对象 没有对应任何数据表
$Model->query("select * from think_user where status=1");

execute方法

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(必须):查询或者操作条件,支持字符串、数组和对象

返回值

当前模型实例

备注

如果不调用where方法,默认不会执行更新和删除操作

TABLE

table 定义要操作的数据表名称,动态改变当前操作的数据表名称,需要写数据表的全名,包含前缀,可以使用别名和跨库操作

用法

table($table)

参数

table(必须):数据表名称,支持操作多个表,支持字符串、数组和对象

返回值

当前模型实例

备注

如果不调用table方法,会自动获取模型对应或者定义的数据表

DATA

data 可以用于新增或者保存数据之前的数据对象赋值

用法

data($data)

参数

data(必须):数据,支持数组和对象

返回值

当前模型实例

备注

如果不调用data方法,则会取当前的数据对象或者传入add和save的数据

FIELD

field 用于定义要查询的字段

用法

field($field,$except=false)

参数

field(必须):字段名,支持字符串和数组,支持指定字段别名;如果为true则表示显式或者数据表的所有字段。 except(可选):是否排除,默认为false,如果为true表示定义的字段为数据表中排除field参数定义之外的所有字段。

返回值

当前模型实例

备注

如果不调用field方法,则默认返回所有字段,和field(’*’)等效

ORDER

order 用于对操作结果排序

用法

order($order)

参数

order(必须):排序的字段名,支持字符串和数组,支持多个字段排序

返回值

当前模型实例

备注

如果不调用order方法,按照数据库的默认规则

\app\common\entity\Article::where('category', $category)->order('sort', 'asc')->select();

LIMIT

limit 用于定义要查询的结果限制(支持所有的数据库类型)

用法

limit($limit)

参数

limit(必须):限制数量,支持字符串

返回值

当前模型实例

备注

如果不调用limit方法,则表示没有限制

GROUP

group 用于数据库的group查询支持

用法

group($group)

参数

group(必须):group的字段名,支持字符串

返回值

当前模型实例

备注

UNION

union 用于数据库的union查询支持

用法

union($union,$all=false)

参数

union(必须):union操作,支持字符串、数组和对象 all(可选):是否采用UNION ALL 操作,默认为false

返回值

当前模型实例

备注

Union方法支持多次调用

常用方法

方法

作用

支持的参数类型

where

用于查询或者更新条件的定义

字符串、数组和对象

table

用于定义要操作的数据表名称

字符串和数组

alias

用于给当前数据表定义别名

字符串

data

用于新增或者更新数据之前的数据对象赋值

数组和对象

field

用于定义要查询的字段(支持字段排除)

字符串和数组

order

用于对结果排序

字符串和数组

limit

用于限制查询结果数量

字符串和数字

group

用于对查询的group支持

字符串

filter

用于数据过滤

字符串

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Heap-Off_By_One及经典b00ks解析

    在使用循环向堆块中写入数据时,在循环设置错误后 导致多写入了一个字节,而产生的漏洞

    偏有宸机
  • ROP-Ret2dl_resolve学习(1)

    该方法的主要原理是利用dl_runtime_resolve函数来对动态链接的函数进行重定位。

    偏有宸机
  • C-Pwn常见函数原型及作用

    format:格式字符串,指定了输入的格式,并按照格式说明符解析输入对应位置的信息并存储于可变参数列表中对应的指针所指位置。每一个指针要求非空,并且与字符串中的...

    偏有宸机
  • 美团一面:如何干掉可恶的SQL注入?

    直接使用 JDBC 的场景,如果代码中存在拼接 SQL 语句,那么很有可能会产生注入,如

    爱撒谎的男孩
  • Android | Tangram动态页面之路(三)使用

    本系列文章主要介绍天猫团队开源的Tangram框架的使用心得和原理,由于Tangram底层基于vlayout,所以也会简单讲解,该系列将按以下大纲进行介绍:

    Holiday
  • 走进Java接口测试之持久层框架Spring-data-jpa

    在接口测试中把 Case存储至数据库中,是比较常见的“数据驱动”做法。而在实际的接口测试用例开发中,对数据库的操作无非就是“增删改查”。就为最普遍的单表操作而言...

    高楼Zee
  • 高并发技术面试专题汇总,BAT技术面试不过如此!

    本文我们通过一篇真实的一线面经,带大家去体验一下 BAT 等互联网公司的面试现场氛围!

    慕容千语
  • Mybatis第二篇| CRUD,这才是程序员入门第一课

    增删改查(CRUD)是程序员必会的技能,我们大部分的时间也都是消耗在增删改查上,当然我们不能只做一个只会CRUD的程序员,当我们掌握并且熟练了CRUD后,我们可...

    Python进击者
  • 使用picard评估文库复杂度

    表示的是文库中unique的分子数目,unique分子数目越多,文库复杂度越高。在数据分析中,重复序列会对下游分析造成影响,在snp calling, peak...

    生信修炼手册
  • Spring系列第13篇:使用继承简化bean配置(abstract & parent)

    我们再回头去看一下上面xml中,serviceB和serviceC两个bean的定义如下:

    路人甲Java

扫码关注云+社区

领取腾讯云代金券