Browse Source

feat: 新短信平台

master
liyang 2 weeks ago
parent
commit
65554fbeea
  1. 4
      app/admin/job/SendSmsFromBackend.php
  2. 47
      app/home/service/BaseHomeService.php
  3. 42
      app/sms/Sms.php
  4. 8
      app/sms/contracts/SmsDriverInterface.php
  5. 165
      app/sms/drivers/WorldSmsDriver.php
  6. 51
      app/utility/SendSms.php
  7. 16
      config/sms.php

4
app/admin/job/SendSmsFromBackend.php

@ -1,6 +1,9 @@
<?php
namespace app\admin\job;
use think\queue\Job;
class SendSmsFromBackend
{
@ -47,5 +50,4 @@ class SendSmsFromBackend
// 删除任务
$job->delete();
}
}

47
app/home/service/BaseHomeService.php

@ -75,7 +75,7 @@ class BaseHomeService
public function getSmsContent(int $type = 1): array
{
$code = random_int(1000, 9999);
$subject = "your code is [$code], valid for 5 minutes";
$subject = "【Acm】あなたの認証コード[$code],有効10分以内";
return ['subject' => $subject, 'code' => $code];
}
@ -95,7 +95,8 @@ class BaseHomeService
return ['title' => $title, 'subject' => $subject, 'code' => $code];
}
public function getEmailTemplateForRegDone(){
public function getEmailTemplateForRegDone()
{
return [
'title' => '账号注册成功',
'content' => '您的账号注册成功.',
@ -136,11 +137,11 @@ class BaseHomeService
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
function getUniqInviteCode($length = 6) {
function getUniqInviteCode($length = 6)
{
$characters = '1234567890abcdefghijklmnpqrstwxyzABCDEFGHIJKLMNPQRSTWXYZ';
$inviteCode = '';
while (true)
{
while (true) {
for ($i = 0; $i < $length; $i++) {
$index = rand(0, strlen($characters) - 1);
$inviteCode .= $characters[$index];
@ -169,11 +170,21 @@ class BaseHomeService
{
$code = '';
$arr = [
'9','t','6', 'k', 'h', '8', '5','f', 'm', 'd', 's', '6'
'9',
't',
'6',
'k',
'h',
'8',
'5',
'f',
'm',
'd',
's',
'6'
];
// redis 去重
while (true)
{
while (true) {
$rand_num = time() . rand(10, 99);
for ($i = 0; $i < strlen($rand_num); $i++) {
$code .= $arr[$rand_num[$i]];
@ -403,7 +414,6 @@ class BaseHomeService
// 由中间件自动续期
Cache::store('redis')->set($tokenKey, $userId, $expired);
Cache::store('redis')->set($userTokenKey, $token, $expired);
}
public function delUserTokenCache($userId)
{
@ -423,7 +433,8 @@ class BaseHomeService
Cache::store('redis')->set($key, $level_info);
}
public function initSetting(){
public function initSetting()
{
$this->initTradeFeeSetting();
$this->initBrokerageRegSetting();
$this->initUserLevelSetting();
@ -432,7 +443,8 @@ class BaseHomeService
$this->initDrawalSetting(1);
return $this->toData(0, 'ok');
}
public function initDigitalList(){
public function initDigitalList()
{
$result = DigitalListModel::getMarketList([
'page' => 1,
'page_size' => 2000
@ -444,7 +456,8 @@ class BaseHomeService
}
return $result['list'];
}
public function getDigitalList(){
public function getDigitalList()
{
$data = $this->redis->keys('DIGITAL:LIST:*');
$list = [];
foreach ($data as $val) {
@ -542,7 +555,6 @@ class BaseHomeService
$res = $this->redis->hGetAll($brokerage_reg_key);
}
return $res;
}
public function initUserLevelSetting()
{
@ -705,7 +717,6 @@ class BaseHomeService
}
return $res;
}
}
private function checkEmpty($value1, $value2, $value3): bool
{
@ -722,7 +733,8 @@ class BaseHomeService
// 如果非空值的个数等于1,则返回 true,否则返回 false
return $count == 3;
}
public function getRedis(){
public function getRedis()
{
$config = \think\facade\Config::get('cache.stores.redis');
$redis = new \Redis();
@ -743,7 +755,8 @@ class BaseHomeService
* @param int $length
* @return false|string
*/
public function generateOrderNumber(int $length=20) {
public function generateOrderNumber(int $length = 20)
{
$prefix = date('ymd'); // 可选的订单号前缀,如需要可以在这里设置
$timestamp = time();
$randomNum = mt_rand(10000, 99999); // 使用 mt_rand() 生成一个四位的随机数
@ -991,6 +1004,4 @@ class BaseHomeService
return $result;
}
}
}

42
app/sms/Sms.php

@ -0,0 +1,42 @@
<?php
namespace app\sms;
use app\sms\contracts\SmsDriverInterface;
class Sms
{
protected $driver;
/**
* Sms constructor.
* @param string|null $channel
* @throws \Exception
*/
public function __construct(?string $channel = null)
{
$channel = $channel ?: config('sms.default');
$drivers = config('sms.channels');
if (!isset($drivers[$channel])) {
throw new \Exception("短信通道 [$channel] 未配置");
}
$class = $drivers[$channel]['driver'];
$config = $drivers[$channel]['config'];
if (!class_exists($class)) {
throw new \Exception("短信驱动类 [$class] 不存在");
}
$this->driver = new $class($config);
if (!($this->driver instanceof SmsDriverInterface)) {
throw new \Exception("[$class] 必须实现 SmsDriverInterface 接口");
}
}
public function send(string $mobile, string $templateId, array $data = []): array
{
return $this->driver->send($mobile, $templateId, $data);
}
}

8
app/sms/contracts/SmsDriverInterface.php

@ -0,0 +1,8 @@
<?php
namespace app\sms\contracts;
interface SmsDriverInterface
{
public function send(string $mobile, string $templateId, array $data = []): array;
}

165
app/sms/drivers/WorldSmsDriver.php

@ -0,0 +1,165 @@
<?php
namespace app\sms\drivers;
use app\sms\contracts\SmsDriverInterface;
use GuzzleHttp\Client;
class WorldSmsDriver implements SmsDriverInterface
{
protected $config;
protected $client;
public function __construct(array $config)
{
$this->config = $config;
$this->client = new Client([
'base_uri' => rtrim($this->config['host'], '/') . '/',
'timeout' => 5.0,
]);
}
/**
* 发送短信
* @param string $mobile 手机号(多个用逗号分隔)
* @param string $templateId 未使用模板可留空
* @param array $data ['content' => '短信内容']
* @return array
*/
public function send(string $mobile, string $templateId = '', array $data = []): array
{
$url = 'sendsms';
$body = [
'account' => $this->config['account'],
'password' => $this->config['password'],
'numbers' => $mobile,
'smstype' => $data['smstype'] ?? 0,
'sender' => $data['title'] ?? '',
'content' => $data['content'] ?? '',
];
try {
$response = $this->client->request('POST', $url, [
'headers' => [
'Content-Type' => 'application/json;charset=utf-8'
],
'body' => json_encode($body, JSON_UNESCAPED_UNICODE),
]);
$result = json_decode($response->getBody()->getContents(), true);
return [
'success' => $result['status'] === 0,
'data' => $result,
'msg' => $result['status'] === 0 ? '发送成功' : '发送失败',
];
} catch (\Throwable $e) {
return [
'success' => false,
'msg' => '请求失败:' . $e->getMessage(),
'data' => [],
];
}
}
/**
* 查询余额
*/
public function getBalance(): array
{
$url = 'getbalance';
$body = [
'version' => '3.4',
'account' => $this->config['account'],
'password' => $this->config['password'],
];
return $this->getJson($url, $body);
}
/**
* 查询短信状态(单条)
*/
public function getStatus(string $msgid): array
{
$url = 'getstatus';
$body = [
'account' => $this->config['account'],
'password' => $this->config['password'],
'msgid' => $msgid,
];
return $this->getJson($url, $body);
}
/**
* 获取接收短信
*/
public function getInbox(): array
{
$url = 'getinbox';
$body = [
'account' => $this->config['account'],
'password' => $this->config['password'],
];
return $this->getJson($url, $body);
}
/**
* 通用 POST 请求
*/
protected function postJson(string $url, array $body): array
{
try {
$response = $this->client->post($url, [
'headers' => [
'Content-Type' => 'application/json;charset=utf-8',
],
'json' => $body,
]);
$result = json_decode($response->getBody()->getContents(), true);
return [
'success' => $result['status'] === 0,
'msg' => $result['status'] === 0 ? '操作成功' : ($result['message'] ?? '失败'),
'data' => $result,
];
} catch (\Throwable $e) {
return [
'success' => false,
'msg' => '请求异常: ' . $e->getMessage(),
'data' => [],
];
}
}
/**
* 通用 GET 请求
*/
protected function getJson(string $url, array $query = []): array
{
try {
$response = $this->client->get($url, [
'headers' => [
'Accept' => 'application/json',
],
'query' => $query,
]);
$result = json_decode($response->getBody()->getContents(), true);
return [
'success' => $result['status'] === 0,
'msg' => $result['status'] === 0 ? '操作成功' : ($result['message'] ?? '失败'),
'data' => $result,
];
} catch (\Throwable $e) {
return [
'success' => false,
'msg' => '请求异常: ' . $e->getMessage(),
'data' => [],
];
}
}
}

51
app/utility/SendSms.php

@ -51,28 +51,39 @@ class SendSms
public function sendMessageToGlobe($toNum, $content, $from, $accessKey, $secret)
{
try {
AlibabaCloud::accessKeyClient($accessKey, $secret)
->regionId('ap-southeast-1') // 服务点对应的公网接入地址: https://www.alibabacloud.com/help/zh/sms/developer-reference/api-dysmsapi-2018-05-01-endpoint?spm=a2c63.p38356.help-menu-44282.d_3_2_1.248f60deo2Ug5G
->asDefaultClient();
$result = AlibabaCloud::rpc()
->product('Dysmsapi')
->version('2018-05-01')
->action('SendMessageToGlobe')
->method('POST')
->host('dysmsapi.ap-southeast-1.aliyuncs.com')
->options([
'query' => [
"To" => $toNum,
"Message" => $content,
"From" => $from, // Sender ID 在阿里云控制台申请
],
])
->request();
$res = $result->toArray();
trace('短信发送结果:'.json_encode([$res]), 'error');
if(!isset($res['ResponseCode']) || $res['ResponseCode'] != 'OK'){
// 新对接的短信平台
$sms = new \app\sms\Sms();
$result = $sms->send($toNum, '', [
'content' => $content,
'title' => $from,
]);
trace('短信发送结果:' . json_encode([$result]), 'error');
if ($result['success'] !== 0) {
trace('短信发送失败:' . json_encode($result), 'error');
return false;
}
// AlibabaCloud::accessKeyClient($accessKey, $secret)
// ->regionId('ap-southeast-1') // 服务点对应的公网接入地址: https://www.alibabacloud.com/help/zh/sms/developer-reference/api-dysmsapi-2018-05-01-endpoint?spm=a2c63.p38356.help-menu-44282.d_3_2_1.248f60deo2Ug5G
// ->asDefaultClient();
// $result = AlibabaCloud::rpc()
// ->product('Dysmsapi')
// ->version('2018-05-01')
// ->action('SendMessageToGlobe')
// ->method('POST')
// ->host('dysmsapi.ap-southeast-1.aliyuncs.com')
// ->options([
// 'query' => [
// "To" => $toNum,
// "Message" => $content,
// "From" => $from, // Sender ID 在阿里云控制台申请
// ],
// ])
// ->request();
// $res = $result->toArray();
// trace('短信发送结果:'.json_encode([$res]), 'error');
// if(!isset($res['ResponseCode']) || $res['ResponseCode'] != 'OK'){
// return false;
// }
return true;
} catch (ClientException $clientException) {
trace('短信发送失败01_' . $clientException->getErrorMessage(), 'error');

16
config/sms.php

@ -0,0 +1,16 @@
<?php
return [
'default' => 'world',
'channels' => [
'world' => [
'driver' => \app\sms\drivers\WorldSmsDriver::class,
'config' => [
'host' => 'http://8.218.111.176:20003/',
'account' => '068109OTP',
'password' => 'y5CjJzUOL',
],
],
// 其他通道...
],
];
Loading…
Cancel
Save