註冊功能是很多網站必做的功能,有註冊功能就要有簡訊驗證碼,本文給大家分享thinkphp實現簡訊驗證註冊功能,感興趣的朋友一起看看吧
前言
註冊時經常需要用到簡訊驗證碼,本文記錄一下思路和具體實現。
簡訊驗證平台使用雲片,簡訊驗證碼的產生使用thinkphp。
思路
1、使用者輸入手機號,請求擷取簡訊驗證碼。
2、thinkphp產生簡訊驗證碼,儲存,同時和其他參數一起發送請求給雲片。
3、雲片傳送簡訊驗證碼到指定手機號。
4、使用者輸入簡訊驗證碼。
5、thinkphp根據驗證碼是否正確、驗證碼是否到期兩個條件判斷是否驗證通過。
代碼實現
驗證介面
使用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); //60sif($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"><p class="input-group"><input type="text" class="mobile" ng-model="mobile" placeholder="手機號"></p><p class="input-group"><input type="text" class="pic-code" ng-model="picCode" placeholder="圖片驗證碼"><img class="img" src="{{picCodeUrl}}" alt="" ng-click="refresh()"></p><p 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></p><button class="confirm-btn" ng-click="next()">下一步</button></form><form action="" class="register-form" ng-show="isShow2"><p class="input-group"><input type="text" class="mobile" ng-model="mobile" placeholder="手機號" disabled="true"></p><p class="input-group"><input type="password" class="password" ng-model="password" placeholder="請輸入密碼"><input type="password" class="password" ng-model="password2" placeholder="請再次輸入密碼"></p><button class="confirm-btn" ng-click="getSMSCode()">註冊</button></form></body></html>// register.jsangular.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
以上就是本文的全部內容,希望對大家的學習有所協助,更多相關內容請關注topic.alibabacloud.com!