#原创# CMSTOP系统快速入门

# CMSTOP #
熟悉CMSTOP系统,首先别急着阅读源码,毕竟作为一款商业的CMS,直接阅读源码反而不能快速的使用起来!从后台的功能使用上去熟悉是比较容易理解整个应用的构建思想的。
后台也是基于MVC的路径的,可以快速的找到对应的控制器,但CMS前台的则是生成的静态页面,路径根据路径的设置(在后台新建栏目、页面时指定)而生成的一系列静态文件,所以直接通过前台的路径去找源码是相对其他MVC系统而言的一大区别。

1、资源下载
源码:https://coding.net/u/webjust/p/cms_top/git
> 核心文件经过了Zend加密,可以通过解密网站进行解密:http://dezend.qiling.org/free/

2、环境搭建
下载PHPSTUDY2016 http://www.php.cn/xiazai/gongju

2.1、服务器端包含(ssi)
Apache下开启SSI配置使html支持include包含的方法

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
<VirtualHost *:80>
    DocumentRoot "D:\phpStudy\WWW\cmstop.info"
    ServerName cmstop.info
    ServerAlias cmstop.info
  <Directory "D:\phpStudy\WWW\cmstop.info">
    Options Indexes FollowSymLinks Includes
    AddType text/html .shtml
    AddOutputFilter INCLUDES .shtml
    AllowOverride None
    Order allow,deny
    Allow from all
  </Directory>
</VirtualHost>

2.2、magic_quotes_gpc函数关闭:
在php.ini文件内找到
magic_quotes_gpc = On
将其改为
magic_quotes_gpc = Off

2.3、支持index.shtml索引页

Select Code
1
2
3
<IfModule dir_module>
    DirectoryIndex index.html index.shtml index.php index.htm l.php
</IfModule>

2.4 win7x64+PHPStudy2018安装redis扩展
https://blog.csdn.net/leejianjun/article/details/79555026
https://windows.php.net/downloads/pecl/releases/redis/3.0.0/php_redis-3.0.0-7.0-nts-vc14-x86.zip
https://windows.php.net/downloads/pecl/releases/igbinary/2.0.5/php_igbinary-2.0.5-7.0-nts-vc14-x86.zip

3、后台操作流程解读
3.1 新增栏目:

以栏目为例,最终会在数据库存储栏目对应的模板文件、URL路径(理解这部分是理解前台的生成页面的URL的关键所在),大部分CMS属于是静态的页面,所以前台会生成静态文件。

这里,我们还要理解CMSTOP一个比较关键的概念「区块」。下面是一个视图文件的源码;

Select Code
1
<!--{template 'system/header.html'}-->

这是引入公共的模板文件

Select Code
1
<!--#include virtual="{ROOT}section/30.html"-->

这是引入区块。可以认为CMSTOP的每一个前台的页面,都是可以由很多个自定义的区块组合而成一个页面,这样维护人员就可以很容易的在页面上添加一个元素,非常灵活,算是其很大的一个特色了。

3.2 区块
以首页为例:

区块中,你可以定义HTML,也可以根据模板引擎的语法自定义动态的输出等内容;

首页模板:

原先的模板如上,替换掉区块以后的代码就是这样的:

你可能会问:怎么不直接定义在模板文件中呢?区块你可以理解为公共部分的提取,我可能会很灵活的用在多个页面,而管理「区块」的任务也不需要由「程序员」来完成,内容管理员就可以维护区块了。是不是很方便处理像CMS页面上的广告位(类似的这种功能)?

最终存储在数据库 `cmstop_section` 的「区块」,都对应1个ID。

生成的区块的静态文件,都存放在 /section 根目录下,而不需要从数据库读取,至于如何生成这些静态文件,则可以进一步的去理解系统里面是如何生成的,要找到这个方法也是顺其自然的。

如果需要了解进一步生成区块静态文件的方法,就可以根据这个方法找到对应的后台控制器方法

以此类推,可以找到生成栏目页、新闻内容页、自定义的页面:

总之,到这里为止,我们应该充分的理解CMSTOP的前台页面的URL是根据后台设置的规则生成的纯静态文件。

4、其他功能

当然作为一个强大的内容管理系统,内容是核心,而其他的组件都是为内容的维护服务的,可以多在后台使用其他的功能,结合对应的表结构来理解,就可以很容易掌握,从而根据需求来进行一些二次开发的任务。官网也有详细的手册:http://www.cmstop.com/help/

结尾:
至于MVC里面的模板,控制器,模型,可以参考二次开发手册,也可以根据系统已经生产的一套页面的源码,去直接借用即可,这里不做过多的阐述:http://doc.cmstop.com/develop/

整理ThinkPHP5笔记

# 整理TP5笔记 #
## 安装
下载:
https://github.com/top-think/think

Windows安装Composer:
https://getcomposer.org/download/

Composer中国全量镜像安装方法,及检测方法

手册:
https://www.kancloud.cn/manual/thinkphp5_1/353946

## 目录结构

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
www  WEB部署目录(或者子目录)
├─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                 命令行入口文件

## 配置
.env
Env::get(”)

应用配置目录 config
模块配置目录 application/module/config

打开调试模式:
‘app_debug’ => true,

读取配置:
use think\facade\Config;
Config::get()

助手函数:config()

数据库配置
D:\wamp\www\tp5.info\config\database.php

## 入口文件
默认的应用入口文件位于public/index.php

Select Code
1
2
3
4
5
6
7
8
9
namespace think;

// 加载基础文件
require __DIR__ . '/../thinkphp/base.php';
// 执行应用并响应
Container::get('app')->run()->send();

// 绑定指定的模块
Container::get('app')->bind('index')->run()->send();    // 绑定当前访问模块

## URL
没有定义路由的情况下典型的URL访问规则是:

Select Code
1
http://serverName/index.php(或者其它应用入口文件)/模块/控制器/操作/[参数名/参数值...]

默认采用PATH_INFO访问地址

根据路由信息生成URL:

Select Code
1
2
3
4
5
6
7
8
9
// 使用\think\facade\Url::build()
echo Url::build('index/blog/read', ['id' => 5]);    //http://tp5.info/blog/5.html
echo '<br>';
echo Url::build('index/blog/read', ['name' => 'admin']);    ///blog/read/name/admin.html
echo '<br>';
echo Url::build('index/blog/read', ['name' => 'admin'], 'shtml', true); //http://tp5.info/blog/read/name/admin.shtml
echo '<br>';
// 助手函数url()
echo url('index/blog/read');    ///blog/read.html

## 路由
D:\wamp\www\tp5.info\route\route.php

1、回调函数
2、字符串:控制器/方法

最基础的路由定义方法是:

Select Code
1
2
3
4
Route::rule('路由表达式','路由地址','请求类型');
Route::rule('new/:id','index/News/read');
Route::rule('new/:id','News/update','POST');
Route::rule('new/:id','News/read','GET|POST');

快捷注册方法的用法为:
Route::快捷方法名(‘路由表达式’,’路由地址’);

Select Code
1
2
3
4
5
Route::get('new/:id','News/read'); // 定义GET请求路由规则
Route::post('new/:id','News/update'); // 定义POST请求路由规则
Route::put('new/:id','News/update'); // 定义PUT请求路由规则
Route::delete('new/:id','News/delete'); // 定义DELETE请求路由规则
Route::any('new/:id','News/read'); // 所有请求都支持的路由规则

规则表达式:
每个参数中以:开头的参数都表示动态变量,并且会自动绑定到操作方法的对应参数
变量用[ ]包含起来后就表示该变量是路由匹配的可选变量
如果希望URL进行完全匹配,可以在路由表达式最后使用$符号

路由标识:
如果你需要快速的根据路由生成URL地址,可以在定义路由的时候指定生成标识。

Select Code
1
2
3
4
// 注册路由到index模块的News控制器的read操作
Route::rule('new/:id','index/News/read')->name('new_read');
// 生成路由地址的时候就可以使用
url('new_read',['id'=>10]);

