"thinkphp5开发restful-api接口" 教程视频 配套文档

11,638 阅读17分钟

视频配套文档, 为知笔记链接失效, 转至掘金 :)

视频教程地址:

thinkphp5开发restful-api接口

正文


课程简介

主要内容

  1. 基于thinkphp5框架, 为移动端APP开发数据接口
  2. php程序员最常见的工作

为app写后台 为app写接口

什么是thinkphp5?

  1. thinkphp5 是php框架thinkphp的最新的一个版本
  2. thinkphp官网
  3. thinkphp5手册
  4. thinkphp的优点

简单易用 功能齐全 利于扩展 方便学习 开发速度快 教程丰富

什么是restful api?

  • 一套api的设计规范

RESTful API 设计指南

为什么是这种搭配

  • 兼顾api和后台

php: thinkphp5 + thinkcmf python: django + xadmin

本课程用到的工具

  1. php开发环境:phpstudy ==> windows + apache + mysql + php
  2. 编辑器:sublime
  3. 接口测试工具:postman
  4. 数据库工具:navicat for mysql

本课程的风格

  1. 通俗易懂
  2. 配套文档

本课程的学习基础

  1. 有php基础
  2. 熟悉mysql数据库

本课程的收获

  1. 学会了一门新的框架
  2. 学会如何为APP提供接口

第1节 常用工具介绍

sublime(最性感的编辑器)

  • 最性感的编辑器

启动速度快(C++) 插件众多(python)

下载sublime

安装版和绿色便携版的区别

  1. 安装板支持右键菜单, 但是不方便迁移
  2. 绿色便携版方便迁移, 但是不支持右键菜单
  3. 推荐绿色便携版, 右键菜单解决方案(sublime_addright.inf)
[Version]
Signature="$Windows NT$"

[DefaultInstall]
AddReg=SublimeText3

