thinkphp5开发restful-api接口学习 笔记二
第4节 为api项目搭建数据库
什么是数据库三大范式
- 每一列都是不可分割的原子数据项
- 实体的属性完全依赖于主关键字
- 任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
数据库中设计中的常见问题
- 字段混在了一起
- 数据表混在了一起
- 不会处理表关系
一对一 (学生姓名, 学号)
一对多 (老师, 学生)
多对多 (学生, 课程)
设计数据库的小技巧
- 一个对象, 一张表
- 一张表, 一个主键
- 表名中有
数据库名
做前缀 - 字段名中有
表名
做前缀 - 前缀后加
缩写
- 数据表关系处理
范式越高越好?
第5节 使用markdown书写接口文档
基本语法
- 六级标题
- 目录索引
- 加粗
- 斜体
- 删除线
- 引用
- 代码段
- 表格
- 行内代码
- 无序列表
- 有序列表
- 图片
- 超链接
第6节(判断数据库中是否有此用户)
用户登录
举例
post
www.test.com/apiapi.test.com
参数 | 必选 | 类型 | 说明 |
---|---|---|---|
time | true | int | 时间戳 (用于确定接口的访问时间) |
token | true | string | 确定访问者身份 (MD5(USER_MD5(time)_USER) ) |
username | true | string | 只接受手机号 |
password | true | string | 用户密码 |
{
"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
配置主域名和二级域名
- 打开phpstudy
其他选项菜单
==>站点域名管理
网站域名:
www.tp5.com
网站域名:G:\phpStudy\WWW\tp5\public
第二域名:api.tp5.com
网站端口:80
- 配置hosts(域名重定向)
127.0.0.1 www.tp5.com 127.0.0.1 api.tp5.com
使用tp5路由进行URL解析
- 为sublime安装新插件(方便操作侧边栏)
package control: install package
SideBarEnhancements
- 修改config.php(开启路由功能)
路径:
G:\phpStudy\WWW\tp5\application\config.php
// 是否开启路由 'url_route_on' => true, // 域名部署 'url_domain_deploy' => true,
设置路由文件
- 方法一:路由里不写参数
D:\phpStudy\WWW\tp5\application\route.php
<?php use think\Route; Route::domain('api', 'api'); Route::get('user', 'user/index');
新建
api/controller/User.php
<?php namespace app\api\controller; class User { public function index() { echo 'user/index'; echo '<br>'; $id = input('id'); echo $id; echo '<br>'; $name = input('name'); print_r($name); } }
访问下面地址都可以打开:
http://api.tp5.com/user/index?id=1&name=lisi
http://api.tp5.com/user?id=1&name=lisi
http://api.tp5.com/user/id/1/name/lisi
http://www.tp5.com/api/user/index?id=1&name=lisi
http://www.tp5.com/api/user/index/id/1/name/lisi
输出:user/index 1 lisi
下面这些访问拿不到参数
http://api.tp5.com/user/index/id/1/name/lisi
输出:user/index
- 方法二:路由里写参数
D:\phpStudy\WWW\tp5\application\route.php
<?php use think\Route; Route::domain('api', 'api'); Route::get('user/:id/:name', 'user/index');
新建 api/controller/User.php
<?php namespace app\api\controller; class User { public function index() { echo 'user/index'; echo '<br>'; $id = input('id'); echo $id; echo '<br>'; $name = input('name'); print_r($name); } }
下面这些访问拿不到参数
http://api.tp5.com/user/1/lisi
http://api.tp5.com/user?id=1&name=lisi
http://www.tp5.com/api/user/index?id=1&name=lisi
http://www.tp5.com/api/user?id=1&name=lisi
http://www.tp5.com/api/user/index/id/1/name/lisi
输出:user/index 1 lisi
*下面这种会报错 *
http://api.tp5.com/user/index?id=1&name=lisi
非法请求:api/user/index
第8节 接口安全
常见的安全问题以及解决方案
- 接口被大规模调用消耗系统资源,影响系统的正常访问,甚至系统瘫痪
解决方案: 获取 timestamp (时间戳), 设置接口失效时间
- 接口数据被黑客篡改(伪造请求)
解决方案: 对参数加密, 生成 token , 判断 token 是否正确
- 数据被黑客截取
解决方案: 使用 https , 用证书对数据进行加密, 即使数据被截取, 对黑客也没有意义
黑客可以获取数据, 但是无法获取数据的加密方法
我们api项目的安全设计
- time
时间戳, 用于判断请求是否超时, 设置为30秒
- token
其他参数加密而来, 保证数据不被篡改
- 敏感信息加密传输
接收加密过的用户密码, 用户密码永不返回
最好使用 https, 所有信息都会被加密
第9节 接口开发前的准备工作(参数过滤)
配置路由
- 开启路由功能
G:\phpStudy\WWW\tp5\application\config.php
// 是否开启路由 'url_route_on' => true, // 域名部署 'url_domain_deploy' => true,
- 配置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) {
//intval() string 11返回11 11hello返回11 hello返回0 array 空array返回0 非空array返回1
//intval($arr['time']) <= 1 等于1就是非空array(不是我们想要的)
//小于1即等于0就是string或者空array或者是空(也不是我们想要的)
//我想要想要的是一串数字,所以 intval($arr['time']) <= 1就报错
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;
验证码原理
- 生成及发送
- 点击获取手机码
- 发送手机号到后台
- 后台生成手机码
- 用session保存手机码及手机号
- 用短信发送平台的接口发送出去
- 验证
- 获取用户输入的手机码及手机号
- 取出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(赛迪云通信)
- 通过调用接口发送短信
- 开启
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; }
- 使用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, '邮箱绑定失败!');
}
}
两个接口合成一个
- 配置路由
G:\phpStudy\WWW\tp5\application\route.php
// 用户绑定邮箱/手机 Route::post('user/bind_username','user/bind_username');
- 验证数据
G:\phpStudy\WWW\tp5\application\api\controller\Common.php
'bind_username' => array( 'user_id' => 'require|number', 'user_name' => 'require', 'code' => 'require|number|length:6', ),
- 书写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,'删除文章失败!');
}
}
}