定义路由:
1、路由到模块/控制器/操作
Route::get(‘blog/:id’,’index/group.blog/read’);
2、路由到操作方法:@[模块/控制器/]操作
Route::get(‘blog/:id’,’@index/blog/read’);
3、路由到重定向地址
Route::get(‘blog/:id’,’/blog/read/id/:id’);
4、闭包定义

Select Code
1
2
3
Route::get('hello', function () {
    return 'hello,world!';
});

5、路由分组
6、RESFUL资源路由
Route::resource(‘blog’,’index/blog’);

## MVC模式
https://www.kancloud.cn/manual/thinkphp5_1/353953
ThinkPHP支持传统的MVC(Model-View-Controller)模式以及流行的MVVM(Model-View-ViewModel)模式的应用开发,但无论采用何种模式,URL的规范仍然是统一的。

– 路由:路由是用于规划(一般同时也会进行简化)请求的访问地址,在访问地址和实际操作方法之间建立一个路由规则 => 路由地址的映射关系。
– 模块:一个典型的应用是由多个模块组成的,这些模块通常都是应用目录下面的一个子目录,每个模块都有自己独立的配置文件、公共文件和类库文件。
– 控制器:一个模块下面有多个控制器负责响应请求,而每个控制器其实就是一个独立的控制器类。控制器主要负责请求的接收,并调用相关的模型处理,并最终通过视图输出。严格来说,控制器不应该过多的介入业务逻辑处理。事实上,控制器是可以被跳过的,通过路由我们可以直接把请求调度到某个模型或者其他的类进行处理。
– 模型:模型类通常完成实际的业务逻辑和数据封装,并返回和格式无关的数据。ThinkPHP的模型层支持多层设计,你可以对模型层进行更细化的设计和分工,例如把模型层分为逻辑层/服务层/事件层等等。
– 视图:控制器调用模型类后,返回的数据通过视图组装成不同格式的输出。视图根据不同的需求,来决定调用模板引擎进行内容解析后输出还是直接输出。视图通常会有一系列的模板文件对应不同的控制器和操作方法,并且支持动态设置模板目录。
– 中间件:中间件主要用于HTTP请求的拦截处理

## 自定义函数
D:\wamp\www\tp5.info\application\common.php

## 控制器
控制器文件通常放在application/module/controller下面,类名和文件名保持大小写一致,并采用驼峰命名(首字母大写)。

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
<?php
namespace app\index\controller;

use think\Controller;

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

渲染输出:

Select Code
1
2
3
4
5
6
7
8
// 默认输出类型设置为JSON 'default_return_type'    => 'json',
return ['name' => 'thinkphp', 'time' => date('Y-m-d H:i:s')]; //输出JSON
// 输出字符串
return 'hello world';
// 输出json
return json(['name' => 'thinkphp', 'time' => date('Y-m-d H:i:s')]);
// 渲染模板输出
return view();  // 指向模板\index\view\index\hello.html

内置了两个跳转方法success和error,用于页面跳转提示。

控制器中间件

## 请求
当前的请求对象由think\Request类负责,在很多场合下并不需要实例化调用,通常使用依赖注入即可。在其它场合(例如模板输出等)则可以使用think\facade\Request静态类操作。

– 构造器注入
– 操作方法依赖注入
– 通过Facade机制来静态调用请求对象的方法
– request助手函数,可以在任何需要的时候直接调用当前请求对象

请求信息:

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
dump($request->host());
dump($request->port());
dump($request->url());
dump($request->pathinfo());
dump($request->param());
dump($request->type());
dump($request->method());
echo '<hr>';
dump(\think\facade\Request::url());
dump(\think\facade\Request::pathinfo());
dump(\think\facade\Request::method());
dump(\think\facade\Request::param());
echo '<hr>';
halt($request);

变量信息:

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dump(\think\facade\Request::has('id'));
dump(\think\facade\Request::param('id'));
// 依赖注入
dump($request->id);
dump($request->param('id'));
dump($request->param('name', 'admin'));
dump($request->param('name', ''));
dump($request->param('name', '', 'strip_tags'));
dump($request->param());
// 助手函数
dump(input());
dump(input('?get.id'));
dump(input('param.id'));
dump(input('param.'));
dump(input('id'));

## 响应
返回字符串:
最简单的响应输出是直接在路由闭包或者控制器操作方法中返回一个字符串

返回JSON:
修改默认输出文件类型;
快捷方法:json()

返回XML:
xml()

渲染模板:
view()

页面重定向
redirect()

附件下载
download()

重定向传参,传入session:
return redirect(‘hello’)->with(‘name’,’thinkphp’);

