ThinkPHP realizes SMS verification and registration

Time:2020-11-27

preface

When registering, we often need to use SMS verification code. This paper records the ideas and specific implementation.
Cloud is used in SMS verification platform, and ThinkPHP is used to generate SMS verification code.

thinking

1. The user enters the mobile phone number and requests to obtain the SMS verification code.
2. ThinkPHP generates SMS verification code, stores it, and sends the request to cloud with other parameters.
3. Cloud sends SMS verification code to the specified mobile phone number.
4. The user input SMS verification code.
5. Whether the two codes pass the verification according to the conditions.

code implementation

Verification interface

Interface address:https://sms.yunpian.com/v1/sms/send.json
Using postman, enter the three required parametersapikeymobileandtext

PHP initiates http / HTTPS request

Use the curl function of PHP to initiate an HTTPS request and bring in the parametersapikeymobileandtext

//Get SMS verification code
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 '= >' [little sun] your verification code is 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 does not support the HTTPS protocol by default, and the protocol is not verified
    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;
}

Generate random SMS verification code

Four digit random SMS verification code is generated by default.

//Generate SMS verification code
public function createSMSCode($length = 4){
    $min = pow(10 , ($length - 1));
    $max = pow(10, $length) - 1;
    return rand($min, $max);
}

integration

Create a new table sun in the database_ 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 Code:

//Get SMS verification code
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 '= >' [little sun] your verification code is'. $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); // do not verify the certificate, the same below
    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' = > 'modified successfully',
                    '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' = >'created successfully ',
                        'obj'=>$smscode_temp
                    );
                    echo json_encode($result,JSON_UNESCAPED_UNICODE);
                }
            }
        }
        
    }
}

Verify SMS verification code

Verify whether the time of SMS verification code is expired and whether the SMS verification code is correct.

//Verify whether the SMS verification code is valid
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' = > 'the verification code has expired, please refresh and get it again'
            );
            echo json_encode($result,JSON_UNESCAPED_UNICODE);
            return;
        }

        if($code != $recordCode){
            $result = array(
                'code' => '2',
                'ext' = > 'wrong verification code, please re-enter'
            );
            echo json_encode($result,JSON_UNESCAPED_UNICODE);
            return;
        }

        $result = array(
            'code' => '0',
            'ext' = > 'validation passed'
        );
        echo json_encode($result,JSON_UNESCAPED_UNICODE);
    }
}

//Verify whether the captcha time has expired
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;
    }
}

improvement

In order to prevent the SMS code from being bombed, it is necessary to verify the SMS code.

ThinkPHP provides the function of generating image captcha. Let’s implement the generation, refresh and verification of captcha.

Generate and refresh image captcha

//Get the image verification code, refresh the image verification code
public function getPicCode(){
    $config = array(
        'fontsize' = > 30, // font size of captcha
        'length' = > 4, // verification code bits
        'usenoise' = > false, // turn off captcha clutter
        'expire'=>600
    );
    $Verify = new \Think\Verify($config);
    $verify > entry (2333); // 2333 is the captcha flag
}

Suppose that the corresponding URL of the function ishttp://localhost/owner-bd/index.php/Home/CheckCode/getPicCode, then, the address of the image verification code is this URL, which can be put into the SRC attribute of the page image tag.

Verify picture captcha

//Verify that the captcha is correct
public function checkPicCode($code){
    $verify = new \Think\Verify();
    if($verify->check($code, 2333)){
        $result = array(
            'code' => '0',
            'ext' = > 'validation passed'
        );
        echo json_encode($result,JSON_UNESCAPED_UNICODE);
    }else{
        $result = array(
            'code' => '1',
            'ext' = > 'wrong verification code, please re-enter'
        );
        echo json_encode($result,JSON_UNESCAPED_UNICODE);
    };
}

