Browse Source

腾讯云短信插件

lizhen_gitee 7 months ago
parent
commit
41d2dff00f

+ 1 - 0
addons/qcloudsms/.addonrc

@@ -0,0 +1 @@
+{"files":[],"license":"regular","licenseto":"19079","licensekey":"P47bFtVaHYmBLqMA QpsUKvS4gwpvmd5u7XrYxvUhTpzItBcPUC5cOXbP+8w=","domains":["jiankangyijia.com"],"licensecodes":[],"validations":["ee54178e5a2dee350213637b622947b4"]}

+ 197 - 0
addons/qcloudsms/Qcloudsms.php

@@ -0,0 +1,197 @@
+<?php
+
+namespace addons\qcloudsms;
+
+use addons\qcloudsms\library\SmsSingleSender;
+use addons\qcloudsms\library\SmsVoicePromptSender;
+use addons\qcloudsms\library\SmsVoiceverifyCodeSender;
+use addons\qcloudsms\library\TtsVoiceSender;
+use think\Addons;
+use think\Config;
+
+/**
+ * 插件
+ */
+class Qcloudsms extends Addons
+{
+    private $appid = null;
+    private $appkey = null;
+    private $config = null;
+    private $sender = null;
+    private $sendError = '';
+
+    public function ConfigInit()
+    {
+        $this->config = $this->getConfig();
+        //如果使用语音短信  更换成语音短信模板
+        if ($this->config['isVoice'] == 1) {
+            $this->config['template'] = $this->config['voiceTemplate'];
+            //语音短信 需要另行设置Aappid 与Appkey
+            $this->appid = $this->config['voiceAppid'];
+            $this->appkey = $this->config['voiceAppkey'];
+        } else {
+            $this->appid = $this->config['appid'];
+            $this->appkey = $this->config['appkey'];
+        }
+    }
+
+    /**
+     * 短信发送行为
+     * @param Sms $params
+     * @return  boolean
+     */
+    public function smsSend(&$params)
+    {
+        $this->ConfigInit();
+        try {
+            if ($this->config['isTemplateSender'] == 1) {
+                $templateID = $this->config['template'][$params->event];
+                if ($this->config['isVoice'] != 1) {
+                    //普通短信发送
+                    $this->sender = new SmsSingleSender($this->appid, $this->appkey);
+                    $result = $this->sender->sendWithParam("86", $params['mobile'], $templateID, ["{$params->code}"], $this->config['sign'], "", "");
+                } else {
+                    //语音短信发送
+                    $this->sender = new TtsVoiceSender($this->appid, $this->appkey);
+                    //参数: 国家码,手机号、模板ID、模板参数、播放次数(可选字段)、用户的session内容,服务器端原样返回(可选字段)
+                    $result = $this->sender->send("86", $params['mobile'], $templateID, [$params->code]);
+                }
+            } else {
+                //判断是否是语音短信
+                if ($this->config['isVoice'] != 1) {
+                    $this->sender = new SmsSingleSender($this->appid, $this->appkey);
+                    //参数:短信类型{1营销短信,0普通短信 }、国家码、手机号、短信内容、扩展码(可留空)、服务的原样返回的参数
+                    $result = $this->sender->send($params['type'], '86', $params['mobile'], $params['msg'], "", "");
+                } else {
+                    $this->sender = new SmsVoiceVerifyCodeSender($this->appid, $this->appkey);
+                    //参数:国家码、手机号、短信内容、播放次数(默认2次)、服务的原样返回的参数
+                    $result = $this->sender->send('86', $params['mobile'], $params['msg']);
+                }
+            }
+
+            $rsp = json_decode($result, true);
+            if ($rsp['result'] == 0 && $rsp['errmsg'] == 'OK') {
+                return true;
+            } else {
+                //记录错误信息
+                $this->setError($rsp);
+                return false;
+            }
+        } catch (\Exception $e) {
+            $this->setError($e->getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 短信发送通知
+     * @param array $params
+     * @return  boolean
+     */
+    public function smsNotice(&$params)
+    {
+        $this->ConfigInit();
+        try {
+            if ($this->config['isTemplateSender'] == 1) {
+                $templateID = $this->config['template'][$params['template']];
+
+                if ($this->config['isVoice'] != 1) {
+                    //普通短信发送
+                    $this->sender = new SmsSingleSender($this->appid, $this->appkey);
+                    $result = $this->sender->sendWithParam("86", $params['mobile'], $templateID, ["{$params['msg']}"], $this->config['sign'], "", "");
+                } else {
+                    //语音短信发送
+                    $this->sender = new TtsVoiceSender($this->appid, $this->appkey);
+                    //参数: 国家码,手机号、模板ID、模板参数、播放次数(可选字段)、用户的session内容,服务器端原样返回(可选字段)
+                    $result = $this->sender->send("86", $params['mobile'], $templateID, [$params['msg']]);
+                }
+            } else {
+                //判断是否是语音短信
+                if ($this->config['isVoice'] != 1) {
+                    $this->sender = new SmsSingleSender($this->appid, $this->appkey);
+                    //参数:短信类型{1营销短信,0普通短信 }、国家码、手机号、短信内容、扩展码(可留空)、服务的原样返回的参数
+                    $result = $this->sender->send($params['type'], '86', $params['mobile'], $params['msg'], "", "");
+                } else {
+                    $this->sender = new SmsVoicePromptSender($this->appid, $this->appkey);
+                    //参数:国家码、手机号、语音类型(目前固定为2)、短信内容、播放次数(默认2次)、服务的原样返回的参数
+                    $result = $this->sender->send('86', $params['mobile'], 2, $params['msg']);
+                }
+            }
+            $rsp = (array)json_decode($result, true);
+            if ($rsp['result'] == 0 && $rsp['errmsg'] == 'OK') {
+                return true;
+            } else {
+                //记录错误信息
+                $this->setError($rsp);
+                return false;
+            }
+        } catch (\Exception $e) {
+            var_dump($e);
+            exit();
+        }
+    }
+
+    /**
+     * 记录失败信息
+     * @param [type] $err [description]
+     */
+    private function setError($err)
+    {
+        $this->sendError = $err;
+    }
+
+    /**
+     * 获取失败信息
+     * @return [type] [description]
+     */
+    public function getError()
+    {
+        return $this->sendError;
+    }
+
+    /**
+     * 检测验证是否正确
+     * @param Sms $params
+     * @return  boolean
+     */
+    public function smsCheck(&$params)
+    {
+        return true;
+    }
+
+    /**
+     * 插件安装方法
+     * @return bool
+     */
+    public function install()
+    {
+        return true;
+    }
+
+    /**
+     * 插件卸载方法
+     * @return bool
+     */
+    public function uninstall()
+    {
+        return true;
+    }
+
+    /**
+     * 插件启用方法
+     * @return bool
+     */
+    public function enable()
+    {
+        return true;
+    }
+
+    /**
+     * 插件禁用方法
+     * @return bool
+     */
+    public function disable()
+    {
+        return true;
+    }
+}

+ 147 - 0
addons/qcloudsms/config.php

@@ -0,0 +1,147 @@
+<?php
+
+return array(
+    array(
+        'name'    => 'appid',
+        'title'   => '应用AppID',
+        'type'    => 'string',
+        'content' =>
+            array(),
+        'value'   => '',
+        'rule'    => 'required',
+        'msg'     => '',
+        'tip'     => '',
+        'ok'      => '',
+        'extend'  => '',
+    ),
+    array(
+        'name'    => 'appkey',
+        'title'   => '应用AppKEY',
+        'type'    => 'string',
+        'content' =>
+            array(),
+        'value'   => '',
+        'rule'    => 'required',
+        'msg'     => '',
+        'tip'     => '',
+        'ok'      => '',
+        'extend'  => '',
+    ),
+    array(
+        'name'    => 'voiceAppid',
+        'title'   => '语音短信AppID',
+        'type'    => 'string',
+        'content' =>
+            array(),
+        'value'   => '',
+        'rule'    => 'required',
+        'msg'     => '使用语音短信必须设置',
+        'tip'     => '',
+        'ok'      => '',
+        'extend'  => '',
+    ),
+    array(
+        'name'    => 'voiceAppkey',
+        'title'   => '语音短信AppKEY',
+        'type'    => 'string',
+        'content' =>
+            array(),
+        'value'   => '',
+        'rule'    => 'required',
+        'msg'     => '使用语音短信必须设置',
+        'tip'     => '',
+        'ok'      => '',
+        'extend'  => '',
+    ),
+    array(
+        'name'    => 'sign',
+        'title'   => '签名',
+        'type'    => 'string',
+        'content' =>
+            array(),
+        'value'   => 'your sign',
+        'rule'    => 'required',
+        'msg'     => '',
+        'tip'     => '',
+        'ok'      => '',
+        'extend'  => '',
+    ),
+    array(
+        'name'    => 'isVoice',
+        'title'   => '是否使用语音短信',
+        'type'    => 'radio',
+        'content' =>
+            array(
+                0 => '否',
+                1 => '是',
+            ),
+        'value'   => '0',
+        'rule'    => 'required',
+        'msg'     => '',
+        'tip'     => '',
+        'ok'      => '',
+        'extend'  => '',
+    ),
+    array(
+        'name'    => 'isTemplateSender',
+        'title'   => '是否使用短信模板发送',
+        'type'    => 'radio',
+        'content' =>
+            array(
+                0 => '否',
+                1 => '是',
+            ),
+        'value'   => '1',
+        'rule'    => 'required',
+        'msg'     => '',
+        'tip'     => '',
+        'ok'      => '',
+        'extend'  => '',
+    ),
+    array(
+        'name'    => 'template',
+        'title'   => '短信模板',
+        'type'    => 'array',
+        'content' =>
+            array(),
+        'value'   =>
+            array(
+            'register'           => '',
+            'resetpwd'           => '',
+            'changepwd'          => '',
+            'changemobile'       => '',
+            'profile'            => '',
+            'notice'             => '',
+            'mobilelogin'        => '',
+            'bind'               => '',
+            ),
+        'rule'    => 'required',
+        'msg'     => '',
+        'tip'     => '',
+        'ok'      => '',
+        'extend'  => '',
+    ),
+    array(
+        'name'    => 'voiceTemplate',
+        'title'   => '语音短信模板',
+        'type'    => 'array',
+        'content' =>
+            array(),
+        'value'   =>
+            array(
+            'register'           => '',
+            'resetpwd'           => '',
+            'changepwd'          => '',
+            'changemobile'       => '',
+            'profile'            => '',
+            'notice'             => '',
+            'mobilelogin'        => '',
+            'bind'               => '',
+            ),
+        'rule'    => 'required',
+        'msg'     => '',
+        'tip'     => '',
+        'ok'      => '',
+        'extend'  => '',
+    ),
+);

+ 15 - 0
addons/qcloudsms/controller/Index.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace addons\qcloudsms\controller;
+
+use think\addons\Controller;
+
+class Index extends Controller
+{
+
+    public function index()
+    {
+        $this->error("当前插件暂无前台页面");
+    }
+
+}

+ 10 - 0
addons/qcloudsms/info.ini

@@ -0,0 +1,10 @@
+name = qcloudsms
+title = 腾讯云短信发送插件
+intro = 腾讯云短信发送插件
+author = Seacent
+website = https://www.seacent.com
+version = 1.0.4
+state = 1
+url = /addons/qcloudsms
+license = regular
+licenseto = 19079

+ 69 - 0
addons/qcloudsms/library/FileVoiceSender.php

@@ -0,0 +1,69 @@
+<?php
+
+namespace addons\qcloudsms\library;
+
+use addons\qcloudsms\library\SmsSenderUtil;
+
+
+/**
+ * 按语音文件fid发送语音通知类
+ *
+ */
+class FileVoiceSender
+{
+    private $url;
+    private $appid;
+    private $appkey;
+    private $util;
+
+    /**
+     * 构造函数
+     *
+     * @param string $appid  sdkappid
+     * @param string $appkey sdkappid对应的appkey
+     */
+    public function __construct($appid, $appkey)
+    {
+        $this->url = "https://cloud.tim.qq.com/v5/tlsvoicesvr/sendfvoice";
+        $this->appid =  $appid;
+        $this->appkey = $appkey;
+        $this->util = new SmsSenderUtil();
+    }
+
+    /**
+     *
+     * 按语音文件fid发送语音通知
+     *
+     * @param string $nationCode  国家码,如 86 为中国
+     * @param string $phoneNumber 不带国家码的手机号
+     * @param string $fid         语音文件fid
+     * @param string $playtimes   播放次数,可选,最多3次,默认2次
+     * @param string $ext         用户的session内容,服务端原样返回,可选字段,不需要可填空串
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function send($nationCode, $phoneNumber, $fid, $playtimes = 2, $ext = "")
+    {
+        $random = $this->util->getRandom();
+        $curTime = time();
+        $wholeUrl = $this->url . "?sdkappid=" . $this->appid . "&random=" . $random;
+
+        // 按照协议组织 post 包体
+        $data = new \stdClass();
+        $tel = new \stdClass();
+        $tel->nationcode = "".$nationCode;
+        $tel->mobile = "".$phoneNumber;
+        $data->tel = $tel;
+        $data->fid = $fid;
+        $data->playtimes = $playtimes;
+
+        // app凭证
+        $data->sig = $this->util->calculateSig($this->appkey, $random,
+            $curTime, array($phoneNumber));
+
+        // unix时间戳,请求发起时间,如果和系统时间相差超过10分钟则会返回失败
+        $data->time = $curTime;
+        $data->ext = $ext;
+
+        return $this->util->sendCurlPost($wholeUrl, $data);
+    }
+}

+ 91 - 0
addons/qcloudsms/library/SmsMobileStatusPuller.php

@@ -0,0 +1,91 @@
+<?php
+
+namespace addons\qcloudsms\library;
+
+use addons\qcloudsms\library\SmsSenderUtil;
+
+/**
+ * 拉取单个手机短信状态类
+ *
+ */
+class SmsMobileStatusPuller
+{
+    private $url;
+    private $appid;
+    private $appkey;
+    private $util;
+
+    /**
+     * 构造函数
+     *
+     * @param string $appid  sdkappid
+     * @param string $appkey sdkappid对应的appkey
+     */
+    public function __construct($appid, $appkey)
+    {
+        $this->url = "https://yun.tim.qq.com/v5/tlssmssvr/pullstatus4mobile";
+        $this->appid =  $appid;
+        $this->appkey = $appkey;
+        $this->util = new SmsSenderUtil();
+    }
+
+    /**
+     * 拉取回执结果
+     *
+     * @param int    $type         拉取类型,0表示回执结果,1表示回复信息
+     * @param string $nationCode   国家码,如 86 为中国
+     * @param string $mobile       不带国家码的手机号
+     * @param int    $beginTime    开始时间(unix timestamp)
+     * @param int    $endTime      结束时间(unix timestamp)
+     * @param int    $max          拉取最大条数,最多100
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    private function pull($type, $nationCode, $mobile, $beginTime, $endTime, $max)
+    {
+        $random = $this->util->getRandom();
+        $curTime = time();
+        $wholeUrl = $this->url . "?sdkappid=" . $this->appid . "&random=" . $random;
+
+        $data = new \stdClass();
+        $data->sig = $this->util->calculateSigForPuller($this->appkey, $random, $curTime);
+        $data->time = $curTime;
+        $data->type = $type;
+        $data->max = $max;
+        $data->begin_time = $beginTime;
+        $data->end_time = $endTime;
+        $data->nationcode = $nationCode;
+        $data->mobile = $mobile;
+
+        return $this->util->sendCurlPost($wholeUrl, $data);
+    }
+
+    /**
+     * 拉取回执结果
+     *
+     * @param string $nationCode   国家码,如 86 为中国
+     * @param string $mobile       不带国家码的手机号
+     * @param int    $beginTime    开始时间(unix timestamp)
+     * @param int    $endTime      结束时间(unix timestamp)
+     * @param int    $max          拉取最大条数,最多100
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function pullCallback($nationCode, $mobile, $beginTime, $endTime, $max)
+    {
+        return $this->pull(0, $nationCode, $mobile, $beginTime, $endTime, $max);
+    }
+
+    /**
+     * 拉取回复信息
+     *
+     * @param string $nationCode   国家码,如 86 为中国
+     * @param string $mobile       不带国家码的手机号
+     * @param int    $beginTime    开始时间(unix timestamp)
+     * @param int    $endTime      结束时间(unix timestamp)
+     * @param int    $max          拉取最大条数,最多100
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function pullReply($nationCode, $mobile, $beginTime, $endTime, $max)
+    {
+        return $this->pull(1, $nationCode, $mobile, $beginTime, $endTime, $max);
+    }
+}

+ 99 - 0
addons/qcloudsms/library/SmsMultiSender.php

@@ -0,0 +1,99 @@
+<?php
+
+namespace addons\qcloudsms\library;
+
+use addons\qcloudsms\library\SmsSenderUtil;
+
+/**
+ * 群发短信类
+ *
+ */
+class SmsMultiSender
+{
+    private $url;
+    private $appid;
+    private $appkey;
+    private $util;
+
+    /**
+     * 构造函数
+     *
+     * @param string $appid  sdkappid
+     * @param string $appkey sdkappid对应的appkey
+     */
+    public function __construct($appid, $appkey)
+    {
+        $this->url = "https://yun.tim.qq.com/v5/tlssmssvr/sendmultisms2";
+        $this->appid =  $appid;
+        $this->appkey = $appkey;
+        $this->util = new SmsSenderUtil();
+    }
+
+    /**
+     * 普通群发
+     *
+     * 普通群发需明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,
+     * 否则系统将使用默认签名。
+     *
+     *
+     * @param int    $type         短信类型,0 为普通短信,1 营销短信
+     * @param string $nationCode   国家码,如 86 为中国
+     * @param array  $phoneNumbers 不带国家码的手机号列表
+     * @param string $msg          信息内容,必须与申请的模板格式一致,否则将返回错误
+     * @param string $extend       扩展码,可填空串
+     * @param string $ext          服务端原样返回的参数,可填空串
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function send($type, $nationCode, $phoneNumbers, $msg, $extend = "", $ext = "")
+    {
+        $random = $this->util->getRandom();
+        $curTime = time();
+        $wholeUrl = $this->url . "?sdkappid=" . $this->appid . "&random=" . $random;
+
+        $data = new \stdClass();
+        $data->tel = $this->util->phoneNumbersToArray($nationCode, $phoneNumbers);
+        $data->type = $type;
+        $data->msg = $msg;
+        $data->sig = $this->util->calculateSig($this->appkey, $random,
+            $curTime, $phoneNumbers);
+        $data->time = $curTime;
+        $data->extend = $extend;
+        $data->ext = $ext;
+
+        return $this->util->sendCurlPost($wholeUrl, $data);
+    }
+
+    /**
+     * 指定模板群发
+     *
+     *
+     * @param  string $nationCode   国家码,如 86 为中国
+     * @param  array  $phoneNumbers 不带国家码的手机号列表
+     * @param  int    $templId      模板id
+     * @param  array  $params       模板参数列表,如模板 {1}...{2}...{3},那么需要带三个参数
+     * @param  string $sign         签名,如果填空串,系统会使用默认签名
+     * @param  string $extend       扩展码,可填空串
+     * @param  string $ext          服务端原样返回的参数,可填空串
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function sendWithParam($nationCode, $phoneNumbers, $templId, $params,
+        $sign = "", $extend = "", $ext = "")
+    {
+        $random = $this->util->getRandom();
+        $curTime = time();
+        $wholeUrl = $this->url . "?sdkappid=" . $this->appid . "&random=" . $random;
+
+        $data = new \stdClass();
+        $data->tel = $this->util->phoneNumbersToArray($nationCode, $phoneNumbers);
+        $data->sign = $sign;
+        $data->tpl_id = $templId;
+        $data->params = $params;
+        $data->sig = $this->util->calculateSigForTemplAndPhoneNumbers(
+            $this->appkey, $random, $curTime, $phoneNumbers);
+        $data->time = $curTime;
+        $data->extend = $extend;
+        $data->ext = $ext;
+
+        return $this->util->sendCurlPost($wholeUrl, $data);
+    }
+}

+ 211 - 0
addons/qcloudsms/library/SmsSenderUtil.php

@@ -0,0 +1,211 @@
+<?php
+
+namespace addons\qcloudsms\library;
+
+/**
+ * 发送Util类
+ *
+ */
+class SmsSenderUtil
+{
+    /**
+     * 生成随机数
+     *
+     * @return int 随机数结果
+     */
+    public function getRandom()
+    {
+        return rand(100000, 999999);
+    }
+
+    /**
+     * 生成签名
+     *
+     * @param string $appkey        sdkappid对应的appkey
+     * @param string $random        随机正整数
+     * @param string $curTime       当前时间
+     * @param array  $phoneNumbers  手机号码
+     * @return string  签名结果
+     */
+    public function calculateSig($appkey, $random, $curTime, $phoneNumbers)
+    {
+        $phoneNumbersString = $phoneNumbers[0];
+        for ($i = 1; $i < count($phoneNumbers); $i++) {
+            $phoneNumbersString .= ("," . $phoneNumbers[$i]);
+        }
+
+        return hash("sha256", "appkey=".$appkey."&random=".$random
+            ."&time=".$curTime."&mobile=".$phoneNumbersString);
+    }
+
+    /**
+     * 生成签名
+     *
+     * @param string $appkey        sdkappid对应的appkey
+     * @param string $random        随机正整数
+     * @param string $curTime       当前时间
+     * @param array  $phoneNumbers  手机号码
+     * @return string  签名结果
+     */
+    public function calculateSigForTemplAndPhoneNumbers($appkey, $random,
+        $curTime, $phoneNumbers)
+    {
+        $phoneNumbersString = $phoneNumbers[0];
+        for ($i = 1; $i < count($phoneNumbers); $i++) {
+            $phoneNumbersString .= ("," . $phoneNumbers[$i]);
+        }
+
+        return hash("sha256", "appkey=".$appkey."&random=".$random
+            ."&time=".$curTime."&mobile=".$phoneNumbersString);
+    }
+
+    public function phoneNumbersToArray($nationCode, $phoneNumbers)
+    {
+        $i = 0;
+        $tel = array();
+        do {
+            $telElement = new \stdClass();
+            $telElement->nationcode = $nationCode;
+            $telElement->mobile = $phoneNumbers[$i];
+            array_push($tel, $telElement);
+        } while (++$i < count($phoneNumbers));
+
+        return $tel;
+    }
+
+    /**
+     * 生成签名
+     *
+     * @param string $appkey        sdkappid对应的appkey
+     * @param string $random        随机正整数
+     * @param string $curTime       当前时间
+     * @param array  $phoneNumber   手机号码
+     * @return string  签名结果
+     */
+    public function calculateSigForTempl($appkey, $random, $curTime, $phoneNumber)
+    {
+        $phoneNumbers = array($phoneNumber);
+
+        return $this->calculateSigForTemplAndPhoneNumbers($appkey, $random,
+            $curTime, $phoneNumbers);
+    }
+
+    /**
+     * 生成签名
+     *
+     * @param string $appkey        sdkappid对应的appkey
+     * @param string $random        随机正整数
+     * @param string $curTime       当前时间
+     * @return string 签名结果
+     */
+    public function calculateSigForPuller($appkey, $random, $curTime)
+    {
+        return hash("sha256", "appkey=".$appkey."&random=".$random
+            ."&time=".$curTime);
+    }
+
+    /**
+     * 生成上传文件授权
+     *
+     * @param string $appkey        sdkappid对应的appkey
+     * @param string $random        随机正整数
+     * @param string $curTime       当前时间
+     * @param array  $fileSha1Sum   文件sha1sum
+     * @return string  授权结果
+     */
+    public function calculateAuth($appkey, $random, $curTime, $fileSha1Sum)
+    {
+        return hash("sha256", "appkey=".$appkey."&random=".$random
+            ."&time=".$curTime."&content-sha1=".$fileSha1Sum);
+    }
+
+    /**
+     * 生成sha1sum
+     *
+     * @param string $content  内容
+     * @return string  内容sha1散列值
+     */
+    public function sha1sum($content)
+    {
+        return hash("sha1", $content);
+    }
+
+    /**
+     * 发送请求
+     *
+     * @param string $url      请求地址
+     * @param array  $dataObj  请求内容
+     * @return string 应答json字符串
+     */
+    public function sendCurlPost($url, $dataObj)
+    {
+        $curl = curl_init();
+        curl_setopt($curl, CURLOPT_URL, $url);
+        curl_setopt($curl, CURLOPT_HEADER, 0);
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($curl, CURLOPT_POST, 1);
+        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 60);
+        curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($dataObj));
+        curl_setopt($curl, CURLOPT_HTTPHEADER, array(
+        'Content-Type: application/json; charset=utf-8',
+        'Content-Length: ' . strlen(json_encode($dataObj)))
+    );
+        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
+
+        $ret = curl_exec($curl);
+        if (false == $ret) {
+            // curl_exec failed
+            $result = "{ \"result\":" . -2 . ",\"errmsg\":\"" . curl_error($curl) . "\"}";
+        } else {
+            $rsp = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+            if (200 != $rsp) {
+                $result = "{ \"result\":" . -1 . ",\"errmsg\":\"". $rsp
+                        . " " . curl_error($curl) ."\"}";
+            } else {
+                $result = $ret;
+            }
+        }
+
+        curl_close($curl);
+
+        return $result;
+    }
+
+    /**
+     * 发送请求
+     *
+     * @param string $req  请求对象
+     * @return string 应答json字符串
+     */
+    public function fetch($req)
+    {
+        $curl = curl_init();
+
+        curl_setopt($curl, CURLOPT_URL, $req->url);
+        curl_setopt($curl, CURLOPT_HTTPHEADER, $req->headers);
+        curl_setopt($curl, CURLOPT_POSTFIELDS, $req->body);
+        curl_setopt($curl, CURLOPT_HEADER, 0);
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($curl, CURLOPT_POST, 1);
+        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 60);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
+
+        $result = curl_exec($curl);
+
+        if (false == $result) {
+            // curl_exec failed
+            $result = "{ \"result\":" . -2 . ",\"errmsg\":\"" . curl_error($curl) . "\"}";
+        } else {
+            $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+            if (200 != $code) {
+                $result = "{ \"result\":" . -1 . ",\"errmsg\":\"". $rsp
+                    . " " . curl_error($curl) ."\"}";
+            }
+        }
+        curl_close($curl);
+
+        return $result;
+    }
+}

+ 107 - 0
addons/qcloudsms/library/SmsSingleSender.php

@@ -0,0 +1,107 @@
+<?php
+
+namespace addons\qcloudsms\library;
+
+use addons\qcloudsms\library\SmsSenderUtil;
+
+/**
+ * 单发短信类
+ *
+ */
+class SmsSingleSender
+{
+    private $url;
+    private $appid;
+    private $appkey;
+    private $util;
+
+    /**
+     * 构造函数
+     *
+     * @param string $appid  sdkappid
+     * @param string $appkey sdkappid对应的appkey
+     */
+    public function __construct($appid, $appkey)
+    {
+        $this->url = "https://yun.tim.qq.com/v5/tlssmssvr/sendsms";
+        $this->appid =  $appid;
+        $this->appkey = $appkey;
+        $this->util = new SmsSenderUtil();
+    }
+
+    /**
+     * 普通单发
+     *
+     * 普通单发需明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名。
+     *
+     * @param int    $type        短信类型,0 为普通短信,1 营销短信
+     * @param string $nationCode  国家码,如 86 为中国
+     * @param string $phoneNumber 不带国家码的手机号
+     * @param string $msg         信息内容,必须与申请的模板格式一致,否则将返回错误
+     * @param string $extend      扩展码,可填空串
+     * @param string $ext         服务端原样返回的参数,可填空串
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function send($type, $nationCode, $phoneNumber, $msg, $extend = "", $ext = "")
+    {
+        $random = $this->util->getRandom();
+        $curTime = time();
+        $wholeUrl = $this->url . "?sdkappid=" . $this->appid . "&random=" . $random;
+
+        // 按照协议组织 post 包体
+        $data = new \stdClass();
+        $tel = new \stdClass();
+        $tel->nationcode = "".$nationCode;
+        $tel->mobile = "".$phoneNumber;
+
+        $data->tel = $tel;
+        $data->type = (int)$type;
+        $data->msg = $msg;
+        $data->sig = hash("sha256",
+            "appkey=".$this->appkey."&random=".$random."&time="
+            .$curTime."&mobile=".$phoneNumber, FALSE);
+        $data->time = $curTime;
+        $data->extend = $extend;
+        $data->ext = $ext;
+
+        return $this->util->sendCurlPost($wholeUrl, $data);
+    }
+
+    /**
+     * 指定模板单发
+     *
+     * @param string $nationCode  国家码,如 86 为中国
+     * @param string $phoneNumber 不带国家码的手机号
+     * @param int    $templId     模板 id
+     * @param array  $params      模板参数列表,如模板 {1}...{2}...{3},那么需要带三个参数
+     * @param string $sign        签名,如果填空串,系统会使用默认签名
+     * @param string $extend      扩展码,可填空串
+     * @param string $ext         服务端原样返回的参数,可填空串
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function sendWithParam($nationCode, $phoneNumber, $templId = 0, $params,
+        $sign = "", $extend = "", $ext = "")
+    {
+        $random = $this->util->getRandom();
+        $curTime = time();
+        $wholeUrl = $this->url . "?sdkappid=" . $this->appid . "&random=" . $random;
+
+        // 按照协议组织 post 包体
+        $data = new \stdClass();
+        $tel = new \stdClass();
+        $tel->nationcode = "".$nationCode;
+        $tel->mobile = "".$phoneNumber;
+
+        $data->tel = $tel;
+        $data->sig = $this->util->calculateSigForTempl($this->appkey, $random,
+            $curTime, $phoneNumber);
+        $data->tpl_id = $templId;
+        $data->params = $params;
+        $data->sign = $sign;
+        $data->time = $curTime;
+        $data->extend = $extend;
+        $data->ext = $ext;
+
+        return $this->util->sendCurlPost($wholeUrl, $data);
+    }
+}

+ 75 - 0
addons/qcloudsms/library/SmsStatusPuller.php

@@ -0,0 +1,75 @@
+<?php
+
+namespace addons\qcloudsms\library;
+
+use addons\qcloudsms\library\SmsSenderUtil;
+
+/**
+ * 拉取短信状态类
+ *
+ */
+class SmsStatusPuller
+{
+    private $url;
+    private $appid;
+    private $appkey;
+    private $util;
+
+    /**
+     * 构造函数
+     *
+     * @param string $appid  sdkappid
+     * @param string $appkey sdkappid对应的appkey
+     */
+    public function __construct($appid, $appkey)
+    {
+        $this->url = "https://yun.tim.qq.com/v5/tlssmssvr/pullstatus";
+        $this->appid =  $appid;
+        $this->appkey = $appkey;
+        $this->util = new SmsSenderUtil();
+    }
+
+    /**
+     * 拉取回执结果
+     *
+     * @param int $type 拉取类型,0表示回执结果,1表示回复信息
+     * @param int $max  最大条数,最多100
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    private function pull($type, $max)
+    {
+        $random = $this->util->getRandom();
+        $curTime = time();
+        $wholeUrl = $this->url . "?sdkappid=" . $this->appid . "&random=" . $random;
+
+        $data = new \stdClass();
+        $data->sig = $this->util->calculateSigForPuller($this->appkey, $random, $curTime);
+        $data->time = $curTime;
+        $data->type = $type;
+        $data->max = $max;
+
+        return $this->util->sendCurlPost($wholeUrl, $data);
+    }
+
+    /**
+     * 拉取回执结果
+     *
+     * @param int $max 拉取最大条数,最多100
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function pullCallback($max)
+    {
+        return $this->pull(0, $max);
+    }
+
+    /**
+     * 拉取回复信息
+     *
+     * @param int $max 拉取最大条数,最多100
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function pullReply($max)
+    {
+        return $this->pull(1, $max);
+    }
+}

+ 71 - 0
addons/qcloudsms/library/SmsVoicePromptSender.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace addons\qcloudsms\library;
+
+use addons\qcloudsms\library\SmsSenderUtil;
+
+/**
+ * 发送语音通知类
+ *
+ */
+class SmsVoicePromptSender
+{
+    private $url;
+    private $appid;
+    private $appkey;
+    private $util;
+
+    /**
+     * 构造函数
+     *
+     * @param string $appid  sdkappid
+     * @param string $appkey sdkappid对应的appkey
+     */
+    public function __construct($appid, $appkey)
+    {
+        $this->url = "https://yun.tim.qq.com/v5/tlsvoicesvr/sendvoiceprompt";
+        $this->appid =  $appid;
+        $this->appkey = $appkey;
+        $this->util = new SmsSenderUtil();
+    }
+
+    /**
+     *
+     * 发送语音通知
+     *
+     * @param string $nationCode  国家码,如 86 为中国
+     * @param string $phoneNumber 不带国家码的手机号
+     * @param string $prompttype  语音类型,目前固定为2
+     * @param string $msg         信息内容,必须与申请的模板格式一致,否则将返回错误
+     * @param string $playtimes   播放次数,可选,最多3次,默认2次
+     * @param string $ext         用户的session内容,服务端原样返回,可选字段,不需要可填空串
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function send($nationCode, $phoneNumber, $prompttype, $msg, $playtimes = 2, $ext = "")
+    {
+        $random = $this->util->getRandom();
+        $curTime = time();
+        $wholeUrl = $this->url . "?sdkappid=" . $this->appid . "&random=" . $random;
+
+        // 按照协议组织 post 包体
+        $data = new \stdClass();
+        $tel = new \stdClass();
+        $tel->nationcode = "".$nationCode;
+        $tel->mobile = "".$phoneNumber;
+
+        $data->tel = $tel;
+        // 通知内容,utf8编码,支持中文英文、数字及组合,需要和语音内容模版相匹配
+        $data->promptfile = $msg;
+        // 固定值 2
+        $data->prompttype = $prompttype;
+        $data->playtimes = $playtimes;
+        // app凭证
+        $data->sig = hash("sha256",
+            "appkey=".$this->appkey."&random=".$random."&time="
+            .$curTime."&mobile=".$phoneNumber, FALSE);
+        // unix时间戳,请求发起时间,如果和系统时间相差超过10分钟则会返回失败
+        $data->time = $curTime;
+        $data->ext = $ext;
+        return $this->util->sendCurlPost($wholeUrl, $data);
+    }
+}

+ 67 - 0
addons/qcloudsms/library/SmsVoiceVerifyCodeSender.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace addons\qcloudsms\library;
+
+use addons\qcloudsms\library\SmsSenderUtil;
+
+/**
+ * 发送语音验证码类
+ *
+ */
+class SmsVoiceVerifyCodeSender
+{
+    private $url;
+    private $appid;
+    private $appkey;
+    private $util;
+
+    /**
+     * 构造函数
+     *
+     * @param string $appid  sdkappid
+     * @param string $appkey sdkappid对应的appkey
+     */
+    public function __construct($appid, $appkey)
+    {
+        $this->url = "https://yun.tim.qq.com/v5/tlsvoicesvr/sendvoice";
+        $this->appid =  $appid;
+        $this->appkey = $appkey;
+        $this->util = new SmsSenderUtil();
+    }
+
+    /**
+     * 发送语音验证码
+     *
+     * @param string $nationCode  国家码,如 86 为中国
+     * @param string $phoneNumber 不带国家码的手机号
+     * @param string $msg         信息内容,必须与申请的模板格式一致,否则将返回错误
+     * @param int    $playtimes   播放次数,可选,最多3次,默认2次
+     * @param string $ext         用户的session内容,服务端原样返回,可选字段,不需要可填空串
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function send($nationCode, $phoneNumber, $msg, $playtimes = 2, $ext = "")
+    {
+        $random = $this->util->getRandom();
+        $curTime = time();
+        $wholeUrl = $this->url . "?sdkappid=" . $this->appid . "&random=" . $random;
+
+        // 按照协议组织 post 包体
+        $data = new \stdClass();
+        $tel = new \stdClass();
+        $tel->nationcode = "".$nationCode;
+        $tel->mobile = "".$phoneNumber;
+
+        $data->tel = $tel;
+        $data->msg = $msg;
+        $data->playtimes = $playtimes;
+        // app凭证
+        $data->sig = hash("sha256",
+            "appkey=".$this->appkey."&random=".$random."&time="
+            .$curTime."&mobile=".$phoneNumber, FALSE);
+        // unix时间戳,请求发起时间,如果和系统时间相差超过10分钟则会返回失败
+        $data->time = $curTime;
+        $data->ext = $ext;
+
+        return $this->util->sendCurlPost($wholeUrl, $data);
+    }
+}

+ 77 - 0
addons/qcloudsms/library/TtsVoiceSender.php

@@ -0,0 +1,77 @@
+<?php
+
+namespace addons\qcloudsms\library;
+
+use addons\qcloudsms\library\SmsSenderUtil;
+
+
+/**
+ * 指定模板发送语音通知类
+ *
+ */
+class TtsVoiceSender
+{
+    private $url;
+    private $appid;
+    private $appkey;
+    private $util;
+
+    /**
+     * 构造函数
+     *
+     * @param string $appid  sdkappid
+     * @param string $appkey sdkappid对应的appkey
+     */
+    public function __construct($appid, $appkey)
+    {
+        $this->url = "https://cloud.tim.qq.com/v5/tlsvoicesvr/sendtvoice";
+        $this->appid =  $appid;
+        $this->appkey = $appkey;
+        $this->util = new SmsSenderUtil();
+    }
+
+    /**
+     *
+     * 指定模板发送语音短信
+     *
+     * @param string $nationCode  国家码,如 86 为中国
+     * @param string $phoneNumber 不带国家码的手机号
+     * @param int    $templId     模板 id
+     * @param array  $params      模板参数列表,如模板 {1}...{2}...{3},需要带三个参数
+     * @param string $playtimes   播放次数,可选,最多3次,默认2次
+     * @param string $ext         用户的session内容,服务端原样返回,可选字段,不需要可填空串
+     * @return string 应答json字符串,详细内容参见腾讯云协议文档
+     */
+    public function send($nationCode, $phoneNumber, $templId, $params, $playtimes = 2, $ext = "")
+    {
+        /*var_dump($nationCode);
+        var_dump($phoneNumber);
+        var_dump($templId);
+        var_dump($params);
+        var_dump($playtimes);
+        exit();*/
+        $random = $this->util->getRandom();
+        $curTime = time();
+        $wholeUrl = $this->url . "?sdkappid=" . $this->appid . "&random=" . $random;
+
+        // 按照协议组织 post 包体
+        $data = new \stdClass();
+        $tel = new \stdClass();
+        $tel->nationcode = "".$nationCode;
+        $tel->mobile = "".$phoneNumber;
+        $data->tel = $tel;
+        $data->tpl_id = $templId;
+        $data->params = $params;
+        $data->playtimes = $playtimes;
+
+        // app凭证
+        $data->sig = $this->util->calculateSig($this->appkey, $random,
+            $curTime, array($phoneNumber));
+
+        // unix时间戳,请求发起时间,如果和系统时间相差超过10分钟则会返回失败
+        $data->time = $curTime;
+        $data->ext = $ext;
+        //var_dump($data);exit();
+        return $this->util->sendCurlPost($wholeUrl, $data);
+    }
+}

+ 10 - 0
application/extra/addons.php

@@ -27,8 +27,18 @@ return [
             'epay',
         ],
         'config_init' => [
+            'qcloudsms',
             'summernote',
         ],
+        'sms_send' => [
+            'qcloudsms',
+        ],
+        'sms_notice' => [
+            'qcloudsms',
+        ],
+        'sms_check' => [
+            'qcloudsms',
+        ],
     ],
     'route' => [
         '/qrcode$' => 'qrcode/index/index',