AliSms.php 9.4 KB
<?php

namespace App\Helper;

class AliSms
{

    private $_msg = array( //状态对照
        1   => "发送成功",
        0   => "其他系统错误",
        -1  => "短信余额不足",
        -2  => "资金账户被锁定",
        -3  => "用户被锁定",
        -4  => "号码在黑名单内",
        -5  => "用户名或密码不正确",
        -6  => "号码不正确",
        -7  => "接口连接失败",
        -8  => "号码格式错误",
        -9  => "通道编号错误",
        -10 => "定时发送时间不正确",
        -11 => "没有输入短信内容",
        -12 => "短信内容超出长度限制",
        -15 => "内容含非法关键字",
        -16 => "超出发送时间范围",
        -17 => "通道被关闭",
        -18 => "短信内容没有签名",
        -30 => "手机未认证",
        -31 => "身份未认证",
        -32 => "请勿重复发送",
        -33 => "验证码已过期,请重新获取",
        -34 => "手机号码格式不正确",
        -35 => "验证码不正确",
    );
    // 保存错误信息
    public $error;
    public $_code      = "";
    public $_name      = "";
    public $_key_str   = ""; // cache full name.
    protected $_expire = 600; // 验证码过期时间(s)
    public $_key       = [
    ];
    // Access Key ID
    private $accessKeyId = '';
    // Access Key Secret
    private $accessKeySecret = '';
    // 签名
    private $signName = '';
    // 模版ID
    public $templateCode = '';

    public function __construct($config = array())
    {
        $config = array(
            'accessKeyId'     => config('aliyunsms.access_key'),
            'accessKeySecret' => config('aliyunsms.access_secret'),
            'signName'        => config('aliyunsms.sign_name'),
            'templateCode'    => config('aliyunsms.login_sms_temp'),
        );
        // 配置参数
        $this->accessKeyId     = $config['accessKeyId'];
        $this->accessKeySecret = $config['accessKeySecret'];
        $this->signName        = $config['signName'];
        $this->templateCode    = $config['templateCode'];
    }

