thinkphp框架

Thinkphp

注意:

每次修改配置文件时,需要先把runtime下的temp下的文件删除掉然后再刷新才能生效

概要

1、完整形式

http://servername/index.php/模块/控制器/方法操作/键值对

2、模块下的类库文件命名空就按统一为:app\模块名,如

app\index\controller\Index

3、基本目录结构

www WEB部署目录(fleastrTest)
├─application 应用目录
│ ├─common 公共模块目录(可以更改)
│ ├─module_name 模块目录
│ │ ├─common.php 模块函数文件
│ │ ├─controller 控制器目录
│ │ ├─model 模型目录
│ │ ├─view 视图目录
│ │ ├─config 配置目录
│ │ └─ … 更多类库目录
│ │
│ ├─command.php 命令行定义文件
│ ├─common.php 公共函数文件
│ └─tags.php 应用行为扩展定义文件
│
├─config 应用配置目录
│ ├─module_name 模块配置目录
│ │ ├─database.php 数据库配置
│ │ ├─cache 缓存配置
│ │ └─ …
│ │
│ ├─app.php 应用配置
│ ├─cache.php 缓存配置
│ ├─cookie.php Cookie配置
│ ├─database.php 数据库配置
│ ├─log.php 日志配置
│ ├─session.php Session配置
│ ├─template.php 模板引擎配置
│ └─trace.php Trace配置
│
├─route 路由定义目录
│ ├─route.php 路由定义
│ └─… 更多
│
├─public WEB目录(对外访问目录)
│ ├─index.php 入口文件
│ ├─router.php 快速测试文件
│ └─.htaccess 用于apache的重写
│
├─thinkphp 框架系统目录
│ ├─lang 语言文件目录
│ ├─library 框架类库目录
│ │ ├─think Think类库包目录
│ │ └─traits 系统Trait目录
│ │
│ ├─tpl 系统模板目录
│ ├─base.php 基础定义文件
│ ├─convention.php 框架惯例配置文件
│ ├─helper.php 助手函数文件
│ └─logo.png 框架LOGO文件
│
├─extend 扩展类库目录
├─runtime 应用的运行时目录(可写,可定制)
├─vendor 第三方类库目录(Composer依赖库)
├─build.php 自动生成定义文件(参考)
├─composer.json composer 定义文件
├─LICENSE.txt 授权说明文件
├─README.md README 文件
├─think 命令行入口文件

控制器

initialize()

如果继承了基类控制器,那么可以定义控制器的初始化方法:initialize()

initialize()方法会在调用控制器方法之前执行

class Index extends Controller
{
    //初始化
    protected function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
        echo 'init';//不能使用return
    }
    public function index()
    {
        return '第一模块的东西';
    }

当调用index方法时,会先调用initialize()方法

在这里插入图片描述

$beforeActionList

当继承Controller类后可以设置一个$beforeActionList属性来创建前置方法

所谓前置,是指无论当调用类中什么方法时,都会先调用数组中的方法。

<?php
class Before extends Controller
{
    protected $beforeActionList = [
        'first',    //数组中写方法名
    ];
    protected function first()
    {
        echo '1<br>';
    }
    public function  one()
    {
        return 'one';
    }
}
?>

在这里插入图片描述

其中还有 两种语法

<?php
   class Before extends Controller
{
    protected $beforeActionList = [
        'first',
        'second' => ['except'=>'one'],//调用one方法时不调用second前置
        'third' => ['only'=>'one,two'],//third前置只能通过调用one和two方法来触发
    ];
    protected function first()
    {
        echo '1<br>';
    }
    protected  function  second()
    {
        return '2<br>';
    }
    protected function  third()
    {
        return '3<br>';
    }
    
    public function  one()
    {
        return 'one';
    }

    public  function two()
    {
        return 'two';
    }
?>

跳转和重定向

Controller类提供了两个跳转的方法:success(msg,url)error(msg)

<?php
class Before extends Controller
{
     protected $wind = true;
     public  function  index()
     {
        if ($this->wind) {
            $this->success('成功','../');
        } else {
            $this->error('失败');
        }

        return 'index';
    }
}
?>

在这里插入图片描述

空方法拦截

    public function _empty($name){
        return '此方法不存在:'.$name;
    }

空控制器拦截

class Error
{
    public function index(Request $r)//控制器拦截有固定参数reque和方法controller
    {
        return '此控制器不存在:'.$r->controller();
    }
}

数据库与模型

首先进入config目录下的database.php进行相关配置

在这里插入图片描述

输出数据库中的内容:

不使用Model

<?php

namespace app\index\controller;
use think\Controller;
use think\Db;

class DataTest extends Controller
{
    public function index(){
        return 'index';
    }

    public function getNoModelData()
    {
        //$data = Db::table('tp_user')->select();//不使用在database.php中配置的前缀
        $data = Db::name('user')->select();//使用在database.php中配置的前缀
        return json($data);//需要转换为json形式输出
    }
}
?>

在这里插入图片描述

使用Model

use app\index\model\User;//根据自己的目录修改
public function getModelData()
{
    $data = User::select();
    return json($data);
}

最终的结果是一样的,但是使用Modle会更简便一些

使用Model需要现在和controller目录同级的目录下创建一个model目录

在这里插入图片描述

其中User.php的内容为

<?php
namespace app\model;


use think\Model;

class User extends Model
{

}

在配置文件app.php

'app_trace'              => false,//改为true可查看原生sql语句

前提是要先去掉json输出

