SmsbaoSender.php 2.2 KB

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