通常我们实名注册用户的时候,都会要求输入手机号,然后获取手机验证码,然后填到页面,像下面这样:
ok,现在来理一下思绪:
1.注册页面
因为这里要说的是短信验证,所以只贴出核心代码,下面是手机号和短信验证码这两部分的前端代码片段:
<div data-v-7cf0b24e="" class="lj_input_standard4">
<span data-v-7cf0b24e="" id="left_span6">手机号</span>
<span data-v-7cf0b24e="" id="asterisk_span6">*</span>
<input v-model="phone" data-v-7cf0b24e="" id="myinput6" name="data[phone]" type="tel" maxlength="11" placeholder="请输入手机号码">
</div>
<div data-v-7cf0b24e="" class="lj_input_standard4">
<span data-v-7cf0b24e="" id="left_span7">短信验证码</span>
<span data-v-7cf0b24e="" id="asterisk_span7">*</span>
<input data-v-7cf0b24e="" id="myinput7" name="data[code]" type="tel" placeholder="请输入验证码">
<div data-v-7cf0b24e="" class="lj_register_getvcode sendCode" id="sendCode" @click="send"
:class="{ login_code_gbb: (phone.length!==11 || wait) }">{{time}}</div>
</div>
这个页面使用vue.js写的,但是你不用先去了解vue.js再来看接下来的内容,so,继续
上面就是表单的两个字段:phone和code,@click=“send”设置了“获取验证码”这个div的单击事件为send();
//send方法
send: function() {
if(app.phone.length!=11 || app.phone!=parseInt(app.phone) || app.wait) return;
$.ajax({
url: '/?c=api&m=mobilecode&phone='+app.phone,
type: 'post',
dataType: 'json',
success: function(res) {
if( res.code ) {
app.timer();
layer.msg('发送成功');
} else {
layer.msg('发送失败');
}
}
});
},
同样的,你可能不懂vue的语法,但是你应该能够看懂:
获取phone字段输入的手机号(经过各种验证之后),并且发起一个ajax请求,正如你看到的那样,这个请求携带了手机号参数,
接下来,继续看请求的接口到底是怎么处理的。
2.api接口
public function mobilecode() {
$phone = $this->input->get("phone") =='' ? $this->input->post("phone") : $this->input->get("phone");
if(!$phone){
exit_json(0,'手机号为空!');
}
if($_COOKIE['wait_time'] && $phone == $_SESSION['phone']){
exit_json(0,'已经发送过短信了,请稍后再试!');
}
$randcode = rand('100000','999999');
$_SESSION['randcode'] = $randcode;
$_SESSION['phone'] = $phone;
$this->load->library('mdysms');
$res = $this->mdysms->sendSms($phone,['code'=>$randcode]);
if($res->Code === 'OK'){
//设置cookie
setcookie("wait_time",1,50);
$_SESSION['phone'] = $phone;
//获取方式
exit_json(1,'短信发送成功!');
}else{
exit_json(0,'短信发送失败!');
}
}
生成随机验证码并存到服务端session中(把手机号也存到session是为了做校验防止同一手机号多次注册);
加载类文件并执行sendSms方法(自定义类文件,用于将验证码和手机号以及必需参数传给阿里短信服务的SDK方法);
3.自定义类文件
这个类用于收集阿里短信服务SDK方法所需的所有参数,并调用AliSDK中的方法
require_once dirname(__FILE__).'/dysms/SignatureHelper.php';
require_once dirname(__FILE__).'/dysms/conf.inc.php';
use Aliyun\DySDKLite\SignatureHelper;
class Mdysms {
public $conf;
public function __construct()
{
$this->conf['accessKeyId'] = ACCESSKEYID;
$this->conf['accessKeySecret'] = ACCESSKEYSECRET;
$this->conf['signName'] = SignName;
$this->conf['templateCode'] = TemplateCode;
}
public function sendSms($phoneNumbers, $param, $templateCode = FALSE, $signName = FALSE)
{
$params['TemplateParam'] = json_encode($param, JSON_UNESCAPED_UNICODE);
$params['TemplateCode'] = $templateCode?$templateCode:$this->conf['templateCode'];
$params['SignName'] = $signName?$signName:$this->conf['signName'];
$params['PhoneNumbers'] = $phoneNumbers;
$helper = new SignatureHelper();
$resp = $helper->request(
$this->conf['accessKeyId'],
$this->conf['accessKeySecret'],
"dysmsapi.aliyuncs.com",
array_merge($params, array(
"RegionId" => "cn-hangzhou",
"Action" => "SendSms",
"Version" => "2017-05-25"
))
);
return $resp;
}
}
这些红字常量是在conf.inc.php中定义的,是购买阿里短信服务时候获取到的。那么,这个request方法用到的参数如下:
accessKeyId-------------------购买短信通知服务获取
accessKeySecret---------------购买短信通知服务获取
signName----------------------购买短信通知服务获取
templateCode------------------购买短信通知服务获取
PhoneNumbers------------------手机号
TemplateParam-----------------在这里就是随机验证码
domain------------------------dysmsapi.aliyuncs.com
RegionId----------------------cn-hangzhou
Action------------------------SendSms
Version-----------------------2017-05-25
4.阿里云的SDK(其实这个可以无视)
<?php
namespace Aliyun\DySDKLite;
/**
* 签名助手 2017/11/19
*
* Class SignatureHelper
*/
class SignatureHelper {
/**
* 生成签名并发起请求
*
* @param $accessKeyId string AccessKeyId (https://ak-console.aliyun.com/)
* @param $accessKeySecret string AccessKeySecret
* @param $domain string API接口所在域名
* @param $params array API具体参数
* @param $security boolean 使用https
* @return bool|\stdClass 返回API接口调用结果,当发生错误时返回false
*/
public function request($accessKeyId, $accessKeySecret, $domain, $params, $security=false) {
$apiParams = array_merge(array (
"SignatureMethod" => "HMAC-SHA1",
"SignatureNonce" => uniqid(mt_rand(0,0xffff), true),
"SignatureVersion" => "1.0",
"AccessKeyId" => $accessKeyId,
"Timestamp" => gmdate("Y-m-d\TH:i:s\Z"),
"Format" => "JSON",
), $params);
ksort($apiParams);
$sortedQueryStringTmp = "";
foreach ($apiParams as $key => $value) {
$sortedQueryStringTmp .= "&" . $this->encode($key) . "=" . $this->encode($value);
}
$stringToSign = "GET&%2F&" . $this->encode(substr($sortedQueryStringTmp, 1));
$sign = base64_encode(hash_hmac("sha1", $stringToSign, $accessKeySecret . "&",true));
$signature = $this->encode($sign);
$url = ($security ? 'https' : 'http')."://{$domain}/?Signature={$signature}{$sortedQueryStringTmp}";
try {
$content = $this->fetchContent($url);
return json_decode($content);
} catch( \Exception $e) {
return false;
}
}
private function encode($str)
{
$res = urlencode($str);
$res = preg_replace("/\+/", "%20", $res);
$res = preg_replace("/\*/", "%2A", $res);
$res = preg_replace("/%7E/", "~", $res);
return $res;
}
private function fetchContent($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"x-sdk-client" => "php/2.0.0"
));
if(substr($url, 0,5) == 'https') {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
}
$rtn = curl_exec($ch);
if($rtn === false) {
trigger_error("[CURL_" . curl_errno($ch) . "]: " . curl_error($ch), E_USER_ERROR);
}
curl_close($ch);
return $rtn;
}
}