阿里云短信验证码发送类

<?php
 /**
 * 阿里云短信验证码发送类
 * @author GavinLau
 * @email gavinliuyu@gmail.com
 * @blog 开源中国: https://my.oschina.net/u/3022696/blog
 * CSDN: http://blog.csdn.net/gavinlauy
 * 新浪博客: http://blog.sina.com.cn/u/3835413802
 * @PHP交流群 440479799(QQ)
 */
class Sms {
    public $error;     // 保存错误信息
    private $accessKeyId = '';    // Access Key ID
    private $accessKeySecret = ''; // Access Access Key Secret
    private $signName = ''; // 签名名称 https://sms.console.aliyun.com/#/sms/Sign短信签名中的签名名称
    private $templateCode = '';    // 模版(阿里云提供)


    public function __construct($cofig = array()) {
        $cofig = array (
            'accessKeyId'       =>  '', //填写自己的
            'accessKeySecret'   =>  '', //填写自己的
            'signName'          =>  '', //填写自己设置的
            'templateCode'      =>  '' //填写自己所需要的
        );
        // 配置参数
        $this->accessKeyId = $cofig['accessKeyId'];
        $this->accessKeySecret = $cofig['accessKeySecret'];
        $this->signName = $cofig['signName'];
        $this->templateCode = $cofig['templateCode'];
    }
/**
     * 编码
     * @param $string   要编码的字符串
     * @return string
     */
    private function percentEncode($string) {
        $string = urlencode($string);
        $string = preg_replace('/\+/', '%20', $string);
        $string = preg_replace('/\*/', '%2A', $string);
        $string = preg_replace('/%7E/', '~', $string);
        return $string;
    }
    /**
     * 计算签名
     * (详细步骤在下面链接中)
     * https://help.aliyun.com/document_detail/44363.html?spm=5176.doc50118.2.4.ZOeshY
     *
     * @param $params   要计算签名的参数
     * @param $accesss_key_secret  秘钥
     * @return string
     */
    private function calculatedSignature($params, $accessKeySecret) {
// 将参数排序(ksort()对数组按照键名排序)
        ksort($params);
// 构造规范化的请求字符串
        $canonicalizedQueryString = '';
        foreach ($params as $key => $value ) {
// 对每个请求参数的名称和值进行编码
            $canonicalizedQueryString .= '&'.$this->percentEncode($key).'='.$this->percentEncode($value);
        }
// 构造用于计算签名的字符串
        // $stringToSign = 'GET&%2F&'.$this->percentEncode(substr($canonicalizedQueryString, 1));
        $stringToSign = 'POST&%2F&'.$this->percentEncode(substr($canonicalizedQueryString, 1));
// 计算签名 HMAC 值,按照 Base64 编码规则把 HMAC 值编码成字符串,即得到签名值(Signature)
        $signature = $this->percentEncode(base64_encode(hash_hmac('sha1', $stringToSign, $accessKeySecret.'&', true)));
        return $signature;
    }
    /**
     * 发送验证码 https://help.aliyun.com/document_detail/44364.html?spm=5176.doc44368.6.126.gSngXV
     *
     * @param unknown $mobile
     * @param unknown $verify_code
     *
     */
    public function send_verify($mobile, $verify_code) {
$aliSendSmsUrl = "http://sms.aliyuncs.com/";
        $prodect = ''; //模板中的参数,自己起个名字(模版不同,对应模版参数不同)


        $params = array(
            'AccessKeyId'       =>  $this->accessKeyId,       //Access Key Id
            'Action'            =>  'SingleSendSms',          //操作接口名,系统规定参数,取值:SingleSendSms
            'Format'            =>  'JSON',                   //返回值类型
            'ParamString'       =>  '{"code":"'.$verify_code.'","product":"'.$prodect.'"}',   //短信模板中的变量
            'RecNum'            =>  $mobile,                  //目标手机号,多个手机号可以逗号分隔
            'SignatureMethod'   =>  'HMAC-SHA1',              //签名方式
            'SignatureNonce'    =>  $this->genPasswd(16),     //随机字符串
            'SignatureVersion'  =>  '1.0',                    //签名算法版本
            'SignName'          =>  $this->signName,          //管理控制台中配置的短信签名(状态必须是验证通过)
            'TemplateCode'      =>  $this->templateCode,      //管理控制台中配置的审核通过的短信模板的模板CODE(状态必须是验证通过)
            'Timestamp'         =>  gmdate('Y-m-d\TH:i:s\Z'), //请求时间戳,UTC时间
            'Version'           =>  "2016-09-27"              //版本号,本版本对应日期
        );
        // 计算签名并把签名结果加入请求参数
        $params ['Signature'] = $this->calculatedSignature($params, $this->accessKeySecret);
        // 发送请求
        //$res = $this->postCUrl("http://sms.aliyuncs.com/?", http_build_query ($params));这个也可以
        foreach($params as $key => $val) {
            $post_data .= '&'.$key.'='.$val;
        }
        $res = $this->postCUrl($aliSendSmsUrl, $post_data);

        return json_decode($res, true);
    }


