Sfoglia il codice sorgente

移动和阿里短信

linwu 1 giorno fa
parent
commit
f583cd5bc5

+ 15 - 1
app/admin/view/company/info.html

@@ -99,7 +99,7 @@
                         <table class="layui-table">
                             <thead>
                                 <tr>
-                                    <th colspan="3">短信平台</th>
+                                    <th colspan="3">创蓝短信平台</th>
                                 </tr>
                             </thead>
                             <tbody>
@@ -110,6 +110,20 @@
                                 </tr>
                             </tbody>
                         </table>
+                        <table class="layui-table">
+                            <thead>
+                            <tr>
+                                <th colspan="3">移动短信平台</th>
+                            </tr>
+                            </thead>
+                            <tbody>
+                            <tr>
+                                <td onclick="copyMobileUrl('https://www.chuanglan.com/');">网址:https://www.chuanglan.com/</td>
+                                <td onclick="copyMobileUrl('18060002035');">用户名:18060002035</td>
+                                <td onclick="copyMobileUrl('jjhc2019');">密码:jjhc2019</td>
+                            </tr>
+                            </tbody>
+                        </table>
                         <table class="layui-table">
                             <thead>
                                 <tr>

+ 65 - 24
app/admin/view/setting/sms.html

@@ -6,6 +6,7 @@
                 <ul class="layui-tab-title">
                     <li class="layui-this">基础配置</li>
                     <li>创蓝</li>
+                    <li>移动</li>
                     <li>阿里</li>
                 </ul>
                 <div class="layui-tab-content">
@@ -72,6 +73,70 @@
                             </div>
                         </div>
                     </div>
+                    <div class="layui-tab-item">
+                        <div class="layui-card">
+                            <div class="layui-card-header">移动短信接口参数</div>
+                            <div class="layui-card-body" pad15>
+                                <div class="layui-form layui-form-pane">
+                                    <div class="layui-form-item">
+                                        <label class="layui-form-label"><span style="color:#f90c05;">*</span>连接地址</label>
+                                        <div class="layui-input-block">
+                                            <input type="text" placeholder="请输入连接地址"
+                                                   name="sms_mas_url"
+                                                   value="{:array_get($sms,'sms_mas_url')}"
+                                                   lay-verify="required"
+                                                   class="layui-input">
+                                        </div>
+                                    </div>
+                                    <div class="layui-form-item">
+                                        <label class="layui-form-label"><span style="color:#f90c05;">*</span>企业名称</label>
+                                        <div class="layui-input-block">
+                                            <input type="text" placeholder="请输入企业名称"
+                                                   name="sms_mas_ecName"
+                                                   value="{:array_get($sms,'sms_mas_ecName')}"
+                                                   lay-verify="required"
+                                                   class="layui-input">
+                                        </div>
+                                    </div>
+                                    <div class="layui-form-item">
+                                        <label class="layui-form-label"><span style="color:#f90c05;">*</span>apId</label>
+                                        <div class="layui-input-block">
+                                            <input type="text" placeholder="请输入apId"
+                                                   name="sms_mas_apId"
+                                                   value="{:array_get($sms,'sms_mas_apId')}"
+                                                   lay-verify="required"
+                                                   class="layui-input">
+                                        </div>
+                                    </div>
+                                    <div class="layui-form-item">
+                                        <label class="layui-form-label"><span style="color:#f90c05;">*</span>secretKey</label>
+                                        <div class="layui-input-block">
+                                            <input type="text" placeholder="请输入secretKey"
+                                                   name="sms_mas_secretKey"
+                                                   value="{:array_get($sms,'sms_mas_secretKey')}"
+                                                   lay-verify="required"
+                                                   class="layui-input">
+                                        </div>
+                                    </div>
+                                    <div class="layui-form-item">
+                                        <label class="layui-form-label"><span style="color:#f90c05;">*</span>签名编码</label>
+                                        <div class="layui-input-block">
+                                            <input type="text" placeholder="请输入签名编码"
+                                                   name="sms_mas_sign"
+                                                   value="{:array_get($sms,'sms_mas_sign')}"
+                                                   lay-verify="required"
+                                                   class="layui-input">
+                                        </div>
+                                    </div>
+                                    <div class="layui-form-item">
+                                        <div class="layui-input-block">
+                                            <button class="layui-btn" lay-submit lay-filter="{$lay_btn}">确认修改</button>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
                     <div class="layui-tab-item">
                         <div class="layui-card">
                             <div class="layui-card-header">阿里云短信接口参数</div>
