126 lines
3.9 KiB
PHP
126 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace app\support;
|
|
|
|
use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;
|
|
use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\SendSmsRequest;
|
|
use Darabonba\OpenApi\Models\Config;
|
|
use support\think\Db;
|
|
|
|
class AppSmsService
|
|
{
|
|
public function sendLoginCode(string $mobile, string $code): array
|
|
{
|
|
$this->bootstrapCaBundle();
|
|
$config = $this->config();
|
|
if (!$this->isConfigured($config)) {
|
|
if ($this->isDebugMode()) {
|
|
return [
|
|
'provider' => 'debug',
|
|
'request_id' => 'debug',
|
|
'biz_id' => 'debug',
|
|
'raw_body' => [
|
|
'Code' => 'OK',
|
|
'Message' => 'DEBUG_SMS_BYPASS',
|
|
],
|
|
'debug_code' => $code,
|
|
];
|
|
}
|
|
|
|
throw new \RuntimeException('短信配置未完成,请先在后台系统配置中填写阿里云短信参数');
|
|
}
|
|
|
|
$client = new Dysmsapi(new Config([
|
|
'accessKeyId' => $config['access_key_id'],
|
|
'accessKeySecret' => $config['access_key_secret'],
|
|
'regionId' => $config['region_id'] ?: 'cn-hangzhou',
|
|
'endpoint' => $config['endpoint'] ?: null,
|
|
]));
|
|
|
|
$response = $client->sendSms(new SendSmsRequest([
|
|
'phoneNumbers' => $mobile,
|
|
'signName' => $config['sign_name'],
|
|
'templateCode' => $config['login_template_code'],
|
|
'templateParam' => json_encode(['code' => $code], JSON_UNESCAPED_UNICODE),
|
|
]));
|
|
|
|
$body = $response->body ? $response->body->toMap() : [];
|
|
$responseCode = (string)($body['Code'] ?? '');
|
|
if ($responseCode !== 'OK') {
|
|
throw new \RuntimeException((string)($body['Message'] ?? '短信发送失败'));
|
|
}
|
|
|
|
return [
|
|
'provider' => 'aliyun_sms',
|
|
'request_id' => (string)($body['RequestId'] ?? ''),
|
|
'biz_id' => (string)($body['BizId'] ?? ''),
|
|
'raw_body' => $body,
|
|
'debug_code' => null,
|
|
];
|
|
}
|
|
|
|
private function config(): array
|
|
{
|
|
$rows = Db::name('system_configs')
|
|
->where('config_group', 'sms')
|
|
->select()
|
|
->toArray();
|
|
|
|
$map = [];
|
|
foreach ($rows as $row) {
|
|
$map[$row['config_key']] = trim((string)($row['config_value'] ?? ''));
|
|
}
|
|
|
|
return [
|
|
'access_key_id' => $map['access_key_id'] ?? '',
|
|
'access_key_secret' => $map['access_key_secret'] ?? '',
|
|
'sign_name' => $map['sign_name'] ?? '',
|
|
'login_template_code' => $map['login_template_code'] ?? '',
|
|
'region_id' => $map['region_id'] ?? 'cn-hangzhou',
|
|
'endpoint' => $map['endpoint'] ?? '',
|
|
];
|
|
}
|
|
|
|
private function isConfigured(array $config): bool
|
|
{
|
|
return $config['access_key_id'] !== ''
|
|
&& $config['access_key_secret'] !== ''
|
|
&& $config['sign_name'] !== ''
|
|
&& $config['login_template_code'] !== '';
|
|
}
|
|
|
|
private function isDebugMode(): bool
|
|
{
|
|
return in_array(strtolower((string)($_ENV['APP_DEBUG'] ?? 'false')), ['1', 'true'], true);
|
|
}
|
|
|
|
private function bootstrapCaBundle(): void
|
|
{
|
|
if (ini_get('curl.cainfo') || ini_get('openssl.cafile')) {
|
|
return;
|
|
}
|
|
|
|
foreach ($this->candidateCaFiles() as $path) {
|
|
if (!is_file($path)) {
|
|
continue;
|
|
}
|
|
|
|
ini_set('curl.cainfo', $path);
|
|
ini_set('openssl.cafile', $path);
|
|
putenv('CURL_CA_BUNDLE=' . $path);
|
|
putenv('SSL_CERT_FILE=' . $path);
|
|
return;
|
|
}
|
|
}
|
|
|
|
private function candidateCaFiles(): array
|
|
{
|
|
return [
|
|
'/etc/ssl/cert.pem',
|
|
'/private/etc/ssl/cert.pem',
|
|
'/opt/homebrew/etc/openssl@3/cert.pem',
|
|
'/usr/local/etc/openssl@3/cert.pem',
|
|
];
|
|
}
|
|
}
|