    /**
     * CUrl封装的post方式请求API的方法
     * @param string $url
     * @param array $data post数据
     * @param int $timeout 超时时间
     */
    public function postCUrl($url, $data, $timeout=3) {
        $ch = curl_init();


        $urlinfo = parse_url($url);
        $domain = $urlinfo['host'];
        $headers = array("Host:".$domain);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);


        //分析是否开启SSL加密
        $ssl = substr($url, 0, 8) == 'https://' ? true : false;
        if ($ssl) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在
        }


        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);


        $res = curl_exec($ch);
        if(curl_error($ch)=='') {
            curl_close($ch);
            return $res;
        }
        curl_close($ch);
        return false;
    }


    /**
     * 生成随机字符串
     * @param $length 生成随机字符串长度
     */
    public function genPasswd($length = 8) {
        // 密码字符集,可任意添加你需要的字符
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $password = '';
        for ( $i = 0; $i < $length; $i++ ) {
            $password .= $chars[ mt_rand(0, strlen($chars) - 1) ];
        }
        return $password;
    }


    /**
     * 获取详细错误信息
     * @param $code 如果有错误,就会有返回Code
     */
    public function getErrorMessage($code) {
        // https://help.aliyun.com/document_detail/44364.html?spm=5176.doc44365.6.572.8bxdsL页面下的错误码
        $message = array(
'InvalidDayuStatus.Malformed' => '账户短信开通状态不正确',
'InvalidSignName.Malformed' => '短信签名不正确或签名状态不正确',
'InvalidTemplateCode.MalFormed' => '短信模板Code不正确或者模板状态不正确',
'InvalidRecNum.Malformed' => '目标手机号不正确,单次发送数量不能超过100',
'InvalidParamString.MalFormed' => '短信模板中变量不是json格式',
'InvalidParamStringTemplate.Malformed' => '短信模板中变量与模板内容不匹配',
'InvalidSendSms' => '触发业务流控',//发送频率太快
'InvalidDayu.Malformed' => '变量不能是url,可以将变量固化在模板中',
'SignatureDoesNotMatch' => '签名不匹配'
        );
        if (isset($message[$code])) {
            return $message[$code];
        }
        return true;
    }
}


$mobile = ""; //手机号
//生成验证码
$code = rand (100000, 999999);


//发送短信
$sms = new Sms();


//测试模式
$res = $sms->send_verify($mobile, $code);
if(isset($res['Code'])){
$sms->error = $sms->getErrorMessage($res['Code']);
echo "短信发送失败,失败原因:".$sms->error;
return false;
}
echo "短信发送成功";
return true;