@@ -108,30 +173,6 @@
                                             <div class="layui-form-mid layui-word-aux"></div>
                                         </div>
                                     </div>
-                                    <div class="layui-form-item">
-                                        <label class="layui-form-label">注册验证</label>
-                                        <div class="layui-input-block">
-                                            <input type="text" name="sms_ali_register"
-                                                   value="{:array_get($sms,'sms_ali_register')}" class="layui-input">
-                                            <div class="layui-form-mid layui-word-aux">注册验证模版CODE,验证码变量名称:code</div>
-                                        </div>
-                                    </div>
-                                    <div class="layui-form-item">
-                                        <label class="layui-form-label">密码重置</label>
-                                        <div class="layui-input-block">
-                                            <input type="text" name="sms_ali_getpassword"
-                                                   value="{:array_get($sms,'sms_ali_getpassword')}" class="layui-input">
-                                            <div class="layui-form-mid layui-word-aux">密码重置模版CODE,验证码变量名称:code</div>
-                                        </div>
-                                    </div>
-                                    <div class="layui-form-item">
-                                        <label class="layui-form-label">登录验证</label>
-                                        <div class="layui-input-block">
-                                            <input type="text" name="sms_ali_mobilelogin"
-                                                   value="{:array_get($sms,'sms_ali_mobilelogin')}" class="layui-input">
-                                            <div class="layui-form-mid layui-word-aux">登录验证模版CODE,验证码变量名称:code</div>
-                                        </div>
-                                    </div>
                                     <div class="layui-form-item">
                                         <div class="layui-input-block">
                                             <button class="layui-btn" lay-submit lay-filter="{$lay_btn}">确认修改</button>

+ 3 - 1
app/admin/view/sms/log.html