 public function getModelData()
    {
        $data = User::select();
        //return json($data);
    }

之后在访问刚才那个页面右下角就会出现这个东西

在这里插入图片描述

打开之后点击SQL即可查看

在这里插入图片描述

基本查询

只查询一条数据,使用find()

$data = Db::name('user')->find();

在这里插入图片描述

获取sql语句

$data = Db::name('user')->find();
return Db::getLastSql();

在这里插入图片描述

指定查询

$data = Db::name('user')->where('age',14)->find();

没有查询到任何值,返回NULL

findOrFail()同样是查询一条数据,在没有数据时返回一个异常

findOrEmpty()同样是查询一条数据,在没有数据时返回一个空数组

获取多列数据,使用select()

$data = Db::name('user')->select();

多列数据在没有数据时返回一个空数组

使用selectOrFail()返回异常

使用提供的助手函数db

$data = \db('user')->select();

通过value()方法,查询指定字段的值(单个)

$data = Db::name('user')->value('name');

在这里插入图片描述

colunm(),查询指定列的值(多个),没有数据则返回空数组

id,指定id作为列值的索引

$data = Db::name('user')->column('name','id');

链式查询

find()select()来结束查询

当同一个对象实例第二次查询后,会保留第一次查询的值,所以使用removeOption()来清除上一次查询保留的值

class DataTest extends Controller
{
    public function index(){        
        $user = Db::name('user');
        $data1 = $user->where('age',14)->order('id','desc')->find();//desc是倒序的意思
        $data2 = $user->removeOption('where')->removeOption('order')->select();
        return Db::getLastSql();
        //return json($data);
    }
}

在这里插入图片描述

增删改

insert()

public function insert()
    {
        $data = [
            'username'  =>  'Tony',
            'password'  =>  'a',
            'id'        =>  '4',
        ];

        //$insert = Db::name('user')->insert($data);
        $insert = Db::name('user')->data($data)->insert();//可使用data,效果和上面一样
        return Db::getLastInsID();//获得ID
        return $insert;//如果新增成功,会返回1
    }

在这里插入图片描述

批量新增

public function insertAll()
    {
        $dataAll = [
            [
                'username'  =>  'Tony',
                'password'  =>  'a',
                'id'        =>  '4',
            ],
            [
                'username'  =>  'Tony2',
                'password'  =>  'a',
                'id'        =>  '4',
            ]
        ];

        Db::name('user')->insertAll($dataAll);
    }
public function update()
    {
       $data = [
           'username' => 'Dam'
       ];
       Db::name('user')->where('id',3)->update($data);
    }

如果表中包含主键,可以换种写法

public function update()
    {
       $data = [
           'username' => 'Dam'
           'id'       => 3
       ];
       Db::name('user')->update($data);
    }

inc,dec,增值减值

Db::name('user')->inc('price',3)->update($data);//第一个值是字段名,第二个值是键长,如price字段若不指定键长,则默认为1,执行一次操作,price的值就增加一,dec则相反,减1

exp()

可以 在字段中使用mysql函数

Db::name('user')->exp('username','UPPER(...)'->update($data);

raw()

public function update()
    {
       $data = [
           'username' => Db::raw('UPPER(username)'),
           'price' => Db::raw('price - 3'),
           'id'  =>  6
       ];
       Db::name('user')->update($data);
    }

setField()

更新一个字段值

Db::name('user')->where('id',3)->setField('username','Sam');

setInc()setDec()

增减一个字段值

Db::name('user')->where('id',3)->setInc('price');

根据主键直接删除

删除一条

Db::name('user')->deldete(2);

删除多条

Db::name('user')->deldete([1,2,3]);

where()

Db::name('user')->where('id',3)->deldete();

删除所有数据

Db::name('user')->deldete(true);

比较查询

Db::name('user')->where('id','=/>/</>=/<=',3)->find();

区间查询

like()

$result = Db::name('user')->where('email','like','la%')->select();//查询email字段中开头是la的数据
$result = Db::name('user')->where('email','like',['la%','da%'],'or')->select();//查询email字段中开头是la或者da的数据

快捷方式

whereLike()whereNolike()

$result = Db::name('user')->whereLike('email','la%')->select();
$result = Db::name('user')->whereNolike('email','la%')->select();

between,innulllike是一样的

链式方法

关联数组查询

 public function index()
    {
        $result = Db::name('user')->where([
            'password'   =>   123,
            'price'      =>   100
        ])->select();
        return json($result);
    }

索引数组查询

public function index()
    {
        $result = Db::name('user')->where([
            ['password'   =>   123],
            ['price'      =>   100]
        ])->select();
        return json($result);
    }

变量传递

$map[] = ['password'   =>   123];
$map[] = ['price'      =>   100];
$result = Db::name('user')->where($map)->select();

field()

指定要查询的字段

Db::name('user')->field('id,username,password')->select();
Db::name('user')->field(['id,username,password'])->select();

给指定的字段设置别名

Db::name('user')->field('id,username as name')->select();
Db::name('user')->field('id','username' => 'name')->select();

给字段设置mysql函数

Db::name('user')->field('id,SUM(price)')->select();

结合details可以屏蔽掉想要不显示的字段

Db::name('user')->field('details,username',true)->select();//将会不显示username的内容

模型

设置主键

protected $pk = 'uid';//设置主键,只能写$pk,这是固定的

设置其他表

protected $table = 'tp_one';//$table也是固定的

初始化init()必须设置为静态方法,会在调用其他方法之前调用此方法

 protected static function init()
    {
        echo '初始化';
    }

数据增删

使用实例化方式添加一条数据

实例化方式,以下两种均可以

$user = new UserModel();
$user = new \app\index\model\User;

新增数据save()

public function insert()
    {
        $user = new UserModel();
        
        $user->username     =   'xi';
        $user->password     =   '123';
        $user->price        =   '19';
        
        $user->save();
       
    }

也可以直接中括号

public function insert()
    {
        $user = new UserModel();
        
       
        $user->save([
              $user->username     =   'xi';
              $user->password     =   '123';
              $user->price        =   '19';        
        ]);
       
    }

批量新增saveAll()

$user = new UserModel();
$dataAll = [
    [
              $user->username     =   'xi';
              $user->password     =   '123';
              $user->price        =   '19';   
    ],
    [
              $user->username     =   'xii';
              $user->password     =   '1234';
              $user->price        =   '18';   
    ]
];
$user->saveAll($dataAll);

删除

delete()

//使用delete之前要先写出要删除的信息
$user->delete();

destroy()

UserModel::destroy(3);
UserModel::destroy('1,2,3');//批量删除

条件删除

UserModel::where('id','>',3)->delete();

闭包删除

UserModel::destroy(function ($query){
    $query->where('id','>',2);
});

修改查询

get()

通过get()方法获取

public function updata()
    {
        $user = UserModel::get(1);
        $user->username    =  'Amy';
        $user->password    =  '123456';
        echo $user->save();
    }

where()find()

只能找一条最近的数据

$user = UserModel::where('username','Tom')->find();
$user->username  =  'Amy';
echo $user->save();

force()

强制更新

echo $user->force()->save();

Db::raw

执行sql函数的方式

$user->price  =  Db::raw('price+1');

inc/dec

增减数据

$user->price  =  ['inc',1];

save([],[])

通过两个数组参数的方式更新数据

$user = new UserModel();
$user->save([
'username'    =>    ‘Amy',
'password'    =>    '123456'
],['id=>3'])//改id=3的数据

saveAll()

批量修改

$list = [
    ['id'=>1,'usrname'=>'Amy'],
    ['id'=>1,'usrname'=>'Jack']
];//第一条必须是主键

update()

1、

UserModel::where('id',1)->update([  
    'username'     =>   'Amy',
]);

2、

UserModel::update([
    'id'           =>   1,
    'username'     =>   'Amy',
]);

isUpdate

强制修改

$user->isUpdata(true)->save();

强制新增

$user->isUpdata(false)->save();

all()

实现IN模式的多数据获取

$user = UserModel::all('1,2,3')

获取某个字段

UserModel::where('id',1)->value('username');

模型获取器

只能对单字段进行操作

public function getStatusAttr($a)//get和Attr是固定的,中间的Status是字段名,也是固定的
    {
        $myGet = [1=>'正常',2=>'错误'];
        return $myGet[$a];
    }

在这里插入图片描述

在这里插入图片描述

对多字段进行操作

public function getNothingAttr($value,$data)
    {
        $myGet = [1=>'正常',2=>'错误'];
        return [$data['status']];
    }

getData()

获取原始值

public function index()
    {
        $user = UserModel::get(1);
        return $user->getData('status');//获取原始值
    }

在这里插入图片描述

模板引擎和视图渲染

自动定位

class See extends Controller
{
public function index()
    {
        //自动定位
        //return $this->fetch();
        return $this->fetch('edit');
    }
}
http://localhost/tp5.1/public/index.php/index/see

在这里插入图片描述

        //多模块时,指定模块下的模板
        return $this->fetch('admin@public/edit');

在这里插入图片描述

如果不继承Controller类,那么可以调用view()助手函数

return view('edit');

赋值和过滤

赋值

assign()

class See extends Controller
{
    public function index()
    {
        $this->assign('name','Tom');
        return $this->fetch('index');
    }

}

在这里插入图片描述

得到:

在这里插入图片描述

通过数组,多个变量赋值

$this->assign([
            'username'    =>   'Amy',  //{$username}
            'password'    =>   '123'   //{$password}
        ]);

display()

可以不通过模板直接解析变量

public function testDisplay()
    {
        $content = '{$username}.{$password}';
        return $this->display($content,[
            'username'    =>   'Amy',
            'password'    =>   '123'
        ]);
    }

使用View::share(),可以在系统任意位置做全局变量赋值

\think\facade\View:;share('key','value')  //支持数组

过滤

filter()

//将所有传入进来的数据中的1转化为换行符
$this->filter(function ($content){
            return str_replace('1','<br/>',$content);
        });

全局执行

inittialize()

public function initialize()
    {
        $this->filter(function ($content) {
            return str_replace('1', '<br/>', $content);
        });
    }

变量输出

当程序运行的时候,会在runtime/temp目录下生成编译文件(可删除)

如果传递的值是数组

$data['username']  = 'Tom';
$data['password']  = '123'; 
$this->assign('user',$data)

模板调用

{$user.username}.{$user.password} //或{$user['password']}

如果传递的值是对象

$obj = new \stdclass \\声明一个空对象
$obj->username = 'Tom';
$this->assign('obj',$obj);

调用

{$obj->username}.{$obj->password}

如果输出的变量没有值,可以直接设置默认值

default

{$user.username|default='没有此用户'}

使用$Think.xxx.yyy方式,可以输出系统的变量

{$Think.get.key}

在模板直接输出常量

//获取系统版本
{$Think.const.PHP_VERSION}
=
{$Think.PHP_VERSION}

模板中的函数与运算符

函数

md5加密

$this->assign('password','123456');
{$password|md5}//竖线后面跟函数名

系统默认会在编译时采用htmlentities过滤函数以防止XSS跨站脚本攻击

在这里插入图片描述

如果某个字符,你不需要转义的话,可以单独使用raw处理

{$user['username']|raw}

多个函数操作,从左到右依次执行

{$password|md5|upper}

也可以直接使用php的语法模式

{:sustr(strtoupper(md5($password)),0,3)}

运算符

{$number + $number}

模板标签

循环标签(暂时先不看)

foreach

比较标签

{eq}..{/eq}{neq}..{notequal}

比较两个值是否相同,相同/不相同则输出包含内容

public function compare()
    {
        $this->assign('username','Tom');
        return $this->fetch('compare');
    }


<body>

{eq name='username' value='Tom'}
    是Tom
{/eq}


</body>

在这里插入图片描述

还可以合并起来

{eq name='username' value='Tom'}
    是Tom
{else/}
    不是Tom
{/eq}

其他的比较标签

{gt}(>)、{egt}(>=)、{lt}(<)、{elt}(<=)、{heq}(===)、{nheq}(!==)

所有标签都可以统一为{compare}标签使用,增加一个type方法指定即可

{compare name='username' value='Tom' type='eq'}
是Tom
{/compare}

定义标签

定义变量

{assign}

{assign name='var' value='123'}
{$var}

定义常量

{define}

{defin name='PI' value='3.141'}
{$Think.const.PI}

也可采用{php}

{php}
     echo 'lala'
{/php}

条件标签(暂时先不看)

模板的加载包含输出

包含

{include}

创建三个html5文件

header.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
头部  <br>

nav.html

导航

footer.html

<br>尾部
</body>
</html>

index.html

{include file='public/header,public/nav'}
主体
{include file='public/footer'}

在这里插入图片描述

调用

public function index()
    {
        $this->assign('title','模板');
        return $this->fetch('index');
    }


//index.html
{include file='public/header,public/nav'  abc='$title'}
主体
{include file='public/footer'}

//header.html
<title>[abc]</title>//用[]调用

在这里插入图片描述

输出替换

引入cssjs

//css
<link href="/tp5.1/public/static/css/basic.css" rel="stylesheet" type="text/css" />

//js
<script type="application/javascript" src="/tp5.1/public/static/js/basic.js"></script>

为了更简便,可以在config下的template.php中添加如下代码

'tpl_replace_string' => [
        '__CSS__' => '/tp5.1/public/static/css',
        '__JS__' => '/tp5.1/public/static/js',
    ]

之后便可以通过这样来访问了

<link href="__CSS__/basic.css" rel="stylesheet" type="text/css" />
<script type="application/javascript" src="__JS__/basic.js"></script>

由于更改的是配置文件刷新,每次都要删除编译文件才能生效

加载

传统方式采用linkscript来调用cssjs文件

但是thinkphp提供了另一种方式

{load}

{load href='__CSS__/basic.css'}
{load href='__JS__/basic.js'}

//还可以连在一起写
{load href='__CSS__/basic.css,__JS__/basic.js'}

//甚至还可以
{css href='__CSS__/basic.css'}
{js href='__JS__/basic.js'}

模板布局和继承

布局

...

继承

...

模板注释

对于在HTML页面中的标签,用HTML注释是无效的,需要使用模板定义的注释:

{//$name}
{/*$name*/}
{/*
多行注释
*/}

注释和{之间不能有空格,否则无法实现注释隐藏

路由

简单来说就是简化路径,在route目录下的route.php中,添加如下代码

\think\facade\Route::get('details/:id','Address/details');
//前面那个details可以随便写,如写成abc也行

//后面的Address/details中,Address表示指向的类,details表示指向的方法

//如果后面只写一个参数,那么默认是方法,这样details就默认是方法
\think\facade\Route::get('details/:id','details');

就可以直接访问了

http://localhost/tp5.1/public/index.php/details/5  

在这里插入图片描述

请求方式有很多种

也可以使用rule

\think\facade\Route::get('details/:id','Address/details');
=
\think\facade\Route::rule('details/:id','Address/details','GET');

强制路由

要先在config目录下的app.php中进行配置,默认是关闭的

访问任何没有配置的页面都会报错

route.php种进行页面的配置

路由规则表达式

//静态路由
Route::get('ad','address/index');
//动静态结合路由
Route::get('details/:id','address/details');
//多参数动静态结合
Route::get('search/:id/:uid','address/search');
//全动态,不相知是否search固定
Route::get(':search/:id/:uid','address/search');
//包含可选参数
Route::get('find/:id/[:content]','address/find');
//可选就是可以只写一个参数,像这样
http://localhost/tp5.1/public/index.php/find/5

//规则完全匹配
Route::get('find/:id/:uid$','address/search');//最后加个$即可
http://localhost/tp5.1/public/index.php/search/5/4/3
//像这样后面多加了一个/3就是错误的

url()

\think\facade\Route::get('url','address/url')->name('det');//取别名

public function url()
    {
        return url('det',['id'=>10]);
    }

变量规则

pattern()

对具体的变量进行单独的规则设置

//对name进行单独限制
\think\facade\Route::get('details/:id','Address/details')
                    ->name('det')
                    ->pattern('id','\d+');

通过数组进行多个值的限制

//对id和uid进行限制
\think\facade\Route::get('find/:id/[:content]','address/find')
    ->parent([
        'id'   =>  '\d+',
        'uid'  =>  '\d+'
    ]);

Route.php中设置全局变量规则:

Route::pattern([
    'id'   =>  '\d+',
    'uid'  =>  '\d+'
])

模糊匹配

动态组合的拼装,地址和参数如果都是模糊动态的,可使用如下方法

\think\facade\Route::get('det/:id','Hello_:name/det')
    ->parent('id','\d+');

HelloWorld.php

 public function det($id)
    {
        return 'det的id:'.$id;
    }

在这里插入图片描述

闭包支持

支持我们可以直接通过URL直接执行,而不需要通过控制器和方法

Route::get('think', function () {
    return 'hello,ThinkPHP5!';
});

调用

//正常调用
\think\facade\Route::get('details/:id','Address/details');
http://localhost/tp5.1/public/index.php/index/group.address/details/id/5
//group与address之间用.连接



//另外方式调用
\think\facade\Route::get('details/:id','group.Address/details');
http://localhost/tp5.1/public/index.php/details/5

隐式传参

在url是看不见的,更加安全

\think\facade\Route::get('details/:id','Address/details?flag=1');

public function details($id)
    {
        echo $this->request->param('flag');
        return 'details调用的id:'.$id;
    }

在这里插入图片描述

可直接调用普通方法及其静态方法

普通方法

\think\facade\Route::rule('details/:id','app\index\controller\Address@details');

public function details($id)
    {
        return 'details调用的id:'.$id;
    }

静态方法

\think\facade\Route::rule('stat/:id','app\index\controller\Address@stat');

public static function stat($id)
    {
        return 'stat调用的id:'.$id;
    }

重定向

//第一种写法
\think\facade\Route::get('details/:id','http://www.liyanhui.com/details/:id')->status(302);

//第二种写法
\think\facade\Route::redirect('details/:id','http://www.liyanhui.com/details/:id',302);

对模板进行传值

Route::view('see/:name','See/other',['password']=>'123456');

路由缓存

清理缓存

//在cmd中进入/tp.5.1
php think clear --route

路由参数

在设置路由的时候,可以设置第三个数组参数

ext()

ext的作用是检测URL后缀,

//这里的意思就是后缀必须是html
\think\facade\Route::get('details/:name/:id','address/details',[ext=>'html']);


//也可以写成如下形式:    
\think\facade\Route::get('details/:name/:id','address/details')->ext('html');

https()

https的作用就是检测是否为https请求,可结合ext使用

\think\facade\Route::get('details/:name/:id','address/details',[ext=>'html','https'=>true]);

\think\facade\Route::get('details/:name/:id','address/details')->ext('html')->https();

全局统一配置后缀,在app.php

url_html_suffix

denyExt()

禁止某些后缀的使用

Route::get('details/:id','address/details')->denyExt('gif|jpg|png')

filter()

设置额外参数

Route::get('details/:id','address/details')->filter('id',10)

就必须这样访问才对

/details/5?id=10

model()

绑定到模型

option()

进行全局路由配置,可多次使用

\think\facade\Route::get('details/:id','group.Address/details');
\think\facade\Route::option('ext','html')->option('https',true);

快捷路由

\think\facade\Route::controller('short','Short');
//用什么方式请求就返回给你什么方式

shrot.php

class Short extends  Controller
{
    public function getInfo()
    {
        return 'getInfo';
    }

http://localhost/tp5.1/public/index.php/short/info

在这里插入图片描述

路由收集

group()

Collect.php

class Collect extends Controller
{
    public function read($id)
    {
        return 'id:'.$id;
    }

    public function who($name)
    {
        return 'name:'.$name;
    }

}
\think\facade\Route::group('col',[
    ':id'      =>    'Collect/read',
    ':name'    =>    'Collect/who'
])->ext('html')->pattern(['id'=>'.........','name'=>'.......']);
    //设置规则,不然匹配时会出错

在这里插入图片描述

append()request()

可以额外添加一个参数,用request请求获取

\think\facade\Route::group('col',[
    ':id'      =>    'Collect/read',
    ':name'    =>    'Collect/who'
])->append(['flag'=>1]);
 public function read($id)
    {
        echo $this->request->param('flag');
        return 'id:'.$id;
    }

在这里插入图片描述

注解路由

注意:语句结尾不需要分号,路由规则结束后,需要有一个空行,否则不能执行规则

 /**
     * @param $id
     * @return string
     * @route('col/:id','get')
     * ->ext('html')
     * ->pattern(['id'=>'\d+'])
     *  就是这个空行
     */

跨域请求

当不同域名之间进行跨域请求时,由于浏览器的安全限制,会被拦截,所以通过

allowCrossDomain()

来解除这个限制

\think\facade\Route::group('col','Collect/read')->allowCrossDomain();
//使用后即可实现跨域请求

路由绑定

bind()

//绑定路由到index模块
Route::bind('index');   ...../user/read/id/5
//绑定路由到User控制器     
Route::bind('index/User');      ...../read/id/5
//绑定路由到read操作
Route::bind('index/User/read');  ..../id/5  

资源路由

在cmd中进入/tp5.1后键入

php think make:controller 路径/Blog

在这里插入图片描述

生成的Blog.php

<?php

namespace app\controller\..\index\controller;

use think\Controller;
use think\Request;

class Blog extends Controller
{
    /**
     * 显示资源列表
     *
     * @return \think\Response
     */
    public function index()
    {
        //
    }

    /**
     * 显示创建资源表单页.
     *
     * @return \think\Response
     */
    public function create()
    {
        //
    }

    /**
     * 保存新建的资源
     *
     * @param  \think\Request  $request
     * @return \think\Response
     */
    public function save(Request $request)
    {
        //
    }

    /**
     * 显示指定的资源
     *
     * @param  int  $id
     * @return \think\Response
     */
    public function read($id)
    {
        //
    }

    /**
     * 显示编辑资源表单页.
     *
     * @param  int  $id
     * @return \think\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * 保存更新的资源
     *
     * @param  \think\Request  $request
     * @param  int  $id
     * @return \think\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * 删除指定资源
     *
     * @param  int  $id
     * @return \think\Response
     */
    public function delete($id)
    {
        //
    }
}

创建资源路由

\think\facade\Route::resource('blog','Blog');

资源路由注册成功后,会自动提供以下七种方法:

GET请求:index(blog),create(blog/create),read(blog/:id),edit(blog/:id/edit)

POST请求:save(blog)

PUT方式模式下:update(blog/:id)

DELETE方式模式下:delete(blog/:id)
    
    http://localhost/........./blog/      (index)
    http://localhost/........./blog/5     (read)
    http://localhost/........./blog/5/edit (edit)

参考https://www.bilibili.com/video/BV17J411K7Zd?p=42

only(),except()

限定/排除系统提供的资源方法是否能进行访问

->only(['index','save'])
    //只有index和save可以访问

->except(['read','delete'])
    //只有read和delete不能访问

rest()

更改默认的方法

\think\facade\Route::rest('create',['GET,'/:id/invent','invent']);

//批量更改
\think\facade\Route::rest([
   'save'     =>  ['POST','','safe'],
   'delete'   =>  ['DELETE','/:id','des']
]);

第一个参数:请求方式
第二个参数:地址
第三个参数:操作

嵌套资源路由

\think\facade\Route::resource('blog','Blog');
\think\facade\Route::resource('blog。Comment','comment');

//访问:
http://localhost/....../blog/100/comment/20 

域名路由

首先要在C:\WINDOWS\System32\drivers\etc中找到hosts文件

在后面添加自创的域名

new.qwe.com 映射二级域名
a.new.qwe.com 映射三级域名

如果像限定在new.qwe.com这个域名下才有效,采用闭包形式

domain()

\think\facade\Route::domain('new',function(){
     \think\facade\Route::get('edit/:id','Collect/edit');
});

//domain()第一个参数表示二级域名的名称

还指出多个二级域名,使用相同的路由规则

\think\facade\Route::domain(['new','blog','live'],function(){
     \think\facade\Route::get('edit/:id','Collect/edit');
});

域名设置还支持绑定指定的模块,如admin模块

\think\facade\Route::domain('new','admin');

三级域名

\think\facade\Route::domain(['*.new','blog','live'],function(){
     \think\facade\Route::get('edit/:id','Collect/edit');
});

路由的URL生成

public function idnex()
{
    return Url::build('Blog/read',id=5&uid=6);
}

//Url::build('地址表达式',['参数'],['URL后缀'],['域名'])
//url('地址表达式',['参数'],['URL后缀'],['域名'])

请求对象和信息

第一种:继承基类

public function index()
    {
        return $this->request->param('name');
    }

使用方法

localhost/....../rely?name=lee

第二种:不继承基类

自己进行依赖注入这个对象

class Rely
{
    public function index(Request $request)
    {
        return $request->param('name');
    }
}

第三种

use think\Request;
class Rely
{
    protected $request;
    public function __construct(Request $request)
    {
        $this->request =  $request;
    }

    public function index()
    {
        return $this->request->param('name');
    }

请求变量

has()

检测全局变量是否已经设置

dump(Request::has('id','get'));

http://localhost/tp5.1/public/index.php/index/rely
//返回false

http://localhost/tp5.1/public/index.php/index/rely?id=10
//返回true

//注意:这里的变量时区分大小写的,写成ID则无法返回结果

param()

能自动识别GET、POST等的当前请求

//获取请求为name的值,过滤
dump(Request::param('name'));
//以数组的形式获取所有请求的变量,过滤
dump(Request::param());
//获取所有请求的变量,不包含上传变量,不过滤
dump(Request::param(false));
//获取所有请求的变量,包含上传变量,过滤
dump(Request::param(true));

过滤条件要在app.php中设置

使用依赖注入的方式,可以将变量作为对象的属性进行调用;

public function read(Request $request)
    {
        return $request->name;
    }

only()

获取指定的变量,也可以设置默认值

dump(Request::only('id,name'));
=
dump(Request::only(['id,name']));

将参数强制转换类型

/s(字符串)、/d(整形)、/b(布尔)、/a(数组)、/f(浮点)
    
Request::param('id/d');

请求类型和HTTP头信息

method()

获取请求类型

return Request::method();

伪造类型_method

<input type='hidden' name='_method' value='PUT'>

获取原始类型

return Request::method(true);

AJAX/PJAX伪装

?_ajax=1和?_pjax=1

使用method无法判断是否为ajax/pjax,必须使用isAjia()isPjax()

HTTP头信息

header()

dump(Request::header());

//可以指定返回什么头信息
dump(Request::header('host'));

响应重定向和文件下载

响应

return

默认输出html的格式

response()

可设置第二参数、状态码,或者调用code()方法

return response($data,201);
return response($data)->code(202);

json()

还能设置header()头文件信息

return json($data)->code(202)->header(['...=>...'])

重定向

redirect(),需要return来执行

return redirect('http://www.baidu.com');

站内重定向

必须要用顶级域名,不然会出错

return redirect('edit/5');

return redirect('/address/details/id/5')

文件下载

download()

//图片写两个参数
return download('1.jpg','lalala')//第二个参数是自己取的名字
    
//文本写三个参数
return download('路径','取的名字',true)

容器和依赖注入

依赖注入

允许通过类的方法传递对象的能力,并且限制了对象的类型,而且传递的对象背后的那个类被自动绑定并且实例化了。

基本模板

One.php

<?php

namespace app\index\model;

class One
{
    public $name='Mr.Tom';
}

Inject.php

<?php

namespace app\index\controller;

use app\index\model\One;

class Inject
{
    protected $one;

    public function __construct(One $one)
    {
        $this->one = $one;
    }

    public function index()
    {
        return $this->one->name;
    }

}

容器

依赖注入的类同意由容器管理,大多数情况下是自动绑定和自动实例化的,

如果像手动绑定和实例化,就要使用bind()app()

class Inject
{
    public function index()
    {
        bind('one','app\index\model\One');
        return app('one')->name;
    }
}

Facade(门面设计模式)

钩子和行为

tags.php进行绑定操作即可

    'app_init'     => [
          'app\behavior\Test',
    ],

自定义钩子

https://www.bilibili.com/video/BV17J411K7Zd?p=52

中间件

前置中简件

主要用于拦截和过滤HTTP请求,并进行相应的处理

通过命令行模式,生成一个中间件文件和文件夹

php think make:middleware Check
class Check
{
    //handle是不能改变的
    public function handle(Request $request, \Closure $next)
    {
         if($request->param('name') == 'index'){
            return redirect('/');   //重定向
         }

        return $next($request);//固定格式
    }
}

后置中间件

请求完毕之后再进行验证,比如写入日志

 public function handle(Request $request, \Closure $next)
 {
     $response = $next($request);
     
     return $response;
 }

验证器

命令行生成文件

php think make:validate index/User

验证规则

User.php

<?php

namespace app\index\validate;

use think\Validate;

class User extends Validate
{
    /**
     * 定义验证规则
     * 格式:'字段名'	=>	['规则1','规则2'...]
     *
     * @var array
     */	
	protected $rule = [
        'name'     =>   'require|max:10',//规则一:不能为空,规则二:不能大于10
        'grades'   =>   'number|between:1,100'
    ];
    
    /**
     * 定义错误信息
     * 格式:'字段名.规则名'	=>	'错误信息'
     *
     * @var array
     */	
    protected $message = [
        'name.require'    =>    '用户名不得为空',
        'name.max'        =>    '姓名不得大于10位'
    ];
}
class Verify
{
    protected $batchValidate  //在头部设置这个,当有多个错误时,都能回显出来,若不设置,就只能回显一个错误
        
    //开启异常
    protected $failException = true;
    
    public function index()
    {
          $data = [
              'name'    =>    '',
              'grades'  =>     40,
          ];

          $validate = new \app\index\validate\User();

          if (!$validate->check($data));
              dump($validate->getError());
    }

}

//返回'name'不能为空


//这样写也是一样的
$this->validate([
     'name'    =>    'Tom',
     'grades'  =>    40,
],\app\index\validate\User::class);

if($result !==true){
    dump($result);
}

可以在User.php中自定义规则

需要在上面的rule中调用才能生效

//自定义规则
protected function checkName($value,$rule)//第一个参数是上传的值,第二个参数是规则
{
    return $rule != $value ? true : '不能使用Tom';
    //不相等则返回True,相等则返回不能使用Tom
}



//调用
/**
     * 定义验证规则
     * 格式:'字段名'	=>	['规则1','规则2'...]
     *
     * @var array
     */	
	protected $rule = [
        'name'     =>   'require|max:10|chekname:Tom',//在这里调用
        'grades'   =>   'number|between:1,100'
    ];

独立验证,不使用User.php

支持自定义方式,但不支持属性方式多规则方式

默认返回一条错误信息,若要批量返回所有错误,必须使用batch()

$data = [
              'name'    =>    '',
              'grades'  =>     40,
          ];

$validate = new Validate()
$validate->rule([    
       'name','require|max:10',
)];

//批量返回
if (!$validate->batch()->check($data));
              dump($validate->getError());
                
                
                
 //甚至可以这样设置规则
      $validate = new Validate()          
      $validate->rule('name',Validate::isRequire()->max(10));          
                

错误信息

如果要在控制器使用独立验证规则,可以在控制器设置错误信息

protected $message = [
        'name.require'    =>    '用户名不得为空',
        'name.max'        =>    '姓名不得大于10位'
    ];

在属性定义错误信息

protected $rule = [
     'name|姓名'   =>   'max:10',
];

场景验证

User.php中添加

protected $scene = [
        'insert'      =>      ['name','price'],
        'edit'        =>      ['name'],
    ];//edit就只会对name进行验证

再加上一个scene

$validate = new \app\index\validate\User();

          if (!$validate->scene('edit')->batch()->check($data));
              dump($validate->getError());

路由验证

还是有两种方法

一种还是在User.php中写规则,在路由中绑定

\think\facade\Route::get('read/:id','Verify/read')->validate(\app\index\validate\User::class);


//还可以在后面加上场景验证
\think\facade\Route::get('read/:id','Verify/read')
    ->validate(\app\index\validate\User::class,'edit');

还有一种就是用独立验证的方式,直接在路由中写

\think\facade\Route::get('read/:id','Verify/read')
    ->validate([
        'id'    =>   'nmuber|between:1,10',
        'email' =>   'email'
        ],'edit',[
        'id.number'   =>   '必须为数字',
        'id.between'  =>   '必须在1-10之间',
        'email'       =>   '格式不对'
    ]
    ],true);

//总共四个参数
//第一个参数是验证规则
//第二个参数是指定什么
//第三个参数是设置错误信息
//第四个参数位true则可以批量显示错误

验证静态调用

使用facade模式进行调用验证

引入facade中的Validate时,回合think\Validate冲突,所以引入一个就行了

//验证邮箱是否合法
dump(Validate::isEmaile('....'));
//验证是否为空
dump(Validate::isRequre(''));
//验证是否为数字
dump(Validate::isNumber('1'));

验证结果只会返回True或者False

支持多规则验证

chekRule()

dump(Validate::checkRule(10,'number|between:1,10'));

表单令牌

随机🐎,保障安全

参考https://www.bilibili.com/video/BV17J411K7Zd?p=60&spm_id_from=pageDriver

Session

Session.php

return [
    'id'             => '',
    // SESSION_ID的提交变量,解决flash上传跨域
    'var_session_id' => '',
    // SESSION 前缀
    'prefix'         => 'think',
    // 驱动方式 支持redis memcache memcached
    'type'           => '',
    // 是否自动开启 SESSION
    'auto_start'     => true,
];

在这里声明会将Session.php中的内容覆盖

public function sess()
{
      Session::init([
            'prefix'         => 'think',
            'auto_start'     => true,
]);
}

使用set()get()来设置Session的存取

Session::set('user','Tom');
echo Session::get('user');
dump(Request::session);
echo $_SESSION['think']['user'];
dump($_SESSION);

has()

判断当前作用域session是否赋值,第二个参数可以指定作用域

Session::has('user','tp');
//赋值成功返回1 or true 

delete()

删除,默认删除当前作用域的值,第二个参数可以指定作用域

Session::delete('user','tp');

作用完之后空壳还存在

在这里插入图片描述

clear()

清理掉当前的作用域,清理完之后就没有了

Session::clear('user','tp');

prefix()

指定作用域

Session::prefix('tp');
Session::set('user','Tom');

pull()

取出当前的值,并删除掉这个session

即先进行get,在进行delete

echo Session::pull(user);

flash()

设置闪存数据,只请求一次有效,在请求就会失效

Session::flash('user','Tom')

flush()

清理掉闪存的数据

Cookie::set('user','Tom',[
    'prefix'    =>   'tp_'
    'expire'    =>   '3600'
]);

forever()

保存十年

Cookie::forever('user','Tom');

has()

判断是否赋值,第二个参数可以设置前缀

Cookie::has('user','tp_');
//赋值成功返回1 or true 

delete()

删除,第二个参数可以设置前缀

Cookie::delete('user','tp');

clear()

清空Cookie,必须指定前缀

Session::clear('user','tp');

分页功能

上传功能

要实现上传,必须要上传表单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="http://localhost/tp5.1/public/index.php/index/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="lala">
    <input type="submit" id="button" value="确定">
</form>

</body>
</html>

单一文件

用以下方式接收并使用move()保存到uploads文件夹中并且进行一些判断

  public function index()
    {
        $file = Request::file('lala');
        $info = $file->move('../application/index/uploads');
        if($info){
            echo $info->getExtension();//获取后缀名
            echo '<br/>';
            echo $info->getSaveName();//获取文件名
        } else {
            echo $file->getError();
        }        
    }

多个文件

表单

<form action="http://localhost/tp5.1/public/index.php/index/upload/uploads" method="post" enctype="multipart/form-data">
    <input type="file" name="image[]">
    <input type="file" name="image[]">
    <input type="file" name="image[]">
    <input type="submit" id="button" value="确定">
</form>

接收

利用foreach循环

public function uploads()
    {
        $files = Request::file('image');
        foreach ($files as $file){
            $info = $file->move('../application/index/uploads');
            if($info){
                echo $info->getExtension();//获取后缀名
                echo '<br/>';
                echo $info->getSaveName();//获取文件名
             } else {
                echo $file->getError();
             }
        }   
    }

上传的文件,可通过validate()方法进行验证

$info = $file->validate([
    'size'  =>   102400,
    'ext'   =>   'jpg,png,gif'
])->move('../application/index/uploads');

生成的规则还支持另外两种方式,md5sha1,或者自己写函数

$file->rule('md5')->move('../application/index/uploads');
$file->rule('sha1')->move('../application/index/uploads');
$file->rule('rand')->move('../application/index/uploads');

缓存功能

验证码功能

命令行安装验证码功能

composer require topthink/think-captcha=2.0.*

成功后会生成

在这里插入图片描述

在模版内添加验证码的显示代码

<div>{:captcha_img()}</div>

或者

<div><img src="{:captcha_src()}" alt="captcha" /></div>

上面两种的最终效果是一样的。

最终表单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>验证码验证</title>
</head>
<body>

<div>{:captcha_img()}</div>
<form action="../../../../public/index.php/index/code" method="post">
    <input type="text" name="code">
    <input type="submit" value="提交">
</form>


</body>
</html>

制作验证码登录

第一种:

public function index()
    {
        $data = [
            'code' => Request::post('code'),
        ];

        $flag = $this->validate($data,[
            'code|验证码' => 'require|captcha'
        ]);

        dump($flag);
    }

第二种:

public function show()
    {
        $captcha = new Captcha();
        return $captcha->entry();
    }

    public function check()
    {
        $captcha = new Captcha();
        dump($captcha->check(Request::post('code')));
    }
<form action="../../../../public/index.php/index/code/check" method="post">

设置验证码的各种属性

$config = [
      //字体大小
      'fontSize'  =>  30,
      //验证码位数
      'length'    =>  3
];
$captcha = new Captcha($config);

图像处理功能

命令行引入

composer require topthink/think-image

数据库与模型事件

模型事件

事件 描述 快捷方法
before_insert 新增前 beforeInsert
after_insert 新增后 afterInsert
before_update 更新前 beforeUpdate
after_update 更新后 afterUpdate
before_write 写入前 beforeWrite
after_write 写入后 afterWrite
before_delete 删除前 beforeDelete
after_delete 删除后 afterDelete
before_restore 恢复前(V5.1.13+ beforeRestore
after_restore 恢复后(V5.1.13+ afterRestore

使用方法

<?php

namespace app\index\model;

use think\Model;

class User extends Model
{
    public static function init()
    {
        self::event('before_insert', function ($user) {
            if (1 != $user->status) {
                return false;
            }
        });
    }
}

关联模型

User模型端,需要关联Profile

class User extends Model
{
    public function profile()
    {
       //hasOne表示一对一关联,参数一表示附表,参数二表示外键
       return $this->hasOne('profile','user_id');
    }
}
$user = UserModel::get(2);
return $user->profile;

小制作

后台登陆验证制作

app/admin/view/Login/login.html

登陆页面

<!Doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>后台登录</title>
    <link href="../../../../../tp5.1/public/static/css/ye.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="admin_login_wrap">
    <h1>后台管理</h1>
    <div class="admin_login_border">
        <div class="admin_input">
            <form action="" method="post">
                <ul class="admin_items">
                    <li>
                        <label for="user">用户名:</label>
                        <input type="text" name="username" value="" id="user" size="15" class="admin_input_style" />
                    </li>
                    <li>
                        <label for="pwd">密码:</label>
                        <input type="password" name="password" value="" id="pwd" size="15" class="admin_input_style" />
                    </li>
                    <li>
                        <div>{:captcha_img()}</div>
                        <input type="text" name="code">
                    </li>
                    <li>
                        <input type="submit" tabindex="3" value="提交" class="btn btn-primary" />
                    </li>
                </ul>
            </form>
        </div>
    </div>
</div>
</body>
</html>

app/admin/model/Login.php

验证

<?php
namespace app\admin\model;
use think\captcha\Captcha;
use think\Controller;
//use think\Model;
use think\facade\Request;

class Login extends Controller
{
    public function login($username,$password){

        $captcha = new Captcha();
        if($captcha->check(Request::post('code'))==true){
            $admin= \think\Db::name('admin')->where('username','=',$username)->find();
            if($admin){
                if($admin['password']==$password){
                    \think\facade\Session::set('id',$admin['id']);
                    \think\facade\Session::set('username',$admin['username']);
                    return 1;
                }else{
                    return 2;
                }

            }else{
                return 3;
            }
        }
        else {
            return 4;
        }
    }
}

app/admin/controller/Login.php

跳转

<?php
namespace app\admin\controller;
use think\Controller;
use app\admin\model\Login as Log;
class Login extends Controller
{
    public function index()
    {
        if(request()->isPost()){
            $login=new Log;
            $status=$login->login(input('username'),input('password'));
            if($status==1){
                return $this->success('登录成功,正在跳转!','Index/index');
            }elseif($status==2){
                return $this->error('密码错误!');
            }elseif($status==3){
                return $this->error('用户不存在!');
            }
            else{
                return $this->error('验证码错误!');
            }
        }
        return $this->fetch('login');
    }

    public function logout(){
        session(null);
        return $this->success('退出成功!',url('index'));
    }


}

app/config/captcha.php

验证码属性设置

<?php
return [
    'imageH'   =>  40,
    'imageW'   =>  150,
    'fontSize' =>  15
];

头像上传

app/public/test/test.html

上传表单(由于本人前端功底实在不佳,只能先写成这样了)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="http://localhost/tp5.1/public/index.php/index/upload" method="post" enctype="multipart/form-data">
    <table>
        <tr>
            <td height="124">当前头像:</td>
            <td>

                <img  width="111" height="120" src="../../../tp5.1/public/static/css/R.png"/>
            </td>
        </tr>
        <tr>
            <td height="21">上传新头像:</td>
            <td><input type="file" name="lala"/>
                <input type="submit" value="上传"/></td>
        </tr>
        <tr>
            <td colspan="2">支持jpg.gif格式的,100k以内</td>
        </tr>
    </table></form>


</body>
</html>

app/index/controller/Upload.php

<?php

namespace app\index\controller;

use think\facade\Request;

class Upload
{
    public function index()
    {
        $file = Request::file('lala');
        $info = $file->validate([
            'size'  =>   102400,
            'ext'   =>   'jpg,gif'
        ])->move('../application/index/uploads');
        if($info){
            echo $info->getExtension();//获取后缀名
            echo '<br/>';
            echo $info->getSaveName();//获取文件名
        } else {
            echo $file->getError();
        }

        dump($info);

    }
}

评论功能

直接用的畅言

posted @ 2022-07-06 14:14  phant0m1  阅读(100)  评论(0编辑  收藏  举报