request($secret_id, $secret_key, $app_id, $sign_name, $template_id, $region, $phone, $code); if (is_wp_error($result)) { $this->log('error', $phone, $result->get_error_message()); return ['success' => false, 'message' => $result->get_error_message(), 'transport' => 'tc3_http']; } $body = json_decode(wp_remote_retrieve_body($result), true); $response = $body['Response'] ?? []; if (isset($response['SendStatusSet'][0]['Code']) && $response['SendStatusSet'][0]['Code'] === 'Ok') { $this->log('sent', $phone, 'Ok'); return ['success' => true, 'message' => __('验证码已发送', 'aksrt'), 'transport' => 'tc3_http']; } $err_code = $response['Error']['Code'] ?? ($response['SendStatusSet'][0]['Code'] ?? 'Unknown'); $err_msg = $response['Error']['Message'] ?? ($response['SendStatusSet'][0]['Message'] ?? __('未知错误', 'aksrt')); $this->log('error', $phone, "{$err_code}: {$err_msg}"); return ['success' => false, 'message' => sprintf('腾讯云: %s', $err_msg), 'transport' => 'tc3_http']; } public function get_status(array $config): array { $missing = $this->validate_config($config); return [ 'provider' => $this->get_key(), 'configured' => empty($missing), 'available' => !empty($config['sms_enabled']) && empty($missing), 'verified' => !empty($config['sms_tencent_verified']), 'transport' => 'tc3_http', 'missing_fields' => $missing, ]; } /** * TC3-HMAC-SHA256 签名请求 */ private function request(string $secret_id, string $secret_key, string $app_id, string $sign_name, string $template_id, string $region, string $phone, string $code) { $service = 'sms'; $host = "{$service}.tencentcloudapi.com"; $action = 'SendSms'; $version = '2021-01-11'; $endpoint = "https://{$host}"; $payload = wp_json_encode([ 'PhoneNumberSet' => [$phone], 'SmsSdkAppId' => $app_id, 'SignName' => $sign_name, 'TemplateId' => $template_id, 'TemplateParamSet' => [$code], ]); $timestamp = time(); $date = gmdate('Y-m-d', $timestamp); // Step 1: CanonicalRequest $http_request_method = 'POST'; $canonical_uri = '/'; $canonical_querystring = ''; $content_type = 'application/json; charset=utf-8'; $canonical_headers = "content-type:{$content_type}\nhost:{$host}\nx-tc-action:" . strtolower($action) . "\n"; $signed_headers = 'content-type;host;x-tc-action'; $hashed_payload = hash('sha256', $payload); $canonical_request = "{$http_request_method}\n{$canonical_uri}\n{$canonical_querystring}\n{$canonical_headers}\n{$signed_headers}\n{$hashed_payload}"; // Step 2: StringToSign $algorithm = 'TC3-HMAC-SHA256'; $credential_scope = "{$date}/{$service}/tc3_request"; $hashed_request = hash('sha256', $canonical_request); $string_to_sign = "{$algorithm}\n{$timestamp}\n{$credential_scope}\n{$hashed_request}"; // Step 3: Signature $secret_date = hash_hmac('sha256', $date, "TC3{$secret_key}", true); $secret_service = hash_hmac('sha256', $service, $secret_date, true); $secret_signing = hash_hmac('sha256', 'tc3_request', $secret_service, true); $signature = hash_hmac('sha256', $string_to_sign, $secret_signing); // Step 4: Authorization header $authorization = "{$algorithm} Credential={$secret_id}/{$credential_scope}, SignedHeaders={$signed_headers}, Signature={$signature}"; return wp_remote_post($endpoint, [ 'timeout' => 10, 'headers' => [ 'Authorization' => $authorization, 'Content-Type' => $content_type, 'Host' => $host, 'X-TC-Action' => $action, 'X-TC-Version' => $version, 'X-TC-Timestamp' => (string) $timestamp, 'X-TC-Region' => $region, ], 'body' => $payload, ]); } private function log(string $level, string $phone, string $message): void { if (!defined('WP_DEBUG') || !WP_DEBUG) return; $masked = substr($phone, 0, 3) . '****' . substr($phone, -4); error_log(sprintf('[AKSRT SMS] [tencent] [%s] Phone: %s — %s', $level, $masked, $message)); } }