Bläddra i källkod

feat(tencentcloud-sms): 实现腾讯云短信发送功能

- 新增 Config 类用于配置管理- 新增 SmsClient 类实现短信发送功能
- 新增单元测试 SmsClientTest
- 更新 Extension 类,添加 EXTENSION_ID 常量
- 更新 config.php,调整配置项并支持多模板管理
runphp 6 månader sedan
förälder
incheckning
a31293a02d
5 ändrade filer med 181 tillägg och 45 borttagningar
  1. 55 45
      config.php
  2. 24 0
      src/Config.php
  3. 1 0
      src/Extension.php
  4. 82 0
      src/SmsClient.php
  5. 19 0
      test/SmsClientTest.php

+ 55 - 45
config.php

@@ -34,7 +34,7 @@ return [[
         'title' => 'AppId',
         'field' => 'app_id',
         'props' => [
-            'placeholder' => '请输入短信应用ID'
+            'placeholder' => '请输入短信应用App ID'
         ],
         '$required' => true,
         '_fc_id' => 'id_Fua8me9rioxkafc',
@@ -45,38 +45,10 @@ return [[
     ],
     [
         'type' => 'input',
-        'title' => 'SignName',
-        'field' => 'sign_name',
-        'props' => [
-            'placeholder' => '请输入短信签名内容'
-        ],
-        '$required' => true,
-        '_fc_id' => 'id_Fdvume9rioxkahc',
-        'name' => 'ref_F7ecme9rioxkaic',
-        'display' => true,
-        'hidden' => false,
-        '_fc_drag_tag' => 'input'
-    ],
-    [
-        'type' => 'input',
-        'title' => 'TemplateId',
-        'field' => 'template_id',
-        'props' => [
-            'placeholder' => '请输入短信模板ID'
-        ],
-        '$required' => true,
-        '_fc_id' => 'id_Fev8me9rioxkajc',
-        'name' => 'ref_Fwj5me9rioxkakc',
-        'display' => true,
-        'hidden' => false,
-        '_fc_drag_tag' => 'input'
-    ],
-    [
-        'type' => 'input',
-        'title' => 'SmsSdkAppId',
-        'field' => 'sms_sdk_app_id',
+        'title' => 'AppKey',
+        'field' => 'app_key',
         'props' => [
-            'placeholder' => '请输入短信SdkAppId'
+            'placeholder' => '请输入短信应用App Key'
         ],
         '$required' => true,
         '_fc_id' => 'id_Fmwkme9rioxkalc',
@@ -87,30 +59,68 @@ return [[
     ],
     [
         'type' => 'input',
-        'title' => 'Endpoint',
-        'field' => 'endpoint',
+        'title' => 'SignName',
+        'field' => 'sign_name',
         'props' => [
-            'placeholder' => '请输入API请求域名(如:sms.tencentcloudapi.com)'
+            'placeholder' => '请输入短信签名内容'
         ],
         '$required' => true,
-        '_fc_id' => 'id_Fj0nme9rioxkanc',
-        'name' => 'ref_Fb2wme9rioxkaoc',
+        '_fc_id' => 'id_Fdvume9rioxkahc',
+        'name' => 'ref_F7ecme9rioxkaic',
         'display' => true,
         'hidden' => false,
         '_fc_drag_tag' => 'input'
     ],
+
     [
-        'type' => 'input',
-        'title' => 'Region',
-        'field' => 'region',
+        'type' => 'group',
+        'field' => 'tencent_sms_templates',
+        'title' => '腾讯短信模板',
         'props' => [
-            'placeholder' => '请输入地域参数(如:ap-guangzhou)'
+            'min' => 1,
+            'max' => 10,
+            'rule' => [[
+                'type' => 'input',
+                'field' => 'template_id',
+                'title' => '模板ID',
+                'props' => [
+                    'placeholder' => '请输入短信模板ID'
+                ],
+                'col' => [
+                    'span' => 12
+                ],
+                '$required' => true,
+                '_fc_id' => 'id_Ffiamf9en7x5abc',
+                'name' => 'ref_F50qmf9en7x5acc',
+                'display' => true,
+                'hidden' => false,
+                '_fc_drag_tag' => 'input'
+            ],
+                [
+                    'type' => 'input',
+                    'field' => 'template_content',
+                    'title' => '短信内容',
+                    'props' => [
+                        'placeholder' => '请输入短信内容',
+                        'rows' => 3,
+                        'type' => 'textarea'
+                    ],
+                    'col' => [
+                        'span' => 12
+                    ],
+                    '$required' => true,
+                    '_fc_id' => 'id_Fex1mf9en7x5adc',
+                    'name' => 'ref_Fm5amf9en7x5aec',
+                    'display' => true,
+                    'hidden' => false,
+                    '_fc_drag_tag' => 'input'
+                ]
+            ]
         ],
-        '$required' => true,
-        '_fc_id' => 'id_Fwtame9rioxkapc',
-        'name' => 'ref_F3snme9rioxkaqc',
+        '_fc_id' => 'id_Fy7kmf9en7x6afc',
+        'name' => 'ref_Fd74mf9en7x6agc',
         'display' => true,
         'hidden' => false,
-        '_fc_drag_tag' => 'input'
+        '_fc_drag_tag' => 'group'
     ]
 ];

+ 24 - 0
src/Config.php

@@ -0,0 +1,24 @@
+<?php
+declare(strict_types=1);
+namespace SixShop\TencentCloudSms;
+
+use SixShop\System\Trait\ConfigTrait;
+
+
+/**
+ * @property string $secret_id
+ * @property string $secret_key
+ * @property string $app_id
+ * @property string $app_key
+ * @property string $sign_name
+ * @property array $tencent_sms_templates
+ */
+class Config
+{
+    use ConfigTrait;
+
+    public function getExtensionID(): string
+    {
+        return Extension::EXTENSION_ID;
+    }
+}

+ 1 - 0
src/Extension.php

@@ -7,6 +7,7 @@ use SixShop\Core\ExtensionAbstract;
 
 class Extension extends ExtensionAbstract
 {
+    public const string EXTENSION_ID = 'tencentcloud_sms';
     protected function getBaseDir(): string
     {
         return dirname(__DIR__);

+ 82 - 0
src/SmsClient.php

@@ -0,0 +1,82 @@
+<?php
+declare(strict_types=1);
+namespace SixShop\TencentCloudSms;
+
+
+use TencentCloud\Common\Credential;
+use TencentCloud\Common\Exception\TencentCloudSDKException;
+use TencentCloud\Common\Profile\ClientProfile;
+use TencentCloud\Common\Profile\HttpProfile;
+use TencentCloud\Sms\V20190711\Models\SendSmsRequest;
+use TencentCloud\Sms\V20190711\SmsClient as TencentCloudSmsClient;
+
+class SmsClient
+{
+    private array $templateMap = [];
+
+    private TencentCloudSmsClient $client;
+
+    private array $errorMesageMap = [
+        'FailedOperation.ContainSensitiveWord' => '包含敏感词',
+        'FailedOperation.InsufficientBalanceInSmsPackage' => '套餐包余量不足',
+        'FailedOperation.PhoneNumberInBlacklist' => '号码在黑名单中',
+        'FailedOperation.SignatureIncorrectOrUnapproved' => '签名未审核通过',
+        'FailedOperation.TemplateIncorrectOrUnapproved' => '模板未审核通过',
+        'FailedOperation.TemplateUnapprovedOrNotExist' => '模板未审核通过或不存在',
+        'InvalidParameterValue.ContentLengthLimit' => '内容长度超出限制',
+        'InvalidParameterValue.IncorrectPhoneNumber' => '号码格式错误',
+    ];
+    public function __construct(private Config $config)
+    {
+        $this->templateMap = array_to_map($this->config->tencent_sms_templates, 'template_id', 'template_content');
+        $cred = new Credential($this->config->secret_id, $this->config->secret_key);
+        $httpProfile = new HttpProfile();
+        $httpProfile->setEndpoint('sms.tencentcloudapi.com');
+        $clientProfile = new ClientProfile();
+        $clientProfile->setHttpProfile($httpProfile);
+        $this->client = new TencentCloudSmsClient($cred, 'ap-guangzhou', $clientProfile);
+    }
+
+    /**
+     * 发送短信
+     *
+     * @param array|string $phoneNumberSet 手机号码列表
+     * @param string $templateId 模板ID
+     * @param array|string $templateParamSet 模板参数
+     */
+    public function sendSms(array|string $phoneNumberSet, string $templateId, array|string $templateParamSet): array
+    {
+        $phoneNumberSet = (array)$phoneNumberSet;
+        $templateParamSet = (array)$templateParamSet;
+        if (!isset($this->templateMap[$templateId])) {
+            throw new \InvalidArgumentException("template_id {$templateId} not found");
+        }
+        try {
+            $resp = $this->client->SendSms($this->getSendSmsRequest($phoneNumberSet, $templateId, $templateParamSet));
+        } catch (TencentCloudSDKException $e) {
+            throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
+        }
+        $resp = json_decode($resp->toJsonString(), true);
+        $this->checkError($resp);
+        return $resp;
+    }
+
+    private function getSendSmsRequest(array $phoneNumberSet, string $templateId, array $templateParamSet): SendSmsRequest
+    {
+        $req =  new SendSmsRequest();
+        $req->setPhoneNumberSet($phoneNumberSet);
+        $req->setSmsSdkAppid($this->config->app_id);
+        $req->setTemplateID($templateId);
+        $req->setSign($this->config->sign_name);
+        $req->setTemplateParamSet($templateParamSet);
+        return $req;
+    }
+    private function checkError(array $resp): void
+    {
+        foreach ($resp['SendStatusSet'] as $statusItem) {
+            if ($statusItem['Code'] !== 'Ok') {
+                throw new \RuntimeException($this->errorMesageMap[$statusItem['Code']] ?? $statusItem['Message']);
+            }
+        }
+    }
+}

+ 19 - 0
test/SmsClientTest.php

@@ -0,0 +1,19 @@
+<?php
+declare(strict_types=1);
+namespace SixShop\TencentCloudSms;
+use PHPUnit\Framework\TestCase;
+
+class SmsClientTest extends TestCase
+{
+    protected SmsClient $smsClient;
+    protected function setUp(): void
+    {
+        $this->smsClient = app()->make(SmsClient::class);
+    }
+
+    public function testSendSms():void
+    {
+        $resp = $this->smsClient->sendSms('13724018360', '2516637', '123456');
+        dump($resp);
+    }
+}