thinkphp6验证码+登陆状态+redis+中间件

tp6笔记

json() 提供 方法
修改 开启报错查看
在这里插入图片描述

env

中开启 de_bug
database配置数据库 会先使用 .env 中的配置在这里插入图片描述
在这里插入图片描述
tp6 中使用
Db:: 需要 use 门面模式 user think\facade/\Db
在这里插入图片描述

app.php

config/app.php 错误信息

多应用模式

composer require topthink/think-multi-app
在当前控制器下创建 route 路由文件夹
配置域名访问
http://www.tp6.com/demo.php/index/test?a=1
在public 下复制index.php 改名为 demo.php
$response = $http->name(‘demo’)->run(); 若是文件名不同 可用 name指向
config 可以在每个 目录下 +
admin / config 当前目录有用
api/config …

路由

多应用 需要 加 文件名 admin/text index/…

config 下 业务状态码

创建 status.php`
return [
‘success’ => 1,
‘error’ => 0,
];

未开启强制路由
都可以
http://www.tp6.com/index.php/demo/index/t demo 应用 inde想控制器 t方法
http://www.tp6.com/demo.php/index/t

在这里插入图片描述
在这里插入图片描述

has 判断某个值是否设置

容器和依赖注入

在这里插入图片描述
在这里插入图片描述

全局中间件

可以通过命令行指令快速生成中间件

php think make:middleware Check

<?php

namespace app\middleware;

class Check
{
    public function handle($request, \Closure $next)
    {
       // 添加中间件执行代码
		...
        return $next($request);
    }
}

在 app/middleware.php

<?php
// 全局中间件定义文件
return [
    // 全局请求缓存
    // \think\middleware\CheckRequestCache::class,
    // 多语言加载
    // \think\middleware\LoadLangPack::class,
    // Session初始化
    // \think\middleware\SessionInit::class
          app\middleware\Check::class,
];

应用中间件

在这里插入图片描述

模板引擎

composer安装
在这里插入图片描述
composer require topthink/think-view

简单的密码+盐处理

密码 123
md5(‘123_md5’) 处理字符串

验证码

composer require topthink/think-captcha

在这里插入图片描述
在这里插入图片描述

验证码使用 验证是时 徐快需要在中间件中开启session在这里插入图片描述

模型分层架构

在这里插入图片描述
思维

验证器

 $data = [
            'username' => $username,
            'password' => $password,
            'captcha' => $captcha,
        ];
        $validate = new \app\admin\validate\AdminUser();
        if(!$validate->check($data)) {
            return show(config("status.error"), $validate->getError());
        }
<?php
/**
 * Created by singwa
 * User: singwa
 * motto: 现在的努力是为了小时候吹过的牛逼!
 * Time: 07:11
 */
namespace app\admin\validate;

use think\Validate;

class AdminUser extends  Validate {
    protected $rule = [
        'username' => 'require',
        'password' => 'require',
        'captcha' => 'require|checkCapcha',
    ];

    protected $message = [
        'username' => '用户名必须,请重新输入',
        'password' => '密码必须',
        'captcha' => '验证码必须',

    ];

    protected function checkCapcha($value, $rule, $data = []) {
        if(!captcha_check($value)) {
            return "您输入的验证码不正确!";
        }

        return true;
    }
}

Url 注意

在这里插入图片描述

如何正确分层之操作datebase

注意使用 init初始化

如何处理在init里无法重定向

在这里插入图片描述

注意 如何 /admin/index/index 写的时候需要+ /’

前置中间件

在这里插入图片描述
preg_match()
1 正则
2 str 匹配2中有无 1
return 1 0

后置中间件

在这里插入图片描述

session

    session('adminUser', $res);        session('adminUser', null);
  • 1

business 业务逻辑层

在business 处理业务逻辑 -> 调用 model 的sql执行 在business进行 异常抛出 在c层try catch 补获
model 放在 common 公共文件里
在这里插入图片描述

redis 实现验证码 存活时间60s

安装 https://blog.csdn.net/kxukai/article/details/106692983

日志

开启日志 runtime 可以查看执行的原生sql语句 进行分析
在这里插入图片描述

工厂模式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
短信可以使用redis 进行限制 存手机号 + 发信息间隔时间~

如何流控 20%阿里云短信 80%百度云短信

案例:2018年年底 央视春晚 百度手机号登录发送验证码分发不同运营商流量, 就是用这个来做的, 并发50万 发送短信验证码。
简单粗暴 实用 最简单的方法往往最有效

$a = rand(0,99);
if($a < 80) {
    // 阿里云逻辑
} else {
    // 百度云逻辑
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

前后端分离 redis+ token 不使用session+cookie

config(‘statis.success’)

在这里插入图片描述

异常处理 try catch

捕获异常时 注意记录日志 以供分析
tp6 helper 全局搜索自带抛出异常 throw_if 同laravel
手动抛出异常

            throw new \think\Exception("不存在该验证码", config('status.code.not_code'));
  • 1

捕获异常

        try {
            $result = (new \app\common\business\User())->login($data);
        } catch (\Exception $e) {
            return show($e->getCode(), $e->getMessage());
        }
  •  

// 阻止数据库抛出异常 被 用户看到 手动抛出~

 try {
                $this->userObj->save($userData);
                $userId = $this->userObj->id;
            }catch (\Exception $e) {
                throw new \think\Exception("数据库内部异常");
            }
  •  

在这里插入图片描述

redis 删除 等于null 即可

redis 写登录 逻辑

前后端分离 所以是 api 接口

  1. 用户点击发送验证码 把 sms . 手机号 存入 redis 内容有 验证码 存活60s //这里sms为了再redis中进行区分别的缓存
  2. 接收数据 转换格式 验证 isajax ispost
    if (!$this->request->isPost() || !$this->request->isAjax() )
            return show(config("status.error"), "非法请求");
        $phoneNumber = input("phone_number",'','trim');
        $code = input("code", 0, "intval");
  •  
  1. validate 验证器 验证参数
  2. 验证 用户输入的 code !== redis中的该手机号对应的 code
        // 用户输入的 code  !==  redis中的该手机号对应的 code
        $redisCode = cache(config("redis.code_pre") . $data['phone_number']);
        if (empty($redisCode) || $redisCode != $data['code']) {
          throw new \think\Exception("不存在该验证码", config('status.code.not_code'));
        } 
  •  

从第五层开始要在 business 逻辑层进行处理 判断
例子 抛出异常最好用 try catch 进行补获 避免数据库抛出暴露信息被用户查看
在这里插入图片描述
5. 还是在common/ business 操作
根据用户手机号 查找有该用户登录记录

   // 需要去判断表 是否有 用户记录   phone_number
        // 生成token
        $user = $this->userObj->getUserByPhoneNumber($data['phone_number']);
  •  

这里model 层在 common/model datebase 操作公共的 可以共用
在这里插入图片描述

然后进行判断 操作用户记录

在这里插入图片描述
6. 然后把生成的token作为k 用户的id 和用户名作为 v 存入redis 存活时间 ~

$redisData = [
            "id" => $userId,
            "username" => $username,
        ];
 $res = cache(config("redis.token_pre") . $token, $redisData, Time::userLoginExpiresTime($data['type']));
  •  

7.最后把前端需要的数据返回

中间件 进行 前端 检测是否登录 2种方法

第一种方法 需要验证login的controller extends 该控制器 进行检测

class AuthBase extends ApiBase
{
    public $userId = 0;
    public $username = "";
    public $accessToken = "";
    public $isLogin = 1;

    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub

//        if ($this->isLogin == 1) {
//            $this->userId = 6; // 测试场景
//            return true;
//        }
        $this->accessToken = $this->request->header("access-token");
        if (!$this->accessToken || !$this->isLogin()) {
            return $this->show(config("status.not_login"), "没有登录");
        }

    }

    /**
     * 判断用户是否登录
     * @return bool
     */
    public function isLogin()
    {
        $userInfo = cache(config("redis.token_pre") . $this->accessToken);
        if (!$userInfo) {
            return false;
        }
        if (!empty($userInfo['id']) && !empty($userInfo['username'])) {
            $this->username = $userInfo['username'];
            $this->userId = $userInfo['id'];
            return true;
        }

        return false;

    }
}

第二种方法使用中间件 进行检测
在api 文件下 创建一个
在这里插入图片描述
修改 middlevare.php 中 对应信息

<?php
declare (strict_types=1);

namespace app\api\middleware;

class Auth
{

    /**
     * 处理请求
     *
     * @param \think\Request $request
     * @param \Closure $next
     * @return Response
     */
    public function handle($request, \Closure $next)
    {
        //前置中间件
//        if (empty(session('adminUser')) && !preg_match("/login/", $request->pathinfo())) {
//            return redirect((string)url('login/index'));
//        }
        //ajax 返回api格式 例如处理rbac

        //这样会处理所有api下的控制器  所以需要

//            return $this->show(config("status.not_login"), "没有登录");
        if (in_array($request->pathinfo(), config('login.need_verify_login')))

            if (!$this->isLogin()) return ajaxReturn(0, '', '未登录,请先登录');

        return $next($request);
    }

    public function end(\think\Response $response)
    {
    }

    /**
     * 判断用户是否登录
     * @return bool
     */
    public function isLogin()
    {

        $token = request()->header("access-token");
        $userInfo = cache(config("redis.token_pre") . $token);
        if (!$userInfo) {
            return false;
        }
        if (!empty($userInfo['id']) && !empty($userInfo['username'])) {
            return true;
        }

        return false;

    }
}

免登录

打开登录界面 前 执行控制器 的 中间件 进行 验证 获得返回数据 进行 重定向至跳转首页 or 等待用户登录

##退出登录
清空当前redis中 k 拼接 对应的token v 为 null
在这里插入图片描述

model 层代码优化

business 逻辑层 在这里插入图片描述
model 层在这里插入图片描述
这里可以父类继承 调用 减少代码量
在这里插入图片描述

面向过程 => 面向对象 统一返回给前端

在这里插入图片描述

模型 使用

在这里插入图片描述
with 会 两次执行sql语句 进行查询 数据量大 大公司常用
withjoin 一次join 查询

sku 建议用2 方便 直接对应sku表的id

统一规格也使用 sku
在这里插入图片描述

系统浏览量 pv

每个商品的浏览量
在这里插入图片描述

商品展示流程

展示商品有自己默认skuid
在这里插入图片描述
用户点击根据skuid 到sku查询到 该商品的goodsid
然后根据goodsid 到goods 获取该商品信息 和 该商品对应的 所有 sku信息
在这里插入图片描述
在这里插入图片描述
这里gids
1,11 :1 : 1 //skuid
1, 11 规格id // 颜色, 尺码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

sku
在这里插入图片描述

购物车

浏览器缓存
mysql redis
存redis 高性能
hash

表如何设计的

流程
1.加入购物车
用户登录状态 点击商品加入购物车
即加入redis 中
(1) 到mysql根据skuid查找该商品的sku数据

2.购物车展示页面

3.购物车删除 修改数量

4.购物车排序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
封装在基础类库
hgetall
在这里插入图片描述
删除 hdel test 1 2
在这里插入图片描述
获取redis 购物车数据 进行排序
在这里插入图片描述
hLen 获取数据

返回值
integer-reply: 哈希集中字段的数量,当 key 指定的哈希集不存在时返回 0

例子
redis> HSET myhash field1 “Hello”
(integer) 1
redis> HSET myhash field2 “World”
(integer) 1
redis> HLEN myhash
(integer) 2
redis>

库存 严谨判断 购物车+ 订单 未支付 …2

hMget 返回 key 指定的哈希集中指定字段的值。 对于哈希集中不存在的每个字段,返回 nil 值。
hGetAll 返回 key 指定的哈希集中所有的字段和值。

在这里插入图片描述

在这里插入图片描述
订单
主表副表在这里插入图片描述

在这里插入图片描述

订单流程

进入 加入 购物车页面 订单确认页面 和 提交订单页面 都需要判断 库存
提交订单流程

  1. 删除购物车 的该商品
  2. 减库存
  3. insert order 主表 副表

redis 延迟队列处理无效订单

用户点击 确定订单时 未支付

存 redis 20分钟有效期 然后脚本每秒 和当前时间比较 小于当前时间的则 把该订单状态改为 已取消 恢复该订单对应sku的库存
存redis 订单id time()+20min
在这里插入图片描述

定时任务

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
暂时有bug 生成 所以要手动挡
在这里插入图片描述
最后在当前tp6 目录的 命令行 运行 php think order 即可开启进程

如果定时任务 进程挂了这么解决? supervise维持进程任务自动重启

支付抽离 单独服务 子服务 微服务

写出用户所有流程

支付流程
从购物车点击进入结算 下单页 先减库存
点击立即付款 跳转支付界面 然后看支付回调
成功 失败 进行数据库处理 库存等等…

Start

前置中间件 检测 是否登录 || 创建一个base来继承 在其中判断 pathinfo 对比
判断前端传来的token 是否存在redis

登录 注册 用redis存储60s 验证码 进行判断 sms . 133333333 验证码 | sms 是标识 拼接手机号 作 k v是验证码 参3存活时间
登录成功 redis 存储 k => user_token . 后台生成唯一token v => 登录的用户信息 然后把token 给header头

进首页 验证
注册登录

  1. 登录流程
    验证登录

购物车
订单
支付

redis 使用场景

posted on 2020-08-27 17:33  冬天不冷-崔俊领  阅读(4783)  评论(0编辑  收藏  举报