## 视图
模板渲染:
//fetch方法
fetch(‘[模板文件]'[,’模板变量(数组)’])

//助手函数view
view(‘[模板文件]'[,’模板变量(数组)’])

//直接解析内容而不通过模板文件display
return $this->display($content, [‘name’ => ‘thinkphp’, ’email’ => ‘thinkphp@qq.com’]);

模板赋值:
//assign方法
//模板渲染时,传入数组
//公共模板变量赋值share

## 模板引擎
变量输出:
//字符串
{$name}
//数组
{$data.name} {$data[‘name’]}
//默认值
{$user.nickname|default=’这个家伙很懒’}
//系统变量输出
{$Think.server.script_name}
//请求变量
{$Request.param.id}

使用函数:
{$Request.param.id|md5}
{:Date(‘Y-m-d H:i:s’)}

运算符:
+ – * /
{$status? ‘正常’ : ‘错误’} //三元运算

原样输出:
{literal}{/literal}

模板注释:
{/* 注释内容 */ } 或 {// 注释内容 }

模板布局:
开启layout_on
//布局文件模板

Select Code
1
2
3
{include file="public/header" /}
{__CONTENT__}
{include file="public/footer" /}

//不开启设置文件模板
{layout name=”layout” /}

模板继承:
模板可以定义一个基础模板(或者是布局),并且其中定义相关的区块(block),然后继承(extend)该基础模板的子模板中就可以对基础模板中定义的区块进行重载。

//定义一个基础模板

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>{block name="title"}标题{/block}</title>
</head>
<body>
{block name="menu"}菜单{/block}
{block name="left"}左边分栏{/block}
{block name="main"}主内容{/block}
{block name="right"}右边分栏{/block}
{block name="footer"}底部{/block}
</body>
</html>

//继承模板
{extend name=”Public:base” /}

//包含文件
{include file=’模版文件1,模版文件2,…’ /}

//传入参数
{include file=”Public/header” title=”$title” keywords=”开源WEB开发框架” /}

内置标签:
– 循环 foreach, for, volist
– 比较
– 条件判断 switch, if, in/notin/between/notbetween, empty…
– 資源文件加載 load
– 原生PHP {php}…{/php}

如:

Select Code
1
2
3
{for start="0" end="10" step="2"}
    {$i},
{/for}

## 调试
– 开启调试模式 ‘app_debug’ => true,
– APP_DEBUG = true
– 开启Trace调试 ‘app_trace’ => true,
– SQL:getLastSql()
– 查看变量 halt(), dump()

## 数据库连接
数据库配置文件 config\database.php

一、查找数据
//think\Db类查找

Select Code
1
2
3
4
5
6
7
8
9
10
// table不能省略表前缀
/*$user = Db::table('tp_user')->find();   //SELECT * FROM `tp_user` LIMIT 1
$user = Db::table('tp_user')->select(); //SELECT * FROM `tp_user`
$user = Db::table('tp_user')->where('id', 1)->find();   //查找不到则返回null
try {
$user = Db::table('tp_user')->where('id', 1)->findOrFail(); //查找不到则抛出异常
//SELECT * FROM `tp_user` WHERE `id` = 1 LIMIT 1
} catch (DataNotFoundException $exception) {
echo $exception->getMessage();
}

// name可以省略表前缀

Select Code
1
2
3
4
5
6
7
8
9
10
11
$user = Db::name('user')->where(['status' => 1])->find();   //SELECT * FROM `tp_user` WHERE `status` = 1 LIMIT 1
//查找某个字段的值
$user = Db::name('user')->where(['id' => 2])->value('name');    //SELECT `name` FROM `tp_user` WHERE `id` = 2
$user = Db::name('user')->where('status', 1)->column('name');   //SELECT `name` FROM `tp_user` WHERE `status` = 1*/
$user = Db::name('user')->where('status', 1)->column('*', 'name');   //指定name字段的值作为索引 返回所有数据
// 分批量处理,chunk方法一般用于命令行操作批处理数据库的数据
Db::name('user')->where('status', 1)->chunk(5, function ($users) {
	foreach ($users as $user) {
		...
	}
});

//db()辅助方法查找

Select Code
1
//$user = db('user')->find(); //SELECT * FROM `tp_user` LIMIT 1

二、新增数据、批量添加数据:

Select Code
1
2
3
4
5
6
7
8
9
$data = ['name' => 'La', 'age' => mt_rand(10, 50)];
$res = Db::name('user')->insert($data); //INSERT INTO `tp_user` (`name` , `age`) VALUES ('La' , 19)
$res = Db::name('user')->insertGetId($data);    //添加数据后如果需要返回新增数据的自增主键
$data = [
    ['name' => 'La', 'age' => mt_rand(10, 50)],
    ['name' => 'Kobe', 'age' => mt_rand(10, 50)],
    ['name' => 'ONil', 'age' => mt_rand(10, 50)],
];
$res = Db::name('user')->insertAll($data);  //INSERT INTO `tp_user` (`name` , `age`) VALUES ( 'La',14 ) , ( 'Kobe',35 ) , ( 'ONil',16 )

三、更新数据

Select Code
1
2
3
4
5
6
7
8
9
10
dump(Db::name('user')->where('id', 17)->update(['name' => 'think_2018']));
//UPDATE `tp_user` SET `name` = 'think_2018' WHERE `id` = 17
dump(Db::name('user')->update(['name' => 'think_2017', 'id' => 16]));   //和上面等同
//UPDATE `tp_user` SET `name` = 'think_2017' WHERE `id` = 16
dump(Db::name('user')->where('id', 17)->setField('name', 'think_php')); //修改某个字段
//UPDATE `tp_user` SET `name` = 'think_php' WHERE `id` = 17
dump(Db::name('user')->where('id', 17)->setInc('age'));
//UPDATE `tp_user` SET `age` = `age` + 1 WHERE `id` = 17
dump(Db::name('user')->where('id', 16)->setDec('age'));
//UPDATE `tp_user` SET `age` = `age` - 1 WHERE `id` = 16

四、删除数据

Select Code
1
2
3
4
5
6
7
8
9
10
//根据主键删除
dump(Db::name('user')->delete(17));
//DELETE FROM `tp_user` WHERE `id` = 17
dump(Db::name('user')->delete([15, 16]));
//DELETE FROM `tp_user` WHERE `id` IN (15,16)
//条件删除
dump(Db::name('user')->where('id', 14)->delete());
//DELETE FROM `tp_user` WHERE `id` = 14
dump(Db::name('user')->where('id', '>', 13)->delete());
//DELETE FROM `tp_user` WHERE `id` > 13

五、链式操作

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$res = Db::name('user')
    ->where('status', 1)
    ->order('create_time')
    ->limit(5)
    ->select();
//SELECT * FROM `tp_user` WHERE `status` = 1 ORDER BY `create_time` LIMIT 5

$res = Db::name('user')
    ->page(2, 5)
    ->select();
//SELECT * FROM `tp_user` LIMIT 5,5

$res = Db::table('tp_user')
    ->field('id, name, age')
    ->group('age')
    ->having('id>10')
    ->fetchSql(true)
    ->select();
//SELECT `id`,`name`,`age` FROM `tp_user` GROUP BY `age` HAVING id>10

// alias, field, join, union, distinct, lock, cache, comment, fetchSql, partition

六、链式查询

Select Code
1
2
3
4
5
6
7
8
9
10
$res = Db::name('user')->fetchSql(true)->count();
//SELECT COUNT(*) AS tp_count FROM `tp_user` LIMIT 1
$res = Db::name('user')->fetchSql(true)->count('id');
//SELECT COUNT(`id`) AS tp_count FROM `tp_user` LIMIT 1
$res = Db::name('user')->fetchSql(true)->max('age');
//SELECT MAX(`age`) AS tp_max FROM `tp_user` LIMIT 1
$res = Db::name('user')->fetchSql(true)->avg('age');
//SELECT AVG(`age`) AS tp_avg FROM `tp_user` LIMIT 1
$res = Db::name('user')->fetchSql(true)->sum('age');
//SELECT SUM(`age`) AS tp_sum FROM `tp_user` LIMIT 1

## 模型
定义一个模型

Select Code
1
2
3
4
5
6
7
8
9
10
<?php

namespace app\common\model;

use think\Model;

class User extends Model
{

}

模型设置:
默认主键为id;//protected $pk = ‘id’;

一、新增数据
新增数据的最佳实践原则:使用create方法新增数据,使用saveAll批量新增数据。

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$User = new User();
// 1. 实例化对象,赋值并保存
$User->name = 'LuLu';
$User->age = mt_rand(1, 99);
//INSERT INTO `tp_user` (`name` , `age`) VALUES ('LuLu' , 68)

// 2. 直接传入数据到save方法批量赋值
dump($User->save(['name' => 'Mai', 'age' => mt_rand(10, 30)])); 
//INSERT INTO `tp_user` (`name` , `age`) VALUES ('Mai' , 17)

// 3. 直接在实例化的时候传入数据
dump((new User(['name' => 'Yao', 'age' => mt_rand(20, 30)]))->save());  
// INSERT INTO `tp_user` (`name` , `age`) VALUES ('Yao' , 23)

// 新增多条数据,saveAll方法新增数据返回的是包含新增模型(带自增ID)的数据集对象。
dump($User->saveAll([
    ['name' => 'Tom', 'age' => mt_rand(1, 5)],
    ['name' => 'Jack', 'age' => mt_rand(1, 8)],
]));
//[ SQL ] INSERT INTO `tp_user` (`name` , `age`) VALUES ('Tom' , 3)
//[ SQL ] INSERT INTO `tp_user` (`name` , `age`) VALUES ('Jack' , 3)

// create方法:创建并写入,返回当前模型的对象实例
$res = User::create(['name' => 'Bob', 'age' => mt_rand(1, 5)]);
// INSERT INTO `tp_user` (`name` , `age`) VALUES ('Bob' , 5)

二、更新数据
更新的最佳实践原则是:如果需要使用模型事件,那么就先查询后更新,如果不需要使用事件,直接使用静态的Update方法进行条件更新,如非必要,尽量不要使用批量更新。

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//查找并更新
$user = User::get(2);
$user->name = '3bangz';
dump($user->save());
//UPDATE `tp_user` SET `name` = '3bangz' WHERE `id` = 2

//直接更新数据
$user = new User;
dump($user->save(['name' => 'update'], ['id' => 2]));
//UPDATE `tp_user` SET `name` = 'update' WHERE `id` = 2

//静态方法更新数据
User::where('id', 2)->update(['name' => 'after update']);
//UPDATE `tp_user` SET `name` = 'after update' WHERE `id` = 2

三、查找
模型查询的最佳实践原则是:在模型外部使用静态方法进行查询,内部使用动态方法查询,包括使用数据库的查询构造器。模型的查询始终返回对象实例,但可以和数组一样使用。

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//查询构造器查找并更新
$user = User::where('age', '>', 50)->find();    //SELECT * FROM `tp_user` WHERE `age` > 50 LIMIT 1
if ($user) {
    $user->age = $user->age - 1;
    dump($user->save());
    // UPDATE `tp_user` SET `age` = 57 WHERE `id` = 8
}
dump(User::where('id', 1)->find()); //返回值为null
try{
    dump(User::where('id', 1)->findOrFail());
} catch (ModelNotFoundException $exception) {
    echo $exception->getMessage();
}
//查找不到时抛出异常信息 model data Not Found:app\common\model\User
// SELECT * FROM `tp_user` WHERE `id` = 1 LIMIT 1

//根据主键获取多条信息
$users = User::all('1,2,3');    //SELECT * FROM `tp_user` WHERE `id` IN (1,2,3)
$users = User::all([1,2,3]);    //SELECT * FROM `tp_user` WHERE `id` IN (1,2,3)
dump($users);
//查询构造器,查询
$users = User::where('age', '>', 60)->select(); //SELECT * FROM `tp_user` WHERE `age` > 60
dump($users);

四、删除
删除的最佳实践原则是:如果删除当前模型数据,用delete方法,如果需要直接删除数据,使用destroy静态方法。

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//删除当前模型
/*$user = User::get(3);
dump($user->delete());*/
//SELECT * FROM `tp_user` WHERE `id` = 3 LIMIT 1
//DELETE FROM `tp_user` WHERE `id` = 3

//静态方法,根据主键删除
dump(User::destroy('5,6,7'));
//SELECT * FROM `tp_user` WHERE `id` IN (2,3,4)
//DELETE FROM `tp_user` WHERE `id` = 4

//闭包函数删除
User::destroy(function ($query) {
	$query->where('id', '<', 10);
});
//SELECT * FROM `tp_user` WHERE `id` < 10

dump(User::where('id', '<', 10)->delete()); //DELETE FROM `tp_user` WHERE `id` < 10

复习ThinkPHP 3.2框架

该篇以ThinkPHP3.2入手,整理常用的ThinkPHP部分,如数据库操作!(推荐看官方手册)

## 第1章 课程简介 ##
本章简要介绍了本门课程的课程内容以及学习目标。
### 1-1 快速入门ThinkPHP框架课程简介
图01

推荐10款PHP框架
https://www.helloweba.net/news/557.html

课程主要内容:
– 理解MVC思想与框架思维
– ThinkPHP基础知识
– ThinkPHP数据库的操作
– 基于ThinkPHP的博客文章系统

图2

## 第2章 关于MVC ##
简要介绍MVC的工作原理。
### 2-1 MVC简析
MVC是一种设计模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器,它们各自处理自己的任务。

模型:处理数据和业务逻辑
视图:通过布局向用户展示数据
控制器:接收用户请求,并调用相应的模型处理

图3

图4

## 第3章 使用ThinkPHP框架建立项目 ##
本章通过介绍ThinkPHP框架的安装和引用,以及对项目目录结构的说明,让大家对ThinkPHP有一个充分的了解,并学会Hello World页面的实现。
### 3-1 框架简介
框架是程序结构代码的集合,而不是业务逻辑代码。集合中包含了许多类、函数和功能包。这个集合是按照一定标准组成的功能体系。体系有很多设计模式,比如MVC等。

### 3-2 ThinkPHP框架学习流程
1、建立一个简单项目,了解项目的运行流程

2、了解TP的URL模式,建立自定义函数库

3、模板技术,调试模式和运行状态

4、数据的常用操作

### 3-3 ThinkPHP框架简介
– 国产、开源、面向对象、MVC框架
– 简单易用,查询语言丰富,详尽的中文文档
– 官网:www.thinkphp.cn

### 3-4 关于单一入口
在一个网站中,所有的请求都是指向同一个脚本文件的。

好处:项目结构规范,控制灵活,更加安全

### 3-5 使用ThinkPHP创建一个项目

Select Code
1
2
3
4
5
// 定义应用目录
define('APP_PATH','./App/');

// 引入ThinkPHP入口文件
require './ThinkPHP/ThinkPHP.php';

### 3-6 ThinkPHP框架目录结构解析
http://document.thinkphp.cn/manual_3_2.html#directory_structure

其中框架目录ThinkPHP的结构如下:
├─ThinkPHP 框架系统目录(可以部署在非web目录下面)
│ ├─Common 核心公共函数目录
│ ├─Conf 核心配置目录
│ ├─Lang 核心语言包目录
│ ├─Library 框架类库目录
│ │ ├─Think 核心Think类库包目录
│ │ ├─Behavior 行为类库目录
│ │ ├─Org Org类库包目录
│ │ ├─Vendor 第三方类库目录
│ │ ├─ … 更多类库目录
│ ├─Mode 框架应用模式目录
│ ├─Tpl 系统模板目录
│ ├─LICENSE.txt 框架授权协议文件
│ ├─logo.png 框架LOGO文件
│ ├─README.txt 框架README文件
│ └─ThinkPHP.php 框架入口文件

## 第4章 ThinkPHP框架的简单操作 ##
本章主要讲解框架的运行原理、ThinkPHP的URL模式以及ThinkPHP的配置文件等内容,旨在让小伙伴们对ThinkPHP框架的基本操作有一个深入的了解和掌握。
### 4-1 ThinkPHP运行流程
http://document.thinkphp.cn/manual_3_2.html#system_process

ThinkPHP框架开发的应用的标准执行流程:

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
用户URL请求
调用应用入口文件(通常是网站的index.php)
载入框架入口文件(ThinkPHP.php)
记录初始运行时间和内存开销
系统常量判断及定义
载入框架引导类(Think\Think)并执行Think::start方法进行应用初始化
设置错误处理机制和自动加载机制
调用Think\Storage类进行存储初始化(由STORAGE_TYPE常量定义存储类型)
部署模式下如果存在应用编译缓存文件则直接加载(直接跳转到步骤22)
读取应用模式(由APP_MODE常量定义)的定义文件(以下以普通模式为例说明)
加载当前应用模式定义的核心文件(普通模式是 ThinkPHP/Mode/common.php)
加载惯例配置文件(普通模式是 ThinkPHP/Conf/convention.php)
加载应用配置文件(普通模式是 Application/Common/Conf/config.php)
加载系统别名定义
判断并读取应用别名定义文件(普通模式是 Application/Common/Conf/alias.php)
加载系统行为定义
判断并读取应用行为定义文件(普通模式是 Application/Common/Conf/tags.php)
加载框架底层语言包(普通模式是 ThinkPHP/Lang/zh-cn.php)
如果是部署模式则生成应用编译缓存文件
加载调试模式系统配置文件(ThinkPHP/Conf/debug.php)
判断并读取应用的调试配置文件(默认是 Application/Common/Conf/debug.php)
判断应用状态并读取状态配置文件(如果APP_STATUS常量定义不为空的话)
检测应用目录结构并自动生成(如果CHECK_APP_DIR配置开启并且RUNTIME_PATH目录不存在的情况下)
调用Think\App类的run方法启动应用
应用初始化(app_init)标签位侦听并执行绑定行为
判断并加载动态配置和函数文件
调用Think\Dispatcher::dispatch方法进行URL请求调度
自动识别兼容URL模式和命令行模式下面的$_SERVER['PATH_INFO']参数
检测域名部署以及完成模块和控制器的绑定操作(APP_SUB_DOMAIN_DEPLOY参数开启)
分析URL地址中的PATH_INFO信息
获取请求的模块信息
检测模块是否存在和允许访问
判断并加载模块配置文件、别名定义、行为定义及函数文件
判断并加载模块的动态配置和函数文件
模块的URL模式判断
模块的路由检测(URL_ROUTER_ON开启)
PATH_INFO处理(path_info)标签位侦听并执行绑定行为
URL后缀检测(URL_DENY_SUFFIX以及URL_HTML_SUFFIX处理)
获取当前控制器和操作,以及URL其他参数
URL请求调度完成(url_dispatch)标签位侦听并执行绑定行为
应用开始(app_begin)标签位侦听并执行绑定行为
调用SESSION_OPTIONS配置参数进行Session初始化(如果不是命令行模式)
根据请求执行控制器方法
如果控制器不存在则检测空控制器是否存在
控制器开始(action_begin)标签位侦听并执行绑定行为
默认调用系统的ReadHtmlCache行为读取静态缓存(HTML_CACHE_ON参数开启)
判断并调用控制器的_initialize初始化方法
判断操作方法是否存在,如果不存在则检测是否定义空操作方法
判断前置操作方法是否定义,有的话执行
Action参数绑定检测,自动匹配操作方法的参数
如果有模版渲染(调用控制器display方法)
视图开始(view_begin)标签位侦听并执行绑定行为
调用Think\View的fetch方法解析并获取模版内容
自动识别当前主题以及定位模版文件
视图解析(view_parse)标签位侦听并执行绑定行为
默认调用内置ParseTemplate行为解析模版(普通模式下面)
模版引擎解析模版内容后生成模版缓存
模版过滤替换(template_filter)标签位侦听并执行绑定行为
默认调用系统的ContentReplace行为进行模版替换
输出内容过滤(view_filter)标签位侦听并执行绑定行为
默认调用系统的WriteHtmlCache行为写入静态缓存(HTML_CACHE_ON参数开启)
调用Think\View类的render方法输出渲染内容
视图结束(view_end)标签位侦听并执行绑定行为
判断后置操作方法是否定义,有的话执行
控制器结束(action_end)标签位侦听并执行绑定行为
应用结束(app_end)标签位侦听并执行绑定行为
执行系统的ShowPageTrace行为(SHOW_PAGE_TRACE参数开启并且不是AJAX请求)
日志信息存储写入

### 4-2 ThinkPHP的配置文件
配置文件是自动加载的,加载的顺序是:
惯例配置->应用配置->模式配置->调试配置->状态配置->模块配置->扩展配置->动态配置

Select Code
1
2
3
4
5
6
7
8
惯例配置文件(位于ThinkPHP/Conf/convention.php)。
应用配置文件也就是调用所有模块之前都会首先加载的公共配置文件(默认位于Application/Common/Conf/config.php)。
为应用模式(后面会有描述)单独定义配置文件,文件命名规范是: Application/Common/Conf/config_应用模式名称.php(仅在运行该模式下面才会加载)
开启调试模式后,调试配置文件(位于ThinkPHP/Conf/debug.php)和应用调试配置文件(位于Application/Common/Conf/debug.php)
状态配置:你需要在公司和家里分别设置不同的数据库测试环境。那么可以这样处理,在公司环境中,我们在入口文件中定义:define('APP_STATUS','office');那么就会自动加载该状态对应的配置文件(位于Application/Common/Conf/office.php)。
模块配置:每个模块会自动加载自己的配置文件(位于Application/当前模块名/Conf/config.php)
扩展配置:'LOAD_EXT_CONFIG' => 'user,db' 
动态配置:C('参数名称','新的参数值'),动态配置赋值仅对当前请求有效,不会对以后的请求造成影响。

获取已经设置的参数值:C(‘参数名称’)
C方法也可以用于读取二维配置:C(‘USER_CONFIG.USER_TYPE’)

### 4-3 ThinkPHP的URL模式
URL参数中解析当前请求的模块、控制器和操作,这是3.2版本的标准URL格式。

http://serverName/index.php/模块/控制器/操作

ThinkPHP框架的URL是区分大小写(主要是针对模块、控制器和操作名,不包括应用参数)的。当URL_CASE_INSENSITIVE设置为true的时候表示URL地址不区分大小写,这个也是框架在部署模式下面的默认设置。

URL模式 URL_MODEL设置
– 普通模式 0
– PATHINFO模式 1
– REWRITE模式 2
– 兼容模式 3

  • 普通模式:http://localhost/?module=home&controller=user&action=login&var=value
  • PATHINFO模式下面的URL访问地址是: http://localhost/index.php/home/user/login/var/value/
  • REWRITE模式:http://localhost/home/user/login/var/value
  • 兼容模式:http://localhost/?s=/home/user/login/var/value

URL生成:U(‘地址表达式’,[‘参数’],[‘伪静态后缀’],[‘显示域名’])
echo U(‘Index/index’, ”, ‘html’, ‘localhost’); //http://localhost/index.php/Home/Index/index.html

### 4-4 隐藏index.php文件
http://document.thinkphp.cn/manual_3_2.html#url_rewrite

### 4-5 URL伪静态
‘URL_HTML_SUFFIX’ => ‘html’, // URL伪静态后缀设置

### 4-6 自定义函数库
\App\Common\Common\function.php

## 第5章 ThinkPHP框架的模板技术 ##
本章主要讲解了ThinkPHP框架的模板的使用以及模板引擎的选择。
### 5-1 建立项目模板
// 不带任何参数 自动定位当前操作的模板文件 $this->display();

创建首页文件路径:’./App/Home/View/Index/index.html’

### 5-2 模板的赋值和输出
$this->assign(‘name’,$value);
// 下面的写法是等效的
$this->name = $value;

采用内置的模板引擎,可以使用: {$name} [ {$email} {$phone} ] 输出同样的内容。

### 5-3 ThinkPHP模板引擎介绍
ThinkPHP内置了一个基于XML的性能卓越的模板引擎 ThinkTemplate,这是一个专门为ThinkPHP服务的内置模板引擎。

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'TMPL_ENGINE_TYPE'      =>  'Think',     // 默认模板引擎 以下设置仅对使用Think模板引擎有效
'TMPL_CACHFILE_SUFFIX'  =>  '.php',      // 默认模板缓存后缀
'TMPL_DENY_FUNC_LIST'   =>  'echo,exit',    // 模板引擎禁用函数
'TMPL_DENY_PHP'         =>  false, // 默认模板引擎是否禁用PHP原生代码
'TMPL_L_DELIM'          =>  '{',            // 模板引擎普通标签开始标记
'TMPL_R_DELIM'          =>  '}',            // 模板引擎普通标签结束标记
'TMPL_VAR_IDENTIFY'     =>  'array',     // 模板变量识别。留空自动判断,参数为'obj'则表示对象
'TMPL_STRIP_SPACE'      =>  true,       // 是否去除模板文件里面的html空格与换行
'TMPL_CACHE_ON'         =>  true,        // 是否开启模板编译缓存,设为false则每次都会重新编译
'TMPL_CACHE_PREFIX'     =>  '',         // 模板缓存前缀标识,可以动态改变
'TMPL_CACHE_TIME'       =>  0,         // 模板缓存有效期 0 为永久,(以数字为值,单位:秒)
'TMPL_LAYOUT_ITEM'      =>  '{__CONTENT__}', // 布局模板的内容替换标识
'LAYOUT_ON'             =>  false, // 是否启用布局
'LAYOUT_NAME'           =>  'layout', // 当前布局名称 默认为layout

// Think模板引擎标签库相关设定
'TAGLIB_BEGIN'          =>  '<',  // 标签库标签开始标记
'TAGLIB_END'            =>  '>',  // 标签库标签结束标记
'TAGLIB_LOAD'           =>  true, // 是否使用内置标签库之外的其它标签库,默认自动检测
'TAGLIB_BUILD_IN'       =>  'cx', // 内置标签库名称(标签使用不必指定标签库名称),以逗号分隔 注意解析顺序
'TAGLIB_PRE_LOAD'       =>  '',   // 需要额外加载的标签库(须指定标签库名称),多个以逗号分隔

### 5-4 ThinkPHP模板引擎之变量输出和运算
模板中使用:Hello,{$name}
默认值输出:{$user.nickname|default=”这家伙很懒,什么也没留下”}
运算符:{$user[‘score’]+10} //在使用运算符的时候,不再支持点语法和常规的函数用法

### 5-5 ThinkPHP模板引擎之调用函数和系统参数
对模板变量使用函数:{$data.name|md5}
函数有多个参数:{$create_time|date=”y-m
支持多个函数过滤,多个函数之间用“|”分割即可:{$name|md5|strtoupper|substr=0,3} 或 {:substr(strtoupper(md5($name)),0,3)}

系统变量:{$Think.server.script_name}

### 5-6 ThinkPHP模板引擎之volist和foreach循环
循环输出系统变量:

Select Code
1
2
3
<volist name="list" id="vo">
{$vo.id}:{$vo.name}<br/>
</volist>
Select Code
1
2
3
<volist name="list" id="vo" key="k" >
{$k}.{$vo.name}
</volist>

没有指定key属性的话,默认使用循环变量i

### 5-7 ThinkPHP模板引擎之FOR循环

Select Code
1
2
<for start="开始值" end="结束值" comparison="" step="步进值" name="循环变量名" >
</for>

开始值和结束值是必须,其他是可选;
comparison 的默认值是lt;

### 5-8 ThinkPHP模板引擎之IF判断

Select Code
1
2
3
4
<if condition="($name eq 1) OR ($name gt 100) "> value1
<elseif condition="$name eq 2"/>value2
<else /> value3
</if>

### 5-9 ThinkPHP模板引擎之Switch判断

Select Code
1
2
3
4
5
<switch name="变量" >
<case value="值1" break="0或1">输出内容1</case>
<case value="值2">输出内容2</case>
<default />默认情况
</switch>

### 5-10 ThinkPHP模板引擎之比较标签
标签 含义
eq或者 equal 等于
neq 或者notequal 不等于
gt 大于
egt 大于等于
lt 小于
elt 小于等于
heq 恒等于
nheq 不恒等于

### 5-11 ThinkPHP模板引擎之区间标签
范围判断标签包括in notin between notbetween四个标签,都用于判断变量是否中某个范围。

### 5-12 ThinkPHP模板引擎之三元运算符

Select Code
1
2
{$status?'正常':'错误'}
{$info['status']?$info['msg']:$info['error']}

注意:三元运算符中暂时不支持点语法。

### 5-13 ThinkPHP模板引擎之案例实战

## 第6章 ThinkPHP框架的调试模式 ##
本章主要讲解了调试模式的用途以及如何使用调试模式进行相关的开发。
### 6-1 ThinkPHP的调试方法
开启调试模式:define(‘APP_DEBUG’,True);
在开启调试模式的状态下,系统会首先导入框架默认的调试模式配置文件,该文件位于系统目录的Conf\debug.php。

显示页面Trace信息
‘SHOW_PAGE_TRACE’ =>true,

系统提供了G方法可以很方便的获取某个区间的运行时间和内存占用情况

除了使用php内置的var_dump和print_r之外,内置了一个对浏览器友好的dump方法,用于输出变量的信息到浏览器查看。

默认情况下只是在调试模式记录日志,要在部署模式开启日志记录,必须在配置中开启LOG_RECORD参数,以及可以在应用配置文件中配置需要记录的日志级别
‘LOG_RECORD’ => true, // 开启日志记录

## 第7章 数据库操作(一) ##
本章主要讲解了ThinkPHP框架独特的CURD的操作方式,以及在查询数据库时所用的连贯操作、视图模型等内容。
### 7-1 连接数据库

Select Code
1
2
3
4
5
6
7
8
9
10
//数据库配置信息
'DB_TYPE'   => 'mysql', // 数据库类型
'DB_HOST'   => 'localhost', // 服务器地址
'DB_NAME'   => 'thinkphp', // 数据库名
'DB_USER'   => 'root', // 用户名
'DB_PWD'    => '123456', // 密码
'DB_PORT'   => 3306, // 端口
'DB_PREFIX' => 'think_', // 数据库表前缀 
'DB_CHARSET'=> 'utf8', // 字符集
'DB_DEBUG'  =>  TRUE, // 数据库调试模式 开启后可以记录SQL日志 3.2.3新增

如果在某个模型类里面定义了connection属性的话,则实例化该自定义模型的时候会采用定义的数据库连接信息。通常用于某些数据表位于当前数据库连接之外的其它数据库。

除了在模型定义的时候指定数据库连接信息外,我们还可以在实例化的时候指定数据库连接信息。

分布式数据库:
内置了分布式数据库的支持,包括主从式数据库的读写分离,但是分布式数据库必须是相同的数据库类型。
配置DB_DEPLOY_TYPE 为1 可以采用分布式数据库支持。
‘DB_HOST’ => ‘192.168.0.1,192.168.0.2’,

对于主从式数据库而言,需要设置读写分离,通过下面的设置就可以:
‘DB_RW_SEPARATE’=>true,
注意:主从数据库的数据同步工作不在框架实现,需要数据库考虑自身的同步或者复制机制。在读写分离的情况下,默认第一个数据库配置是主服务器的配置信息,负责写入数据,设置了DB_MASTER_NUM参数,则可以支持多个主服务器写入。

### 7-2 实例化模型
准备表:

Select Code
1
2
3
4
5
6
7
8
CREATE TABLE IF NOT EXISTS tp_user(
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30) NOT NULL DEFAULT '',
age TINYINT(1) NOT NULL DEFAULT 2,
create_time DATETIME NULL DEFAULT CURRENT_TIMESTAMP()
)DEFAULT CHARSET=utf8;

INSERT tp_user(id,name,age) VALUES(NULL,'Ada',10),(NULL,'Lucy',10),(NULL,'May',18),(NULL,'Kitty',22),(NULL,'David',30);

创建模型类文件
参数 实例化的模型文件(假设当前模块为Home)
User 对应的模型类文件的 \Home\Model\UserModel.class.php
UserType 对应的模型类文件的 \Home\Model\UserTypeModel.class.php

D方法实例化
当 \Home\Model\UserModel 类不存在的时候,D函数会尝试实例化公共模块下面的 \Common\Model\UserModel 类。
D方法可以自动检测模型类,如果存在自定义的模型类,则实例化自定义模型类,如果不存在,则会实例化系统的\Think\Model基类,同时对于已实例化过的模型,不会重复去实例化。

Select Code
1
2
$User = D('User');
//相当于 $User = new \Home\Model\UserModel();

M方法实例化模型
D方法实例化模型类的时候通常是实例化某个具体的模型类,如果你仅仅是对数据表进行基本的CURD操作的话,使用M方法实例化的话,由于不需要加载具体的模型类,所以性能会更高。

Select Code
1
2
$User = M('User');
//和用法 $User = new \Think\Model('User'); 等效
Select Code
1
2
3
4
5
$model = new Model('User'); //等同于M('User')
$model = M('User');
$User = D('User');  //实例化Common\Model\UserModel模型
dump($User->getUserInfo(1));
$all_user = $model->select();

实例化空模型类

Select Code
1
2
3
4
5
6
//实例化空模型
$Model = new Model();
//或者使用M快捷方法是等效的
$Model = M();
//进行原生的SQL查询
$Model->query('SELECT * FROM think_user WHERE status = 1');

### 7-3 CURD操作之添加数据

Select Code
1
2
3
4
5
6
7
$User = D('User');
//新增用户
$data = [
	'name' => 'zhangsan',
	'age' => 28
];
$res = $User->add($data);   //返回值为主键id值
Select Code
1
2
3
4
5
6
7
8
$User = D('User');
//批量新增用户
$data = [
	['name' => 'lisi', 'age' => 20],
	['name' => 'wangwu', 'age' => 58],
	['name' => 'liujiu', 'age' => 1]
];
$res = $User->addAll($data);   //返回值为主键id值
Select Code
1
$User->fetchSql(true)->addAll($data) //只生成SQL,不执行

### 7-4 CURD操作之查询数据

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
$user = $User->order('id desc')->find();
echo $User->getLastSql();
echo '<br>';
$user = $User->find();
echo $User->getLastSql();   //SELECT * FROM `tp_user` LIMIT 1
echo '<br>';
$user = $User->order('id desc')->find();
echo $User->getLastSql();   //SELECT * FROM `tp_user` ORDER BY id desc LIMIT 1
echo '<br>';
$user = $User->order('id desc')->select();
echo $User->getLastSql();   //SELECT * FROM `tp_user` ORDER BY id desc
echo '<br>';
$where = [
	'id' => 1,
];
$user = $User->where($where)->order('id desc')->find();
echo $User->getLastSql();   //SELECT * FROM `tp_user` WHERE `id` = 1 ORDER BY id desc LIMIT 1
echo '<br>';
$where = [
	'id' => 1,
	'name' => 'Ada'
];
$user = $User->where($where)->order('id desc')->find();
echo $User->getLastSql();   //SELECT * FROM `tp_user` WHERE `id` = 1 AND `name` = 'Ada' ORDER BY id desc LIMIT 1
echo '<br>';
//连贯操作之字段值
$user = $User->getField('id,name');
echo $User->getLastSql();   //SELECT `id`,`name` FROM `tp_user`
echo '<br>';
$where = [
	'name' => ['like', 'A%'],
];
$user = $User->where($where)->order('id desc')->select();
echo $User->getLastSql();   //SELECT * FROM `tp_user` WHERE `name` LIKE 'A%' ORDER BY id desc 
echo '<br>';
//区间查询
$where = [
	'id' => [
		['gt', 1],
		['lt', 3]
	]
];
$user = $User->where($where)->getField('id,name');
echo $User->getLastSql();   //SELECT `id`,`name` FROM `tp_user` WHERE ( `id` > 1 AND `id` < 3 )
echo '<br>';

### 7-5 CURD操作之更新数据

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
// 更新数据
$data['name'] = 'Think';
$data['update_time'] = date('Y-m-d H:i:s', time());
$res = $User->where(['id' => 1])->save($data);  //1
// 更新字段值
$res = $User->where(['id' => 2])->setField('name', 'after...');
// 自增1
$res = $User->where(['id' => 3])->setInc('age');
// 自增3
$res = $User->where(['id' => 4])->setInc('age', 3);
// 自减
$res = $User->where(['id' => 5])->setDec('age');
dump($res);

### 7-6 CURD操作之删除数据

Select Code
1
2
3
4
5
6
7
8
$where = ['id' => 2];
$res = $User->where($where)->fetchSql(true)->delete();  //DELETE FROM `tp_user` WHERE `id` = 2

$where = ['id' => ['in', [2,3,4]]];
$res = $User->where($where)->fetchSql(true)->delete();  //DELETE FROM `tp_user` WHERE `id` IN (2,3,4)

$where = ['id' => ['lt', 5]];
$res = $User->where($where)->fetchSql(true)->delete();  //DELETE FROM `tp_user` WHERE `id` < 5

## 第8章 数据库操作(二) ##
本章主要讲解了ThinkPHP框架独特的CURD的操作方式,以及在查询数据库时所用的连贯操作、视图模型等内容。
### 8-1 连贯操作之order排序
$Model->where(‘status=1’)->order(‘id desc,status’)->limit(5)->select();

### 8-2 连贯操作之field方法
$Model->field(‘id,nickname as name’)->select();

### 8-3 连贯操作之limit和page方法

Select Code
1
2
3
4
$User->where('status=1')->field('id,name')->limit(10)->select();
$Article->limit('10,25')->select();
$Article->page('1,10')->select(); // 查询第一页数据
$Article->page('2,10')->select(); // 查询第二页数据

### 8-4 连贯操作之group和having方法

Select Code
1
2
3
4
5
$this->field('username,max(score)')->group('user_id')->select();
//SELECT username,max(score) FROM think_score GROUP BY user_id

$this->field('username,max(score)')->group('user_id')->having('count(test_time)>3')->select(); 
//SELECT username,max(score) FROM think_score GROUP BY user_id HAVING count(test_time)>3

### 8-5 多表查询之table方法

Select Code
1
2
3
4
5
$Model->table('think_user')->where('status>1')->select();

$Model->field('user.name,role.title')
->table(array('think_user'=>'user','think_role'=>'role'))
->limit(10)->select();

### 8-6 多表查询之join方法

Select Code
1
2
3
4
5
$Model = M('Artist');
$Model
->join('think_work ON think_artist.id = think_work.artist_id')
->join('think_card ON think_artist.card_id = think_card.id')
->select();

INNER JOIN: 如果表中有至少一个匹配,则返回行,等同于 JOIN
LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
FULL JOIN: 只要其中一个表中存在匹配,就返回行

### 8-7 多表查询之union方法

Select Code
1
2
3
4
5
$Model->field('name')
->table('think_user_0')
->union('SELECT name FROM think_user_1')
->union('SELECT name FROM think_user_2')
->select();

//每个union方法相当于一个独立的SELECT语句。

### 8-8 过滤查询之distinct方法
$Model->distinct(true)->field(‘name’)->select();
//SELECT DISTINCT name FROM think_user

## 第9章 关于命名范围的使用 ##
本章介绍了命名范围在实际项目中的使用方法和适用场景。
### 9-1 命名范围的使用
要使用命名范围功能,主要涉及到模型类的_scope属性定义和scope连贯操作方法的使用。

*Common\Model\UserModel.class.php*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected $_scope = array(
	'normal' => [
		'order' => 'id asc',
	],
	'latest' => [
		'order' => 'id desc',
		'limit' => 5,
	]
);

$res = $User->scope('normal')->fetchSql(true)->select();
dump($res); //SELECT * FROM `tp_user` ORDER BY id asc
$res = $User->scope('latest')->fetchSql(true)->select();
dump($res); //SELECT * FROM `tp_user` ORDER BY id desc LIMIT 5

PHP常用命令

Select Code
1
2
3
4
5
6
7
8
9
[root@localhost ~]# php --help
Usage: php [options] [-f] <file> [--] [args...]

-h               This help
-i               PHP information
-m               Show compiled in modules
-v               Version number

--ini            Show configuration file names

php -v 查看版本
php -h 帮助
php -i 等同于phpinfo()
php –ini 查看配置文件

php -m 查看安装好的模块

PHP面试题试试回答看

1. PHP是什么意思?
2. 什么是面向对象?主要特征是什么?
3. SESSION 与 COOKIE的区别是什么,请从协议,产生的原因与作用说明?
4. 不使用COOKIE向客户端发送一个COOKIE
5. 简述COOKIE的设置及获取过程
6. HTTP状态中302,403,500,200,404,502代码含义
7. 请写出数据类型int char varchar datetime text的意思,比较char和varchar的区别
8. MyISAM和InnoDB的基本区别,索引结构如何实现?
9. isset()和empty()的区别?
10. include和require的区别?
11. PHP中单引号与双引号的区别。
12. 请说明PHP中传值与传引用的区别,分别用在什么时候?
13. IN, NOT IN, EXIST, NOT EXIST的作用和区别
14. 面向对象中接口和抽象类的区别与使用场景
15. echo(), print(), print_r()的区别
16. `mysql_fetch_row()`和`mysql_fetch_array()`之间有什么区别
17. 请描述两点以上XHTML和HTML之间的显著区别
18. HTTP协议中GET和POST的区别
19. 表单中GET和POST提交方法的区别
20. foo()与@foo()的区别
21. 线性表和顺序表的区别
22. 什么是数据库索引,主键索引、唯一索引的区别,索引的缺点是什么?
23. IE浏览器与非IE浏览器的划分,区别是什么?
24. 数据库中的事务是什么?
25. 解释:左连接、右连接、内连接、索引
26. 简述无限极分类的实现原理
27. 举例:能够使PHP和HTML分离的模板引擎
28. 举例:版本控制管理工具
29. 写出三种以上MySQL数据库存储引擎的名称
30. 什么是模板技术?
31. 实现中文字符串截取无乱码的方法
32. 用PHP写出显示客户端IP和服务器端IP的代码
33. 数据库索引有几类,分别是什么,什么时候该用索引
34. 写几个魔术方法并说明作用
35. `$_REQUEST`, `$_POST`, `$_GET`, `$_COOKIE`, `$_SESSION`, `$_FILE`的意思是什么?
36. 数组中下标最好是什么类型
37. ++i, i++哪个效率更高,为什么?
38. `magic_quotes_gpc()`, `magic_quotes_runtime()`的意思是什么?
39. 框架中什么是单入口,多入口,单一入口有什么缺点?
40. 你对Memcache的理解,优点有什么?
41. 对关系数据库而言,索引是相当重要的概念,请回答有关索引的几个问题?
– 索引的目标是什么?
– 索引对数据库系统的负面影响是什么?
– 为数据表建立索引的原则有哪些?
– 什么情况下不宜建立索引?
42. web应用中,数据库的读取频率远高于写入频率,如何优化MySQL而应对此种场景?
43. 如果是一个WEB频繁访问的查询,查询应该如何优化?
44. 数据库设计时,常遇到哪些性能瓶颈,常用解决方案。
45. 请详述在开发过程中用什么方法来加快页面的加载速度
46. 描述大流量高并发网站的解决方案
47. 对于大流量的网站您采用什么方法来解决访问量问题?
48. 如何设计或配置MySQL,才能达到高效的目的。
49. 设定网站的用户量在千万级,但是活跃的用户只有1%,如何通过优化数据库提高活跃用户的访问速度?
50. 什么是XSS攻击,如何防止?
51. SQL注入漏洞产生的原因,如何防止?
52. 如何防止SQL注入。
53. 用PHP写一个用户登录系统需要注意哪些?
54. 如何实现多个线程安全的写入一个文件数据
55. 什么是满二叉树,什么是完全二叉树?
56. 字符串数组,数组转字符串,字符串截取,字符串替换,字符串查找的函数?
57. 描述GD库
58. 写出Zend框架的目录结构,简单说明目录的作用
59. 谈谈对MVC的理解
60. PHP如何抛出和接收错误?
61. PHP的网站主要攻击问题有哪些?
62. 几个重要的PHP.INI配置选项
63. 使用过哪些PHP框架?试试描述各自的优缺点?
64. 如何在页面之间传递变量数据?
65. 写出多个PHP数组函数,并说明作用
66. 你所知道的一些PHP技术、PHP论坛系统、PHP商城系统、开发框架等;
67. 你所知道的设计模式
68. 说说你对代码管理的看法,常使用什么版本控制器
69. 说说对于SVN的了解,简述其优缺点?
70. 如何找到PHP.INI配置文件
71. PHP加速模式/扩展?PHP调试模式/工具?
72. 你常用的mysql命令
73. 写出10个LINUX命令
74. 写出LINUX配置文件/服务的位置(5个)
75. 写出5个MYSQL的操作关键字
76. 列出5个PHP操作MYSQL的函数
77. 数据库的配置文件路径
78. 什么是时间戳,获取当前时间戳的函数
79. 给定一个网址URL,如何获取网页中的内容?
80. 简述如何获取当前执行脚本路径,包括其参数
81. 如何使用PHP环境变量,获取网页的地址,IP地址等
82. 求2个日期之间的天数
83. PHP中如何定义一个常量?如何定义值传递的变量?
84. PHP可以对string类型的10和数值11进行比较吗?
85. 什么情况下需要用endif来结束条件语句?
86. 优化MySQL数据库的方法?
87. 实现中文字符串截取无乱码的方法。
88. 分别指出php.ini中 `magic_quotes_gpc`, `magic_quotes_runtime`两项参数的作用.
89. 用面向对象来实现A对象继承B和C对象
90. 写出Smarty模板引擎中你最常用的关键词
91. 如何快速下载一个远程http服务器上的图片文件到本地?
92. 一个字节占多少bit ? 一个IPv4地址占几个字节? 一个IPv6地址呢?
93. MADSL宽带连接, 理想情况下, 最大下载速度是多少KB/s ?
94. 用PHP打印出前一天的时间,打印格式是2007年5月10日22:21:21
95. 抓取远程图片到本地,你会用什么函数?
96. 正在浏览当前页面用户的 IP 地址:127.0.0.1
97. 查询(query)的字符串(URL 中第一个问号 ? 之后的内容):id=1&bi=2
98. 在PHP中,heredoc是一种特殊的字符串,它的结束标志必须
99. 如何声明一个名为”myclass”的没有方法和属性的类?
– 如何实例化一个名为”myclass”的对象?
– 你如何访问和设置一个类的属性?
100. 指出一些在PHP输入一段HTML代码的办法。
101. 哪个函数可以打开一个文件,以对文件进行读和写操作?
102. 简述Linux下安装PHP的过程?
103. 简述Linux下安装Mysql的过程?
104. 简述Linux下安装apache的过程?
105. linux下建立压缩包,解压缩包的命令
106. 写出匹配URL的正则表达式
107. 请用正则表达式(Regular Expression)写一个函数验证电子邮件的格式是否正确
108. 请写一个函数验证电子邮件的格式是否正确
109. 请写出一个正则表达式,用于匹配一个HTML文件中``标记中的图片地址
110. 写出一个正则表达式,过虑网页上的所有JS/VBS脚本(即把scrīpt标记及其内容都去掉)
111. 在PHP中`error_reporting()`这个函数有什么作用?
112. Windows平台, Apache Http Server启动失败, 排错思路是什么?
113. php读取文件内容的几种方法和函数?
114. 以下程序,变量str什么值的情况下输出111? `if( ! $str ) { echo 111; }`
115. 请写出常见的排序算法,并用PHP实现冒泡排序,将数组$a = array()按照从小到大的方式进行排序。常见的排序算法: 冒泡排序法、快速排序法、简单选择排序法、堆排序法、直接插入排序法、希尔排序法、合并排序法。
116. 使用PHP描述快速排序算法,对象可以是一个数组?
117. 使用PHP描述顺序查找和二分查找(也叫做折半查找)算法,顺序查找必须考虑效率,对象可以是一个有序数组
118. 写一个二维数组排序算法函数,能够具有通用性,可以调用php内置函数
119. 请以空格作为间隔,拆分字符串’Apple Orange Banana Strawberry’,组成数组$fruit, 数组中所有元素都用小写字母,并按照字母先后次序排序
120. 对于用户输入一串字符串$string,要求$string中只能包含大于0的数字和英文逗号,请用正则 表达式验证,对于不符合要求的$string返回出错信息
121. 请写一段程序,在服务器创建一个文件fruit.dat,将试题3中得到的数组写入到改文件中,然后写一段程序从文件中读取并还原数组@author zhuwenqiong
122. 单例模式,创建mysqli数据库链接的单例对象
123. js中网页前进和后退的代码
124. 简述如何得到当前执行脚本路径,包括所得到参数。
125. JS表单弹出对话框函数是?获得输入焦点函数是?
126. JS的转向函数是?怎么引入一个外部JS文件?
127. 用javascript取得一个input的值?取得一个input的属性?
128. 用Jquery取得一个input的值?取得一个input的属性?
129. 写一个简单的jquery显示隐藏代码?
130. 假设a.html和b.html在同一个文件夹下面,用javascript实现当打开a.html五秒钟后,自动跳转到b.html。
131. 请您写一段ajax提交的js代码,或者写出ajax提交的过程逻辑。
132. SQL: 增加一个字段性别sex,写出修改语句; 查询出年龄介于20岁到30岁之间的用户
133. 写一个函数,算出两个文件的相对路径
134. 写一个函数,能够遍历一个文件夹下的所有文件和子文件夹。
135. Linux的目录进行遍历,编写shell脚本
136. 写一个函数,尽可能高效的,从一个标准 url 里取出文件的扩展名。例如: http://www.sina.com.cn/abc/de/fg.php?id=1 需要取出 php 或 .php
137. 有一个网页地址, 比如PHP开发资源网主页: http://www.phpres.com/index.html,如何得到它的内容?
138. 请写一个函数,实现以下功能:字符串“open_door” 转换成 “OpenDoor”、”make_by_id” 转换成 ”MakeById”。
139. 有一个一维数组,里面存储整形数据,请写一个函数,将他们按从大到小的顺序排列。要求执行效率高。并说明如何改善执行效率。(该函数必须自己实现,不能使用php函数)
140. 使用php写一段简单查询,查出所有姓名为“张三”的内容并打印出来(PDO实现)
141. 写出发贴数最多的十个人名字的SQL,利用下表:members(id,username,posts,pass,email)