TP5 實現簡訊驗證碼註冊功能

Pak.ho發表於2020-11-05

TP5 實現簡訊驗證碼註冊功能

1.首先在 common.php 中封裝 curl 函式,用於請求第三方介面

if(!function_exists('curl_request')){
    /**
     * @param string $url 請求地址
     * @param bool $post post 請求,預設為 get 請求,如果為 true,就表示 post 請求
     * @param array $params 請求引數
     * @param bool $https 是否為 https 請求
    */
    function curl_request($url, $post = true, $params = [], $https = true)
    {
        // 初始化請求
        $ch = curl_init($url);
        if($post) {
            // 如果 $post 為 true,就設定請求方式為 post 請求,預設為 get 請求
            curl_setopt($ch, CURLOPT_POST, true);
            // 並且設定 post 請求的請求引數
            curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        }
        if($https) {
            // 如果 $https 為 true,禁止從伺服器驗證本地證照
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        }
        // 傳送請求,獲取返回結果
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $res = curl_exec($ch);
        // 關閉請求
        curl_close($ch);
        // 返回結果
        return $res;
    }
}

2.還是在 common.php 中封裝傳送簡訊驗證碼的函式,這裡呼叫的是第三方的簡訊介面

if(!function_exists('sendmsg')) {
    /**
     * @param string $phone 手機號碼
     * @param string $content 簡訊模板
    */
    function sendmsg($phone, $content)
    {
        // 獲取請求地址、appkey
        $gateway = config('msg.gateway');
        $appkey = config('msg.appkey');
        // 拼接請求地址
        $url = $gateway . '?appkey=' . $appkey;
        // 呼叫封裝的 curl_request 函式,傳送請求
        $params = [
          'mobile' => $phone,
          'content' => $content
        ];
        // 這裡傳送的是 post 請求,並且請求地址是 https 的
        $res = curl_request($url, true, $params, true);
        // 判斷請求是否傳送失敗
        if(!$res) {
            return '請求傳送失敗';
        }
        // 處理結果
        $arr = json_decode($res, true);
        if(isset($arr['code']) && $arr['code'] == 10000) {
            // 簡訊介面呼叫成功
            return true;
        } else {
            // 簡訊介面呼叫失敗
            return '簡訊傳送失敗';
        }
    }
}

補充:上面的第三方請求地址、appkey,我都記錄在 config.php 當中

// 簡訊配置
'msg' => [
    'gateway' => 'https://xxxxxx',    // 介面地址
    'appkey' => 'xxxxxxxxxxxxx',      // appkey
],

3.其次在控制器中定義傳送簡訊驗證碼的介面

public function sendcode()
{
    // 接收引數
    $params = input();
    // 引數檢測
    $validate = $this->validate($params, [
        'phone' => 'require|regex:1[3-9]\d{9}'
    ]);
    if($validate !== true) {
        $res = [
            'code' => 400,
            'msg' => '引數錯誤'
        ];
        return json($res);
    }
    // 獲取上一次傳送驗證碼的時間
    $last_time = cache('register_time_' . $params['phone']);
    // 判斷當前傳送驗證碼的時間減去上一次傳送驗證碼的時間,是否小於 60
    if((time() - $last_time) < 60) {
        $res = [
            'code' => 400,
            'msg' => '傳送頻繁,稍後再試'
        ];
        return json($res);
    }
    // 傳送驗證碼 (生成驗證碼、生成簡訊內容、傳送簡訊)
    $code = mt_rand(1000, 9999);
    $content = "【XX】你的驗證碼是:{$code},3分鐘內有效!";
    // $result = sendmsg($params['phone'], $content);   // 為了不減少第三方簡訊介面的傳送次數,這裡暫時遮蔽,開發完畢後自行開啟
    $result = true; // 直接將 $result 設定為 true,進行簡訊介面的測試,開發完畢後自行刪除
    if($result === true) {
        // 將驗證碼儲存到快取,用於後續的驗證
        cache('register_code_' . $params['phone'], $code, 180);
        // 將當前傳送驗證碼的時間存到快取,用於防止使用者頻繁傳送驗證碼
        cache('register_time_' . $params['phone'], time(), 180);
        // 返回成功結果
        $res = [
            'code' => 200,
            'msg' => '簡訊傳送成功',
            'data' => $code		// 開發完畢之後,將其刪掉
        ];
        return json($res);
    } else {
        // 返回失敗結果
        $res = [
            'code' => 400,
            'msg' => $result
        ];
        return json($res);
    }
}