?>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于msg的文章目中处理Error Msg的方法小结不针对任何人的说: 看到有人把Error Msg写死到代码里,我就有上去忽他一巴掌的冲动。比如如下代码: int funcFoo() { UpdateData(); int error_code = 0; if (!IsInPutsUseName()) error_code = -1; else if(!IsInputAllPsw()) error_code = -2; else if(!IsTwoPswTheSame()) error_code = -3; else if(!IsThePswMachWithDatabase()) error_code = -4; if (error_code != 0) { switch(error_code) { case -1 : MessageBox("请输入用户名,然后重试!", "未输入用户名", MB_OK | MB_ICONWARNING); break; case -2 : MessageBox("请输入所有的密码,然后重试!", "未输入密码", MB_OK | MB_ICONWARNING); break; case -3 : MessageBox("您输入的两次密码不一致,请重新输入!", "密码不一致", MB_OK | MB_ICONWARNING); break; case -4 : MessageBox("您输入的密码错误,请重新输入", "密码错误", MB_OK | MB_ICONWARNING); break; case default : break; } DeleteInputPsw(); return error_code; } UpdateData(false); return error_code; } 理由如下: 1. 这样的源码不易阅读。假设用户提供的一个错误息,我要追踪其源码,我去那里找呀?可能有很多处地方都会有重复的类似的MSG出现,比如"请输入用户名,然后重试!"和"请您输入用户名,然后重试!"就会被认为是2条不同的MSG。这样很难排错。 2. 用户那里有可能弹出你估计之外的错误。实际上我们经常遇到这种情况,某程序崩溃探出一个错误号,没息。因为没有对应好。 3. 不利于发展为多语言版本?(你指望专业翻译在你的代码里搜索字符串?) 4.不利于全局统计。估计自己都不知道自己的工程里已经存在了多少种MSG字符串了吧? 5.专业软件的错误息是应该由专业语言措辞人员去对应的,而不是由程序员决定最终的版本。比如我代码里写一个errorcode:992,“没输密码!”,就会被专业措辞人员修饰为"请输入用户名,然后重试!" 解决的方法 也有多种,各有其优点和不足之处,写在这里供大家参考: 1.最古老的做法,是把息写入一个文本文件里面: // xxxxxxxxxx 一些注释 xxxxxxxxxxx // xxxxxxxxxx 一些注释 xxxxxxxxxxx // xxxxx Error Code : 998 // xxxxx Msg : "请输入用户名,然后重试!" // xxxxx 描述: ... #define Error_998_MSG "请输入用户名,然后重试!" // xxxxxxxxxx 一些注释 xxxxxxxxxxx // xxxxxxxxxx 一些注释 xxxxxxxxxxx // xxxxx Error Code : 999 // xxxxx Msg : "xxxxxxxxx, xxxxxxxxxxxxxxx!" // xxxxx 描述: ... #define Error_999_MSG "xxxxxxxxxxxxxxxx!" 诸如此类的做法,当系统启动的时候把这些资源读入内存中 优点:已经基本上解决了上述所说的弊病; 缺点:跨平台交互不容易,尤其是文件内码不同的情况,比如utf-8环境、ansi char环境、unicode环境........... 2. 写入xml文件里面:(推荐) 这种做法和上述方法类似,不过解决了上述方法的缺点。常用于Web相关的开发。 优点:标记语言,交互方便。扩展方便,功能强大且无限制。 缺点:编写人员必须熟悉xml语法,或者有专用的用于简化生成这个xml文件的程序。 3. 写入数据库里面: 应用这种方法的也很多,我就遇到若干这种做法的项目。形象一点的说,你可以参考Sql Server中的错误息,它也是写在一个系统表里面。 优点:利用SQL的优势,编写、修改都很方便,程序员、翻译、维护人员和用户都很轻松。客户甚至可以自己修改MSG息。 缺点:一般这种做法只用于数据库相关的应用,比如MIS系统。另外,如果出现数据库根本连接不上的错误,这种错误息还要当作特例解决。 另外,交互-速度较慢。 今天在论坛上偶见此问题,遂废话一堆,抛砖引玉,希望大家批评指正。 -------------

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值