For the above methods, we use the check method provided by ThinkPHP, which is very simple to implement. However, if you want to get the validation details, there is no way. For example, the verification code is wrong, the verification code may time out, the input verification code may be wrong, the verification code has been used, and so on. If necessary, you can override the captcha class of ThinkPHP or the check method of ThinkPHP.

Run through the front and back

Back end modification

Verify image captcha function, change to called function:

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

At the top of the function of getting SMS verification code, add and call the image verification code function. Only after passing the verification, can the request be sent to the cloud.

//Get SMS verification code
public function getSMSCode(){
    $picCode = $_POST['picCode'];
    if(!$this->checkPicCode($picCode)){
        $result = array(
            'code' => '1',
            'ext' = > 'wrong verification code, please re-enter'
        );
        echo json_encode($result,JSON_UNESCAPED_UNICODE);
        return;
    }
    /*Omission*/
}

Front end core code

<!--register.html-->
<!DOCTYPE html>
<html lang="zh" ng-app="sunApp">
<head>
    <meta charset="UTF-8">
    < title > registration
</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 = "mobile number" > "
        </div>
        <div class="input-group">
            < input type = "text" class = "PIC code" ng model = "piccode" placeholder = "picture captcha" > "
            <img class="img" ng-click="refresh()">
        </div>
        <div class="input-group">
            < input type = "text" class = "SMS code" ng model = "smscode" placeholder = "SMS verification code" > "
            <button class="btn-sms" ng-click="getSMSCode()" ng-disabled="btnSMSDisabled">{{btnSMSText}}</button>
        </div>
        < button class = "confirm BTN" ng Click = "next()" > next < / button > next step
    </form>

    <form action="" class="register-form" ng-show="isShow2">
        <div class="input-group">
            < input type = "text" class = "mobile" ng model = "mobile" placeholder = "mobile number" disabled = "true" >
        </div>
        <div class="input-group">
            < input type = password "class =" password "ng model =" password "placeholder = please input password" > "
            < input type = password "class =" password "ng model =" password2 "placeholder = please enter the password again" >
        </div>
        < button class = "confirm BTN" ng Click = "getsmscode()" > register < / 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  ='get verification code';
    $scope.btnSMSDisabled = false;
    $scope.checkOver = false;

    //Get SMS verification code
    $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 +'s';
                    if(time == 0) {
                        $interval.cancel(timer);
                        $scope.btnSMSDisabled = false;
                        $ scope.btnSMSText  ='recapture ';
                    }
                }, 1000);
            }
        }, function errorCallback(response) {
            console.log(response.data);
        });
    }

    //Verify SMS verification code
    $scope.next = function(){
        if(!$scope.checkOver){
            console.log ('failed validation');
            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);
        });
    }

    //Refresh image captcha
    $scope.refresh = function(){
        $scope.picCodeUrl = '/owner-bd/index.php/Home/CheckCode/getPicCode?'+Math.random();
    }

});

optimization

The security of the above code is not very good, we can use tools to bypass the front-end verification. To avoid this problem, you can add a session value to the checkpiccode and checksmscode functions to mark.

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

When you add the value of true to the user in the last two steps, verify whether it is true in the last step.

achievements

ThinkPHP realizes SMS verification and registration

Postscript

Code that may be useful in the future:

echo json_ encode($_ Session); // print the data in the session
echo session_ Id(); // print the ID of the current session

bookmark

Cloud net
https://www.yunpian.com/

Curl function
http://php.net/manual/zh/ref….

Curl foundation example
http://php.net/manual/zh/curl…

Using JSON in PHP language
http://www.ruanyifeng.com/blo…

ThinkPHP captcha
http://document.thinkphp.cn/m…

Modify the captcha class of ThinkPHP
http://www.cnblogs.com/BTMast…

ThinkPHP version 3.2, unable to read$_ SESSION[‘verify_ code’]
http://www.cnblogs.com/lovezb…

LICEcap – Download
http://licecap.en.softonic.com/

Gif dynamic picture with mosaic fuzzy advertising text
http://www.leawo.cn/space-138…