| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162 |
- <?php
- declare(strict_types=1);
- namespace app\miniapi\service;
- use app\miniapi\exception\ApiException;
- use support\Log;
- /**
- * smsbao.com HTTP API. The account password is passed through untouched; when it looks like a
- * 32 character digest the provider treats it as the MD5 password. Responses are plain status
- * numbers and are never echoed to the caller.
- */
- final class SmsbaoSender implements SmsSender
- {
- private const FAILURES = [
- '-1' => '参数不全',
- '-2' => '账户或密码错误',
- '-3' => '账户余额不足',
- '-4' => '账户余额已冻结',
- '30' => '验证码间隔太短',
- '40' => '账户不存在',
- '41' => '内容包含敏感词',
- '42' => '账户余额不足',
- ];
- public function send(string $phone, string $content): void
- {
- $url = (string) config('mini_api.sms_endpoint', '') . '?' . http_build_query([
- 'u' => (string) config('mini_api.sms_user', ''),
- 'p' => (string) config('mini_api.sms_password', ''),
- 'm' => $phone,
- 'c' => $content,
- ]);
- $ch = curl_init($url);
- curl_setopt_array($ch, [
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_CONNECTTIMEOUT => 5,
- CURLOPT_TIMEOUT => 10,
- CURLOPT_SSL_VERIFYPEER => true,
- CURLOPT_SSL_VERIFYHOST => 2,
- CURLOPT_FOLLOWLOCATION => false,
- ]);
- $raw = curl_exec($ch);
- $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- $error = curl_error($ch);
- curl_close($ch);
- if ($raw === false || $status !== 200) {
- Log::warning('mini_api.sms_transport', ['http' => $status, 'transport_error' => $error]);
- throw new ApiException(50302, '短信服务暂时不可用,请稍后再试', 503);
- }
- $code = trim((string) $raw);
- if ($code === '0') {
- return;
- }
- // Provider status only. The request URL carries the password, so it is never logged.
- Log::warning('mini_api.sms_rejected', ['status' => $code, 'reason' => self::FAILURES[$code] ?? 'unknown']);
- throw new ApiException(50302, '短信发送失败,请稍后再试', 503);
- }
- }
|