如今,短信驗(yàn)證碼已成為網(wǎng)站、app的基礎(chǔ)必備應(yīng)用,應(yīng)用場(chǎng)景十分豐富,隨著移動(dòng)互聯(lián)網(wǎng)的發(fā)展會(huì)越來越多。作為一名碼農(nóng),對(duì)第三方短信接口也是必須掌握的。本文php中文網(wǎng)將介紹使用工廠模式怎么實(shí)現(xiàn)thinkphp6.0接入阿里云短信。
一、環(huán)境要求
????PHP版本 >= 7.1.0????開發(fā)環(huán)境必須安裝有composer????已開通阿里云短信服務(wù),并且已獲取AccessKey,創(chuàng)建模板和簽名????最重要的,阿里云賬戶余額一定要有錢。
這里我就不演示開通短信服務(wù)和創(chuàng)建簽名模板了,小伙伴們可以查看官方文檔:https://help.aliyun.com/document_detail/108072.html?spm=a2c4g.11186623.6.565.1b4825903BoqGV
二、使用Composer安裝Thinkphp6.0
如果您是第一次安裝,請(qǐng)?jiān)诿钚兄星袚Q到您的web目錄執(zhí)行下面的命令
立即學(xué)習(xí)“PHP免費(fèi)學(xué)習(xí)筆記(深入)”;
composer?create-project?topthink/think?sms
本教程將安裝在C盤www目錄下? ?三、使用Composer安裝 Alibaba Cloud SDK for PHP
進(jìn)到剛剛創(chuàng)建的sms項(xiàng)目下執(zhí)行下面的命令
composer?require?alibabacloud/sdk
四、使用編輯器打開項(xiàng)目 ,并在config文件夾下創(chuàng)建sms.php配置文件來管理阿里短信配置信息
<?php return [ //阿里云短信API接口地址 'host' =>?'dysmsapi.aliyuncs.com', ????//AccessKey?ID ????'access_key_id'?????=>?'您的AccessKey?ID', ????//Access?Key?Secret ????'access_key_secret'?=>?'您的Access?Key?Secret', ????//地區(qū)ID ????'region_id'?????????=>?'cn-hangzhou', ????//模板CODE ????'template_code'?????=>?'您的模板CODE', ????//簽名名稱 ????'sign_name'?????????=>?'您的短信簽名名稱', ];
五、順便在config文件夾下打開cache.php添加redis緩存配置,后面發(fā)送短信驗(yàn)證碼會(huì)用到
<?php // +---------------------------------------------------------------------- // | 緩存設(shè)置 // +---------------------------------------------------------------------- return [ // 默認(rèn)緩存驅(qū)動(dòng) 'default' =>?env('cache.driver',?'redis'), ????//?緩存連接方式配置 ????'stores'??=>?[ ????????'file'?=>?[ ????????????//?驅(qū)動(dòng)方式 ????????????'type'???????=>?'File', ????????????//?緩存保存目錄 ????????????'path'???????=>?'', ????????????//?緩存前綴 ????????????'prefix'?????=>?'', ????????????//?緩存有效期?0表示永久緩存 ????????????'expire'?????=>?0, ????????????//?緩存標(biāo)簽前綴 ????????????'tag_prefix'?=>?'tag:', ????????????//?序列化機(jī)制?例如?['serialize',?'unserialize'] ????????????'serialize'??=>?[], ????????], ????????//?Redis緩存 ????????'redis'?=>??[ ????????????//服務(wù)器地址 ????????????'host'??????=>??'127.0.0.1', ????????????//redis端口 ????????????'port'??????=>??6379, ????????????//驅(qū)動(dòng)方式 ????????????'type'??????=>??'redis', ????????????//緩存前綴 ????????????'prefix'????=>?'sms_code_', ????????] ????], ];
六、在app目錄下創(chuàng)建common/lib/sms/Sms.php接口類,用來約束發(fā)送短信驗(yàn)證碼的方法
<?php namespace appcommonlibsms; //定義實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼的接口類,用來約束發(fā)送驗(yàn)證碼的方法 interface Sms { /** * @desc 發(fā)送短信驗(yàn)證碼的方法 * @param string $phone 手機(jī)號(hào) * @param int $code 驗(yàn)證碼 * @return mixed */ public static function sendCode(string $phone, int $code); }
七、在common/lib/sms目錄下創(chuàng)建AliSms類來實(shí)現(xiàn)Sms接口的smsSend()
<?php namespace appcommonlibsms; use AlibabaCloudClientAlibabaCloud; use AlibabaCloudClientExceptionClientException; use AlibabaCloudClientExceptionServerException; class AliSms implements Sms { /** * @desc 阿里云發(fā)送短信驗(yàn)證碼 * @param string $phone 手機(jī)號(hào) * @param int $code 驗(yàn)證碼 * @return mixed|void * @throws ClientException */ public static function sendCode(string $phone, int $code) { //判斷手機(jī)號(hào)和驗(yàn)證碼是否為空 if (empty($phone) || empty($code)){ return false; } AlibabaCloud::accessKeyClient(config('sms.access_key_id'), config('sms.access_key_secret'))->regionId(config('sms.region_id'))->asDefaultClient(); ????????try?{ ????????????$result?=?AlibabaCloud::rpc() ????????????????->product('Dysmsapi') ????????????????//?->scheme('https')?//?https?|?http ????????????????->version('2017-05-25') ????????????????->action('SendSms') ????????????????->method('POST') ????????????????->host(config('sms.host')) ????????????????->options([ ????????????????????'query'?=>?[ ????????????????????????'RegionId'?=>config('sms.region_id'), ????????????????????????'SignName'?=>?config('sms.sign_name'), ????????????????????????'PhoneNumbers'??=>??$phone, ????????????????????????'TemplateCode'??=>??config('sms.template_code'), ????????????????????????'TemplateParam'?=>??json_encode(['code'??=>??$code]), ????????????????????], ????????????????])->request(); ????????}?catch?(ClientException?$e)?{ ????????????return?false; ????????}?catch?(ServerException?$e)?{ ????????????return?false; ????????} ????????return?true; ????} }
八、在commonlib目錄下創(chuàng)建生成短信驗(yàn)證碼的類 Code.php
<?php namespace appcommonlib; class Code { /** * @desc 生成4位或6位短信驗(yàn)證碼,默認(rèn)為4位 * @param int $length 驗(yàn)證碼長度 * @return int */ public static function getCode(int $length = 4) { $code = rand(1000,9999); if ($length == 6){ $code = rand(100000,999999); } return $code; } }
九、在common目錄下創(chuàng)建service/Sms.php
<?php namespace appcommonService; use appcommonlibCode; class Sms { /** * @param string $phone 手機(jī)號(hào) * @param int $lengthCode 驗(yàn)證碼長度 * @param string $type 短信廠家,默認(rèn)選用AliSms * @return mixed */ public static function sendCode(string $phone,int $lengthCode,string $type='AliSms') { //生成短信驗(yàn)證碼 $code = Code::getCode(4); //使用工廠模式 調(diào)用Lib層發(fā)送短信 $class = "appcommonlibsms".$type; $sms = $class::sendCode($phone,$code); if ($sms){ //發(fā)送成功,把短信驗(yàn)證碼存儲(chǔ)Redis緩存中,并給失效時(shí)間 cache($phone,$code,300); } return $sms; } }
十、在common目錄下創(chuàng)建validate/SmsValidate驗(yàn)證器
<?php namespace appcommonalidate; use thinkValidate; class SmsValidate extends Validate { //驗(yàn)證規(guī)則 protected $rule = [ 'phone' =>??'require|mobile', ????????'code'??????=>??'require|number' ????]; ????//錯(cuò)誤信息 ????protected?$message?=?[ ????????'phone.require'?????=>??'請(qǐng)輸入手機(jī)號(hào)', ????????'phone.mobile'??????=>??'手機(jī)號(hào)格式錯(cuò)誤', ????????'code.require'??????=>??'短信驗(yàn)證碼不能為空', ????????'code.number'???????=>??'短信驗(yàn)證碼必須為純數(shù)字' ????]; ????//驗(yàn)證場(chǎng)景 ????protected?$scene?=?[ ????????'sendCode'??=>??['phone'] ????]; }
十一、在controller目錄下創(chuàng)建Sms.php
<?php namespace appcontroller; use appcommonalidateSmsValidate; class Sms { /** * @desc 發(fā)送短信驗(yàn)證碼 * @return hink esponseJson */ public function code() { if (request()->isPost()){ ????????????//獲取手機(jī)號(hào) ????????????$data?=??[ ????????????????'phone'?=>??request()->param('phone','','trim'), ????????????]; ????????????//參數(shù)校驗(yàn) ????????????$validate?=?new?SmsValidate(); ????????????if?(!$validate->scene('sendCode')->check($data)){ ????????????????return?json(['code'=>0,'msg'=>$validate->getError()]); ????????????} ????????????//發(fā)送短信驗(yàn)證碼 ????????????if?(ppcommonServiceSms::sendCode($data['phone'],6,'AliSms')){ ????????????????return?json(['code'=>1,'msg'=>'發(fā)送成功,請(qǐng)注意查收。']); ????????????}else{ ????????????????return?json(['code'=>0,'msg'=>'發(fā)送失敗,請(qǐng)稍后重試!']); ????????????} ????????} ????} }
十二、使用postman測(cè)試發(fā)送短信驗(yàn)證碼
不輸入手機(jī)號(hào)或輸入錯(cuò)誤手機(jī)號(hào)會(huì)給相應(yīng)的提示。
輸入正確的手機(jī)號(hào),提示發(fā)送短信驗(yàn)證成功這時(shí)我們來看看收到的驗(yàn)證碼和緩存中的驗(yàn)證碼是否一致
到這里我們的發(fā)送驗(yàn)證碼已經(jīng)完成
十三、這時(shí)我們需要校驗(yàn)驗(yàn)證碼是否正確,在appcontroller目錄下創(chuàng)建Login.php
<?php namespace appcontroller; use appcommonalidateSmsValidate; class Login { public function index() { //接收參數(shù) $data = [ 'phone' =>??request()->param('phone','','trim'), ????????????'code'??=>??request()->param('code','','trim'), ????????]; ????????//參數(shù)校驗(yàn) ????????$validate?=?new?SmsValidate(); ????????if?(!$validate->check($data)){ ????????????return?json(['code'=>0,'msg'=>$validate->getError()]); ????????} ????????//從Redis中獲取驗(yàn)證碼 ????????$redisCode?=?cache($data['phone']); ????????//判斷驗(yàn)證碼是否正確 ????????if?(empty($redisCode)){ ????????????return?json(['code'=>0,'msg'=>'驗(yàn)證碼已過期,請(qǐng)重新發(fā)送!']); ????????} ????????if?($redisCode?!=?$data['code']){ ????????????return?json(['code'=>0,'msg'=>'驗(yàn)證碼輸入錯(cuò)誤,請(qǐng)重新輸入!']); ????????} ????????return?'驗(yàn)證成功'; ????} }
十四、使用PostMan校驗(yàn)驗(yàn)證碼是否正確
輸入錯(cuò)誤的驗(yàn)證碼,會(huì)給出響應(yīng)的提示
輸入正確的驗(yàn)證碼,提示驗(yàn)證成功
看到這里我相信很多小伙伴的驗(yàn)證碼都已發(fā)送成功了。
不知道小伙伴們有沒有發(fā)現(xiàn)文中有兩處參數(shù)校驗(yàn)的代碼相識(shí)度很高,在后續(xù)的thinkphp技術(shù)文章中我會(huì)對(duì)這個(gè)問題進(jìn)行優(yōu)化,感興趣的小伙伴請(qǐng)關(guān)注。