DNSPod.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. <?php
  2. namespace App\Utils\DDNS;
  3. use App\Utils\Library\Templates\DNS;
  4. use Arr;
  5. use Http;
  6. use Log;
  7. class DNSPod implements DNS
  8. {
  9. // 开发依据: https://docs.dnspod.cn/api/
  10. private const API_HOST = 'https://dnsapi.cn/';
  11. private string $loginToken;
  12. private array $domainData;
  13. public function __construct(private readonly string $subDomain)
  14. {
  15. $this->loginToken = sysConfig('ddns_key').','.sysConfig('ddns_secret');
  16. $data = $this->analysisDomain();
  17. if ($data) {
  18. $this->domainData = $data;
  19. } else {
  20. abort(400, '域名存在异常');
  21. }
  22. }
  23. private function analysisDomain(): array
  24. {
  25. $domains = data_get($this->send('Domain.List', ['type' => 'mine']), 'domains.*.name');
  26. if ($domains) {
  27. foreach ($domains as $domain) {
  28. if (str_contains($this->subDomain, $domain)) {
  29. return ['rr' => rtrim(substr($this->subDomain, 0, -strlen($domain)), '.'), 'host' => $domain];
  30. }
  31. }
  32. Log::error('[DNS] DNSPod - 错误域名 '.$this->subDomain.' 不在账号拥有域名里');
  33. }
  34. exit(400);
  35. }
  36. private function send(string $action, array $parameters = []): array
  37. {
  38. $response = Http::timeout(15)->asForm()->post(self::API_HOST.$action, array_merge(['login_token' => $this->loginToken, 'format' => 'json'], $parameters));
  39. if ($response->ok()) {
  40. $data = $response->json();
  41. if (Arr::get($data, 'status.code') === 1) {
  42. return Arr::except($data, ['status']);
  43. }
  44. Log::error('[DNSPod - '.$action.'] 返回错误信息:'.Arr::get($data, 'status.message'));
  45. } else {
  46. Log::error('[DNSPod - '.$action.'] 请求失败');
  47. }
  48. exit(400);
  49. }
  50. public function store(string $ip, string $type): bool
  51. {
  52. $ret = $this->send('Record.Create', [
  53. 'domain' => $this->domainData['host'],
  54. 'sub_domain' => $this->domainData['rr'],
  55. 'record_type' => $type,
  56. 'record_line_id' => 0,
  57. 'value' => $ip,
  58. ]);
  59. return (bool) $ret;
  60. }
  61. public function update(string $latest_ip, string $original_ip, string $type): bool
  62. {
  63. $record = Arr::first($this->getRecordId($type, $original_ip));
  64. if ($record) {
  65. $ret = $this->send('Record.Modify', [
  66. 'domain' => $this->domainData['host'],
  67. 'record_id' => $record,
  68. 'sub_domain' => $this->domainData['rr'],
  69. 'record_type' => $type,
  70. 'record_line_id' => 0,
  71. 'value' => $latest_ip,
  72. ]);
  73. }
  74. return (bool) ($ret ?? false);
  75. }
  76. private function getRecordId(string $type, string $ip): array|false
  77. {
  78. $parameters = ['domain' => $this->domainData['host'], 'sub_domain' => $this->domainData['rr']];
  79. if ($type) {
  80. $parameters['record_type'] = $type;
  81. }
  82. $records = $this->send('Record.List', $parameters);
  83. if ($records) {
  84. $filtered = Arr::get($records, 'records');
  85. if ($ip) {
  86. $filtered = Arr::where($filtered, static function (array $value) use ($ip) {
  87. return $value['value'] === $ip;
  88. });
  89. }
  90. return data_get($filtered, '*.id');
  91. }
  92. return false;
  93. }
  94. public function destroy(string $type, string $ip): int
  95. {
  96. $records = $this->getRecordId($type, $ip);
  97. $count = 0;
  98. if ($records) {
  99. foreach ($records as $record) {
  100. $result = $this->send('Record.Remove', ['domain' => $this->domainData['host'], 'record_id' => $record]);
  101. if ($result === []) {
  102. $count++;
  103. }
  104. }
  105. }
  106. return $count;
  107. }
  108. }