= $max_per_hour) { $reset_time = (int) (get_transient($exp_key) ?: time()); $remaining = max(0, $reset_time - time()); $minutes = (int) ceil($remaining / 60); return sprintf(__('You have reached the hourly comment limit. Try again in %d minutes.', 'aksrt'), $minutes); } if ($hourly_count === false) { set_transient($hour_key, 1, HOUR_IN_SECONDS); set_transient($exp_key, time() + HOUR_IN_SECONDS, HOUR_IN_SECONDS); } else { set_transient($hour_key, ((int) $hourly_count) + 1, HOUR_IN_SECONDS); } set_transient($last_key, time(), $min_interval); return true; } // ============================================================ // 5. GeoIP // ============================================================ private function check_geoip(array $config, string $ip) { if (empty($config['geoip_enabled'])) { return true; } $block_countries = $config['geoip_block_countries'] ?? []; if (!is_array($block_countries) || empty($block_countries)) { return true; } $country_code = $this->lookup_geoip($ip, $config); if ($country_code === null) { return true; } $country_code = strtoupper($country_code); $block_upper = array_map('strtoupper', $block_countries); if (in_array($country_code, $block_upper, true)) { return sprintf(__('Comments from your region (%s) are currently blocked.', 'aksrt'), esc_html($country_code)); } return true; } private function lookup_geoip(string $ip, array $config): ?string { // 优先复用 IP 归属地模块的查询能力(含缓存) if (class_exists('AKSRT_IP_Geo')) { $result = AKSRT_IP_Geo::get_instance()->lookup($ip); if (!empty($result['country'])) { return $result['country']; } } // 回退到内置查询 $ip_geo_config = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_ip_geo_settings() : []; $provider = (string) ($ip_geo_config['ip_geo_provider'] ?? $config['geoip_provider'] ?? 'ip-api.com'); $api_key = (string) ($ip_geo_config['ip_geo_api_key'] ?? $config['geoip_api_key'] ?? ''); if ($provider === 'ipinfo' || $provider === 'ipinfo.io') { return $this->geoip_ipinfo($ip, $api_key); } return $this->geoip_ipapi($ip); } /** * Free ip-api.com endpoint. */ private function geoip_ipapi(string $ip): ?string { $url = 'http://ip-api.com/json/' . urlencode($ip) . '?fields=status,countryCode,message'; $response = wp_remote_get($url, [ 'timeout' => 5, 'headers' => ['Accept' => 'application/json'], ]); if (is_wp_error($response)) { return null; } $body = json_decode((string) wp_remote_retrieve_body($response), true); if (($body['status'] ?? '') === 'success') { return $body['countryCode'] ?? null; } return null; } private function geoip_ipinfo(string $ip, string $api_key): ?string { $url = 'https://ipinfo.io/' . urlencode($ip) . '/json?token=' . urlencode($api_key ?: ''); $response = wp_remote_get($url, [ 'timeout' => 5, 'headers' => ['Accept' => 'application/json'], ]); if (is_wp_error($response)) { return null; } $body = json_decode((string) wp_remote_retrieve_body($response), true); return $body['country'] ?? null; } // ============================================================ // Utilities // ============================================================ private function get_client_ip(): string { $keys = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP']; foreach ($keys as $key) { if (!empty($_SERVER[$key])) { $parts = explode(',', (string) $_SERVER[$key]); $ip = trim($parts[0]); if (filter_var($ip, FILTER_VALIDATE_IP)) { return $ip; } } } return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; } }