第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,'刪除文章失敗!');
}
}
}