Memcache 配置, 在 /app/config/config.ini 文件添加以下代码:
[memcache] host = 127.0.0.1 port = 11211 prefix = api
在 Visual NMP 中,默认已经安装了 Memcache, 可直接使用。如服务未开启,直接打开即可。 默认连接端口:11211。缓存键名前缀:prefix = api,方便区分项目,可随意设置, 一般设置为项目名。
「PHP开发APP接口实战001」开发环境搭建
短信配置, 在 /app/config/config.php 文件添加以下代码:
'sms' => [ 'times' => 3, // 同一手机一小时内发送短信次数, 0 为不限制 'interval' => 60, // 同一手机两次发送间隔时间(单位:秒), 0 为不限制 'valid_time' => 300, // 短信验证码有效时间(单位:秒), 0 为久有效 ],创建 Memcache 操作类 XMemcache
在 /app/library 目录下创建文件 XMemcache.php, 添加以下代码:
memcache = new Memcache(); // 加载配置参数
$this->config = Config::instance()->get('memcache', 'ini'); // 连接Memcache服务器
$this->memcache->addServer($this->config['host'], $this->config['port']); $this->tag = $tag;
}
public static function instance($tag = null)
{ if (!self::$instance) self::$instance = new self($tag); return self::$instance;
}
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);
}
public function set($key, $value, $timeout = 604800, $iszip = 0)
{
$value = serialize($value); return $this->memcache->set($this->formatKey($key), $value, $iszip, $timeout);
}
public function get($key)
{
$value = $this->memcache->get($this->formatKey($key)); return unserialize($value);
}
public function delete($key)
{ return $this->memcache->delete($this->formatKey($key));
}
public function flush()
{ return $this->memcache->flush();
}
private function formatKey($key)
{ return $this->config['prefix'] . ':' . $this->tag . ':' . $key;
}
}生成短信验证码这里重写了一些 Memcache 常用的操作函数。 如:设置缓存 set(), 追加缓存 append(), 获取缓存 get(), 删除缓存 delete(), 清空缓存 flush()
值得注意的是,我们还对缓存键名进行了重写,方便区分项目和模块。
在 /app/library 目录下创建文件 SMS.php, 添加以下代码:
config = Config::instance()->get('sms');
} public static function instance()
{ if (!self::$instance) self::$instance = new self(); return self::$instance;
}
}这里实现了实例化时,自己加载配置参数。
增加验证码改送函数 send(), 用于外部调用。如:
public function send($mobile)
{
}此函数里面分四步走:
验证指定手机号,当前是否可以发送验证码
生成四位数字验证码,并配置上生成时间
调用 XMemcache 缓存验证码
调用第三方接口,发送验证码,并返回发送状态。(市场上有许多发送第三方平台,都有)
这里调换一下顺序,先讲解生成和缓存验证码。
首先,添加函数generateCode(), 随机生成4位数字验证码
private function generateCode()
{ return rand(1000, 9999);
}然后,在 send() 函数中添加代码:
$item = [ 'code' => $this->generateCode(), // 生成短信验证码 'time' => time(), // 生成时间 'verified' => 0, // 验证状态: 0 未验证, 1 已验证 ];
这里除了生成验证码,同时初始化生成时间time, 验证状态verified,用于验证发送时间和检查验证码是否已验证。
缓存验证码,在 send() 函数中添加代码:
// 缓存短信验证码
XMemcache::instance('sms')->append($mobile, $item, 3600);这里完成了几个工作:
将 $item 存于以指定手机号为键名的缓存下
同一手机号多次发送,都存在同一键名下,用于统计1小时内验证码发送次数。
缓存有效时间设置为 1 小时
现在我们再回来讲解验证是否允许向指定手机号发送验证码。
验证规则:
同一手机两次发送间隔时间1分钟(可配置间隔时间)
同一手机1小时内最多只能发送3次验证码(可配置发送次数)
首先,添加函数 getCacheCodes() 和 validateSend(), 如:
private function getCacheCodes($mobile)
{
$codes = XMemcache::instance('sms')->get($mobile); if (!$codes) return []; foreach ($codes as $index => $item) { // 过滤发送超过1小时的验证码
if (time() - $item['time'] > 3600) { unset($codes[$index]);
}
} // 重置数组索引
$codes = array_values($codes); // 更新缓存
XMemcache::instance('sms')->set($mobile, $codes); return $codes;
}
private function validateSend($mobile)
{
$codes = $this->getCacheCodes($mobile); if ($this->config['times'] > 0 && count($codes) >= $this->config['times']) { throw new Exception('一小时内最多只能发送' . $this->config['times'] . '次短信验证码');
}
$lastCode = end($codes); if ($this->config['interval'] > 0 && time() - $lastCode['time'] <= $this->config['interval']) { throw new Exception('发送频率太快');
}
}
函数 getCacheCodes() 获取指定手机1小时内发送的验证码。
函数 validateSend() 实现:
验证一小时内向同一手机发送短信验证码次数是否超过了配置次数;
验证上次发送验证码是否已经超过配置时间;
然后在 send() 函数中,所有代码之前插入代码 $this->validateSend($mobile);。
send() 函数完整代码:
public function send($mobile)
{ // 验证短信发送次数
$this->validateSend($mobile);
$item = [ 'code' => $this->generateCode(), // 生成短信验证码
'time' => time(), // 生成时间
'verified' => 0, // 验证状态: 0 未验证, 1 已验证
]; // 缓存短信验证码
XMemcache::instance('sms')->append($mobile, $item, 3600); // 发送短信验证码
return $item;
}再在控制器 SmsController 类的 sendAction() 函数中加入以下代码:
// 发送验证码
$result = SMS::instance()->send($this->getPost('user_mobile')); if ($result) {// Output::instance($this->response)->success(’发送成功‘);
Output::instance($this->response)->success((object)$result);
} else {
Output::instance($this->response)->fail('发送失败');
}SmsController.php 完整代码:这里没有真正实现调用第三方接口,而是直接返回了发送的验证码,以供测试使用。正式代码,只返回发送状态。
isPost(); // 验证请求参数
XValidationSms::send($this->getPost()); // 发送验证码
$result = SMS::instance()->send($this->getPost('user_mobile')); if ($result) {// Output::instance($this->response)->success(’发送成功‘);
Output::instance($this->response)->success((object)$result);
} else {
Output::instance($this->response)->fail('发送失败');
}
}
}接口调试示例请求地址:http://127.0.0.1:20081/sms/send
请求方式:POST
请求参数:user_mobile=18088888888
返回数据:
{ "status": "1", "value": "发送成功"}开发调试时返回数据 :
{ "status": "1", "item": { "code": "1139", "time": "1520663958", "verified": "0"
}
}
作者:一念觀心
链接:https://www.jianshu.com/p/0dbdf556b4f3



