fix(ip-geo): harden full-chain IP geolocation reliability

Capture real client IPs behind CDN, improve provider fallbacks and
negative cache, fix admin credential dependsOn for polling mode, and
map country labels to ISO codes for moderation GeoIP blocks.
This commit is contained in:
kate522 committed 2026-07-27 15:39:16 +08:00
1 parent c206928746
commit 59f5d5d98a
12 files changed
+256 -54

No files matched your search

+76 -16
View File
@@ -92,25 +92,76 @@ trait ModerationPart2 {
}
private function lookup_geoip(string $ip, array $config): ?string {
// 优先复用 IP 归属地模块的查询能力(含缓存)
if (class_exists('\AKSRT\Extensions\IPGeo')) {
$result = \AKSRT\Extensions\IPGeo::get_instance()->lookup($ip);
if (!empty($result['country'])) {
return $result['country'];
// Dedicated ISO country-code path for block lists (CN/US/…).
// IPGeo returns localized names ("中国") which are not ISO codes.
$provider = sanitize_key((string) ($config['geoip_provider'] ?? 'ipapi'));
$api_key = (string) ($config['geoip_api_key'] ?? '');
if ($provider === 'ipinfo' || $provider === 'ipinfo.io') {
$code = $this->geoip_ipinfo($ip, $api_key);
if ($code !== null) {
return $code;
}
}
// 回退到内置查询
$ip_geo_config = class_exists('\AKSRT\Settings\Settings')
? \AKSRT\Settings\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);
$code = $this->geoip_ipapi($ip);
if ($code !== null) {
return $code;
}
return $this->geoip_ipapi($ip);
// Last resort: map IPGeo country label → ISO when possible.
if (class_exists('\AKSRT\Extensions\IPGeo')) {
$result = \AKSRT\Extensions\IPGeo::get_instance()->lookup($ip);
$label = trim((string) ($result['country'] ?? ''));
if ($label !== '') {
return $this->country_label_to_iso($label);
}
}
return null;
}
/**
* Map common country labels / ISO aliases to ISO-3166 alpha-2.
*/
private function country_label_to_iso(string $label): ?string {
$raw = trim($label);
if ($raw === '') {
return null;
}
if (preg_match('/^[A-Za-z]{2}$/', $raw)) {
return strtoupper($raw);
}
$map = [
'中国' => 'CN', '中华人民共和国' => 'CN', 'china' => 'CN', 'cn' => 'CN',
'美国' => 'US', '美利坚合众国' => 'US', 'united states' => 'US', 'usa' => 'US', 'us' => 'US',
'日本' => 'JP', 'japan' => 'JP', 'jp' => 'JP',
'韩国' => 'KR', '大韩民国' => 'KR', 'south korea' => 'KR', 'korea' => 'KR', 'kr' => 'KR',
'香港' => 'HK', '中国香港' => 'HK', 'hong kong' => 'HK', 'hk' => 'HK',
'澳门' => 'MO', '中国澳门' => 'MO', 'macao' => 'MO', 'macau' => 'MO', 'mo' => 'MO',
'台湾' => 'TW', '中国台湾' => 'TW', 'taiwan' => 'TW', 'tw' => 'TW',
'新加坡' => 'SG', 'singapore' => 'SG', 'sg' => 'SG',
'英国' => 'GB', 'united kingdom' => 'GB', 'uk' => 'GB', 'gb' => 'GB',
'德国' => 'DE', 'germany' => 'DE', 'de' => 'DE',
'法国' => 'FR', 'france' => 'FR', 'fr' => 'FR',
'俄罗斯' => 'RU', 'russia' => 'RU', 'ru' => 'RU',
'澳大利亚' => 'AU', 'australia' => 'AU', 'au' => 'AU',
'加拿大' => 'CA', 'canada' => 'CA', 'ca' => 'CA',
'印度' => 'IN', 'india' => 'IN', 'in' => 'IN',
'越南' => 'VN', 'vietnam' => 'VN', 'vn' => 'VN',
'泰国' => 'TH', 'thailand' => 'TH', 'th' => 'TH',
'马来西亚' => 'MY', 'malaysia' => 'MY', 'my' => 'MY',
'菲律宾' => 'PH', 'philippines' => 'PH', 'ph' => 'PH',
'印度尼西亚' => 'ID', 'indonesia' => 'ID', 'id' => 'ID',
];
$key = function_exists('mb_strtolower') ? mb_strtolower($raw, 'UTF-8') : strtolower($raw);
if (isset($map[$raw])) {
return $map[$raw];
}
if (isset($map[$key])) {
return $map[$key];
}
return null;
}
/**
@@ -154,7 +205,16 @@ trait ModerationPart2 {
// ============================================================
private function get_client_ip(): string {
$keys = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP'];
if (function_exists('aksrt_get_client_ip')) {
return (string) aksrt_get_client_ip();
}
$keys = [
'HTTP_CF_CONNECTING_IP',
'HTTP_TRUE_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_REAL_IP',
'HTTP_CLIENT_IP',
];
foreach ($keys as $key) {
if (!empty($_SERVER[$key])) {
$parts = explode(',', (string) $_SERVER[$key]);