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


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

什么是數據庫三大范式

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

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

  1. 字段混在了一起


  1. 數據表混在了一起

  1. 不會處理表關系

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

設計數據庫的小技巧

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

范式越高越好?

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

基本語法

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

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

用戶登錄舉例

post www.test.com/api api.test.com

參數 必選 類型 說明
time true int 時間戳 (用於確定接口的訪問時間)
token true string 確定訪問者身份 (MD5(USER_MD5(time)_USER))
username true string 只接受手機號
password true string 用戶密碼
   {
       "ret": 200, // 返回結果狀態。200:接口正常請求並返回/40*:服務端的數據有誤/500:服務器運行錯誤
       "data": {
           "user_id": "27", // 用戶id
           "user_tag": "1" // 用戶身份
       },
       "msg": "" // 401:用戶名不存在!/402:手機號不存在!/403:密碼不正確!
   }

第7節 為項目配置URL

需求分析

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

配置主域名和二級域名

  1. 打開phpstudy
  2. 其他選項菜單 ==> 站點域名管理

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

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

使用tp5路由進行URL解析

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

package control: install package
SideBarEnhancements

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM