false, 'message' => __('自定义接口 URL 未配置', 'aksrt'), 'transport' => 'custom_http']; } // 替换模板变量 $replacements = [ '{phone}' => $phone, '{code}' => $code, '{time}' => (string) time(), ]; $body = str_replace(array_keys($replacements), array_values($replacements), $body_tpl); // 解析自定义 headers $headers = ['Accept' => 'application/json']; if ($headers_raw !== '') { foreach (explode("\n", $headers_raw) as $line) { $line = trim($line); if ($line === '') continue; $parts = explode(':', $line, 2); if (count($parts) === 2) { $headers[trim($parts[0])] = trim(str_replace(array_keys($replacements), array_values($replacements), $parts[1])); } } } // 鉴权 if ($auth_key !== '' && $auth_value !== '') { $replaced_value = str_replace(array_keys($replacements), array_values($replacements), $auth_value); if ($auth_type === 'header') { $headers[$auth_key] = $replaced_value; } } $args = [ 'timeout' => 10, 'headers' => $headers, ]; if (in_array($method, ['POST', 'PUT', 'PATCH'], true)) { $args['body'] = $body; $result = wp_remote_request($url, array_merge($args, ['method' => $method])); } else { // GET — append body as query params $url_with_params = add_query_arg(json_decode($body, true) ?: [], $url); $result = wp_remote_get($url_with_params, $args); } if (is_wp_error($result)) { $this->log('error', $phone, $result->get_error_message()); return ['success' => false, 'message' => $result->get_error_message(), 'transport' => 'custom_http']; } $status_code = wp_remote_retrieve_response_code($result); $response_body = wp_remote_retrieve_body($result); // 判定成功规则 if ($success_rule !== '') { $matched = $this->check_success_rule($success_rule, $status_code, $response_body); if ($matched) { $this->log('sent', $phone, "status={$status_code}"); return ['success' => true, 'message' => __('验证码已发送', 'aksrt'), 'transport' => 'custom_http']; } $this->log('error', $phone, "status={$status_code}, rule not matched"); return ['success' => false, 'message' => sprintf(__('自定义接口返回异常 (HTTP %d)', 'aksrt'), $status_code), 'transport' => 'custom_http']; } // 默认:HTTP 2xx 视为成功 if ($status_code >= 200 && $status_code < 300) { $this->log('sent', $phone, "status={$status_code}"); return ['success' => true, 'message' => __('验证码已发送', 'aksrt'), 'transport' => 'custom_http']; } $this->log('error', $phone, "status={$status_code}"); return ['success' => false, 'message' => sprintf(__('自定义接口返回 HTTP %d', 'aksrt'), $status_code), 'transport' => 'custom_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_custom_verified']), 'transport' => 'custom_http', 'missing_fields' => $missing, ]; } /** * 校验成功规则 * * 支持格式: * - "status:200" — HTTP 状态码匹配 * - "json:code=0" — JSON 响应中字段匹配 * - "contains:success" — 响应体包含字符串 */ private function check_success_rule(string $rule, int $status_code, string $body): bool { $parts = explode(':', $rule, 2); if (count($parts) < 2) return false; $type = trim($parts[0]); $value = trim($parts[1]); switch ($type) { case 'status': return (string) $status_code === $value; case 'json': $json = json_decode($body, true); if (!is_array($json)) return false; $kv = explode('=', $value, 2); if (count($kv) !== 2) return false; $key = trim($kv[0]); $expected = trim($kv[1]); return (string) ($json[$key] ?? '') === $expected; case 'contains': return strpos($body, $value) !== false; default: return false; } } 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] [custom] [%s] Phone: %s — %s', $level, $masked, $message)); } }