tp5(thinkphp 5)后端开发

编译环境
php 7.3.29,windows可能需要找个教程安装一下,
macOs系统自带apache,只需要把 /etc/apache2 路径下的 httpd.conf 关于php的配置的注释取消掉即可。

在这里插入图片描述

依赖包管理器:composer,安装教程,常用命令

创建工程命令:

composer create-project topthink/think 项目名称 --prefer-dist

项目目录结构
我使用的编辑工具是phpStorm

phpStorm的环境配置。

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

开发

前后端分离项目,首先把跨越问题解决了
在这里插入图片描述
public/index.php : 程序的入口文件

if($_SERVER['REQUEST_METHOD'] == 'OPTIONS'){
    
    
    //允许的源域名
    header("Access-Control-Allow-Origin: *");
    //允许的请求头信息
    header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
    //允许的请求类型
    header('Access-Control-Allow-Methods: GET, POST, PUT,DELETE,OPTIONS,PATCH');
    exit;
}

数据库配置
application文件夹下,有一个database.php文件。在里面配置即可。

接下来是建立对象关系映射。
application创建一个模块。有创建模块的命令。
模块名称可以随便起一个合法的名字即可。
在这里我创建了一个index模块,该模块下建立了三个包:controller,model,utils。
model
model包即是用来建立对象关系映射的。
model/Users

<?php

namespace app\index\model;


use think\model;

class Users extends model
{
    
    
	// 只需要把表的名字声明好即可。
    protected $table = 'users';
}

controller
controller是用来实现业务逻辑的。
这里我实现了,注册,注销账户,修改密码,登录,获取所有用户的联系信息,修改某用户的联系信息。
其中,注销账户,修改密码,修改某用户的联系信息是做了权限校验的,确保是本账号才可以操作。
controller/User

<?php

namespace app\index\controller;

use app\index\utils\Token;
use think\Db;
use think\Request;
use think\Exception;
use app\index\model\Users;