4.定義手機號註冊介面

public function phone()
{
    // 接收引數
    $params = input();
    // 引數檢測
    $rule = [
        'phone|手機號碼' => 'require|regex:1[3-9]\d{9}|unique:user,phone',
        'code|驗證碼' => 'require|length:4',
        'password|密碼' => 'require|length:6,12|confirm:repassword'
    ];
    $validate = $this->validate($params, $rule);
    if($validate !== true) {
        $this->error($validate);
    }
    // 驗證碼校驗
    $code = cache('register_code_' . $params['phone']);
    if($code != $params['code']) {
        $this->error('驗證碼錯誤');
    }
    // 驗證碼校驗成功一次後,將當前快取中對應手機號的驗證碼刪除
    cache('register_code_' . $params['phone'], null);
    // 密碼加密,encrypt_password() 是封裝的密碼加密函式,這裡就不多說了
    $params['password'] = encrypt_password($params['password']);
    // 設定使用者名稱的預設值
    $params['username'] = $params['phone'];
    // 註冊使用者
    User::create($params, true);
    // 頁面跳轉
    $this->redirect('home/login/login');
}

5.最後是前端程式碼的展示

<!-- html -->
<form action="{:url('phone')}" method="post" id="reg_form" class="sui-form form-horizontal">
	<div class="control-group">
		<label class="control-label">手機號:</label>
		<div class="controls">
			<input type="text" id="phone" name="phone" placeholder="請輸入你的手機號" class="input-xfat input-xlarge">
			<span class="error"></span>
		</div>
	</div>
	<div class="control-group">
		<label for="code" class="control-label">驗證碼:</label>
		<div class="controls">
			<input type="text" id="code" name="code" placeholder="驗證碼" class="input-xfat input-xlarge" style="width:120px">
			<button type="button" class="btn-xlarge" id="dyMobileButton">傳送驗證碼</button>
			<span class="error"></span>
		</div>
	</div>
	<div class="control-group">
		<label for="password" class="control-label">登入密碼:</label>
		<div class="controls">
			<input type="password" id="password" name="password" placeholder="設定登入密碼" class="input-xfat input-xlarge">
			<span class="error"></span>
		</div>
	</div>
	<div class="control-group">
		<label for="repassword" class="control-label">確認密碼:</label>
		<div class="controls">
			<input type="password" id="repassword" name="repassword" placeholder="再次確認密碼" class="input-xfat input-xlarge">
			<span class="error"></span>
		</div>
	</div>
	<div class="control-group">
		<label for="inputPassword" class="control-label">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>
		<div class="controls">
			<input name="m1" type="checkbox" value="2" checked=""><span>同意協議並註冊《XXX使用者協議》</span>
		</div>
	</div>
	<div class="control-group">
		<label class="control-label"></label>
		<div class="controls btn-reg">
			<a id="reg_btn" class="sui-btn btn-block btn-xlarge btn-danger reg-btn" href="javascript:;">完成註冊</a>
		</div>
	</div>
</form>
// javascript
$('#dyMobileButton').on('click', function() {
	// 獲取手機號
	var phone = $('#phone').val()
	// 定時器
	var time = 60
	if(trim(phone) == '') {
		// 如果手機號碼為空
		$('#phone').next().html('手機號碼不能為空')
		return
	} else if(!/^1[3-9]\d{9}$/.test(phone)) {
		// 如果不符合手機號碼的格式
		$('#phone').next().html('手機號碼格式不正確')
		return
	} else {
		//清空錯誤提示
		$('#phone').next().html('')
	}
	// 設定倒數計時
	var timer = setInterval(() => {
		time--
		if(time > 0) {
			// 正在倒數計時
			$(this).html(`${time}秒後,重新傳送`)
			$(this).attr('disabled', true)
		} else {
			// 停止倒數計時
			$(this).html('傳送驗證碼')
			$(this).attr('disabled', false)
			clearInterval(timer)
		}
	}, 1000)
	// 傳送請求
	$.ajax({
		url: '{:url("home/login/sendcode")}',
		type: 'post',
		data: `phone=${phone}`,
		dataType: 'json',
		success: function(res) {
			console.log(res)
			alert(res.msg)
			return
		}
	})
})

程式設計師小白,如有寫得不好地方,還請多多指教、多多見諒!

相關文章