配置參數(shù)
- Memcache 配置豪嗽, 在
/app/config/config.ini
文件添加以下代碼:
[memcache]
host = 127.0.0.1
port = 11211
prefix = api
在 Visual NMP 中茴厉,默認(rèn)已經(jīng)安裝了 Memcache, 可直接使用寻狂。如服務(wù)未開啟瞬项,直接打開即可蔗蹋。 默認(rèn)連接端口:
11211
。緩存鍵名前綴:prefix = api
囱淋,方便區(qū)分項(xiàng)目媒役,可隨意設(shè)置蜓谋, 一般設(shè)置為項(xiàng)目名。
「PHP開發(fā)APP接口實(shí)戰(zhàn)001」開發(fā)環(huán)境搭建
- 短信配置, 在
/app/config/config.php
文件添加以下代碼:
'sms' => [
'times' => 3, // 同一手機(jī)一小時(shí)內(nèi)發(fā)送短信次數(shù), 0 為不限制
'interval' => 60, // 同一手機(jī)兩次發(fā)送間隔時(shí)間(單位:秒)耻讽, 0 為不限制
'valid_time' => 300, // 短信驗(yàn)證碼有效時(shí)間(單位:秒), 0 為久有效
],
創(chuàng)建 Memcache 操作類 XMemcache
在 /app/library
目錄下創(chuàng)建文件 XMemcache.php
, 添加以下代碼:
<?php
/**
* 緩存
*/
class XMemcache
{
public static $instance;
private $memcache = null; // Memcache 對(duì)象
private $config = null; // 配置參數(shù)
private $tag = null; // 標(biāo)識(shí)
private function __construct($tag = null)
{
// 初始化 Memcache 對(duì)象
$this->memcache = new Memcache();
// 加載配置參數(shù)
$this->config = Config::instance()->get('memcache', 'ini');
// 連接Memcache服務(wù)器
$this->memcache->addServer($this->config['host'], $this->config['port']);
$this->tag = $tag;
}
/**
* @param null $tag 緩存標(biāo)識(shí)
* @return XMemcache
*/
public static function instance($tag = null)
{
if (!self::$instance) self::$instance = new self($tag);
return self::$instance;
}
/**
* 添加緩存,若不存在則追加基公,若不存在則新增
* @param $key 鍵名
* @param $value 緩存內(nèi)容
* @param int $timeout 0永久有效条篷,604800 7天,最大不能超過30天
* @param int $iszip
* @return mixed
*/
public function append($key, $value, $timeout = 604800, $iszip = 0)
{
if ($values = $this->get($key)) {
$values[] = $value;
} else {
$values = [$value];
}
$this->set($key, $values, $timeout, $iszip);
}
/**
* 設(shè)置緩存
* @param $key 鍵名
* @param $value 緩存內(nèi)容
* @param int $timeout 0永久有效芦倒,604800 7天艺挪,最大不能超過30天
* @param int $iszip
* @return mixed
*/
public function set($key, $value, $timeout = 604800, $iszip = 0)
{
$value = serialize($value);
return $this->memcache->set($this->formatKey($key), $value, $iszip, $timeout);
}
/**
* 根據(jù)KEY獲得緩存內(nèi)容
* @param $key
* @return mixed
*/
public function get($key)
{
$value = $this->memcache->get($this->formatKey($key));
return unserialize($value);
}
/**
* 刪除指定緩存
* @param $key
* @return mixed
*/
public function delete($key)
{
return $this->memcache->delete($this->formatKey($key));
}
/**
* 清空緩存
* @return mixed
*/
public function flush()
{
return $this->memcache->flush();
}
/**
* 重寫緩存鍵名,格式: [prefix]:[tag]:[key]
* @param $key
* @return string
*/
private function formatKey($key)
{
return $this->config['prefix'] . ':' . $this->tag . ':' . $key;
}
}
這里重寫了一些
Memcache
常用的操作函數(shù)兵扬。 如:設(shè)置緩存set()
, 追加緩存append()
, 獲取緩存get()
, 刪除緩存delete()
, 清空緩存flush()
值得注意的是麻裳,我們還對(duì)緩存鍵名進(jìn)行了重寫,方便區(qū)分項(xiàng)目和模塊器钟。
生成短信驗(yàn)證碼
- 在
/app/library
目錄下創(chuàng)建文件SMS.php
, 添加以下代碼:
<?php
/**
* 短信驗(yàn)證碼
*/
class SMS
{
public static $instance;
// 配置參數(shù)
private $config = null;
private function __construct()
{
// 加載短信配置參數(shù)
$this->config = Config::instance()->get('sms');
}
public static function instance()
{
if (!self::$instance) self::$instance = new self();
return self::$instance;
}
}
這里實(shí)現(xiàn)了實(shí)例化時(shí)津坑,自己加載配置參數(shù)。
- 增加驗(yàn)證碼改送函數(shù)
send()
, 用于外部調(diào)用傲霸。如:
/**
* 發(fā)送短信驗(yàn)證碼
* @param $mobile
* @return array
* @throws Exception
*/
public function send($mobile)
{
}
此函數(shù)里面分四步走:
- 驗(yàn)證指定手機(jī)號(hào)疆瑰,當(dāng)前是否可以發(fā)送驗(yàn)證碼
- 生成四位數(shù)字驗(yàn)證碼,并配置上生成時(shí)間
- 調(diào)用
XMemcache
緩存驗(yàn)證碼- 調(diào)用第三方接口昙啄,發(fā)送驗(yàn)證碼乃摹,并返回發(fā)送狀態(tài)。(市場上有許多發(fā)送第三方平臺(tái)跟衅,都有)
- 這里調(diào)換一下順序孵睬,先講解生成和緩存驗(yàn)證碼。
首先伶跷,添加函數(shù)generateCode()
, 隨機(jī)生成4位數(shù)字驗(yàn)證碼
/**
* 隨機(jī)生成4位數(shù)字驗(yàn)證碼
* @return int
*/
private function generateCode()
{
return rand(1000, 9999);
}
然后掰读,在 send()
函數(shù)中添加代碼:
$item = [
'code' => $this->generateCode(), // 生成短信驗(yàn)證碼
'time' => time(), // 生成時(shí)間
'verified' => 0, // 驗(yàn)證狀態(tài): 0 未驗(yàn)證, 1 已驗(yàn)證
];
這里除了生成驗(yàn)證碼叭莫,同時(shí)初始化生成時(shí)間
time
蹈集, 驗(yàn)證狀態(tài)verified
,用于驗(yàn)證發(fā)送時(shí)間和檢查驗(yàn)證碼是否已驗(yàn)證雇初。
- 緩存驗(yàn)證碼拢肆,在
send()
函數(shù)中添加代碼:
// 緩存短信驗(yàn)證碼
XMemcache::instance('sms')->append($mobile, $item, 3600);
這里完成了幾個(gè)工作:
- 將
$item
存于以指定手機(jī)號(hào)為鍵名的緩存下- 同一手機(jī)號(hào)多次發(fā)送,都存在同一鍵名下,用于統(tǒng)計(jì)1小時(shí)內(nèi)驗(yàn)證碼發(fā)送次數(shù)郭怪。
- 緩存有效時(shí)間設(shè)置為 1 小時(shí)
- 現(xiàn)在我們?cè)倩貋碇v解驗(yàn)證是否允許向指定手機(jī)號(hào)發(fā)送驗(yàn)證碼支示。
驗(yàn)證規(guī)則:
- 同一手機(jī)兩次發(fā)送間隔時(shí)間1分鐘(可配置間隔時(shí)間)
- 同一手機(jī)1小時(shí)內(nèi)最多只能發(fā)送3次驗(yàn)證碼(可配置發(fā)送次數(shù))
首先,添加函數(shù) getCacheCodes()
和 validateSend()
鄙才, 如:
/**
* 獲取1小時(shí)內(nèi)發(fā)送的驗(yàn)證碼
* @param $mobile
* @return null
*/
private function getCacheCodes($mobile)
{
$codes = XMemcache::instance('sms')->get($mobile);
if (!$codes)
return [];
foreach ($codes as $index => $item) {
// 過濾發(fā)送超過1小時(shí)的驗(yàn)證碼
if (time() - $item['time'] > 3600) {
unset($codes[$index]);
}
}
// 重置數(shù)組索引
$codes = array_values($codes);
// 更新緩存
XMemcache::instance('sms')->set($mobile, $codes);
return $codes;
}
/**
* 驗(yàn)證是不否允許發(fā)送
* @param $mobile
* @throws Exception
*/
private function validateSend($mobile)
{
$codes = $this->getCacheCodes($mobile);
if ($this->config['times'] > 0 && count($codes) >= $this->config['times']) {
throw new Exception('一小時(shí)內(nèi)最多只能發(fā)送' . $this->config['times'] . '次短信驗(yàn)證碼');
}
$lastCode = end($codes);
if ($this->config['interval'] > 0 && time() - $lastCode['time'] <= $this->config['interval']) {
throw new Exception('發(fā)送頻率太快');
}
}
- 函數(shù)
getCacheCodes()
獲取指定手機(jī)1小時(shí)內(nèi)發(fā)送的驗(yàn)證碼颂鸿。- 函數(shù)
validateSend()
實(shí)現(xiàn):
驗(yàn)證一小時(shí)內(nèi)向同一手機(jī)發(fā)送短信驗(yàn)證碼次數(shù)是否超過了配置次數(shù);
驗(yàn)證上次發(fā)送驗(yàn)證碼是否已經(jīng)超過配置時(shí)間攒庵;
然后在 send()
函數(shù)中嘴纺,所有代碼之前插入代碼 $this->validateSend($mobile);
。
send()
函數(shù)完整代碼:
/**
* 發(fā)送短信驗(yàn)證碼
* @param $mobile
* @return array
* @throws Exception
*/
public function send($mobile)
{
// 驗(yàn)證短信發(fā)送次數(shù)
$this->validateSend($mobile);
$item = [
'code' => $this->generateCode(), // 生成短信驗(yàn)證碼
'time' => time(), // 生成時(shí)間
'verified' => 0, // 驗(yàn)證狀態(tài): 0 未驗(yàn)證浓冒, 1 已驗(yàn)證
];
// 緩存短信驗(yàn)證碼
XMemcache::instance('sms')->append($mobile, $item, 3600);
// 發(fā)送短信驗(yàn)證碼
/* ... 調(diào)用第三方接口 ... */
return $item;
}
- 再在控制器
SmsController
類的sendAction()
函數(shù)中加入以下代碼:
// 發(fā)送驗(yàn)證碼
$result = SMS::instance()->send($this->getPost('user_mobile'));
if ($result) {
// Output::instance($this->response)->success(’發(fā)送成功‘);
Output::instance($this->response)->success((object)$result);
} else {
Output::instance($this->response)->fail('發(fā)送失敗');
}
這里沒有真正實(shí)現(xiàn)調(diào)用第三方接口栽渴,而是直接返回了發(fā)送的驗(yàn)證碼,以供測試使用稳懒。正式代碼熔萧,只返回發(fā)送狀態(tài)。
SmsController.php
完整代碼:
<?php
class SmsController extends BaseController
{
/**
* 發(fā)送短驗(yàn)證碼
*/
public function sendAction()
{
// 驗(yàn)證請(qǐng)求方法是否是POST
$this->isPost();
// 驗(yàn)證請(qǐng)求參數(shù)
XValidationSms::send($this->getPost());
// 發(fā)送驗(yàn)證碼
$result = SMS::instance()->send($this->getPost('user_mobile'));
if ($result) {
// Output::instance($this->response)->success(’發(fā)送成功‘);
Output::instance($this->response)->success((object)$result);
} else {
Output::instance($this->response)->fail('發(fā)送失敗');
}
}
}
接口調(diào)試示例
- 請(qǐng)求地址:http://127.0.0.1:20081/sms/send
- 請(qǐng)求方式:POST
- 請(qǐng)求參數(shù):user_mobile=18088888888
- 返回?cái)?shù)據(jù):
{
"status": "1",
"value": "發(fā)送成功"
}
開發(fā)調(diào)試時(shí)返回?cái)?shù)據(jù) :
{
"status": "1",
"item": {
"code": "1139",
"time": "1520663958",
"verified": "0"
}
}
示例代碼下載
鏈接:https://pan.baidu.com/s/1gvyi8eX3JdlEUzzndpLVoQ 密碼:839z