浏览代码

增加短信配置接口

Anyon 4 年之前
父节点
当前提交
30eb70c27b
共有 3 个文件被更改,包括 252 次插入0 次删除
  1. 18 0
      app/data/controller/Config.php
  2. 176 0
      app/data/service/MessageService.php
  3. 58 0
      app/data/view/config/message.html

+ 18 - 0
app/data/controller/Config.php

@@ -2,6 +2,7 @@
 
 namespace app\data\controller;
 
+use app\data\service\MessageService;
 use think\admin\Controller;
 
 /**
@@ -12,6 +13,23 @@ use think\admin\Controller;
 class Config extends Controller
 {
     /**
+     * 短信接口配置
+     * @auth true
+     * @menu true
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function message()
+    {
+        $this->title = '短信接口配置';
+        if ($this->request->isGet()) {
+            $this->result = MessageService::instance()->balance();
+        }
+        $this->__sysconf('open');
+    }
+
+    /**
      * 关于我们描述
      * @auth true
      * @menu true

+ 176 - 0
app/data/service/MessageService.php

@@ -0,0 +1,176 @@
+<?php
+
+namespace app\data\service;
+
+use think\admin\Service;
+
+/**
+ * 短信支持服务
+ * Class MessageService
+ * @package app\data\service
+ */
+class MessageService extends Service
+{
+    /**
+     * 平台授权账号
+     * @var string
+     */
+    protected $username;
+
+    /**
+     * 平台授权密码
+     * @var string
+     */
+    protected $password;
+
+    /**
+     * 短信服务初始化
+     * @return MessageService|void
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    protected function initialize()
+    {
+        $this->username = sysconf('zt.username');
+        $this->password = sysconf('zt.password');
+    }
+
+    /**
+     * 发送自定义短信内容
+     * @param string $phone
+     * @param string $content
+     * @return array
+     */
+    public function send(string $phone, string $content): array
+    {
+        [$state, $message, $record] = $this->_request('v2/sendSms', ['mobile' => $phone, 'content' => $content]);
+        $this->app->db->name('DataMemberMessage')->insert([
+            'phone' => $phone, 'content' => $content, 'result' => $message, 'status' => $state ? 1 : 0,
+        ]);
+        return [$state, $message, $record];
+    }
+
+    /**
+     * 短信条数查询
+     */
+    public function balance(): array
+    {
+        [$state, $message, $result] = $this->_request('v2/balance', []);
+        return [$state, $message, $state ? $result['sumSms'] : 0];
+    }
+
+    /**
+     * 验证手机短信验证码
+     * @param string $code 验证码
+     * @param string $phone 手机号验证
+     * @param string $tplcode
+     * @return boolean
+     */
+    public function checkVerifyCode(string $code, string $phone, string $tplcode = 'zt.tplcode_register')
+    {
+        $cache = $this->app->cache->get($ckey = md5("code-{$tplcode}-{$phone}"), []);
+        return is_array($cache) && isset($cache['code']) && $cache['code'] == $code;
+    }
+
+    /**
+     * 验证手机短信验证码
+     * @param string $phone 手机号码
+     * @param integer $wait 等待时间
+     * @param string $tplcode 模板编号
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function sendVerifyCode(string $phone, int $wait = 120, string $tplcode = 'zt.tplcode_register')
+    {
+        $content = sysconf($tplcode) ?: '您的短信验证码为{code},请在十分钟内完成操作!';
+        $cache = $this->app->cache->get($ckey = md5("code-{$tplcode}-{$phone}"), []);
+        // 检查是否已经发送
+        if (is_array($cache) && isset($cache['time']) && $cache['time'] > time() - $wait) {
+            $dtime = ($cache['time'] + $wait < time()) ? 0 : ($wait - time() + $cache['time']);
+            return [1, '短信验证码已经发送!', ['time' => $dtime]];
+        }
+        // 生成新的验证码
+        [$code, $time] = [rand(100000, 999999), time()];
+        $this->app->cache->set($ckey, ['code' => $code, 'time' => $time], 600);
+        // 尝试发送短信内容
+        [$state] = $this->send($phone, preg_replace_callback("|{(.*?)}|", function ($matches) use ($code) {
+            return $matches[1] === 'code' ? $code : $matches[1];
+        }, $content));
+        if ($state) return [1, '短信验证码发送成功!', [
+            'time' => ($time + $wait < time()) ? 0 : ($wait - time() + $time)],
+        ]; else {
+            $this->app->cache->delete($ckey);
+            return [0, '短信发送失败,请稍候再试!', []];
+        }
+    }
+
+    /**
+     * 执行网络请求
+     * @param string $url 接口请求地址
+     * @param array $data 接口请求参数
+     * @return array
+     */
+    private function _request(string $url, array $data): array
+    {
+        $encode = md5(md5($this->password) . ($tkey = time()));
+        $option = ['headers' => ['Content-Type:application/json;charset=UTF-8']];
+        $request = json_encode(array_merge($data, ['username' => $this->username, 'password' => $encode, 'tKey' => $tkey]));
+        $result = json_decode(http_post("https://api.mix2.zthysms.com/{$url}", $request, $option), true);
+        if (empty($result['code'])) {
+            return [0, '接口请求网络异常', []];
+        } elseif (intval($result['code']) === 200) {
+            return [1, $this->_error($result['code']), $result];
+        } else {
+            return [0, $this->_error($result['code']), $result];
+        }
+    }
+
+    /**
+     * 获取状态描述
+     * @param integer $code
+     * @return string
+     */
+    private function _error(int $code): string
+    {
+        $arrs = [
+            200  => '提交成功',
+            4001 => '用户名错误',
+            4002 => '密码不能为空',
+            4003 => '短信内容不能为空',
+            4004 => '手机号码错误',
+            4006 => 'IP鉴权错误',
+            4007 => '用户禁用',
+            4008 => 'tKey错误',
+            4009 => '密码错误',
+            4011 => '请求错误',
+            4013 => '定时时间错误',
+            4014 => '模板错误',
+            4015 => '扩展号错误',
+            4019 => '用户类型错误',
+            4023 => '签名错误',
+            4025 => '模板变量内容为空',
+            4026 => '手机号码数最大2000个',
+            4027 => '模板变量内容最大200组',
+            4029 => '请使用 POST 请求',
+            4030 => 'Content-Type 请使用 application/json',
+            4031 => '模板名称不能为空',
+            4032 => '模板类型不正确',
+            4034 => '模板内容不能为空',
+            4035 => '模板名称已经存在',
+            4036 => '添加模板信息失败',
+            4037 => '模板名称最大20字符',
+            4038 => '模板内容超过最大字符数',
+            4040 => '模板内容缺少变量值或规则错误',
+            4041 => '模板内容中变量规范错误',
+            4042 => '模板变量个数超限',
+            4044 => '接口24小时限制提交次数超限',
+            9998 => 'JSON解析错误',
+            9999 => '非法请求',
+        ];
+        return $arrs[$code] ?? $code;
+    }
+
+}

