You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
4.0 KiB
123 lines
4.0 KiB
<?php
|
|
|
|
namespace App\Services\Sms;
|
|
|
|
use App\Models\SmsVerification;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class SubmailSmsClient
|
|
{
|
|
/**
|
|
* @param array<string, string> $vars
|
|
*/
|
|
public function sendTemplate(string $to, string $project, array $vars): SmsSendResult
|
|
{
|
|
$appId = trim((string) config('sms.submail.app_id'));
|
|
$appKey = trim((string) config('sms.submail.app_key'));
|
|
$endpoint = rtrim((string) config('sms.submail.endpoint'), '?&');
|
|
$timeout = (int) config('sms.timeout', 5);
|
|
$signName = $this->normalizeSignName((string) config('sms.submail.sign_name'));
|
|
|
|
$payload = [
|
|
'appid' => $appId,
|
|
'to' => $to,
|
|
'project' => $project,
|
|
'signature' => $appKey,
|
|
'vars' => json_encode($vars, JSON_UNESCAPED_UNICODE),
|
|
];
|
|
if ($signName !== '') {
|
|
$payload['sms_signature'] = $signName;
|
|
}
|
|
|
|
try {
|
|
$response = Http::timeout($timeout)
|
|
->acceptJson()
|
|
->asForm()
|
|
->post($endpoint, $payload);
|
|
} catch (\Throwable $e) {
|
|
Log::error('sms.submail network_error', [
|
|
'project' => $project,
|
|
'mobile_mask' => $this->maskMobile($to),
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return SmsSendResult::failure(
|
|
SmsVerification::PROVIDER_SUBMAIL,
|
|
null,
|
|
'NETWORK_ERROR',
|
|
'Submail SMS request failed: '.$e->getMessage(),
|
|
['error' => 'network_error', 'exception' => $e::class]
|
|
);
|
|
}
|
|
|
|
$json = $response->json();
|
|
$summary = $this->responseSummary(is_array($json) ? $json : [], $response->status());
|
|
$status = is_array($json) && isset($json['status']) ? (string) $json['status'] : '';
|
|
$sendId = is_array($json) && isset($json['send_id']) && is_scalar($json['send_id'])
|
|
? (string) $json['send_id']
|
|
: null;
|
|
$code = is_array($json) && isset($json['code']) && is_scalar($json['code'])
|
|
? (string) $json['code']
|
|
: (string) $response->status();
|
|
$message = is_array($json) && isset($json['msg']) && is_scalar($json['msg'])
|
|
? (string) $json['msg']
|
|
: '';
|
|
|
|
if ($response->successful() && $status === 'success') {
|
|
return SmsSendResult::success(
|
|
SmsVerification::PROVIDER_SUBMAIL,
|
|
$sendId,
|
|
$code !== '' ? $code : 'success',
|
|
$message !== '' ? $message : 'OK',
|
|
$summary
|
|
);
|
|
}
|
|
|
|
if (! $response->successful() && $code === (string) $response->status()) {
|
|
$code = 'HTTP_'.$response->status();
|
|
}
|
|
|
|
return SmsSendResult::failure(
|
|
SmsVerification::PROVIDER_SUBMAIL,
|
|
$sendId,
|
|
$code !== '' ? $code : 'SEND_FAILED',
|
|
$message !== '' ? $message : 'Submail SMS send failed.',
|
|
$summary
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $response
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function responseSummary(array $response, int $httpStatus): array
|
|
{
|
|
return [
|
|
'http_status' => $httpStatus,
|
|
'status' => $response['status'] ?? null,
|
|
'send_id' => $response['send_id'] ?? null,
|
|
'fee' => $response['fee'] ?? null,
|
|
'code' => $response['code'] ?? null,
|
|
'msg' => $response['msg'] ?? null,
|
|
];
|
|
}
|
|
|
|
private function maskMobile(string $mobile): string
|
|
{
|
|
if (strlen($mobile) < 11) {
|
|
return '***';
|
|
}
|
|
|
|
return substr($mobile, 0, 3).'****'.substr($mobile, -4);
|
|
}
|
|
|
|
private function normalizeSignName(string $signName): string
|
|
{
|
|
$signName = trim($signName);
|
|
$stripped = preg_replace('/^[\[【]+|[\]】]+$/u', '', $signName);
|
|
|
|
return is_string($stripped) ? trim($stripped) : $signName;
|
|
}
|
|
}
|