[SublimeText3]
hkcr,"*\\shell\\SublimeText3",,,"用 SublimeText3 打开"
hkcr,"*\\shell\\SublimeText3\\command",,,"""%1%\sublime_text.exe"" ""%%1"" %%*"
hkcr,"Directory\shell\SublimeText3",,,"用 SublimeText3 打开"
hkcr,"*\\shell\\SublimeText3","Icon",0x20000,"%1%\sublime_text.exe, 0"
hkcr,"Directory\shell\SublimeText3\command",,,"""%1%\sublime_text.exe"" ""%%1"""

激活sublime

  1. 不激活, 也没事
  2. 激活码, 简单方便
  3. 激活码
—– BEGIN LICENSE —–
Michael Barnes
Single User License
EA7E-821385
8A353C41 872A0D5C DF9B2950 AFF6F667
C458EA6D 8EA3C286 98D1D650 131A97AB
AA919AEC EF20E143 B361B1E7 4C8B7F04
B085E65E 2F5F5360 8489D422 FB8FC1AA
93F6323C FD7F7544 3F39C318 D95E6480
FCCC7561 8A4A1741 68FA4223 ADCEDE07
200C25BE DBBC4855 C4CFB774 C5EC138C
0FEC1CEF D9DCECEC D3A5DAD1 01316C36
—— END LICENSE ——
  1. 更多激活码

sublime常用配置

{
    "font_face": "YaHei Consolas Hybrid", // 字体名称
    "font_size": 13, // 字体大小
    "save_on_focus_lost": true, // 自动保存
    "word_wrap": true, // 开启自动换行
}

sublime安装插件

  1. 插件官网
  2. 安装package control(ctrl + ~)
import urllib.request,os,hashlib; h = 'df21e130d211cfc94d9b0905775a7c0f' + '1e3d39e33b79698005270310898eea76'; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); by = urllib.request.urlopen( 'http://packagecontrol.io/' + pf.replace(' ', '%20')).read(); dh = hashlib.sha256(by).hexdigest(); print('Error validating download (got %s instead of %s), please try manual install' % (dh, h)) if dh != h else open(os.path.join( ipp, pf), 'wb' ).write(by)
  1. 搜索插件(ctrl + shift + p, package install)
  2. 安装

postman(接口测试)

  1. postman的前世今生
  2. 官方文档 (全英文, 图文并茂)
  3. 测试接口

心知天气接口: api.seniverse.com/v3/weather/…

  1. 常用设置

选择 http 方法 自动生成代码 接口鉴权 设置接受数据的方式 设置字体大小 保存接口以备后用 post 参数的两种方式

navicat(数据库管理)

  1. 下载与安装
  2. 新建mysql连接
  3. 新建数据库
  4. 新建数据表(图形化界面/自动完成)
  5. 查看表结构
  6. 原生sql查询
  7. 导入/导出数据库

phpstudy(php开发环境)

  1. 为什么选择phpstudy

一次性安装,无须配置即可使用 完美支持win10, 支持自定义php版本

  1. 启动/停止/重启

运行环境(选择 非系统模式 就可以了) 支持右键分开启停 切换版本(切记: NTS版本的PHP,APACHE不支持REWRITE! )

  1. 快速跳转配置文件

php-ini php配置文件(自动识别版本 http-conf apache配置文 mysql-ini mysql配置文 vhosts-conf apache虚拟主机配置文

  1. 快速跳转软件位置

hosts 网站根目录

  1. 查看phpinfo

phpinfo路径: G:\phpStudy\WWW\phpinfo.php

  1. php扩展及设置

php扩展 (等于直接操作 php.ini ) 参数开关设置 (等于直接操作 php.ini ) 参数值设置 (等于直接操作 php.ini )

  1. 操作mysql

快速打开命令行 快速新建数据库 设置mysql (等于直接操作 mysql.ini ) MYSQL工具 =====> 参数值设置

  1. 为apache增加模块 (等于直接操作 httpd.conf )

第2节 以豆瓣网为例, 讲解restful api设计规范

什么是restful api

  • 目前比较成熟的一套互联网应用程序的API设计理论

豆瓣电影api

  1. 应该尽量将API部署在专用域名之下

http://api.douban.com/v2/user/1000001?apikey=XXX

  1. 应该将API的版本号放入URL

http://api.douban.com/v2/user/1000001?apikey=XXX

  1. 在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数。

api.douban.com/v2/book/:id (获取图书信息) api.douban.com/v2/movie/subject/:id (电影条目信息) api.douban.com/v2/music/:id (获取音乐信息) api.douban.com/v2/event/:id (获取同城活动)

  1. 对于资源的具体操作类型,由HTTP动词表示。常用的HTTP动词有下面四个(对应增/删/改/查)。

GET(select):从服务器取出资源(一项或多项)。 eg. 获取图书信息 GET api.douban.com/v2/book/:id POST(create):在服务器新建一个资源。 eg. 用户收藏某本图书 POST api.douban.com/v2/book/:id… PUT(update):在服务器更新资源(客户端提供改变后的完整资源)。 eg. 用户修改对某本图书的收藏 PUT api.douban.com/v2/book/:id… DELETE(delete):从服务器删除资源。 eg. 用户删除某篇笔记 DELETE api.douban.com/v2/book/ann…

  1. 如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果

?limit=10:指定返回记录的数量 eg. 获取图书信息 GET api.douban.com/v2/book/:id?limit=10

  1. 服务器向用户返回的状态码和提示信息

每个状态码代表不同意思, 就像代号一样 2系 代表正常返回 4系 代表数据异常 5系 代表服务器异常

错误码 错误信息 含义 状态码
6000 book_not_found 图书不存在 404
6002 unauthorized_error 没有修改权限 403
6004 review_content_short(should more than 150) 书评内容过短(需多于150字) 400
6006 review_not_found 书评不存在 404
6007 not_book_request 不是豆瓣读书相关请求 403
6008 people_not_found 用户不存在 404
6009 function_error 服务器调用异常 400
6010 comment_too_long(should less than 350) 短评字数过长(需少于350字) 400
6011 collection_exist(try PUT if you want to update) 该图书已被收藏(如需更新请用PUT方法而不是POST) 409
6012 invalid_page_number(should be digit less than 1000000) 非法页码(页码需要是小于1000000的数字) 400
6013 chapter_too_long(should less than 100) 章节名过长(需小于100字) 400

接口安全

  1. API的身份认证应该使用OAuth 2.0框架。
  2. 技术团队自己约定的规则

增加两个参数 time, token time为时间戳, 用于判断接口请求是否超时 token为时间戳加密后的字符串, 加密规则只有你们技术团队自己知道


第3节 thinkphp5简易教程

什么是thinkphp

  1. 国人开发的php框架
  2. 源码中文注释, 方便理解
  3. 中文文档详尽
  4. 使用者多, 教程丰富

官网

安装

  1. 官网下载, 复制粘贴
  2. 检查环境
  3. 访问public文件夹

配置虚拟主机

  1. 配置vhosts-conf
  2. 修改hosts

URL路径设计

格式化php代码

  1. 安装phpfmt插件

ctrl+shift+p 搜索phpfmt enter

  1. 配置插件
{
    "format_on_save": true,
    "php_bin": "G:/phpStudy/php/php-7.0.12-nts/php.exe",
}
  1. psr1和psr2区别

花括号点位置不同

API友好

<?php
namespace app\index\controller;
class Index {
    public function index() {
        $data = array(
            'name' => 'red_panda',
            'address' => 'China',
        );
        $code = 200;
        $msg = 'ok';
        return ['data' => $data, 'code' => $code, 'message' => $msg];
    }
}
'default_return_type'=>'json'

获取请求参数

<?php
namespace app\index\controller;
use \think\Request;
class Index {
    public function index() {
        $request = Request::instance();
        echo '请求方法:' . $request->method() . '<br/>';
        echo '访问地址:' . $request->ip() . '<br/>';
        echo '请求参数:';
        dump($request->param());
        echo '请求参数:仅包含name,sex';
        dump($request->only(['name', 'sex']));
        echo '请求参数:排除name,sex';
        dump($request->except(['name', 'sex']));
    }
}

判断请求类型

// 是否为 GET 请求
if (Request::instance()->isGet()) echo "当前为 GET 请求";
// 是否为 POST 请求
if (Request::instance()->isPost()) echo "当前为 POST 请求";
// 是否为 PUT 请求
if (Request::instance()->isPut()) echo "当前为 PUT 请求";
// 是否为 DELETE 请求
if (Request::instance()->isDelete()) echo "当前为 DELETE 请求";
// 是否为 Patch 请求
if (Request::instance()->isPatch()) echo "当前为 PATCH 请求";

验证参数数据

<?php
namespace app\index\controller;
use \think\Validate;
class Index {
    public function index() {
        $rule = [
            'name' => 'require|max:25',
            'age' => 'number|between:1,120',
            'email' => 'email',
        ];
        $msg = [
            'name.require' => '名称必须',
            'name.max' => '名称最多不能超过25个字符',
            'age.number' => '年龄必须是数字',
            'age.between' => '年龄只能在1-120之间',
            'email' => '邮箱格式错误',
        ];
        $data = input('post.');
        $validate = new Validate($rule, $msg);
        $result = $validate->check($data);
        if (!$validate->check($data)) {
            dump($validate->getError());
        }
    }
}

连接数据库

/* 数据库设置 */
'database' => [
    // 数据库类型
    'type'        => 'mysql',
    // 服务器地址
    'hostname'    => '127.0.0.1',
    // 数据库名
    'database'    => 'thinkphp',
    // 数据库用户名
    'username'    => 'root',
    // 数据库密码
    'password'    => '',
    // 数据库连接端口
    'hostport'    => '',
    // 数据库连接参数
    'params'      => [],
    // 数据库编码默认采用utf8
    'charset'     => 'utf8',
    // 数据库表前缀
    'prefix'      => '',
    // 数据库调试模式
    'debug'       => false,
],

原生sql语句查询

<?php
namespace app\index\controller;
use think\Db;
class Index
{
    public function index()
    {
        $res = Db::query('select version()');
        return $res;
    }
}

第4节 为api项目搭建数据库

什么是数据库三大范式

  1. 每一列都是不可分割的原子数据项
  2. 实体的属性完全依赖于主关键字
  3. 任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)

数据库中设计中的常见问题

  1. 字段混在了一起

  1. 数据表混在了一起

  1. 不会处理表关系

一对一 (学生姓名, 学号) 一对多 (老师, 学生) 多对多 (学生, 课程)

设计数据库的小技巧

  1. 一个对象, 一张表
  2. 一张表, 一个主键
  3. 表名中有数据库名做前缀
  4. 字段名中有表名做前缀
  5. 前缀后加缩写
  6. 数据表关系处理

范式越高越好?


第5节 使用markdown书写接口文档

基本语法

  1. 六级标题
  2. 目录索引
  3. 加粗
  4. 斜体
  5. 删除线
  6. 引用
  7. 代码段
  8. 表格
  9. 行内代码
  10. 无序列表
  11. 有序列表
  12. 图片
  13. 超链接

用户登录举例

---
    # 第6节(判断数据库中是否有此用户)
    > `post`  ~~www.test.com/api~~  `api.test.com`
    |参数|必选|类型|说明|
    |:-|:-:|:-:|:-|
    |*time*|*true*|*int*|*时间戳* (用于确定接口的访问时间)|
    |*token*|*true*|*string*|*确定访问者身份* (`MD5(USER_MD5(time)_USER)`)|
    |username    |true    |string|只接受`手机号`|
    |password    |true    |string   |用户密码|
    ``` javascript
    {
        "ret": 200, // 返回结果状态。200:接口正常请求并返回/40*:服务端的数据有误/500:服务器运行错误
        "data": {
            "user_id": "27", // 用户id
            "user_tag": "1" // 用户身份
        },
        "msg": "" // 401:用户名不存在!/402:手机号不存在!/403:密码不正确!
    }
    ```

第7节 为项目配置URL

需求分析

  • api.tp5.com/user/2 ===> www.tp5.com/index.php/api/user/index/id/2

配置主域名和二级域名

  1. 打开phpstudy
  2. 其他选项菜单 ==> 站点域名管理

网站域名:www.tp5.com 网站域名:G:\phpStudy\WWW\tp5\public 第二域名:api.tp5.com 网站端口: 80

  1. 配置hosts(域名重定向)
127.0.0.1 www.tp5.com
127.0.0.1 api.tp5.com

使用tp5路由进行URL解析

  1. 为sublime安装新插件(方便操作侧边栏)

package control: install package SideBarEnhancements

  1. 新建user.php文件

路径:G:\phpStudy\WWW\tp5\application\api\controller\User.php

<?php
namespace app\api\controller;

class User{
    public function index($id){
        echo 'controller: user          function: index';
        echo '<br/>';
        echo $id;
    }
}
  1. 修改config.php(开启路由功能)

路径:G:\phpStudy\WWW\tp5\application\config.php

// 是否开启路由
'url_route_on' => true,
  1. 配置路由规则

路径:G:\phpStudy\WWW\tp5\application\route.php

<?php
use think\Route;

// api.tp5.com ===> www.tp5.com/index.php/api
Route::domain('api','api');
// api.tp5.com/user/2 ===> www.tp5.com/index.php/api/user/index/id/2
Route::rule('user/:id','user/index');

第8节 接口安全

常见的安全问题以及解决方案

  1. 接口被大规模调用消耗系统资源,影响系统的正常访问,甚至系统瘫痪

解决方案: 获取 timestamp (时间戳), 设置接口失效时间

  1. 接口数据被黑客篡改(伪造请求)

解决方案: 对参数加密, 生成 token , 判断 token 是否正确

  1. 数据被黑客截取

解决方案: 使用 https , 用证书对数据进行加密, 即使数据被截取, 对黑客也没有意义

黑客可以获取数据, 但是无法获取数据的加密方法

我们api项目的安全设计

  1. time

时间戳, 用于判断请求是否超时, 设置为30秒

  1. token

其他参数加密而来, 保证数据不被篡改

  1. 敏感信息加密传输

接收加密过的用户密码, 用户密码永不返回 最好使用 https, 所有信息都会被加密

第9节 接口开发前的准备工作(参数过滤)

配置路由

  1. 开启路由功能

G:\phpStudy\WWW\tp5\application\config.php

// 是否开启路由
'url_route_on' => true,
// 域名部署
'url_domain_deploy' => true,
  1. 配置route.php

G:\phpStudy\WWW\tp5\application\route.php

<?php
use think\Route;

// api.tp5.com ===> www.tp5.com/index.php/api
Route::domain('api','api');
// post api.tp5.com/user  --->  user.php login()
Route::post('user','user/login');

使用common.php统一处理参数过滤 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

<?php
namespace app\api\controller;
use think\Controller;
use think\Request;
use think\Validate;
class Common extends Controller {
    protected $request; // 用来处理参数
    protected $validater; // 用来验证数据/参数
    protected $params; // 过滤后符合要求的参数
    protected $rules = array(
            'User'=>array(......);
    protected function _initialize() {
        parent::_initialize();
        $this->request = Request::instance();
        $this->check_time($this->request->only(['time']));
        $this->check_token($this->request->param());
        $this->params = $this->check_params($this->request->except(['time','token']));
    }

自定义返回信息函数 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

 
/**
* api 数据返回
 
 * @param  [int] $code [结果码 200:正常/4**数据问题/5**服务器问题]
 * @param  [string] $msg  [接口要返回的提示信息]
 * @param  [array]  $data [接口要返回的数据]
 * @return [string]       [最终的json数据]
*/
public function return_msg($code, $msg = '', $data = []) {
 
    /*********** 组合数据  ***********/
    $return_data['code'] = $code;
    $return_data['msg']  = $msg;
    $return_data['data'] = $data;
 
    /*********** 返回信息并终止脚本  ***********/
    echo json_encode($return_data);die;
}

验证time G:\phpStudy\WWW\tp5\application\api\controller\Common.php

 
/**
* 验证请求是否超时
 * @param  [array] $arr [包含时间戳的参数数组]
 * @return [json]      [检测结果]
*/
public function check_time($arr) {
    if (!isset($arr['time']) || intval($arr['time']) <= 1) {
        $this->return_msg(400, '时间戳不正确!');
    }
    if (time() - intval($arr['time']) > 60) {
        $this->return_msg(400, '请求超时!');
    }
}

验证token G:\phpStudy\WWW\tp5\application\api\controller\Common.php

 
/**
* 验证token(防止篡改数据)
 * @param  [array] $arr [全部请求参数]
 * @return [json]      [token验证结果]
*/
public function check_token($arr) {
 
    /*********** api传过来的token  ***********/
    if (!isset($arr['token']) || empty($arr['token'])) {
        $this->return_msg(400, 'token不能为空!');
    }
    $app_token = $arr['token']; // api传过来的token
 
    /*********** 服务器端生成token  ***********/
    unset($arr['token']);
    $service_token = '';
    foreach ($arr as $key => $value) {
        $service_token .= md5($value);
    }
    $service_token = md5('api_' . $service_token . '_api'); // 服务器端即时生成的token
 
    /*********** 对比token,返回结果  ***********/
    if ($app_token !== $service_token) {
        $this->return_msg(400, 'token值不正确!');
    }
}

为每个接口配置验证规则 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

protected $rules = array(
    'User' => array(
        'login' => array(
            'user_name' => ['require', 'chsDash', 'max' => 20],
            'user_pwd'  => 'require|length:32',
        ),
    ),
);

验证参数 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

 
/**
* 验证参数 参数过滤
 * @param  [array] $arr [除time和token外的所有参数]
 * @return [return]      [合格的参数数组]
*/
public function check_params($arr) {
 
    /*********** 获取参数的验证规则  ***********/
    $rule = $this->rules[$this->request->controller()][$this->request->action()];
 
    /*********** 验证参数并返回错误  ***********/
    $this->validater = new Validate($rule);
    if (!$this->validater->check($arr)) {
        $this->return_msg(400, $this->validater->getError());
    }
 
    /*********** 如果正常,通过验证  ***********/
    return $arr;
}

第9节 获取验证码

接口文档 新建api_user表

DROP TABLE IF EXISTS `api_user`;
CREATE TABLE `api_user` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_phone` char(11) NOT NULL,
  `user_nickname` varchar(255) NOT NULL COMMENT '昵称',
  `user_email` varchar(255) NOT NULL,
  `user_rtime` int(11) NOT NULL COMMENT 'register time',
  `user_pwd` char(32) NOT NULL,
  `user_icon` varchar(255) NOT NULL COMMENT '用户头像',
  PRIMARY KEY (`user_id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

验证码原理

  1. 生成及发送
  • 点击获取手机码
  • 发送手机号到后台
  • 后台生成手机码
  • 用session保存手机码及手机号
  • 用短信发送平台的接口发送出去
  1. 验证
  • 获取用户输入的手机码及手机号
  • 取出session保存的内容
  • 对比验证
  • 返回信息, 结束

配置路由

注意: get方式没有参数名, 所以要注意参数的顺序, 对号入座.

G:\phpStudy\WWW\tp5\application\route.php

// 获取验证码
Route::get('code/:time/:token/:username/:is_exist','code/get_code');

参数过滤

在common.php里简单过滤, 具体验证放在code.php里

G:\phpStudy\WWW\tp5\application\api\controller\Common.php

'Code' => array(
    'get_code' => array(
        'username' => 'require',
        'is_exist' => 'require|number|length:1',
    ),
),

检测用户名 G:\phpStudy\WWW\tp5\application\api\controller\Code.php

namespace app\api\controller;
use phpmailer\phpmailer;
use submail\messagexsend;
 
class Code extends Common {
    public function get_code() {
        $username      = $this->params['username'];
        $exist         = $this->params['is_exist'];
        $username_type = $this->check_username($username); // 检查用户名, 决定用下面哪那个函数
        switch ($username_type) {
        case 'phone':
            $this->get_code_by_username($username, 'phone', $exist); // 通过手机获取验证码
            break;
        case 'email':
            $this->get_code_by_username($username, 'email', $exist); // 通过邮箱获取验证码
            break;
        }
    }
}

G:\phpStudy\WWW\tp5\application\api\controller\Common.php

public function check_username($username) {
    /*********** 判断是否为邮箱  ***********/
    $is_email = Validate::is($username, 'email') ? 1 : 0;
    /*********** 判断是否为手机  ***********/
    $is_phone = preg_match('/^1[34578]\d{9}$/', $username) ? 4 : 2;
    /*********** 最终结果  ***********/
    $flag = $is_email + $is_phone;
    switch ($flag) {
    /*********** not phone not email  ***********/
    case 2:
        $this->return_msg(400, '邮箱或手机号不正确!');
        break;
    /*********** is email not phone  ***********/
    case 3:
        return 'email';
        break;
    /*********** is phone not email  ***********/
    case 4:
        return 'phone';
        break;
    }
}

通过用户名(手机/邮箱)获取验证码 G:\phpStudy\WWW\tp5\application\api\controller\Code.php

public function get_code_by_username($username, $type, $exist) {
    if ($type == 'phone') {
        $type_name = '手机';
    } else {
        $type_name = '邮箱';
    }
    /*********** 检测手机号/邮箱是否存在  ***********/
    $this->check_exist($username, $type, $exist);
    /*********** 检查验证码请求频率 30秒一次  ***********/
    if (session("?" . $username . '_last_send_time')) {
        if (time() - session($username . '_last_send_time') < 30) {
            $this->return_msg(400, $type_name . '验证码,每30秒只能发送一次!');
        }
    }
    /*********** 生成验证码  ***********/
    $code = $this->make_code(6);
    /*********** 使用session存储验证码, 方便比对, md5加密   ***********/
    $md5_code = md5($username . '_' . md5($code));
    session($username . '_code', $md5_code);
    /*********** 使用session存储验证码的发送时间  ***********/
    session($username . '_last_send_time', time());
    /*********** 发送验证码  ***********/
    if ($type == 'phone') {
        $this->send_code_to_phone($username, $code);
    } else {
        $this->send_code_to_email($username, $code);
    }
}

判断用户名(手机/邮箱)是否应该存在 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

public function check_exist($value, $type, $exist) {
    $type_num  = $type == "phone" ? 2 : 4;
    $flag      = $type_num + $exist;
    $phone_res = db('user')->where('user_phone', $value)->find();
    $email_res = db('user')->where('user_email', $value)->find();
    switch ($flag) {
    /*********** 2+0 phone need no exist  ***********/
    case 2:
        if ($phone_res) {
            $this->return_msg(400, '此手机号已被占用!');
        }
        break;
    /*********** 2+1 phone need exist  ***********/
    case 3:
        if (!$phone_res) {
            $this->return_msg(400, '此手机号不存在!');
        }
        break;
    /*********** 4+0 email need no exist  ***********/
    case 4:
        if ($email_res) {
            $this->return_msg(400, '此邮箱已被占用!');
        }
        break;
    /*********** 4+1 email need  exist  ***********/
    case 5:
        if (!$email_res) {
            $this->return_msg(400, '此邮箱不存在!');
        }
        break;
    }
}

生成验证码 G:\phpStudy\WWW\tp5\application\api\controller\Code.php

public function make_code($num) {
    $max = pow(10, $num) - 1;
    $min = pow(10, $num - 1);
    return rand($min, $max);
}

通过邮箱发送验证码

去邮箱开启smtp php需要开启php_openssl 现在phpmailer并把需要的文件添加进thinkphp5

  • G:\phpStudy\WWW\tp5\extend\phpmailer\phpmailer.php
namespace phpmailer;
use phpmailer\smtp;
class PHPMailer ......
class phpmailerException extends \Exception...... // 需要加\
  • G:\phpStudy\WWW\tp5\extend\phpmailer\smtp.php
namespace phpmailer;
class SMTP ......

G:\phpStudy\WWW\tp5\application\api\controller\Code.php

public function send_code_to_email($email, $code) {
    $toemail = $email;
    $mail    = new PHPMailer();
    $mail->isSMTP();
    $mail->CharSet    = 'utf8'; // 设置字符集
    $mail->Host       = 'smtp.126.com'; // smtp服务器
    $mail->SMTPAuth   = true;
    $mail->Username   = "xujunhao_api@126.com";
    $mail->Password   = "xujunhao890518"; // 自己设置的smtp密码, 与登录密码无关
    $mail->SMTPSecure = 'ssl';
    $mail->Port       = 994;
    $mail->setFrom('xujunhao_api@126.com', '接口测试');
    $mail->addAddress($toemail, 'test');
    $mail->addReplyTo('xujunhao_api@126.com', 'Reply');
    $mail->Subject = "您有新的验证码!"; // 邮件标题
    $mail->Body    = "这是一个测试邮件,您的验证码是$code,验证码的有效期为1分钟,本邮件请勿回复!"; // 邮件内容
    if (!$mail->send()) {
        $this->return_msg(400, $mail->ErrorInfo);
    } else {
        $this->return_msg(200, '验证码已经发送成功,请注意查收!');
    }
}

通过手机发送验证码 使用submail(赛迪云通信)

  1. 通过调用接口发送短信
  • 开启php_curl
  • 安装本地证书下载证书
  • G:\phpStudy\php\php-5.5.38\php.ini
[curl]
; A default value for the CURLOPT_CAINFO option. This is required to be an
; absolute path.
curl.cainfo = "G:\phpStudy\php\php-5.5.38\cacert.pem"
  • G:\phpStudy\WWW\tp5\application\api\controller\Code.php
public function send_code_to_phone($phone, $code) {
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, 'https://api.mysubmail.com/message/xsend');
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_POST, 1);
    $data = [
        'appid'   => '15180',
        'to'      => $phone,
        'project' => '9CTTG2',
        'vars'    => '{"code":' . $code . ',"time":"60"}',
        'signature'=>'76a9e82484c83345b7850395ceb818fb',
    ];
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    $res = curl_exec($curl);
    curl_close($curl);
    $res = json_decode($res);
    if ($res->status != 'success') {
        $this->return_msg(400,$res->msg);
    }else{
        $this->return_msg(200,'手机验证码已发送, 每天发送5次, 请在一分钟内验证!');
    }
    dump($res->staus);die;
}
  1. 使用sdk发送验证码
  • 下载sdk, 把需要的文件加入thinkphp5
  • G:\phpStudy\WWW\tp5\extend\submail\message.php
namespace submail;
class message {......
  • G:\phpStudy\WWW\tp5\extend\submail\messagexsend.php
namespace submail;
use submail\message;
class MESSAGEXsend {

    protected $appid = '';

    protected $appkey = '';

    protected $sign_type = '';

    protected $To = array();

    protected $Addressbook = array();

    protected $Project = '';

    protected $Vars = array();

    function __construct() {
        $this->appid  = "15180";
        $this->appkey = "76a9e82484c83345b7850395ceb818fb";
        $this->sign_type = 'normal';
    }
  • G:\phpStudy\WWW\tp5\application\api\controller\Code.php
public function send_code_to_phone($phone, $code) {
    $submail = new MESSAGEXsend();
    $submail->SetTo($phone);
    $submail->SetProject('9CTTG2');
    $submail->AddVar('code', $code);
    $submail->AddVar('time', 60);
    $xsend = $submail->xsend();
    if ($xsend['status'] !== 'success') {
        $this->return_msg(400, $xsend['msg']);
    } else {
        $this->return_msg(200, '手机验证码已发送, 每天发送5次, 请在一分钟内验证!');
    }
}

第10节 用户注册

接口文档 配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 用户注册
Route::post('user/register','user/register');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

protected $rules = array(
    'User' => array(
        'register' => array(
            'user_name' => 'require',
            'user_pwd'  => 'require|length:32',
            'code'      => 'require|number|length:6',
        ),
    ),
);

关闭数据库字段检查 G:\phpStudy\WWW\tp5\application\database.php

// 是否严格检查字段是否存在
'fields_strict'   => false,

书写register函数 G:\phpStudy\WWW\tp5\application\api\controller\User.php

public function register() {
    /*********** 接收参数  ***********/
    $data = $this->params;
    /*********** 检查验证码  ***********/
    $this->check_code($data['user_name'], $data['code']);
    /*********** 检测用户名  ***********/
    $user_name_type = $this->check_username($data['user_name']);
    switch ($user_name_type) {
    case 'phone':
        $this->check_exist($data['user_name'], 'phone', 0);
        $data['user_phone'] = $data['user_name'];
        break;
    case 'email':
        $this->check_exist($data['user_name'], 'email', 0);
        $data['user_email'] = $data['user_name'];
        break;
    }
    /*********** 将用户信息写入数据库  ***********/
    unset($data['user_name']);
    $data['user_rtime'] = time(); // register time
    $res                = db('user')->insert($data);
    if (!$res) {
        $this->retrun_msg(400, '用户注册失败!');
    } else {
        $this->return_msg(200, '用户注册成功!');
    }
}

检查验证码 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

public function check_code($user_name, $code) {
    /*********** 检测是否超时  ***********/
    $last_time = session($user_name . '_last_send_time');
    if (time() - $last_time > 60) {
        $this->return_msg(400, '验证超时,请在一分钟内验证!');
    }
    /*********** 检测验证码是否正确  ***********/
    $md5_code = md5($user_name . '_' . md5($code));
    if (session($user_name . "_code") !== $md5_code) {
        $this->return_msg(400, '验证码不正确!');
    }
    /*********** 不管正确与否,每个验证码只验证一次  ***********/
    session($user_name . '_code', null);
}

第11节 用户登录

接口文档 配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 用户登录
Route::post('user/login','user/login');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

protected $rules = array(
    'User' => array(
        'login'    => array(
            'user_name' => 'require',
            'user_pwd'  => 'require|length:32',
        ),
    ),
);

书写login函数 G:\phpStudy\WWW\tp5\application\api\controller\User.php

public function login() {
    /*********** 接收参数  ***********/
    $data = $this->params;
    /*********** 检测用户名  ***********/
    $user_name_type = $this->check_username($data['user_name']);
    switch ($user_name_type) {
    case 'phone':
        $this->check_exist($data['user_name'], 'phone', 1);
        $db_res = db('user')
            ->field('user_id,user_name,user_phone,user_email,user_rtime,user_pwd')
            ->where('user_phone', $data['user_name'])
            ->find();
        break;
    case 'email':
        $this->check_exist($data['user_name'], 'email', 1);
        $db_res = db('user')
            ->field('user_id,user_name,user_phone,user_email,user_rtime,user_pwd')
            ->where('user_email', $data['user_name'])
            ->find();
        break;
    }
    if ($db_res['user_pwd'] !== $data['user_pwd']) {
        $this->return_msg(400, '用户名或者密码不正确!');
    } else {
        unset($db_res['user_pwd']); // 密码永不返回
        $this->return_msg(200, '登录成功!', $db_res);
    }
}

第12节 用户上传头像

接口文档 配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 用户上传你头像
Route::post('user/icon','user/upload_head_img');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

protected $rules = array(
    'User' => array(
        'upload_head_img' => array(
            'user_id'   => 'require|number',
            'user_icon' => 'require|image|fileSize:2000000000|fileExt:jpg,png,bmp,jpeg',
        ),
    ),
);

修改参数过滤 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

$this->params = $this->check_params($this->request->param(true));

编写upload_head_img函数 G:\phpStudy\WWW\tp5\application\api\controller\User.php

public function upload_head_img() {
    /*********** 接收参数  ***********/
    $data = $this->params;
    /*********** 上传文件,获得路径  ***********/
    $head_img_path = $this->upload_file($data['user_icon'], 'head_img');
    /*********** 存入数据库  ***********/
    $res = db('user')->where('user_id', $data['user_id'])->setField('user_icon', $head_img_path);
    if ($res) {
        $this->return_msg(200, '头像上传成功!', $head_img_path);
    } else {
        $this->return_msg(400, '上传头像失败!');
    }
}

编写upload_file函数 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

public function upload_file($file, $type = '') {
    $info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
    if ($info) {
        $path = '/uploads/' . $info->getSaveName();
        /*********** 裁剪图片  ***********/
        if (!empty($type)) {
            $this->image_edit($path, $type);
        }
        return str_replace('\\', '/', $path);
    } else {
        $this->return_msg(400, $file->getError());
    }
}

编写image_edit函数 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

public function image_edit($path, $type) {
    $image = Image::open(ROOT_PATH . 'public' . $path);
    switch ($type) {
    case 'head_img':
        $image->thumb(200, 200, Image::THUMB_CENTER)->save(ROOT_PATH . 'public' . $path);
        break;
    }
}

第13节 用户修改密码

接口文档 配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 用户修改密码
Route::post('user/change_pwd','user/change_pwd');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

protected $rules = array(
    'User' => array(
        'change_pwd'      => array(
            'user_name'    => 'require',
            'user_ini_pwd' => 'require|length:32',
            'user_pwd'     => 'require|length:32',
        ),
    ),
);

编写change_pwd函数 G:\phpStudy\WWW\tp5\application\api\controller\User.php

public function change_pwd() {
    /*********** 接收参数  ***********/
    $data = $this->params;
    /*********** 检查用户名并取出数据库中的密码  ***********/
    $user_name_type = $this->check_username($data['user_name']);
    switch ($user_name_type) {
    case 'phone':
        $this->check_exist($data['user_name'], 'phone', 1);
        $where['user_phone'] = $data['user_name'];
        break;
    case 'email':
        $this->check_exist($data['user_name'], 'email', 1);
        $where['user_email'] = $data['user_name'];
        break;
    }
    /*********** 判断原始密码是否正确  ***********/
    $db_ini_pwd = db('user')->where($where)->value('user_pwd');
    if ($db_ini_pwd !== $data['user_ini_pwd']) {
        $this->return_msg(400, '原密码错误!');
    }
    /*********** 把新的密码存入数据库  ***********/
    $res = db('user')->where($where)->setField('user_pwd', $data['user_pwd']);
    if ($res !== false) {
        $this->return_msg(200, '密码修改成功!');
    } else {
        $this->return_msg(400, '密码修改失败!');
    }
}

第14节 找回密码

接口文档 配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 用户找回密码
Route::post('user/find_pwd','user/find_pwd');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

protected $rules = array(
    'User' => array(
        'find_pwd'        => array(
            'user_name' => 'require',
            'user_pwd'  => 'require|length:32',
            'code'      => 'require|number|length:6',
        ),
    ),
);

书写find_pwd函数 G:\phpStudy\WWW\tp5\application\api\controller\User.php

public function find_pwd() {
    /*********** 接收参数  ***********/
    $data = $this->params;
    /*********** 检测验证码  ***********/
    $this->check_code($data['user_name'], $data['code']);
    /*********** 检测用户名  ***********/
    $user_name_type = $this->check_username($data['user_name']);
    switch ($user_name_type) {
    case 'phone':
        $this->check_exist($data['user_name'], 'phone', 1);
        $where['user_phone'] = $data['user_name'];
        break;
    case 'email':
        $this->check_exist($data['user_name'], 'email', 1);
        $where['user_email'] = $data['user_name'];
        break;
    }
    /*********** 修改数据库  ***********/
    $res = db('user')->where($where)->setField('user_pwd', $data['user_pwd']);
    if ($res !== false) {
        $this->return_msg(200, '密码修改成功!');
    } else {
        $this->return_msg(400, '密码修改失败!');
    }
}

第15节 用户手机号/邮箱绑定

接口文档 配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 用户绑定手机号
Route::post('user/bind_phone','user/bind_phone');
// 用户绑定邮箱
Route::post('user/bind_email','user/bind_email');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

'bind_phone'        => array(
    'user_id' => 'require|number',
    'phone'  => ['require','regex'=>'/^1[34578]\d{9}$/'],
    'code'      => 'require|number|length:6',
),
 
'bind_email'        => array(
    'user_id' => 'require|number',
    'email'  => 'require|email',
    'code'      => 'require|number|length:6',
),

书写bind_phone函数 G:\phpStudy\WWW\tp5\application\api\controller\User.php

public function bind_phone() {
    /*********** 接收参数  ***********/
    $data = $this->params;
    /*********** 检查验证码  ***********/
    $this->check_code($data['phone'], $data['code']);
    /*********** 修改数据库  ***********/
    $res = db('user')->where('user_id', $data['user_id'])->setField('user_phone', $data['phone']);
    if ($res !== false) {
        $this->return_msg(200, '手机号绑定成功!');
    } else {
        $this->return_msg(400, '手机号绑定失败!');
    }
}

书写bind_email函数 G:\phpStudy\WWW\tp5\application\api\controller\User.php

public function bind_email() {
    /*********** 接收参数  ***********/
    $data = $this->params;
    /*********** 检查验证码  ***********/
    $this->check_code($data['email'], $data['code']);
    /*********** 修改数据库  ***********/
    $res = db('user')->where('user_id', $data['user_id'])->setField('user_email', $data['email']);
    if ($res !== false) {
        $this->return_msg(200, '邮箱绑定成功!');
    } else {
        $this->return_msg(400, '邮箱绑定失败!');
    }
}

两个接口合成一个

  1. 配置路由

G:\phpStudy\WWW\tp5\application\route.php

// 用户绑定邮箱/手机
Route::post('user/bind_username','user/bind_username');
  1. 验证数据

G:\phpStudy\WWW\tp5\application\api\controller\Common.php

'bind_username'        => array(
    'user_id' => 'require|number',
    'user_name'  => 'require',
    'code'      => 'require|number|length:6',
),
  1. 书写bind_username函数

G:\phpStudy\WWW\tp5\application\api\controller\User.php

public function bind_username() {
    /*********** 接收参数  ***********/
    $data = $this->params;
    /*********** 检测验证码  ***********/
    $this->check_code($data['user_name'], $data['code']);
    /*********** 判断用户名  ***********/
    $user_name_type = $this->check_username($data['user_name']);
    switch ($user_name_type) {
    case 'phone':
        $type_text                 = '手机号';
        $update_data['user_phone'] = $data['user_name'];
        break;
    case 'email':
        $type_text                 = '邮箱';
        $update_data['user_email'] = $data['user_name'];
        break;
    }
    /*********** 修改数据库  ***********/
    $res = db('user')->where('user_id', $data['user_id'])->update($update_data);
    if ($res !== false) {
        $this->return_msg(200, $type_text . '绑定成功!');
    } else {
        $this->return_msg(400, $type_text . '绑定失败!');
    }
}

第16节 用户修改昵称

接口文档 配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 用户修改昵称
Route::post('user/nickname','user/set_nickname');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

'set_nickname'        => array(
    'user_id' => 'require|number',
    'user_nickname'  => 'require|chsDash',
),

编写set_nickname函数 G:\phpStudy\WWW\tp5\application\api\controller\User.php

public function set_nickname(){
    /*********** 接收参数  ***********/
    $data = $this->params;
    /*********** 检测昵称  ***********/
    $res = db('user')->where('user_nickname',$data['user_nickname'])->find();
    if ($res) {
        $this->return_msg(400,'该昵称已被占用!');
    }
    /*********** 写入数据库  ***********/
    $res = db('user')->where('user_id',$data['user_id'])->setField('user_nickname',$data['user_nickname']);
    if (!$res) {
        $this->return_msg(400,'修改昵称失败!');
    }else{
        $this->return_msg(200,'昵称修改成功!');
    }
}

第17节 新增文章

接口文档 新建api_article表

DROP TABLE IF EXISTS `api_article`;
CREATE TABLE `api_article` (
  `article_id` int(11) NOT NULL AUTO_INCREMENT,
  `article_title` varchar(255) NOT NULL,
  `article_uid` int(11) NOT NULL COMMENT 'user id',
  `article_content` text NOT NULL,
  `article_ctime` int(11) NOT NULL,
  PRIMARY KEY (`article_id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 新增文章
Route::post('article','article/add_article');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

'Article' => array(
    'add_article' => array(
        'article_uid' => 'require|number',
        'article_title' => 'require|chsDash',
    ),
),

编写add_article函数 G:\phpStudy\WWW\tp5\application\api\controller\Article.php

<?php
namespace app\api\controller;
class Article extends Common {
    public function add_article() {
        /*********** 接收参数  ***********/
        $data                  = $this->params;
        $data['article_ctime'] = time();
        /*********** 写入数据库  ***********/
        $res = db('article')->insertGetId($data);
        if ($res) {
            $this->return_msg(200, '新增文章成功!',$res);
        } else {
            $this->return_msg(400, '新增文章失败!');
        }
    }
}

参数安全html代码实体化

防止跨域脚本攻击

G:\phpStudy\WWW\tp5\application\config.php

// 默认全局过滤方法 用逗号分隔多个
'default_filter'         => 'htmlspecialchars',

第18节 查看文章列表

接口文档

配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 查看文章列表
Route::get('articles/:time/:token/:user_id/[:num]/[:page]','article/article_list');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

'Article' => array(
    'article_list' => array(
        'user_id' => 'require|number',
        'num' => 'number',
        'page' => 'number',
    ),
),

编写article_list函数 G:\phpStudy\WWW\tp5\application\api\controller\Article.php

<?php
namespace app\api\controller;
class Article extends Common {
    public function article_list() {
        /*********** 接收参数  ***********/
        $data = $this->params;
        if (!isset($data['num'])) {
            $data['num'] = 10;
        }
        if (!isset($data['page'])) {
            $data['page'] = 1;
        }
        /*********** 查询数据库  ***********/
        $where['article_uid'] = $data['user_id'];
        $where['article_isdel'] = 0;
        $count                = db('article')->where($where)->count();
        $page_num             = ceil($count / $data['num']);
        $field                = "article_id,article_ctime,article_title,user_nickname";
        $join                 = [['api_user u', 'u.user_id = a.article_uid']];
        $res                  = db('article')->alias('a')->field($field)->join($join)->where($where)->page($data['page'], $data['num'])->select();
        /*********** 判断并输出  ***********/
        if ($res === false) {
            $this->return_msg(400, '查询失败!');
        } elseif (empty($res)) {
            $this->return_msg(200, '暂无数据!');
        } else {
            $return_data['articles'] = $res;
            $return_data['page_num'] = $page_num;
            $this->return_msg(200, '查询成功!', $return_data);
        }
    }
}

第19节 查看单个文章

接口文档 配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 获取单个文章信息
Route::get('article/:time/:token/:article_id','article/article_detail');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

'Article' => array(
    'article_detail' => array(
        'article_id' => 'require|number',
    ),
),

编写article_detail函数 G:\phpStudy\WWW\tp5\application\api\controller\Article.php

<?php
namespace app\api\controller;
class Article extends Common {
    public function article_detail() {
        /*********** 接收参数  ***********/
        $data = $this->params;
        /*********** 查询数据库  ***********/
        $field                  = 'article_id,article_title,article_ctime,article_content,user_nickname';
        $where['article_id']    = $data['article_id'];
        $join                   = [['api_user u', 'u.user_id = a.article_uid']];
        $res                    = db('article')->alias('a')->join($join)->field($field)->where($where)->find();
        $res['article_content'] = htmlspecialchars_decode($res['article_content']);
        /*********** 判断结果并输出  ***********/
        if (!$res) {
            $this->return_msg(400, '查询失败!');
        } else {
            $this->return_msg(200, '查询成功!', $res);
        }
    }
}

第20节 修改文章

接口文档 配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 修改/更新文章
Route::put('article','article/update_article');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

'Article' => array(
    'update_article' => array(
        'article_id' => 'require|number',
        'article_title'=>'chsDash'
    ),
),

编写update_article函数 G:\phpStudy\WWW\tp5\application\api\controller\Article.php

<?php
namespace app\api\controller;
class Article extends Common {
    public function update_article() {
        /*********** 接收参数  ***********/
        $data = $this->params;
        /*********** 存入数据库  ***********/
        $res = db('article')->where('article_id', $data['article_id'])->update($data);
        if ($res !== false) {
            $this->return_msg(200, '修改文章成功!');
        } else {
            $this->return_msg(400, '修改文章失败!');
        }
    }
}

第21节 删除文章

接口文档 配置路由 G:\phpStudy\WWW\tp5\application\route.php

// 删除文章
Route::delete('article/:time/:token/:article_id','article/del_article');

验证数据 G:\phpStudy\WWW\tp5\application\api\controller\Common.php

'Article' => array(
    'del_article' => array(
        'article_id' => 'require|number',
    ),
),

为逻辑删除增加字段article_isdel

DROP TABLE IF EXISTS `api_article`;
CREATE TABLE `api_article` (
  `article_id` int(11) NOT NULL AUTO_INCREMENT,
  `article_title` varchar(255) NOT NULL,
  `article_uid` int(11) NOT NULL COMMENT 'user id',
  `article_content` text NOT NULL,
  `article_ctime` int(11) NOT NULL,
  `article_isdel` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除 1:yes 0:no',
  PRIMARY KEY (`article_id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

编写del_article函数 G:\phpStudy\WWW\tp5\application\api\controller\Article.php

<?php
namespace app\api\controller;
class Article extends Common {
    public function del_article(){
        /*********** 接收参数  ***********/
        $data = $this->params;
        /*********** 删除数据(逻辑删除)  ***********/
        $res = db('article')->where('article_id',$data['article_id'])->setField('article_isdel',1);
        /*********** 删除数据(物理删除)  ***********/
        // $res = db('article')->delete($data['article_id']);
        if ($res) {
            $this->return_msg(200,'删除文章成功');
        }else{
            $this->return_msg(400,'删除文章失败!');
        }
    }
}