thinkphp中where()和whereOr()有很多种用法,组合成不同的SQL语句,有些常用的可能都了解,但对于一些特殊的,比如一个字段多种条件、一个条件查询多个字段等。
//最简单的实用方法,多条件并列查询,基本形式:['字段名1'=>['SQL运算符','值'],'字段名1'=>['SQL运算符','值'],……] $where = ['name' => ['like', '%国%'], 'age' => ['>=', 18]]; Db::table('user') ->where($where) ->find(); //SQL语句 SELECT * FROM `user` WHERE `name` LIKE '%国%' AND `age` >= 18 LIMIT 1
//特殊用法(|和&),多个字段用同一个条件查询,并且用and或or连接 //or(|)的用法 $where = ['name|address' => ['like', '%国%']]; Db::table('user') ->where($where) ->find(); //SQL语句 SELECT * FROM `user` WHERE ( `name` LIKE '%国%' OR `address` LIKE '%国%' ) LIMIT 1 //and(&)的用法 $where = ['name&address' => ['like', '%国%']]; Db::table('user') ->where($where) ->find(); //SQL语句 SELECT * FROM `user` WHERE ( `name` LIKE '%国%' AND `address` LIKE '%国%' ) LIMIT 1
//复杂查询,一个字段同时满足多种查询条件 $where = ['name' => [['like', '%国%'],['like', '%天%'],'or']]; Db::table('user') ->where($where) ->find(); //SQL语句 SELECT * FROM `user` WHERE ( `name` LIKE '%国%' or `name` LIKE '%天%' ) LIMIT 1 //其中如果or不写默认为and连接,或者这里也可以写上and $where = ['name' => [['like', '%国%'],['like', '%天%'],'and']]; Db::table('user') ->where($where) ->find(); where = ['name' => [['like', '%国%'],['like', '%天%']]]; Db::table('user') ->where($where) ->find(); //以上两种方式生成的SQL语句相同 SELECT * FROM `user` WHERE ( `name` LIKE '%国%' AND `name` LIKE '%天%' ) LIMIT 1
//最简单的实用方法,多条件or查询,基本形式:['字段名1'=>['SQL运算符','值'],'字段名1'=>['SQL运算符','值'],……] $where = ['name' => ['like', '%国%'], 'age' => ['>=', 18]]; Db::table('user') ->where($where) ->find(); //SQL语句 SELECT * FROM `user` WHERE `name` LIKE '%国%' OR `age` >= 18 LIMIT 1
//复杂用法,在whereOr中使用and,并且多个and之间用or连接(TP6写法) $where = [//第一维代表多个条件 [//第二维之间用or链接 //第三维之间用and连接 ['create_time', '<=', time()], ['status', '=', '1'] ], [ ['id', '>=', 10], ['update_time', '>=', time()], ] ]; Db::table('user') ->whereOr($where) ->find(); //SQL语句 SELECT * FROM `user` WHERE (create_time <= time() and status = 1) or (update_time >= time() and id >= 10)
//模糊搜索后,按照搜索结果排序,比如:文章模糊搜索标题和内容,搜索结果优先显示标题 $where = ['title|content' => ['like', '%国%']]; Db::table('article') ->whereOr($where) ->order('titlelike "%国%" desc') ->find();
这个错误一般是数据库断开后不再自动连接导致的。
需要将 config['break_reconnect'] 的值设置为 true, 才会开启断线重连。
一般在database.php 配置文件中:
//断线重连 'break_reconnect' => true,
但有些版本不在此文件中,可以从thinkphp/library/think/db/Connection.php找到,再找不到,请全局搜索!
最后,一般造成这样的原因可能是因为数据库连接次数过多,还是要优化代码,可以考虑添加缓存,减少数据库的连接。
THINK_PATH 框架系统目录 ROOT_PATH 框架应用根目录 APP_PATH 应用目录(默认为application) CONF_PATH 配置目录(默认为APP_PATH) LIB_PATH 系统类库目录(默认为 THINK_PATH.'library/') CORE_PATH 系统核心类库目录 (默认为 LIB_PATH.'think/') TRAIT_PATH 系统trait目录(默认为 LIB_PATH.'traits/') EXTEND_PATH 扩展类库目录(默认为 ROOT_PATH . 'extend/') VENDOR_PATH 第三方类库目录(默认为 ROOT_PATH . 'vendor/') RUNTIME_PATH 应用运行时目录(默认为 ROOT_PATH.'runtime/') LOG_PATH 应用日志目录 (默认为 RUNTIME_PATH.'log/') CACHE_PATH 项目模板缓存目录(默认为 RUNTIME_PATH.'cache/') TEMP_PATH 应用缓存目录(默认为 RUNTIME_PATH.'temp/')
Elasticsearch是一个基于java语言开发的分布式多用户的全文搜索引擎,在云计算中,能够达到实时搜索,稳定、可靠、快速,安装方便。
官方客户端在java、PHP、Python、.NET等其他语言都是可用的。
Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。
首先安装java环境,因为Elasticsearch是基于java运行的。参考:java的安装。
下载Elasticsearch,建议最新版,其他版本我下载后出现问题,解决非常麻烦。
GitHub下载地址:https://github.com/elastic/elasticsearch
下载成功后打开根目录样式如下:
命令行启动Elasticsearch服务:
elasticsearch.bat
浏览器访问以下地址,如果如图显示则安装成功!
http://localhost:9200/
end
此工具是为了对Elasticsearch中的数据进行可视化管理,类似于Navicat。
安装使用参考查看:Elasticsearch-Head的安装。
Elasticsearch-analysis-ik中文分词器是为了将中文搜索条件进行分词搜索使用的。
安装使用参考查看:Elasticsearch-analysis-ik的安装。
1、首先下载composer
2、cmd进入项目根目录下
3、使用composer命令进行安装:
composer require elasticsearch/elasticsearch
4、end
use Elasticsearch\ClientBuilder; class Es extends BaseController { protected $client; public $index_name;//索引值,类似于数据库名 /** * Es constructor. * @param string $index_name 索引名称 */ public function __construct($index_name = "shx") { parent::__construct(); //给定默认值 $this->index_name = $index_name; //自动连接Elasticsearch服务器 $this->client = ClientBuilder::create()->setHosts(['127.0.0.1:9200'])->build(); } /** * ELasticsearch初次使用 */ public function index() { //删除原索引 //$this->delete_index(); //创建新索引 //$this->create_index(); //自定义内容,也可换成数据库内容 $docs = []; $docs[] = ['id' => 1, 'name' => '叶凡', 'content' => '我做的ui界面强无敌。', 'age' => 23]; $docs[] = ['id' => 2, 'name' => '秦昊', 'content' => '我的php代码无懈可击。', 'age' => 24]; $docs[] = ['id' => 3, 'name' => '萧炎', 'content' => 'C的生活,快乐每一天。', 'age' => 29]; $docs[] = ['id' => 4, 'name' => '林动', 'content' => '就没有我做不出的前端页面。', 'age' => 26]; $docs[] = ['id' => 5, 'name' => '唐三', 'content' => 'php是最好的语言。', 'age' => 21]; $docs[] = ['id' => 6, 'name' => '秦宇', 'content' => '别烦我,我正在敲bug呢!', 'age' => 25]; $docs[] = ['id' => 7, 'name' => '宋书航', 'content' => '为所欲为,不行就删库跑路', 'age' => 27]; foreach ($docs as $k => $v) { //添加文档 $this->add_doc($v['id'], $v); } //查看映射(整个index索引的相关信息,不包括数据) //$res = $this->get_mapping(); //搜索结果 $search_where = [ 'bool' => [ 'should' => [ [ 'match' => [ 'content' => [ 'query' => '删库 别烦我',//查询内容 'boost' => 3, // 权重大 ] ] ], [ 'match' => [ 'name' => [ 'query' => '删库 别烦我', 'boost' => 2, ] ] ], ], ], ]; //按照搜索条件,age倒序排列,每页10条数据,查看第一页的数据 //$data = $this->search_doc($search_where, ['age' => ['order' => 'desc']], 0, 10); //按照搜索条件,按照匹配度由高到低排序,每页2条数据,查看第一页的数据 $data = $this->search_doc($search_where, [], 0, 2); dump($data); } /** * 创建索引 * @return array|mixed */ public function create_index() { //给定索引名 $index_name = $this->index_name; // 只能创建一次 $params = [ 'index' => $index_name, 'body' => [ //定义映射中的一些设置 'settings' => [ 'number_of_shards' => 5,//数据分片数,默认为5,有的时候也会用3 'number_of_replicas' => 0//数据备份数,如果只有一台机器,则设置为0 ] ] ]; try { //完成创建索引的映射 return $this->client->indices()->create($params); } catch (Elasticsearch\Common\Exceptions\BadRequest400Exception $e) { $msg = $e->getMessage(); $msg = json_decode($msg, true); return $msg; } } /** * 删除索引 * @return array */ public function delete_index() { //给定索引名 $index_name = $this->index_name; $params = ['index' => $index_name]; //删除指定索引,包括其中的数据映射等 $response = $this->client->indices()->delete($params); return $response; } /** * 查看映射 * @return array */ public function get_mapping() { //给定索引名 $index_name = $this->index_name; $params = [ 'index' => $index_name, ]; //查看指定索引下指定 $response = $this->client->indices()->getMapping($params); return $response; } /** * 添加文档,一次仅插入一条 * @param $id 此条数据索引id * @param $doc 此条数据具体内容,例:['name'=>'shx'] * @return array|callable */ public function add_doc($id, $doc) { //给定索引名 $index_name = $this->index_name; $params = [ 'index' => $index_name, 'id' => $id, 'body' => $doc ]; //添加一条文档 $response = $this->client->index($params); return $response; } /** * 判断文档存在 * @param $id 索引id * @return bool */ public function exists_doc($id) { //给定索引名 $index_name = $this->index_name; $params = [ 'index' => $index_name, 'id' => $id ]; //判断文档是否存在 $response = $this->client->exists($params); return $response; } /** * 获取文档 * @param $id 索引id * @return array|callable */ public function get_doc($id) { //给定索引名 $index_name = $this->index_name; $params = [ 'index' => $index_name, 'id' => $id ]; //获取指定id的文档内容 $response = $this->client->get($params); return $response; } /** * 更新文档,一次仅更新一次 * @param $id 需要更新的索引id * @param $update_data 更新内容,例:['name'=>'shxtest'] * @return array|callable */ public function update_doc($id, $update_data) { //给定索引名 $index_name = $this->index_name; // 可以灵活添加新字段,最好不要乱添加 $params = [ 'index' => $index_name, 'id' => $id, 'body' => [ 'doc' => $update_data ] ]; $response = $this->client->update($params); return $response; } /** * 删除文档 * @param $id 索引id * @return array|callable */ public function delete_doc($id) { //给定索引名 $index_name = $this->index_name; $params = [ 'index' => $index_name, 'id' => $id ]; $response = $this->client->delete($params); return $response; } /** * 查询文档 * @param $search_where 检索条件 * @param array $order 排序,此处如果传空数组,则会按相似度由高到低进行排序。例如:['age' => ['order' => 'desc']] * @param int $from 分页的页数,从0开始为第一页 * @param int $size 分页条数(每页显示多少条) * @return array|callable */ public function search_doc($search_where, $order, $from = 0, $size = 2) { //给定索引名 $index_name = $this->index_name; $params = [ 'index' => $index_name, 'body' => [ //检索条件 'query' => $search_where, //排序内容 'sort' => $order, //页数 'from' => $from, //每页条数 'size' => $size ] ]; $results = $this->client->search($params); return $results; } }
MySQL中的数据库就相当于Elasticsearch的index索引。
MySQL中的数据表就相当于Elasticsearch的type。
MySQL中的每行数据就相当于Elasticsearch的doument。
MySQL中的表字段就相当于Elasticsearch的Field。
MySQL中的视图就相当于Elasticsearch的Mapping。
注意:MySQL和Elasticsearch无任何直接关系,只是在此举例说明。
elasticsearch运行是基于java的,所以如果想要使用elasticsearch首先需要安装java环境。
如果安装最新版ES插件,请检查PHP版本,例如当前安装elasticsearch7.11,则PHP版本必须大于等于7.1。
//快捷查询 Db::table('think_user') ->where('name|title','like','thinkphp%') ->where('create_time&update_time','>',0) ->find(); //sql: SELECT * FROM `think_user` WHERE ( `name` LIKE 'thinkphp%' OR `title` LIKE 'thinkphp%' ) AND ( `create_time` > 0 AND `update_time` > 0 ) LIMIT 1
->whereOr([//第一维代表多个条件 [//第二维之间用or链接 //第三维之间用and连接 ['create_time', '<=', time()], ['status', '=', '1'] ],[ ['id', '>=', 10], ['update_time', '>=', time()], ] ]) //拼凑出来的结果: //where (create_time <= time() and status = 1) //or (update_time >= time() and id >= 10)
适用于多对多,并且有中间表的,例如,不同用户关联不同的兴趣标签,关联数据单独存在一个表中:
建表:
article表(字段:id,……)
label表(字段:id,name,……)
article_label表(字段:id,article_id,label_id,createtime,……)
article模型中:
//方法名随意,调用时使用此方法名 public function Labels(){ //参数1:关联模型 //参数2:中间表表名,不带表前缀 //参数3:中间表 关联 关联模型的外键 //参数4:中间表 关联 当前模型的外键 return $this->belongsToMany('LabelModel', 'article_label','label_id','article_id'); }
控制器中使用:
//查询 $data=ArticleModel::with('Labels')->select(); //使用,因为查询结果为对象,所以调用方式如下: //打印第一条文章数据下第一个标签的名字 dump($data[0]->Labels[0]->name); //接口调用:直接用json_encode()处理后自动变成三维数组 echo json_encode($data); //删除 $data = ArticleModel::find(1);//查询文章信息 $data->Labels()->detach();//删除article_label表中当前文章的信息 //添加 $label_ids=[1,2,3,4,5,6,7,8,9];//需要绑定的label表主键id //参数1是需要绑定的多个label_id,参数2是其他需要补充的字段 $data->Labels()->attach($label_ids,['createtime'=> time()]);//保存
一般用于一条记录对应多条记录,例如某个文章的评论:
建表:
article表(字段:id,……)
comment表(字段:id,article_id,content,……)
article模型中:
//方法名字随意,调用时方法名作为参数使用 public function comments(){ //参数1:关联模型名 //参数2:关联模型外键 //参数3:当前模型表主键 return $this->hasMany('CommentModel','article_id','id'); }
控制器中使用:
$data=ArticleModel::with('comments')->select(); //使用,因为查询结果为对象,所以调用方式如下: //打印第一条文章数据下第一条评论数据的内容 dump($data[0]->comments[0]->content); //接口调用:直接用json_encode()处理后自动变成三维数组 echo json_encode($data);
一般用于多级分类存在同一个表中:
建表:
classify表(字段:id,name,level,pid,……)
classify模型中:
//方法名字随意,调用时方法名作为参数使用 public function secondClassify(){ //参数1:当前模型名 //参数2:上级id(原关联模型外键) //参数3:当前模型表主键 return $this->hasMany('ClassifyModel','pid','id'); }
控制器中使用:
//查询一级分类,自动补全二级 $data=ClassifyModel::with('secondClassify')->where('level',1)->select(); //使用,因为查询结果为对象,所以调用方式如下: //打印第一条一级分类数据下第一个二级分类的名称 dump($data[0]->secondClassify[0]->name); //接口调用:直接用json_encode()处理后自动变成三维数组 echo json_encode($data);
一般用于主记录查询子记录(子表有关联记录在主表),例如一个用户信息只对应一个用户:
建表:
user表(字段:id,message_id,……)
message表(字段:id,user_id,……)
user模型中:
//方法名字随意,调用时方法名作为参数使用 public function user(){ //参数1:关联模型名 //参数2:关联模型外键 //参数3:当前模型主键 return $this->hasOne('UserModel','message_id','id'); }
控制器中使用:
$data=UserModel::with('user')->select(); //使用,因为查询结果为对象,所以调用方式如下: //打印当前用户信息对应的用户生日 dump($data[0]->user->birthday); //接口调用:直接用json_encode()处理后自动变成三维数组 echo json_encode($data);
一般用于主记录查询子记录(子表有一条记录属于主表),例如一个用户只有一条用户信息:
建表:
user表(字段:id,message_id,……)
message表(字段:id,user_id,……)
classify模型中:
//方法名字随意,调用时方法名作为参数使用 public function messages(){ //参数1:关联模型名 //参数2:关联模型外键 //参数3:当前模型主键 return $this->belongsTo('MessageModel','message_id','id'); }
控制器中使用:
$data=UserModel::with('messages')->select(); //使用,因为查询结果为对象,所以调用方式如下: //打印第一条用户数据下子信息的金额 dump($data[0]->messages->money); //接口调用:直接用json_encode()处理后自动变成三维数组 echo json_encode($data);
//取单列:获取所有标签名,输出结构:[id=>name] LabelModel::column('name','id'); //取多列:获取所有标签名和创建时间,输出结构:[id=>[id,name,createtime]] LabelModel::where('status',1)->column('name,createtime','id');
cache()可以用于select、find、value和column方法,以及其衍生方法,使用cache方法后,在缓存有效期之内不会再次进行数据库查询操作,而是直接获取缓存中的数据,关于数据缓存的类型和设置可以参考缓存部分。
1. 简单的存储
//查询news表中id=10的新闻存储于cache中 //写true默认读取配置的中缓存时间 db('news')->cache(true)->find(10); //你也可以自定义时间,60秒表示: db('news')->cache(true,60)->find(10);
2. 指定缓存标识
//等同于使用缓存时的键,默认读取配置的中缓存时间: db('news')->cache('key')->find(15); //全局读取这条数据: $data = \think\Cahce::get('key');
3.支持设置缓存标签:
//缓存键:key,缓存时间:60秒,标签为:tagName db('news')->cache('key',60,'tagName')->find(15); //全局读取带标签的缓存: Db::name('news')->cache('news_list',60,'shx')->select(); $data = \think\Cache::tag('shx')->get('news_list');
直接在网站运行目录的.htaccess文件中输入以下内容:
Apache:
<IfModule mod_rewrite.c> RewriteEngine on RewriteBase / RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.php?s=/$1 [QSA,PT,L] </IfModule>
Nginx:
location / { if (!-e $request_filename){ rewrite ^(.*)$ /index.php?s=$1 last; break; } }
在vendor\topthink下执行composer命令,默认安装最新发送电子邮件的插件包:
composer require phpmailer/phpmailer
安装图例:
引入方式:
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\Exception;
使用方法:
$mail = new PHPMailer(true);// Passing `true` enables exceptions try { //服务器配置 $mail->CharSet = "UTF-8";//设定邮件编码 $mail->SMTPDebug = 0;// 调试模式输出 $mail->isSMTP();// 使用SMTP $mail->Host = 'smtp.qq.com';// SMTP服务器 $mail->SMTPAuth = true;// 允许 SMTP 认证 $mail->Username = '*******@qq.com';// SMTP 用户名 即邮箱的用户名 $mail->Password = '**********';// SMTP 密码 部分邮箱是授权码(例如163邮箱) $mail->SMTPSecure = 'ssl';// 允许 TLS 或者ssl协议 $mail->Port = 465;// 服务器端口 25 或者465 具体要看邮箱服务器支持 $mail->setFrom('******@qq.com', 'shx');//发件人 $mail->addAddress($email, 'Joe');// 收件人 //$mail->addAddress('ellen@example.com');// 可添加多个收件人 //$mail->addReplyTo('xxxx@163.com', 'info');//回复的时候回复给哪个邮箱 建议和发件人一致 //$mail->addCC('cc@example.com');//抄送 //$mail->addBCC('bcc@example.com');//密送 //发送附件 // $mail->addAttachment('../xy.zip');// 添加附件 // $mail->addAttachment('../thumb-1.jpg', 'new.jpg');// 发送附件并且重命名 //Content $mail->isHTML(true);// 是否以HTML文档格式发送 发送后客户端可直接显示对应HTML内容 $mail->Subject = '我是邮件标题'; $mail->Body = '我是邮件内容'; $mail->AltBody = '如果邮件客户端不支持HTML则显示此内容'; $mail->send(); return '邮件发送成功'; } catch (Exception $e) { return '邮件发送失败: ' . $mail->ErrorInfo; }
本人用的是QQ邮箱的相关配置,所以这里申请方式就以QQ邮箱为例。
登入QQ邮箱。
进入设置,点击账户,向下翻,开启POP3/SMTP服务。
记录一下授权码,就是代码中的SMTP密码,无法复看,一旦忘记就只能重新申请!
SMTP Error: Could not authenticate.错误怎么解决?
网上大多数说的解决方案是:替换某个函数或者开启php.ini的某些功能。我个人曾多次出现此情况,前面的两个修改方案从未成功解决过错误,也可能我的问题和他们的报错原因不一样。本人多次入坑,强烈建议直接重新申请一次授权码就可以了,简单快捷!
这个错误我发现只要我配置好以后隔段时间如果不去使用它,可能就会产生这个错误,我的代码和配置从没动过,但是隔一段时间仍旧失效,所以我怀疑QQ邮箱这边可能有一定验证机制,长时间不使用就会出现类似于注销的情况。