@@ -39,9 +39,11 @@
             cols: [
                 [
                     {field: 'id', width: 80,title: 'ID'},
-                    {field: 'token', width: 160, title: 'token'},
+                    {field: 'token', width: 180, title: 'token'},
                     {field: 'ip', width: 120, title: 'ip'},
                     {field: 'content', title: '内容'},
+                    {field: 'template_code', width: 150, title: '模板编号'},
+                    {field: 'template_param', width: 180, title: '模板参数'},
                     {field: 'create_time', width: 160, title: '发送时间'},
                     {field: 'status_text', width: 120, title: '状态'},
                     {field: 'error', width: 160,title: '错误提示'},

+ 23 - 13
app/api/controller/Sms.php

@@ -2,8 +2,8 @@
 
 namespace app\api\controller;
 
+use ali\AliyunSMS;
 use app\api\ApiBaseController;
-use app\common\model\SettingModel;
 use app\common\model\SmsAuthModel;
 use app\common\model\SmsLogModel;
 use app\common\service\SmsService;
@@ -31,22 +31,32 @@ class Sms extends ApiBaseController
         }
 
         //发送短信
-        $type    = input('post.type', '');
-        $mobile  = input('post.mobile', '');
-        $content = input('post.content', '');
-        if (empty($mobile) || empty($content)) {
-            ajax_error('手机号或内容不能为空!');
+        $type           = input('post.type', '');
+        $mobile         = input('post.mobile', '');
+        $content        = input('post.content', '');
+        $template_code  = input('post.template_code', '');
+        $template_param = input('post.template_param', '');
+        if ($type == 'ali') {
+            if (empty($mobile) || empty($template_code) || empty($template_param)) {
+                ajax_error('手机号或模板号或模板参数不能为空!');
+            }
+        } else {
+            if (empty($mobile) || empty($content)) {
+                ajax_error('手机号或内容不能为空!');
+            }
         }
-        $res     = SmsService::apiSend($mobile, $content, $type);
+        $res = SmsService::apiSend($mobile, $content, $type, $template_code, $template_param);
 
         //记录日志
         $log = [
-            'ip'      => $ip,
-            'token'   => $token,
-            'mobile'  => $mobile,
-            'content' => $content,
-            'status'  => $res['code'] ? 2 : 1,
-            'error'   => $res['code'] ? $res['msg'] : '',
+            'ip'             => $ip,
+            'token'          => $token,
+            'mobile'         => $mobile,
+            'content'        => $content,
+            'template_code'  => $template_code,
+            'template_param' => json_encode($template_param),
+            'status'         => $res['code'] ? 2 : 1,
+            'error'          => $res['code'] ? $res['msg'] : '',
         ];
         SmsLogModel::create($log);
 

+ 8 - 1
app/common/model/SettingModel.php

@@ -12,9 +12,16 @@ class SettingModel extends BaseModel
         'sms_type',
         'sms_chuanglan_appkey',
         'sms_chuanglan_secret',
+        'sms_mas_url',
+        'sms_mas_ecName',
+        'sms_mas_apId',
+        'sms_mas_secretKey',
+        'sms_mas_sign',
     ];
     const SMS_TYPE = [
-        'chuanglan\\Chuanglan' => '创蓝'
+        'chuanglan' => '创蓝',
+        'mas' => '移动MAS',
+        'ali' => '阿里云短信',
     ];
     const SYSTEM = [
         'site_name',

+ 22 - 7
app/common/service/SmsService.php

@@ -28,20 +28,35 @@ class SmsService
         return $sms->send($mobile, ['message' => $msg]);
     }
 
-    public static function apiSend($mobile, $content, $sms_obj = '')
+    public static function apiSend($mobile, $content, $sms_type = '', $template_code = '', $template_param = '')
     {
-        if (empty($sms_obj)) {
-            $sms_obj = SettingModel::getConfigValue('sms_type');
-            if (empty($sms_obj)) {
+        $sms_obj_arr = [
+            'chuanglang' => 'chuanglan\\Chuanglan',
+            'mas'        => 'mas\\Mas',
+            'ali'        => 'ali\\Ali',
+        ];
+        if (empty($sms_type)) {
+            $sms_type = SettingModel::getConfigValue('sms_type');
+            if (empty($sms_type)) {
                 return ['code' => 1, 'msg' => '未配置默认模板'];
             }
         }
+        if (empty($sms_obj_arr[$sms_type])) {
+            if (empty($sms_type)) {
+                return ['code' => 1, 'msg' => '模板类型错误'];
+            }
+        }
 
-        if (!in_array($sms_obj, array_keys(SettingModel::SMS_TYPE))) {
+        if (!in_array($sms_type, array_keys(SettingModel::SMS_TYPE))) {
             return ['code' => 1, 'msg' => '平台类型不存在'];
         }
 
-        $sms = new $sms_obj();
-        return $sms->send($mobile, ['message' => $content]);
+        $sms_obj = $sms_obj_arr[$sms_type];
+        $sms     = new $sms_obj();
+        return $sms->send($mobile, [
+            'message'        => $content,
+            'template_code'  => $template_code,
+            'template_param' => $template_param,
+        ]);
     }
 }

+ 132 - 0
extend/ali/Ali.php

@@ -0,0 +1,132 @@
+<?php
+
+namespace ali;
+
+use app\common\model\SettingModel;
+use think\facade\Log;
+
+/**
+ * 阿里云短信服务 PHP 示例
+ *
+ * 功能:
+ * 1. 自动生成签名
+ * 2. 支持单条短信发送
+ * 3. 完善的错误处理
+ * 4. 响应结果解析
+ */
+class Ali
+{
+    // 阿里云短信服务配置
+    private $accessKeyId;      // 替换为您的AccessKey ID
+    private $accessKeySecret; // 替换为您的AccessKey Secret
+    private $signName;             // 短信签名
+    private $regionId = 'cn-hangzhou';                // 区域ID
+    private $endpoint = 'dysmsapi.aliyuncs.com';      // 短信服务域名
+
+    // 发送短信
+    public function send($phone, $smslog_param)
+    {
+        $config = SettingModel::getConfigValue(['sms_ali_accesskeyid', 'sms_ali_accesskeysecret', 'sms_ali_signname']);
+        if (empty($config['sms_ali_accesskeyid']) || empty($config['sms_ali_accesskeysecret']) || empty($config['sms_ali_signname'])) {
+            return ['code' => 1, 'msg' => '请绑定模板参数'];
+        }
+
+        $this->accessKeyId     = $config['sms_ali_accesskeyid'];
+        $this->accessKeySecret = $config['sms_ali_accesskeysecret'];
+        $this->signName        = $config['sms_ali_signname'];
+        $templateCode          = $smslog_param['template_code'];
+        $templateParam         = $smslog_param['template_param'];
+
+        // 公共参数
+        $params = [
+            'RegionId'         => $this->regionId,
+            'AccessKeyId'      => $this->accessKeyId,
+            'Format'           => 'JSON',
+            'SignatureMethod'  => 'HMAC-SHA1',
+            'SignatureVersion' => '1.0',
+            'SignatureNonce'   => uniqid(),
+            'Timestamp'        => gmdate('Y-m-d\TH:i:s\Z'),
+            'Action'           => 'SendSms',
+            'Version'          => '2017-05-25',
+            'PhoneNumbers'     => $phone,
+            'SignName'         => $this->signName,
+            'TemplateCode'     => $templateCode,
+        ];
+
+        // 添加模板参数(如果有)
+        if (!empty($templateParam)) {
+            $params['TemplateParam'] = json_encode($templateParam);
+        }
+
+        // 生成签名
+        $params['Signature'] = $this->generateSignature($params);
+
+        // 构建请求URL
+        $url = 'https://' . $this->endpoint . '/?' . http_build_query($params);
+
+        // 发送HTTP请求
+        return $this->sendRequest($url);
+    }
+
+    // 生成签名
+    private function generateSignature($params)
+    {
+        // 参数排序
+        ksort($params);
+
+        // 构造查询字符串
+        $queryString = '';
+        foreach ($params as $key => $value) {
+            $queryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($value);
+        }
+
+        // 构造签名字符串
+        $stringToSign = 'GET&%2F&' . $this->percentEncode(substr($queryString, 1));
+
+        // 计算签名
+        $signature = base64_encode(hash_hmac('sha1', $stringToSign, $this->accessKeySecret . '&', true));
+
+        return $signature;
+    }
+
+    // URL编码
+    private function percentEncode($str)
+    {
+        $res = urlencode($str);
+        $res = str_replace(['+', '*'], ['%20', '%2A'], $res);
+        $res = preg_replace('/%7E/', '~', $res);
+        return $res;
+    }
+
+    // 发送HTTP请求
+    private function sendRequest($url)
+    {
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
+
+        $response = curl_exec($ch);
+        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+        if (curl_errno($ch)) {
+            Log::error('短信发送失败:' . curl_error($ch));
+            return ['code' => 1, 'msg' => '短信发送失败'];
+        }
+
+        curl_close($ch);
+        if ($httpCode !== 200) {
+            Log::error('短信发送失败,状态码:' . $httpCode);
+            return ['code' => 1, 'msg' => '短信发送失败,状态码:' . $httpCode];
+        }
+
+        $res = json_decode($response, true);
+        if ($res['Code'] == 'OK') {
+            return ['code' => 0];
+        } else {
+            Log::error('短信发送失败:' . $response . "。原始参数:" . $url);
+            return ['code' => 1, 'msg' => $res['Message']];
+        }
+    }
+}

+ 74 - 0
extend/mas/Mas.php

@@ -0,0 +1,74 @@
+<?php
+/**
+ * 手机短信类
+ */
+
+namespace mas;
+
+use app\common\model\SettingModel;
+use think\facade\Log;
+
+class Mas
+{
+    private $_error_arr = [
+        'IllegalMac'      => 'mac校验不通过。',
+        'IllegalSignId'   => '无效的签名编码。',
+        'InvalidMessage'  => '非法消息,请求数据解析失败。',
+        'InvalidUsrOrPwd' => '非法用户名/密码。',
+        'NoSignId'        => '未匹配到对应的签名信息。',
+        'success'         => '数据验证通过。',
+        'TooManyMobiles'  => '手机号数量超限(>5000),应≤5000。',
+    ];
+
+    /**
+     * 短信发送
+     * @param $mobile
+     * @param $smslog_param
+     * @return array
+     */
+    public function send($mobile, $smslog_param)
+    {
+        $config = SettingModel::getConfigValue(['sms_mas_url', 'sms_mas_ecName', 'sms_mas_apId', 'sms_mas_secretKey', 'sms_mas_sign']);
+        if (empty($config['sms_mas_url']) || empty($config['sms_mas_ecName']) || empty($config['sms_mas_apId']) || empty($config['sms_mas_secretKey']) || empty($config['sms_mas_sign'])) {
+            return ['code' => 1, 'msg' => '请绑定模板参数'];
+        }
+
+        //请求参数
+        $param        = [
+            'ecName'    => $config['sms_mas_ecName'],
+            'apId'      => $config['sms_mas_apId'],
+            'mobiles'   => $mobile,
+            'content'   => $smslog_param['message'],
+            'sign'      => $config['sms_mas_sign'],
+            'addSerial' => '',
+        ];
+        $param['mac'] = md5($param['ecName'] . $param['apId'] . $config['sms_mas_secretKey'] . $param['mobiles'] . $param['content'] . $param['sign'] . $param['addSerial']);
+        $postFields   = base64_encode(json_encode($param));
+
+        //发送请求
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, $config['sms_mas_url']);
+        curl_setopt($ch, CURLOPT_HTTPHEADER, [
+                'Content-Type: application/json; charset=utf-8',   //json版本需要填写  Content-Type: application/json;
+            ]
+        );
+        curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); //若果报错 name lookup timed out 报错时添加这一行代码
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($ch, CURLOPT_POST, 1);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
+        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
+        $ret = curl_exec($ch);
+        curl_close($ch);
+        $rsp = json_decode($ret, true);
+
+        if (!$rsp['success']) {
+            Log::error('短信发送失败:' . json_encode($rsp) . "。原始参数:" . $postFields);
+            $error = $this->_error_arr[$rsp['rspcod']] ?? '未知错误';
+            return ['code' => 1, 'msg' => $error];
+        } else {
+            return ['code' => 0];
+        }
+    }
+}

+ 17 - 7
短信接口文档.md

@@ -12,13 +12,23 @@
 
 请求参数(可不传,不传按默认值处理):
 
-| 字段名     | 类型   | 是否必填 | 描述        |
-|---------| ------ |------|-----------|
-| mobile  | string | 是    | 手机号       |
-| content | string | 是    | 短信内容      |
-| type    | string | 否    | 短信平台,目前只有"chuanglan\\Chuanglan" |
-
-数组参数说明:
+| 字段名            | 类型     | 是否必填 | 描述                 |
+|----------------|--------|------|--------------------|
+| mobile         | string | 是    | 手机号                |
+| content        | string | 否    | 短信内容               |
+| template_code  | string | 否    | 模板号,ali平台使用        |
+| template_param | object | 否    | 模板参数,ali平台使用       |
+| type           | string | 否    | 短信平台,默认"chuanglan" |
+
+短信平台参数说明:
+
+| 参数        | 描述      |
+|-----------|---------|
+| chuanglan | 创蓝短信    |
+| mas       | 移动MAS短信 |
+| ali       | 阿里云短信   |
+
+响应参数说明:
 
 | 字段名  | 类型      | 描述      |
 |------|---------|---------|