Files
wordpress-theme-aksrt/inc/classes/moderation-traits/trait-aksrt-moderation-part-2.php
T

164 lines
5.8 KiB
PHP

<?php
defined('ABSPATH') || exit;
trait AKSRT_Moderation_Part_2 {
private function normalize_text(string $text): string {
$text = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', '', $text);
$text = preg_replace('/\s+/u', '', (string) $text);
if (function_exists('mb_strtolower')) {
return mb_strtolower((string) $text, 'UTF-8');
}
return strtolower((string) $text);
}
// ============================================================
// 4. Rate limit
// ============================================================
private function check_rate_limit(array $data, array $config, string $ip) {
if (empty($config['rate_limit_enabled'])) {
return true;
}
$min_interval = max(1, (int) ($config['rate_limit_min_interval'] ?? 8));
$max_per_hour = max(1, (int) ($config['rate_limit_max_per_hour'] ?? 15));
$prefix = 'aksrt_rate_';
$last_key = $prefix . md5($ip . '_last');
$hour_key = $prefix . md5($ip . '_hourly');
$exp_key = '_' . $prefix . md5($ip . '_hourly_expiry');
$last_comment_time = get_transient($last_key);
if ($last_comment_time !== false) {
$elapsed = time() - (int) $last_comment_time;
if ($elapsed < $min_interval) {
$wait_time = $min_interval - $elapsed;
return sprintf(__('You are commenting too fast. Please wait %d seconds.', 'aksrt'), $wait_time);
}
}
$hourly_count = get_transient($hour_key);
if ($hourly_count !== false && (int) $hourly_count >= $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';
}
}