+ 58 - 0
app/data/view/config/message.html

@@ -0,0 +1,58 @@
+{extend name="../../admin/view/main"}
+
+{block name="content"}
+<div class="layui-badge nowrap think-bg-red padding-5 padding-left-10 font-s15 layui-anim layui-anim-upbit">
+    注意:短信接口配置的参数不能随意修改,会影响到会员注册发送短信通知功能,若有需要调整请联系客服!
+</div>
+<div class="think-box-shadow">
+    <form style="width:800px" onsubmit="return false;" data-auto="true" action="{$request->url()}" method="post" class='layui-form layui-card noshadow' autocomplete="off">
+
+        <div class="layui-card-body padding-left-40">
+
+            <label class="layui-form-item block relative">
+                <span class="color-green font-w7 margin-right-10">接口查询状态</span><span class="nowrap color-desc">Status</span>
+                {if empty($result.0)}
+                <span class="layui-input layui-bg-gray color-red">{$result.1|default=''}</span>
+                {elseif $result.0 eq 1}
+                <span class="layui-input layui-bg-gray color-green">平台剩余 {$result.2|default=0} 条可用短信</span>
+                {else}
+                <span class="layui-input layui-bg-gray color-text">没有结果</span>
+                {/if}
+                <span class="help-block layui-hide">可用短信条数不足时可以联系 18122377655 充值</span>
+            </label>
+
+            <label class="layui-form-item block relative">
+                <span class="color-green font-w7 margin-right-10">短信授权账号</span><span class="nowrap color-desc">Username</span>
+                <input name="zt.username" required placeholder="请输入短信授权账号" value="{:sysconf('zt.username')}" class="layui-input">
+                <span class="help-block">短信授权账号,可以联系 18122377655 获取账号与密码</span>
+            </label>
+
+            <label class="layui-form-item block relative">
+                <span class="color-green font-w7 margin-right-10">短信授权密码</span><span class="nowrap color-desc">Password</span>
+                <input name="zt.password" required placeholder="请输入短信授权密码" value="{:sysconf('zt.password')}" class="layui-input">
+                <span class="help-block">短信授权密码,可以联系 18122377655 获取账号与密码</span>
+            </label>
+
+            <label class="layui-form-item block relative">
+                <span class="color-green font-w7 margin-right-10">短信发送安全码</span><span class="nowrap color-desc">SecureCode</span>
+                <input name="zt.secure_code" required placeholder="请输入短信发送安全码" value="{:sysconf('zt.secure_code')}" class="layui-input">
+                <span class="help-block">短信发送安全码,调用接口发短信时需要传入此参数</span>
+            </label>
+
+            <label class="layui-form-item block relative">
+                <span class="color-green font-w7 margin-right-10">会员注册通知模板</span><span class="nowrap color-desc">RegisterTemplate</span>
+                <textarea class="layui-textarea" name="zt.tplcode_register">{:sysconf('zt.tplcode_register')}</textarea>
+                <span class="help-block">会员注册短信模板,验证码变量使用 {code} 代替</span>
+            </label>
+
+            <div class="hr-line-dashed"></div>
+
+            <div class="layui-form-item text-center margin-top-20">
+                <button class="layui-btn" type="submit">保存配置</button>
+            </div>
+
+        </div>
+    </form>
+
+</div>
+{/block}