    /**
     * 规范化字符串以符合阿里云短信接口
     * @param $string
     * @return mixed|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;
    }

    /**
     * 签名
     *
     * @param unknown $parameters
     * @param unknown $accessKeySecret
     * @return string
     */
    private function computeSignature($parameters, $accessKeySecret)
    {
        ksort($parameters);
        $canonicalizedQueryString = '';
        foreach ($parameters as $key => $value) {
            $canonicalizedQueryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($value);
        }
        $stringToSign = 'GET&%2F&' . $this->percentencode(substr($canonicalizedQueryString, 1));
        $signature    = 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_sms($mobile, $paramstring)
    {
        $params = array(
            // 公共参数
            'SignName'         => $this->signName,
            'Format'           => 'JSON',
            'Version'          => '2016-09-27',
            'AccessKeyId'      => $this->accessKeyId,
            'SignatureVersion' => '1.0',
            'SignatureMethod'  => 'HMAC-SHA1',
            'SignatureNonce'   => uniqid(),
            'Timestamp'        => gmdate('Y-m-d\TH:i:s\Z'),
            // 接口参数
            'Action'           => 'SingleSendSms',
            'TemplateCode'     => $this->templateCode,
            'RecNum'           => $mobile,
            'ParamString'      => $paramstring,
        );
        // 计算签名并把签名结果加入请求参数
        $params['Signature'] = $this->computeSignature($params, $this->accessKeySecret);

        // 发送请求
        $url    = 'https://sms.aliyuncs.com/?' . http_build_query($params);
        $result = http_get($url); //TODO:上线前打开
        if (isset($result['Code'])) {
            $this->error = $this->getErrorMessage($result['Code']);
            return false;
        }
        return true;
    }

    /**
     * 发送验证码 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)
    {
        if ($this->checkMobile($mobile) === false) {
            $this->error = $this->_msg[-34];
            return -34;
        }
        $session = cache($this->_key_str . $mobile);
        if ($session && time() - $session['time'] < 60) {
            if ($session['code'] == null) {
                return true;
            } else {
                $this->error = $this->_msg[-32];
                return -32;
            }
        }
        $this->_code = rand(1000, 9999);
        $params      = array(
            // 公共参数
            'SignName'         => $this->signName,
            'Format'           => 'JSON',
            'Version'          => '2016-09-27',
            'AccessKeyId'      => $this->accessKeyId,
            'SignatureVersion' => '1.0',
            'SignatureMethod'  => 'HMAC-SHA1',
            'SignatureNonce'   => uniqid(),
            'Timestamp'        => gmdate('Y-m-d\TH:i:s\Z'),
            // 接口参数
            'Action'           => 'SingleSendSms',
            'TemplateCode'     => $this->templateCode,
            'RecNum'           => $mobile,
            'ParamString'      => '{"msgcode":"' . $this->_code . '"}',
        );
        // 计算签名并把签名结果加入请求参数
        $params['Signature'] = $this->computeSignature($params, $this->accessKeySecret);
        // 发送请求
        $url    = 'https://sms.aliyuncs.com/?' . http_build_query($params);
        $result = http_get($url); //TODO:上线前打开
        //        $result =1;
        if ($result) {
            $session         = array();
            $session['code'] = $this->_code; // 把校验码保存到session
            $session['time'] = time(); // 验证码创建时间
            cache($this->_key_str . $mobile, $session, $this->_expire);
        } else {
            return $this->error = $this->_msg[0];
        }
        if (isset($result['Code'])) {
            $this->error = $this->getErrorMessage($result['Code']);
            return false;
        }
        return true;
    }
    /**
     * 验证手机号码
     */
    public function checkMobile($tel)
    {
        if (preg_match("/^1[3,4,6,5,8,7,9][0-9]{1}[0-9]{8}$/", $tel)) {
            //验证通过
            return true;
        } else {
            $this->error = $this->_msg[-34];
            //手机号码格式不对
            return false;
        }
    }

    /**
     * 验证码是否正确
     * @param string $key 手机号码
     * @param int|string $code 验证码
     * @param int|string $type 类型   reg-注册时获取 sms-快速登录时 pwd-修改密码时 bind-绑定手机时 unbind-解绑时
     * @return boolean 验证短信验证码是否正确
     */
    public function check($key, $code, $type = 'reg')
    {
        $this->_key_str = $type . '_' . $key;
        $session        = cache($this->_key_str);
        if (empty($code) || empty($session)) {
            $this->error = $this->_msg[-33] . $this->_key_str;
            return false;
        }
        if (time() - $session['time'] > $this->_expire) {
            cache($this->_key_str, null);
            $this->error = $this->_msg[-33] . $this->_key_str;
            return false;
        }
        if ($code == $session['code']) {
            return true;
        }
        $this->error = $this->_msg[-35] . $this->_key_str;
        return false;
    }

    /**
     * 验证成功后调用清空验证码
     */
    public function afterCheck()
    {
        cache($this->_key_str, null);
    }

    /**
     * 获取详细错误信息
     *
     * @param unknown $status
     */
    public function getErrorMessage($status)
    {

        $message = array(
            'InvalidDayuStatus.Malformed'          => '账户短信开通状态不正确',
            'InvalidSignName.Malformed'            => '短信签名不正确或签名状态不正确',
            'InvalidTemplateCode.MalFormed'        => '短信模板Code不正确或者模板状态不正确',
            'InvalidRecNum.Malformed'              => '目标手机号不正确,单次发送数量不能超过100',
            'InvalidParamString.MalFormed'         => '短信模板中变量不是json格式',
            'InvalidParamStringTemplate.Malformed' => '短信模板中变量与模板内容不匹配',
            'InvalidSendSms'                       => '1小时只能请求7次,谢谢',
            'InvalidDayu.Malformed'                => '变量不能是url,可以将变量固化在模板中',
        );
        if (isset($message[$status])) {
            return $message[$status];
        }
        return $status;
    }

    private function _addlog($name, $title)
    {
        $this->_keys["code"] = $this->_code;
//        addlog($this->_keys, $title, 1, $this->_url);
    }
}