thinkphp5開發restful-api接口學習 筆記二

第4節 爲api項目搭建數據庫

什麼是數據庫三大範式javascript

  1. 每一列都是不可分割的原子數據項
  2. 實體的屬性徹底依賴於主關鍵字
  3. 任何非主屬性不依賴於其它非主屬性(在2NF基礎上消除傳遞依賴)

數據庫中設計中的常見問題php

  1. 字段混在了一塊兒


  1. 數據表混在了一塊兒

  1. 不會處理表關係

一對一 (學生姓名, 學號)
一對多 (老師, 學生)
多對多 (學生, 課程)html

設計數據庫的小技巧java

  1. 一個對象, 一張表
  2. 一張表, 一個主鍵
  3. 表名中有數據庫名作前綴
  4. 字段名中有表名作前綴
  5. 前綴後加縮寫
  6. 數據表關係處理

範式越高越好?

第5節 使用markdown書寫接口文檔

基本語法sql

  1. 六級標題
  2. 目錄索引
  3. 加粗
  4. 斜體
  5. 刪除線
  6. 引用
  7. 代碼段
  8. 表格
  9. 行內代碼
  10. 無序列表
  11. 有序列表
  12. 圖片
  13. 超連接

第6節(判斷數據庫中是否有此用戶)

用戶登陸舉例thinkphp

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 用戶密碼
{
       "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
網站端口: 80json

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

使用tp5路由進行URL解析

  1. 爲sublime安裝新插件(方便操做側邊欄)

package control: install package
SideBarEnhancementsapi

  1. 修改config.php(開啓路由功能)

路徑:G:\phpStudy\WWW\tp5\application\config.php跨域

// 是否開啓路由
'url_route_on' => true,
// 域名部署
'url_domain_deploy' => true,

設置路由文件

  1. 方法一:路由裏不寫參數

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);
   }
}

訪問下面地址均可以打開:

  1. http://api.tp5.com/user/index?id=1&name=lisi
  2. http://api.tp5.com/user?id=1&name=lisi
  3. http://api.tp5.com/user/id/1/name/lisi
  4. http://www.tp5.com/api/user/index?id=1&name=lisi
  5. 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
  1. 方法二:路由裏寫參數

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);
   }
}

下面這些訪問拿不到參數

  1. http://api.tp5.com/user/1/lisi
  2. http://api.tp5.com/user?id=1&name=lisi
  3. http://www.tp5.com/api/user/index?id=1&name=lisi
  4. http://www.tp5.com/api/user?id=1&name=lisi
  5. 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節 接口安全

常見的安全問題以及解決方案

  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) {
    //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;

驗證碼原理

  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,'刪除文章失敗!');
        }
    }
}
相關文章
相關標籤/搜索