前言
注册时经常需要用到短信验证码,本文记录一下思路和具体实现。
短信验证平台使用云片,短信验证码的生成使用thinkphp。
思路
1、用户输入手机号,请求获取短信验证码。
2、thinkphp生成短信验证码,存储,同时和其他参数一起发送请求给云片。
3、云片发送短信验证码到指定手机号。
4、用户输入短信验证码。
5、thinkphp根据验证码是否正确、验证码是否过期两个条件判断是否验证通过。
代码实现
验证接口
接口地址:https://sms.yunpian.com/v1/sms/send.json。
使用postman,输入三个必须的参数apikey、mobile和text。
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时再添加。
成果
后记
以后也许有用的代码:
echo json_encode($_SESSION);// 打印出session中的数据 echo session_id();// 打印当前session的id
以上所述是小编给大家介绍的Thinkphp实现短信验证注册,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!
本文向大家介绍AngularJS实现注册表单验证功能,包括了AngularJS实现注册表单验证功能的使用技巧和注意事项,需要的朋友参考一下 本文为大家分享了案例: 注册表单验证,供大家参考,具体内容如下 需要使用的两张图片: dui.gif:cuo.gif: 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。
本文向大家介绍Android实现短信验证功能的代码,包括了Android实现短信验证功能的代码的使用技巧和注意事项,需要的朋友参考一下 在我们现在开发APP过程中,当用户注册时,短信验证是必不可少的操作,这里我们就是用一个免费的第三方短信验证SDK-MOP 首先看下效果图 获取AppKey和AppSecret 首先进入官网,登录(没有帐号的自己去注册一个)。鼠标移动到右侧头像处,点击进入后台。 官
本文向大家介绍Vue.js实现移动端短信验证码功能,包括了Vue.js实现移动端短信验证码功能的使用技巧和注意事项,需要的朋友参考一下 现在的短信验证码一般为4位或6位,则页面中会相应的显示4个或6个文本框,如图所示 当点击注册进入到输入验证码页面的时候,第一个框自动获取光标,依次输入,不可直接输入第三个或第四个框的值, input输入框是循环出来的,代码如下: 第一第三行不解释,相信聪明的你可以
本文向大家介绍Android实现自动填充短信验证码功能,包括了Android实现自动填充短信验证码功能的使用技巧和注意事项,需要的朋友参考一下 前言 短信验证码获取并自动填写现在已经成为一个人性化App的标配了,这篇文章将实现一个短信验证码获取并自动填写的demo。其实就是读取指定号码的短信并提取出验证码,然后赋值给EditText显示。 demo效果图: 读取短信 Android系统在接受到一条
本文向大家介绍ASP.NET实现用户注册和验证功能(第4节),包括了ASP.NET实现用户注册和验证功能(第4节)的使用技巧和注意事项,需要的朋友参考一下 在前几篇文章中小编已经为大家分享几篇关于验证控件实现的文章,今天我们再具体为用户登录页面添加输入数据验证功能和验证码功能。 学习内容 1、创建ASP.NET应用程序。 在E:\Solution1目录下双击文件,运行Visual Studio 2
本文向大家介绍Android实现短信验证码自动拦截读取功能,包括了Android实现短信验证码自动拦截读取功能的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Android短信验证码自动拦截读取 的具体代码,供大家参考,具体内容如下 知识准备: 1.观察者模式的理解【文章稍后来到~~】 2.Android的Cursor使用【Android基础】 3.正则表达式使用【Java基础