class User
{
    
    
    /**
     * 注册
     * 校验函数还可以进行拆分
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function register(){
    
    

        // 获取 请求对象
        $request = Request::instance();
        // 从请求对象中 获取 phone,email, pwd 参数
        $phone = $request->param("phone");
        $email = $request->param("email");
        $pwd = $request->param("pwd");

        // 校验 phone, email, pwd 格式是否正确
        if (!preg_match(PhoneRule, $phone)) {
    
    
            return json(["msg"=>"error! phone 格式不正确"]);
        } elseif (!preg_match(EmailRule, $email)){
    
    
            return json(["msg"=>"error! email 格式不正确"]);
        } elseif (!preg_match(PwdRule, $pwd)){
    
    
            return json(["msg"=>"error! 密码至少包含数字和英文,长度6-20!"]);
        }

        // 查询 phone 或者 email 是否被注册过
        if(Users::where('phone', $phone)->find()){
    
    
            $user = Users::where('phone', $phone)->find();
            return json(["msg"=>"error! phone已被注册!"]);
        }elseif (Users::where('email', $email)->find()){
    
    
            return json(["msg"=>"error! email已被注册!"]);
        }

        // 经过上述的校验都没问题,校验函数返回一个 Users对象
        try {
    
    
            // 插入数据
            $newUser = new Users();
            $newUser->phone = $phone;
            $newUser->email = $email;
            // 对密码加密 ===========
            $newUser->pwd = md5($pwd);
            //========
            // 提交数据
            $newUser->save();

            // 注册:发不发放token?
            $token = 0;

            return json(["msg"=>"success! 注册成功!", "token"=>$token]);
        }catch (Exception $ex){
    
    
            return json(["error"=>$ex, "msg"=>"error! 注册失败!"]);
        }
    }

    /**
     * 登录
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function login(){
    
    
        $request = Request::instance();
        // 手机号码 或者 邮箱登陆
        // 获取 登录的方式 type
        $type = $request->param("type");
        if ($type == "0"){
    
    
            // type = 0, 手机号登录
            // 查询phone
            $phone = $request->param("phone");
            $user = Users::where('phone', $phone)->find();
            if(!$user){
    
    
                return json(["msg"=>"error! 用户不存在!"]);
            }
        }elseif ($type==="1"){
    
    
            // type = 1, 邮箱登录
            // 查询email
            $email = $request->param("email");
            $user = Users::where('email', $email)->find();
            if(!$user){
    
    
                return json(["msg"=>"error! 用户不存在!"]);
            }
        }else{
    
    
            // type 不对,直接返回提示
            return json(["msg"=>"error! 请选择登录方式!"]);
        }
        // 获取到用户的密码,直接加密
        $pwd = md5($request->param("pwd"));
        // 密码 密文比对
        // 根据手机号 查找 密码字段 的内容
        // 然后用户提交加密后的密码进行比对
        if ($user->pwd != $pwd){
    
    
            return json(["msg"=>"error! 密码错误!"]);
        }

        // 发放token
        $token = Token::getToken($user);

        return json(["msg"=>"success! 登录成功!", "token"=>$token]);
    }

    /**
     * 修改密码
     * 需要加token权限
     * 确保是在登录状态才能进行此操作
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function updatePwd(){
    
    
        $request = Request::instance();
        $checkRes = Token::checkToken($request);
        if($checkRes!==true){
    
    
            return json(["msg"=>$checkRes]);
        }
        {
    
    
            // 获取当前用户的 uid 或者 phone 或者 email
            // 根据这些信息查询数据库,获取数据库对象
            // 这里假设根据 phone 来获进行查找
            $phone = $request->param("phone");
            $user = Users::where("phone",$phone)->find();
            $pwd = $request->param("pwd");
            // 修改的密码也需要满足注册用户时的密码规则
            if (!preg_match(PwdRule, $pwd)){
    
    
                return json(["msg"=>"error! 密码至少包含数字和英文,长度6-20!"]);
            }
            $user->pwd = md5($pwd);
            // 保存提交
            $user->save();
            return json(["msg"=>"修改密码成功!"]);
        }

    }

    /**
     * 销毁账号
     * 需要加token权限
     * 确保是在登录状态才能进行此操作
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function destroyUser(){
    
    
        $request = Request::instance();
        // 获取当前用户的 uid 或者 phone 或者 email
        // 根据这些信息查询数据库,获取数据库对象
        // 这里假设根据 phone 来获进行查找

        $checkRes = Token::checkToken($request);
        if ($checkRes!==true){
    
    
            return json(["msg"=>$checkRes]);
        }

        $phone = $request->param("phone");
        $user = Users::where("phone",$phone)->find();
        // 删除提交
        $user->delete();
        return json(["msg"=>"success! 销毁成功!"]);
    }

    /**
     * 获取所有用户的联系信息
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function getUsersContactInfo(){
    
    
        // select() 是选择全部, find() 是选择一条
        $result=Db::name('users')
            ->field('uid,phone,email')
            ->select();
        return json($result);
    }

    /**
     * 修改某用户的联系信息
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function updateUsersContactInfo(){
    
    
        // 获取 请求对象
        $request = Request::instance();

        $checkRes = Token::checkToken($request);
        if ($checkRes!==true){
    
    
            return json(["msg"=>$checkRes]);
        }

        // 从请求对象中 获取 phone,email, pwd 参数
        $phone = $request->param("phone");
        $email = $request->param("email");
        $uid = $request->param("uid");

        // 根据uid获取用户对象
        $user = Users::where('uid', $uid)->find();
        // 检查phone是否为空,为空则说明用户不需要修改phone
        if($phone != ""){
    
    
            // 检查 phone 的格式
            if (!preg_match(PhoneRule, $phone)) {
    
    
                return json(["msg"=>"error! phone 格式不正确"]);
            }
            // 修改用户的 phone
            $user->phone = $phone;
        }
        if($email != ""){
    
    
            // 检查 email 的格式
            if (!preg_match(EmailRule, $email)) {
    
    
                return json(["msg"=>"error! email 格式不正确"]);
            }
            // 修改用户的 email
            $user->email = $email;
        }
        // 保存提交
        $user->save();
        return json(["msg"=>"success! 修改成功!"]);
    }

    public function controllerTest(){
    
    
        test("llll");
    }
}

Token发放和校验
我把Token发放和校验放在utils文件夹下,把它看作是一个工具,封装在Token类里面,但是我只需要里面的处理函数,不需要创建一个Tokne对象,把发放token和校验token用的是静态方法。直接使用类名调用即可。
// 写这个类的时候卡壳了,思路没问题,但是结果和我的预期不一样,这种是最难受的
// 为什么卡壳?
// 对token校验的时候,token的值是用户传过来的,没法预判,所以把用户传过来的token直接放进JWT::decode 里进行校验会出错,所以要做一个异常处理,但是这个异常是 \Exception 类型,我最初写的是think\Exception,一直捕获不到,这个bug找了挺久的。所以,异常的最顶层应该是\Exception吧。

<?php

namespace app\index\utils;

use app\index\model\Users;
use Firebase\JWT\JWT;

class Token
{
    
    
    // 生成token的方式不公开
    private static function generateToken($data){
    
    
        $key = 'key';   //秘钥:自定义
        $payload = array(
            'iss' => 'kary',                      //签发人(官方字段:非必需)
            'aud' => 'public',                    //受众(官方字段:非必需)
            'iat' => time(),                      //签发时间
            'nbf' => time(),                      //生效时间,立即生效
            'exp' => time() + 60*60*24*7,         //过期时间,一周
            'uid' => $data->uid,                        //自定义字段
        );
        //加密生成token
        return JWT::encode($payload, $key);
    }

    // 只公开获取token的方式
    public static function getToken($data){
    
    
        return self::generateToken($data);
    }

    public static function checkToken($request){
    
    
        $authorization = $request->header("authorization");
        // 获取token
        {
    
    
            // 异常捕获无效
            try {
    
    
                $token = substr($authorization,8,-1);
            }catch (\Exception $ex){
    
    
                $token = $authorization;
            }
        }

        try {
    
    
            // 1.如果当前时间大于 exp,或者小于nbf,token无效,进行拦截
            $key = 'key';
            JWT::$leeway = 60;//当前时间减去60,把时间留点余地
            $decode = JWT::decode($token, $key, array('HS256'));
            // 查数据库,用户不存在
            if(Users::where('uid', $decode->uid)->find()){
    
    
                // 比较当前时间大于 exp,或者小于nbf,token无效,进行拦截
                if($decode->nbf > time()){
    
    
                    return "权限伪造!";
                }elseif ($decode->exp < time()){
    
    
                    return "权限过期,请重新登录!";
                }
            }else{
    
    
                return "账户不存在!";
            }
        }catch (\Exception $ex){
    
    
            // token 无效
            return "权限不足!";
        }
        return true;
    }
}

其中在用户注册和登录的时候,需要对用户提交的手机号码,电子邮箱,密码的格式进行校验,需要用到正则表达式进行判别,正则表达是太长了,为了使代码尽可能简洁,把正则表达式放到常量文件里面定义,用的时候直接使用表达式的名字即可。响应体也可以封装在这里。
application/common.php

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <[email protected]>
// +----------------------------------------------------------------------

// 应用公共文件

// 校验表达式
define('PhoneRule', "/^1[3456789]\d{9}$/");
define('EmailRule', "/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/");
define('PwdRule', "/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/");

// 响应体 统一封装
function writeJson($code, $data, $msg = 'ok', $errorCode = 0)
{
    
    
    $data = [
        'code' => $errorCode,
        'result' => $data,
        'message' => $msg
    ];
    return json($data, $code);
}

路由
public文件夹下有一个route.php,
application 文件夹下也有一个route.php,
public文件夹下的route.php应该是主路由,application 文件夹下route.php的路由是子路由。
这两个路由的关系在请求接口时会体现。
public文件夹下route.php,可以不用管,把精力放在application 文件夹下route.php。

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <[email protected]>
// +----------------------------------------------------------------------

use think\Route;
// route参数的controller可以省略

// 增:注册
Route::post('/register','index/User/register');
// 删:注销账户
Route::post('/destroyUser', 'index/User/destroyUser');
// 改:修改密码
Route::post('/updatePwd', 'index/User/updatePwd');
// 查:登录
Route::post('/login', 'index/User/login');
// 查:获取所有用户的联系信息
Route::get('/getUsersContactInfo', 'index/User/getUsersContactInfo');
// 改:修改某用户的联系信息
Route::put('/updateUsersContactInfo', 'index/User/updateUsersContactInfo');


// 测试接口
Route::get('/controllerTest', 'index/User/controllerTest');


// 借口测试
Route::get('/test', function () {
    
    

    // find 查找只能找到一条记录
    $all = \app\index\model\IwalaCurrency::all();
    echo "\njust is one case!\n";
    return json($all);
});
Route::get(路由路径, 执行函数);

最近熟悉php和tp5做得一些事情。分享一下!!!

猜你喜欢

转载自blog.csdn.net/wjl__ai__/article/details/124675856
tp5