thinkphp5開發restful-api接口javascript
主要內容php
爲app寫後臺 爲app寫接口html
什麼是thinkphp5
?java
簡單易用 功能齊全 利於擴展 方便學習 開發速度快 教程豐富python
什麼是restful api
?mysql
爲何是這種搭配程序員
本課程用到的工具sql
windows
+ apache
+ mysql
+ php
本課程的風格
本課程的學習基礎
本課程的收穫
sublime(最性感的編輯器
)
啓動速度快(
C++
) 插件衆多(python
)
下載sublime
安裝版和綠色便攜版的區別
sublime_addright.inf
)
[Version]
Signature="$Windows NT$"
[DefaultInstall]
AddReg=SublimeText3
[SublimeText3]
hkcr,"*\\shell\\SublimeText3",,,"用 SublimeText3 打開"
hkcr,"*\\shell\\SublimeText3\\command",,,"""%1%\sublime_text.exe"" ""%%1"" %%*"
hkcr,"Directory\shell\SublimeText3",,,"用 SublimeText3 打開"
hkcr,"*\\shell\\SublimeText3","Icon",0x20000,"%1%\sublime_text.exe, 0"
hkcr,"Directory\shell\SublimeText3\command",,,"""%1%\sublime_text.exe"" ""%%1"""
複製代碼
激活sublime
—– BEGIN LICENSE —–
Michael Barnes
Single User License
EA7E-821385
8A353C41 872A0D5C DF9B2950 AFF6F667
C458EA6D 8EA3C286 98D1D650 131A97AB
AA919AEC EF20E143 B361B1E7 4C8B7F04
B085E65E 2F5F5360 8489D422 FB8FC1AA
93F6323C FD7F7544 3F39C318 D95E6480
FCCC7561 8A4A1741 68FA4223 ADCEDE07
200C25BE DBBC4855 C4CFB774 C5EC138C
0FEC1CEF D9DCECEC D3A5DAD1 01316C36
—— END LICENSE ——
複製代碼
sublime經常使用配置
{
"font_face": "YaHei Consolas Hybrid", // 字體名稱
"font_size": 13, // 字體大小
"save_on_focus_lost": true, // 自動保存
"word_wrap": true, // 開啓自動換行
}
複製代碼
sublime安裝插件
ctrl + ~
)
import urllib.request,os,hashlib; h = 'df21e130d211cfc94d9b0905775a7c0f' + '1e3d39e33b79698005270310898eea76'; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); by = urllib.request.urlopen( 'http://packagecontrol.io/' + pf.replace(' ', '%20')).read(); dh = hashlib.sha256(by).hexdigest(); print('Error validating download (got %s instead of %s), please try manual install' % (dh, h)) if dh != h else open(os.path.join( ipp, pf), 'wb' ).write(by)
複製代碼
ctrl + shift + p
, package install
)postman(接口測試
)
心知天氣接口: api.seniverse.com/v3/weather/…
選擇 http 方法 自動生成代碼 接口鑑權 設置接受數據的方式 設置字體大小 保存接口以備後用 post 參數的兩種方式
navicat(數據庫管理
)
圖形化界面
/自動完成
)phpstudy(php開發環境
)
一次性安裝,無須配置便可使用 完美支持win10, 支持自定義php版本
運行環境(選擇
非系統模式
就能夠了) 支持右鍵分開啓停 切換版本(切記:NTS版本的PHP,APACHE不支持REWRITE!
)
配置文件
php-ini
php配置文件(自動識別版本http-conf
apache配置文mysql-ini
mysql配置文vhosts-conf
apache虛擬主機配置文
軟件位置
hosts 網站根目錄
phpinfo路徑:
G:\phpStudy\WWW\
phpinfo.php
php擴展
(等於直接操做php.ini
)參數開關設置
(等於直接操做php.ini
)參數值設置
(等於直接操做php.ini
)
快速打開命令行 快速新建數據庫 設置mysql (等於直接操做
mysql.ini
)MYSQL工具
=====>參數值設置
httpd.conf
)什麼是restful api
http://api.douban.com
/v2/user/1000001?apikey=XXX
http://api.douban.com/v2
/user/1000001?apikey=XXX
不能有動詞,只能有名詞
,並且所用的名詞每每與數據庫的表格名對應
。通常來講,數據庫中的表都是同種記錄的"集合"(collection),因此API中的名詞也應該使用複數。api.douban.com/v2/
book
/:id (獲取圖書信息) api.douban.com/v2/movie
/subject/:id (電影條目信息) api.douban.com/v2/music
/:id (獲取音樂信息) api.douban.com/v2/event
/:id (獲取同城活動)
增/刪/改/查
)。GET(
select
):從服務器取出資源(一項或多項)。 eg. 獲取圖書信息GET
api.douban.com/v2/book/:id POST(create
):在服務器新建一個資源。 eg. 用戶收藏某本圖書POST
api.douban.com/v2/book/:id… PUT(update
):在服務器更新資源(客戶端提供改變後的完整資源)。 eg. 用戶修改對某本圖書的收藏PUT
api.douban.com/v2/book/:id… DELETE(delete
):從服務器刪除資源。 eg. 用戶刪除某篇筆記DELETE
api.douban.com/v2/book/ann…
?limit=10:指定返回記錄的數量 eg. 獲取圖書信息
GET
api.douban.com/v2/book/:id?limit=10
每一個狀態碼錶明不一樣意思, 就像代號同樣 2系 表明正常返回 4系 表明數據異常 5系 表明服務器異常
錯誤碼 錯誤信息 含義 狀態碼 6000 book_not_found 圖書不存在 404 6002 unauthorized_error 沒有修改權限 403 6004 review_content_short(should more than 150) 書評內容太短(需多於150字) 400 6006 review_not_found 書評不存在 404 6007 not_book_request 不是豆瓣讀書相關請求 403 6008 people_not_found 用戶不存在 404 6009 function_error 服務器調用異常 400 6010 comment_too_long(should less than 350) 短評字數過長(需少於350字) 400 6011 collection_exist(try PUT if you want to update) 該圖書已被收藏(如需更新請用PUT方法而不是POST) 409 6012 invalid_page_number(should be digit less than 1000000) 非法頁碼(頁碼須要是小於1000000的數字) 400 6013 chapter_too_long(should less than 100) 章節名過長(需小於100字) 400
接口安全
增長兩個參數
time
,token
time
爲時間戳, 用於判斷接口請求是否超時token
爲時間戳加密後的字符串, 加密規則只有大家技術團隊本身知道
什麼是thinkphp
官網
安裝
配置虛擬主機
URL路徑設計
格式化php代碼
ctrl+shift+p
搜索phpfmt
enter
{
"format_on_save": true,
"php_bin": "G:/phpStudy/php/php-7.0.12-nts/php.exe",
}
複製代碼
花括號點位置不一樣
API友好
<?php
namespace app\index\controller;
class Index {
public function index() {
$data = array(
'name' => 'red_panda',
'address' => 'China',
);
$code = 200;
$msg = 'ok';
return ['data' => $data, 'code' => $code, 'message' => $msg];
}
}
複製代碼
'default_return_type'=>'json'
複製代碼
獲取請求參數
<?php
namespace app\index\controller;
use \think\Request;
class Index {
public function index() {
$request = Request::instance();
echo '請求方法:' . $request->method() . '<br/>';
echo '訪問地址:' . $request->ip() . '<br/>';
echo '請求參數:';
dump($request->param());
echo '請求參數:僅包含name,sex';
dump($request->only(['name', 'sex']));
echo '請求參數:排除name,sex';
dump($request->except(['name', 'sex']));
}
}
複製代碼
判斷請求類型
// 是否爲 GET 請求
if (Request::instance()->isGet()) echo "當前爲 GET 請求";
// 是否爲 POST 請求
if (Request::instance()->isPost()) echo "當前爲 POST 請求";
// 是否爲 PUT 請求
if (Request::instance()->isPut()) echo "當前爲 PUT 請求";
// 是否爲 DELETE 請求
if (Request::instance()->isDelete()) echo "當前爲 DELETE 請求";
// 是否爲 Patch 請求
if (Request::instance()->isPatch()) echo "當前爲 PATCH 請求";
複製代碼
驗證參數數據
<?php
namespace app\index\controller;
use \think\Validate;
class Index {
public function index() {
$rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email',
];
$msg = [
'name.require' => '名稱必須',
'name.max' => '名稱最多不能超過25個字符',
'age.number' => '年齡必須是數字',
'age.between' => '年齡只能在1-120之間',
'email' => '郵箱格式錯誤',
];
$data = input('post.');
$validate = new Validate($rule, $msg);
$result = $validate->check($data);
if (!$validate->check($data)) {
dump($validate->getError());
}
}
}
複製代碼
鏈接數據庫
/* 數據庫設置 */
'database' => [
// 數據庫類型
'type' => 'mysql',
// 服務器地址
'hostname' => '127.0.0.1',
// 數據庫名
'database' => 'thinkphp',
// 數據庫用戶名
'username' => 'root',
// 數據庫密碼
'password' => '',
// 數據庫鏈接端口
'hostport' => '',
// 數據庫鏈接參數
'params' => [],
// 數據庫編碼默認採用utf8
'charset' => 'utf8',
// 數據庫表前綴
'prefix' => '',
// 數據庫調試模式
'debug' => false,
],
複製代碼
原生sql語句查詢
<?php
namespace app\index\controller;
use think\Db;
class Index {
public function index() {
$res = Db::query('select version()');
return $res;
}
}
複製代碼
什麼是數據庫三大範式
數據庫中設計中的常見問題
一對一 (學生姓名, 學號) 一對多 (老師, 學生) 多對多 (學生, 課程)
設計數據庫的小技巧
數據庫名
作前綴表名
作前綴縮寫
範式越高越好?
基本語法
用戶登陸
舉例
---
# 第6節(判斷數據庫中是否有此用戶)
> `post` ~~www.test.com/api~~ `api.test.com`
|參數|必選|類型|說明|
|:-|:-:|:-:|:-|
|*time*|*true*|*int*|*時間戳* (用於肯定接口的訪問時間)|
|*token*|*true*|*string*|*肯定訪問者身份* (`MD5(USER_MD5(time)_USER)`)|
|username |true |string|只接受`手機號`|
|password |true |string |用戶密碼|
``` javascript
{
"ret": 200, // 返回結果狀態。200:接口正常請求並返回/40*:服務端的數據有誤/500:服務器運行錯誤
"data": {
"user_id": "27", // 用戶id
"user_tag": "1" // 用戶身份
},
"msg": "" // 401:用戶名不存在!/402:手機號不存在!/403:密碼不正確!
}
```
複製代碼
需求分析
api.tp5.com/user/2
===> www.tp5.com/index.php/api/user/index/id/2
配置主域名和二級域名
其餘選項菜單
==> 站點域名管理
網站域名:
www.tp5.com
網站域名:G:\phpStudy\WWW\tp5\public
第二域名:api.tp5.com
網站端口:80
127.0.0.1 www.tp5.com
127.0.0.1 api.tp5.com
複製代碼
使用tp5路由進行URL解析
package control: install package SideBarEnhancements
路徑:
G:\phpStudy\WWW\tp5\application\api\controller\User.php
<?php namespace app\api\controller; class User{ public function index($id){ echo 'controller: user function: index'; echo '<br/>'; echo $id; } } 複製代碼
路徑:
G:\phpStudy\WWW\tp5\application\config.php
// 是否開啓路由 'url_route_on' => true, 複製代碼
路徑:
G:\phpStudy\WWW\tp5\application\route.php
<?php use think\Route; // api.tp5.com ===> www.tp5.com/index.php/api Route::domain('api','api'); // api.tp5.com/user/2 ===> www.tp5.com/index.php/api/user/index/id/2 Route::rule('user/:id','user/index'); 複製代碼
常見的安全問題以及解決方案
解決方案: 獲取 timestamp (時間戳), 設置接口失效時間
解決方案: 對參數加密, 生成 token , 判斷 token 是否正確
解決方案: 使用 https , 用證書對數據進行加密, 即便數據被截取, 對黑客也沒有意義
黑客能夠獲取數據, 可是沒法獲取數據的加密方法
咱們api項目的安全設計
時間戳, 用於判斷請求是否超時, 設置爲30秒
其餘參數加密而來, 保證數據不被篡改
接收加密過的用戶密碼, 用戶密碼永不返回 最好使用 https, 全部信息都會被加密
配置路由
G:\phpStudy\WWW\tp5\application\config.php
// 是否開啓路由 'url_route_on' => true, // 域名部署 'url_domain_deploy' => true, 複製代碼
G:\phpStudy\WWW\tp5\application\route.php
<?php use think\Route; // api.tp5.com ===> www.tp5.com/index.php/api Route::domain('api','api'); // post api.tp5.com/user ---> user.php login() Route::post('user','user/login'); 複製代碼
使用common.php
統一處理參數過濾 G:\phpStudy\WWW\tp5\application\api\controller\Common.php
<?php
namespace app\api\controller;
use think\Controller;
use think\Request;
use think\Validate;
class Common extends Controller {
protected $request; // 用來處理參數
protected $validater; // 用來驗證數據/參數
protected $params; // 過濾後符合要求的參數
protected $rules = array(
'User'=>array(......);
protected function _initialize() {
parent::_initialize();
$this->request = Request::instance();
$this->check_time($this->request->only(['time']));
$this->check_token($this->request->param());
$this->params = $this->check_params($this->request->except(['time','token']));
}
複製代碼
自定義返回信息函數 G:\phpStudy\WWW\tp5\application\api\controller\Common.php
/** * api 數據返回 * @param [int] $code [結果碼 200:正常/4**數據問題/5**服務器問題] * @param [string] $msg [接口要返回的提示信息] * @param [array] $data [接口要返回的數據] * @return [string] [最終的json數據] */
public function return_msg($code, $msg = '', $data = []) {
/*********** 組合數據 ***********/
$return_data['code'] = $code;
$return_data['msg'] = $msg;
$return_data['data'] = $data;
/*********** 返回信息並終止腳本 ***********/
echo json_encode($return_data);die;
}
複製代碼
驗證time G:\phpStudy\WWW\tp5\application\api\controller\Common.php
/** * 驗證請求是否超時 * @param [array] $arr [包含時間戳的參數數組] * @return [json] [檢測結果] */
public function check_time($arr) {
if (!isset($arr['time']) || intval($arr['time']) <= 1) {
$this->return_msg(400, '時間戳不正確!');
}
if (time() - intval($arr['time']) > 60) {
$this->return_msg(400, '請求超時!');
}
}
複製代碼
驗證token G:\phpStudy\WWW\tp5\application\api\controller\Common.php
/** * 驗證token(防止篡改數據) * @param [array] $arr [所有請求參數] * @return [json] [token驗證結果] */
public function check_token($arr) {
/*********** api傳過來的token ***********/
if (!isset($arr['token']) || empty($arr['token'])) {
$this->return_msg(400, 'token不能爲空!');
}
$app_token = $arr['token']; // api傳過來的token
/*********** 服務器端生成token ***********/
unset($arr['token']);
$service_token = '';
foreach ($arr as $key => $value) {
$service_token .= md5($value);
}
$service_token = md5('api_' . $service_token . '_api'); // 服務器端即時生成的token
/*********** 對比token,返回結果 ***********/
if ($app_token !== $service_token) {
$this->return_msg(400, 'token值不正確!');
}
}
複製代碼
爲每一個接口配置驗證規則 G:\phpStudy\WWW\tp5\application\api\controller\Common.php
protected $rules = array(
'User' => array(
'login' => array(
'user_name' => ['require', 'chsDash', 'max' => 20],
'user_pwd' => 'require|length:32',
),
),
);
複製代碼
驗證參數 G:\phpStudy\WWW\tp5\application\api\controller\Common.php
/** * 驗證參數 參數過濾 * @param [array] $arr [除time和token外的全部參數] * @return [return] [合格的參數數組] */
public function check_params($arr) {
/*********** 獲取參數的驗證規則 ***********/
$rule = $this->rules[$this->request->controller()][$this->request->action()];
/*********** 驗證參數並返回錯誤 ***********/
$this->validater = new Validate($rule);
if (!$this->validater->check($arr)) {
$this->return_msg(400, $this->validater->getError());
}
/*********** 若是正常,經過驗證 ***********/
return $arr;
}
複製代碼
接口文檔 新建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, 把須要的文件加入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次, 請在一分鐘內驗證!'); } } 複製代碼
接口文檔 配置路由 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);
}
複製代碼
接口文檔 配置路由 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);
}
}
複製代碼
接口文檔 配置路由 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;
}
}
複製代碼
接口文檔 配置路由 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, '密碼修改失敗!');
}
}
複製代碼
接口文檔 配置路由 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, '密碼修改失敗!');
}
}
複製代碼
接口文檔 配置路由 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', ), 複製代碼
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 . '綁定失敗!'); } } 複製代碼
接口文檔 配置路由 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,'暱稱修改爲功!');
}
}
複製代碼
接口文檔 新建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',
複製代碼
配置路由 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);
}
}
}
複製代碼
接口文檔 配置路由 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);
}
}
}
複製代碼
接口文檔 配置路由 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, '修改文章失敗!');
}
}
}
複製代碼
接口文檔 配置路由 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,'刪除文章失敗!');
}
}
}
複製代碼