Thinkphp实现短信验证注册功能


Posted in PHP onOctober 18, 2016

前言

注册时经常需要用到短信验证码,本文记录一下思路和具体实现。

短信验证平台使用云片,短信验证码的生成使用thinkphp。

思路

1、用户输入手机号,请求获取短信验证码。

2、thinkphp生成短信验证码,存储,同时和其他参数一起发送请求给云片。

3、云片发送短信验证码到指定手机号。

4、用户输入短信验证码。

5、thinkphp根据验证码是否正确、验证码是否过期两个条件判断是否验证通过。

代码实现

验证接口

接口地址:https://sms.yunpian.com/v1/sms/send.json。

使用postman,输入三个必须的参数apikey、mobile和text。

Thinkphp实现短信验证注册功能

php发起http/https请求

使用php的curl函数发起https请求,带入参数apikey、mobile和text。

// 获取短信验证码
public function getSMSCode(){
// create curl resource 
$ch = curl_init(); 
// set url
$url = 'https://sms.yunpian.com/v1/sms/send.json'; 
curl_setopt($ch, CURLOPT_URL, $url); 
// set param
$paramArr = array(
'apikey' => '******',
'mobile' => '******',
'text' => '【小太阳】您的验证码是1234'
);
$param = '';
foreach ($paramArr as $key => $value) {
$param .= urlencode($key).'='.urlencode($value).'&';
}
$param = substr($param, 0, strlen($param)-1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
//curl默认不支持https协议,设置不验证协议
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 
//return the transfer as a string 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
// $output contains the output string 
$output = curl_exec($ch); 
// close curl resource to free up system resources 
curl_close($ch); 
echo $output;
}

生成随机短信验证码

默认生成四位的随机短信验证码。

// 生成短信验证码
public function createSMSCode($length = 4){
$min = pow(10 , ($length - 1));
$max = pow(10, $length) - 1;
return rand($min, $max);
}

整合

在数据库新建表sun_smscode:

DROP TABLE IF EXISTS `sun_smscode`;
CREATE TABLE `sun_smscode` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`mobile` varchar(11) NOT NULL,
`code` int(4) NOT NULL,
`create_at` datetime NOT NULL,
`update_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
thinkphp代码:
// 获取短信验证码
public function getSMSCode(){
// create curl resource 
$ch = curl_init(); 
// set url
$url = 'https://sms.yunpian.com/v1/sms/send.json'; 
curl_setopt($ch, CURLOPT_URL, $url); 
// set param
$mobile = $_POST['mobile'];
$code = $this->createSMSCode();
$paramArr = array(
'apikey' => '******',
'mobile' => $mobile,
'text' => '【小太阳】您的验证码是'.$code
);
$param = '';
foreach ($paramArr as $key => $value) {
$param .= urlencode($key).'='.urlencode($value).'&';
}
$param = substr($param, 0, strlen($param)-1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //不验证证书下同
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 
//return the transfer as a string 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
// $output contains the output string 
$output = curl_exec($ch); 
// close curl resource to free up system resources 
curl_close($ch); 
//$outputJson = json_decode($output);
$outputArr = json_decode($output, true);
//echo $outputJson->code;
//echo $outputArr['code'];
if($outputArr['code'] == '0'){
$data['mobile'] = $mobile;
$data['code'] = $code;
$smscode = D('smscode');
$smscodeObj = $smscode->where("mobile='$mobile'")->find();
if($smscodeObj){
$data['update_at'] = date('Y-m-d H:i:s');
$success = $smscode->where("mobile='$mobile'")->save($data);
if($success !== false){
$result = array(
'code' => '0',
'ext' => '修改成功',
'obj' => $smscodeObj
);
}
echo json_encode($result,JSON_UNESCAPED_UNICODE);
}else{
$data['create_at'] = date('Y-m-d H:i:s');
$data['update_at'] = $data['create_at'];
if($smscode->create($data)){
$id = $smscode->add();
if($id){
$smscode_temp = $smscode->where("id='$id'")->find();
$result = array(
'code'=> '0',
'ext'=> '创建成功',
'obj'=>$smscode_temp
);
echo json_encode($result,JSON_UNESCAPED_UNICODE);
}
}
}
}
}

验证短信验证码

验证短信验证码时间是否过期,验证短信验证码是否正确。

// 验证短信验证码是否有效
public function checkSMSCode(){
$mobile = $_POST['mobile'];
$code = $_POST['code'];
$nowTimeStr = date('Y-m-d H:i:s');
$smscode = D('smscode');
$smscodeObj = $smscode->where("mobile='$mobile'")->find();
if($smscodeObj){
$smsCodeTimeStr = $smscodeObj['update_at'];
$recordCode = $smscodeObj['code'];
$flag = $this->checkTime($nowTimeStr, $smsCodeTimeStr);
if(!$flag){
$result = array(
'code' => '1',
'ext' => '验证码过期,请刷新后重新获取'
);
echo json_encode($result,JSON_UNESCAPED_UNICODE);
return;
}
if($code != $recordCode){
$result = array(
'code' => '2',
'ext' => '验证码错误,请重新输入'
);
echo json_encode($result,JSON_UNESCAPED_UNICODE);
return;
}
$result = array(
'code' => '0',
'ext' => '验证通过'
);
echo json_encode($result,JSON_UNESCAPED_UNICODE);
}
}
// 验证验证码时间是否过期
public function checkTime($nowTimeStr,$smsCodeTimeStr){
//$nowTimeStr = '2016-10-15 14:39:59';
//$smsCodeTimeStr = '2016-10-15 14:30:00';
$nowTime = strtotime($nowTimeStr);
$smsCodeTime = strtotime($smsCodeTimeStr);
$period = floor(($nowTime-$smsCodeTime)/60); //60s
if($period>=0 && $period<=20){
return true;
}else{
return false;
}
}

改进

为了防止短信轰炸,在请求获取短信验证码时,需要加入图片验证码。

thinkphp提供了生成图片验证码的函数,下面我们来实现验证码的生成、刷新和验证。

生成和刷新图片验证码

// 获取图片验证码,刷新图片验证码
public function getPicCode(){
$config = array(
'fontSize'=>30, // 验证码字体大小
'length'=>4, // 验证码位数
'useNoise'=>false, // 关闭验证码杂点
'expire'=>600
);
$Verify = new \Think\Verify($config);
$Verify->entry(2333);//2333是验证码标志
}

假设,该函数的对应url为http://localhost/owner-bd/index.php/Home/CheckCode/getPicCode,那么,图片验证码的地址就是这个url,放入页面图片标签的src属性即可。

验证图片验证码

// 验证验证码是否正确
public function checkPicCode($code){
$verify = new \Think\Verify();
if($verify->check($code, 2333)){
$result = array(
'code' => '0',
'ext' => '验证通过'
);
echo json_encode($result,JSON_UNESCAPED_UNICODE);
}else{
$result = array(
'code' => '1',
'ext' => '验证码错误,请重新输入'
);
echo json_encode($result,JSON_UNESCAPED_UNICODE);
};
}

以上方法,我们利用了thinkphp提供的check方法,实现起来很简单。但是,如果想要得到验证细节,就没有办法了。比如,验证码错误,可能验证码超时,可能因为输入验证码错误,可能因为验证码已经使用过等等。必要的时候,可以重写thinkphp的验证码类,或者重写thinkphp的check方法。

跑通前后端

后端修改

验证图片验证码函数,改为被调用函数:

public function checkPicCode($picCode){
$verify = new \Think\Verify();
if($verify->check($picCode, 2333)){
return true;
}else{
return false;
};
}

在获取短信验证码函数的最顶部,添加调用图片验证码函数,只有通过验证,才发送请求给云片。

// 获取短信验证码
public function getSMSCode(){
$picCode = $_POST['picCode'];
if(!$this->checkPicCode($picCode)){
$result = array(
'code' => '1',
'ext' => '验证码错误,请重新输入'
);
echo json_encode($result,JSON_UNESCAPED_UNICODE);
return;
}
/*省略*/
}

前端核心代码

<!--register.html-->
<!DOCTYPE html>
<html lang="zh" ng-app="sunApp">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body ng-controller="registerController">
<form action="" class="register-form" ng-show="isShow1">
<div class="input-group">
<input type="text" class="mobile" ng-model="mobile" placeholder="手机号">
</div>
<div class="input-group">
<input type="text" class="pic-code" ng-model="picCode" placeholder="图片验证码">
<img class="img" src="{{picCodeUrl}}" alt="" ng-click="refresh()">
</div>
<div class="input-group">
<input type="text" class="sms-code" ng-model="SMSCode" placeholder="短信验证码">
<button class="btn-sms" ng-click="getSMSCode()" ng-disabled="btnSMSDisabled">{{btnSMSText}}</button>
</div>
<button class="confirm-btn" ng-click="next()">下一步</button>
</form>
<form action="" class="register-form" ng-show="isShow2">
<div class="input-group">
<input type="text" class="mobile" ng-model="mobile" placeholder="手机号" disabled="true">
</div>
<div class="input-group">
<input type="password" class="password" ng-model="password" placeholder="请输入密码">
<input type="password" class="password" ng-model="password2" placeholder="请再次输入密码">
</div>
<button class="confirm-btn" ng-click="getSMSCode()">注册</button>
</form>
</body>
</html>
// register.js
angular.module('sunApp').controller('registerController', function ($scope,$http,$httpParamSerializer,$state,$interval) { 
$scope.picCodeUrl = '/owner-bd/index.php/Home/CheckCode/getPicCode';
$scope.isShow1 = true;
$scope.isShow2 = false;
$scope.btnSMSText = '获取验证码';
$scope.btnSMSDisabled = false;
$scope.checkOver = false;
// 获取短信验证码
$scope.getSMSCode = function(){
var param = {
mobile: $scope.mobile,
picCode: $scope.picCode
};
$http({
method:'POST',
url:'/owner-bd/index.php/Home/SMS/getSMSCode',
//url: '/owner-fd/mock/common.json',
headers:{
'Content-Type':'application/x-www-form-urlencoded'
},
dataType: 'json',
data: $httpParamSerializer(param)
}).then(function successCallback(response) {
console.log(response.data);
if(response.data.code == '0'){
$scope.checkOver = true;
$scope.btnSMSDisabled = true;
var time = 60;
var timer = null;
timer = $interval(function(){
time = time - 1;
$scope.btnSMSText = time+'秒';
if(time == 0) {
$interval.cancel(timer);
$scope.btnSMSDisabled = false;
$scope.btnSMSText = '重新获取';
}
}, 1000);
}
}, function errorCallback(response) {
console.log(response.data);
});
}
// 验证短信验证码
$scope.next = function(){
if(!$scope.checkOver){
console.log('未通过验证');
return;
}
var param = {
mobile: $scope.mobile,
code: $scope.SMSCode
};
$http({
method:'POST',
url:'/owner-bd/index.php/Home/SMS/checkSMSCode',
//url: '/owner-fd/mock/common.json',
headers:{
'Content-Type':'application/x-www-form-urlencoded'
},
dataType: 'json',
data: $httpParamSerializer(param)
}).then(function successCallback(response) {
console.log(response.data);
if(response.data.code == '0'){
$scope.isShow1 = false;
$scope.isShow2 = true;
}
}, function errorCallback(response) {
console.log(response.data);
});
}
// 刷新图片验证码
$scope.refresh = function(){
$scope.picCodeUrl = '/owner-bd/index.php/Home/CheckCode/getPicCode?'+Math.random();
}
});

优化

以上代码,安全性不是很好,我们可以利用工具绕过前端验证。为了避免这个问题,可以在checkPicCode和checkSMSCode函数中添加session值来标记。

$_SESSION['checkPicCode'] = true;
$_SESSION['checkSMSCode'] = true;

在最后一步,向数据库中添加用户时,先验证一下两个session值是否都为true,都为true时再添加。

成果

Thinkphp实现短信验证注册功能

后记

以后也许有用的代码:

echo json_encode($_SESSION);// 打印出session中的数据
echo session_id();// 打印当前session的id

以上所述是小编给大家介绍的Thinkphp实现短信验证注册,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

PHP 相关文章推荐
用php来检测proxy
Oct 09 PHP
php+javascript的日历控件
Nov 19 PHP
php处理斐波那契数列非递归方法
Feb 04 PHP
ThinkPHP调试模式与日志记录概述
Aug 22 PHP
php程序员应具有的7种能力小结
Nov 27 PHP
Laravel 5框架学习之模型、控制器、视图基础流程
Apr 08 PHP
纯php生成随机密码
Oct 30 PHP
PHP使用Pear发送邮件(Windows环境)
Jan 05 PHP
yii2 页面底部加载css和js的技巧
Apr 21 PHP
thinkPHP中钩子的使用方法实例分析
Nov 16 PHP
PHP获取HTTP body内容的方法
Dec 31 PHP
YII2框架中查询生成器Query()的使用方法示例
Mar 18 PHP
php基于单例模式封装mysql类完整实例
Oct 18 #PHP
php封装的mysqli类完整实例
Oct 18 #PHP
PHP实现文件上传下载实例
Oct 18 #PHP
Yii实现文章列表置顶功能示例
Oct 18 #PHP
Yii统计不同类型邮箱数量的方法
Oct 18 #PHP
详解PHP归并排序的实现
Oct 18 #PHP
Yii框架中sphinx索引配置方法解析
Oct 18 #PHP
You might like
PHP setcookie指定domain参数后,在IE下设置cookie失效的解决方法
2011/09/09 PHP
PHP消息队列实现及应用详解【队列处理订单系统和配送系统】
2019/05/20 PHP
MacOS下PHP7.1升级到PHP7.4.15的方法
2021/02/22 PHP
jquery获取ASP.NET服务器端控件dropdownlist和radiobuttonlist生成客户端HTML标签后的value和text值
2010/06/28 Javascript
异步加载script的代码
2011/01/12 Javascript
javascript针对DOM的应用分析(四)
2012/04/15 Javascript
js实现幻灯片效果(基于jquery插件)
2013/11/05 Javascript
Checbox的操作含已选、未选及判断代码
2013/11/07 Javascript
搭建pomelo 开发环境
2014/06/24 Javascript
页面加载完后自动执行一个方法的js代码
2014/09/06 Javascript
JavaScript插入排序算法原理与实现方法示例
2018/08/06 Javascript
React 父子组件通信的实现方法
2019/12/05 Javascript
js get和post请求实现代码解析
2020/02/06 Javascript
Python实现抓取城市的PM2.5浓度和排名
2015/03/19 Python
Python自然语言处理之词干,词形与最大匹配算法代码详解
2017/11/16 Python
利用python在excel里面直接使用sql函数的方法
2019/02/08 Python
详解Python爬取并下载《电影天堂》3千多部电影
2019/04/26 Python
python画双y轴图像的示例代码
2019/07/07 Python
Python PyInstaller库基本使用方法分析
2019/12/12 Python
Python文本文件的合并操作方法代码实例
2020/03/31 Python
Keras搭建自编码器操作
2020/07/03 Python
HTML5为输入框添加语音输入功能的实现方法
2017/02/06 HTML / CSS
倩碧英国官网:Clinique英国
2018/08/10 全球购物
英国奢侈品概念店:Base Blu
2019/05/16 全球购物
俄罗斯电子产品、计算机和家用电器购物网站:OLDI
2019/10/27 全球购物
大学生求职简历的自我评价范文
2013/10/12 职场文书
中秋手机店促销方案
2014/06/16 职场文书
2014年收银工作总结
2014/11/13 职场文书
大学生个人学习总结
2015/02/15 职场文书
英语导游欢迎词
2015/09/30 职场文书
解决Tkinter中button按钮未按却主动执行command函数的问题
2021/05/23 Python
pytorch 如何使用amp进行混合精度训练
2021/05/24 Python
mysql 带多个条件的查询方式
2021/06/05 MySQL
深入浅出讲解Java8函数式编程
2022/01/18 Java/Android
redis lua限流算法实现示例
2022/07/15 Redis