PHP做的DDNS更新脚本

把DnspodClient.class.php文件放到class文件夹下面

<?php

class DnspodClient
{
	private $secretId;
	private $secretKey;
	private $endpoint = "dnspod.tencentcloudapi.com";
	private $service = "dnspod";
	private $version = "2021-03-23";

	/**
	 * Constructor
	 * @param string $secretId
	 * @param string $secretKey
	 */
	public function __construct($secretId, $secretKey)
	{
		$this->secretId = $secretId;
		$this->secretKey = $secretKey;
	}

	/**
	 * DescribeRecordList
	 * @param string $domain
	 * @param string $subdomain
	 * @return array
	 */
	public function describeRecordList($domain, $subdomain)	{
		$action = "DescribeRecordList";

		$payload = [
			"Domain" => $domain,
			"Subdomain" => $subdomain
		];

		return $this->request($action, $payload);
	}


	/**
	* Update DNS Record
	* @param string $domain    Domain name
	* @param int    $recordId  Record ID to update
	* @param string $value     New value for the record
	* @return array
	*/
	public function updateRecord($Domain, $record) {
		$action = "ModifyRecord";
		$payload = [
			"Domain"   => $Domain,
			"RecordType" => $record['Type'],
			"RecordLine" => $record['Line'],
			"Value"    => $record['Value'],
			"RecordId" => $record['RecordId'],
			//"DomainId" => $record[''],
			"SubDomain" => $record['Name'],
			"RecordLineId" => $record['LineId'],
			"MX" => $record['MX'],
			"TTL" => $record['TTL'],
			//"Weight" => $record['Weight'],
			"Status" => $record['Status'],
			"Remark" => $record['Remark'],
			//"DnssecConflictMode" => $record[''],
		];
		if ($record['Weight']) {
			$payload["Weight"] = $record['Weight'];
		}
		return $this->request($action, $payload);
	}

	/**
	* Update a specific record's value by domain and record name
	*
	* @param string $domain  Domain name
	* @param string $subDomain  Subdomain to match
	* @param string $value     New value to update
	* @return array|null       API response or null if no record updated
	*/
	public function updateRecordValue($domain, $subDomain, $value) {
		// Fetch current records for the domain/subdomain
		$result = $this->describeRecordList($domain, $subDomain);

		if (!isset($result['Response']['RecordList']) || empty($result['Response']['RecordList'])) {
			return null; // No records found
		}

		foreach ($result['Response']['RecordList'] as $record) {
			if ($record['Value'] === $value) {
				return ['code' => 'NoNeedChangeValue'];
			}
			// Only update 'A' records with different value
			if ($record['Type'] === 'A' && $record['Value'] !== $value) {
				$record['Value'] = $value;
				// Update the record using existing updateRecord method
				return $this->updateRecord($domain, $record);
			}
		}

		return null; // No record updated
	}


	/**
	 * Send request to Tencent DNSPod API
	 */
	private function request($action, $payload) {
		$timestamp = time();
		$algorithm = "TC3-HMAC-SHA256";

		// ************ Step 1: Build Canonical Request ************
		$httpRequestMethod = "POST";
		$canonicalUri = "/";
		$canonicalQueryString = "";
		$canonicalHeaders = "content-type:application/json\nhost:" . $this->endpoint . "\n";
		$signedHeaders = "content-type;host";

		$payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE);

		$hashedRequestPayload = hash('sha256', $payloadJson);

		$canonicalRequest = $httpRequestMethod . "\n"
			. $canonicalUri . "\n"
			. $canonicalQueryString . "\n"
			. $canonicalHeaders . "\n"
			. $signedHeaders . "\n"
			. $hashedRequestPayload;

		// ************ Step 2: Build String To Sign ************
		$date = gmdate("Y-m-d", $timestamp);
		$credentialScope = $date . "/" . $this->service . "/tc3_request";

		$hashedCanonicalRequest = hash('sha256', $canonicalRequest);
		$stringToSign = $algorithm . "\n"
			. $timestamp . "\n"
			. $credentialScope . "\n"
			. $hashedCanonicalRequest;

		// ************ Step 3: Calculate Signature ************
		$secretDate = hash_hmac('sha256', $date, "TC3" . $this->secretKey, true);
		$secretService = hash_hmac('sha256', $this->service, $secretDate, true);
		$secretSigning = hash_hmac('sha256', "tc3_request", $secretService, true);
		$signature = hash_hmac('sha256', $stringToSign, $secretSigning);

		// ************ Step 4: Build Authorization ************
		$authorization = $algorithm
			. " Credential=" . $this->secretId . "/" . $credentialScope
			. ", SignedHeaders=" . $signedHeaders
			. ", Signature=" . $signature;

		// ************ Step 5: Send HTTP POST ************
		$headers = [
			"Authorization: $authorization",
			"Content-Type: application/json",
			"Host: " . $this->endpoint,
			"X-TC-Action: $action",
			"X-TC-Timestamp: $timestamp",
			"X-TC-Version: " . $this->version,
			"X-TC-Region: ap-guangzhou"
		];

		$ch = curl_init("https://" . $this->endpoint);
		curl_setopt($ch, CURLOPT_POST, true);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $payloadJson);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

		$response = curl_exec($ch);
		$errno = curl_errno($ch);

		if ($errno) {
			throw new Exception("Curl error: " . curl_error($ch));
		}

		curl_close($ch);

		return json_decode($response, true);
	}
}

创建index.php文件

<?php

require __DIR__ . '/class/DnspodClient.class.php';

// Get input safely
$domain = isset($_GET['domain']) ? trim($_GET['domain']) : '';
$subdomain = isset($_GET['subdomain']) ? trim($_GET['subdomain']) : '';
$ip = $_SERVER['REMOTE_ADDR'] ?? '';

// Validate input
if (empty($domain) || empty($subdomain)) {
    header('Content-Type: application/json');
    echo json_encode(['error' => 'Domain and subdomain are required']);
    exit;
}

if (!filter_var($ip, FILTER_VALIDATE_IP)) {
    header('Content-Type: application/json');
    echo json_encode(['error' => 'Invalid IP address']);
    exit;
}

try {
    // Initialize client with SecretId and SecretKey
    $client = new DnspodClient("YourSecretId", "YourSecretKey");

    // Update the A record value
    $result = $client->updateRecordValue($domain, $subdomain, $ip);

    header('Content-Type: application/json');
    echo json_encode($result);

} catch (Exception $e) {
    header('Content-Type: application/json');
    echo json_encode(['error' => $e->getMessage()]);
}
posted on 2025-11-27 21:08  项希盛  阅读(0)  评论(0)    收藏  举报