Files

117 lines
3.2 KiB
PHP
Raw Permalink Normal View History

<?php
require_once __DIR__ . '/CountryCodeNormalizer.php';
class GeoIpCountryResolver
{
/** @var GeoIp2\Database\Reader|null */
private static $reader = null;
/** @var array<string, string|null> */
private static $requestCache = [];
/** @var string|null */
private static $lastSource = null;
/**
* @param string $ip
* @return array{code:?string, source:string}
*/
public static function resolveWithMeta($ip)
{
$ip = ClientIpResolver::normalizeIp($ip);
if ($ip === null) {
self::$lastSource = 'invalid_ip';
return ['code' => null, 'source' => 'invalid_ip'];
}
if (array_key_exists($ip, self::$requestCache)) {
self::$lastSource = 'request';
return ['code' => self::$requestCache[$ip], 'source' => 'request'];
}
$cached = GeoIpCountryCache::get($ip);
if ($cached !== false) {
self::$requestCache[$ip] = $cached;
self::$lastSource = 'cache';
return ['code' => $cached, 'source' => 'cache'];
}
$code = self::lookupMmdb($ip);
GeoIpCountryCache::set($ip, $code);
self::$requestCache[$ip] = $code;
self::$lastSource = 'mmdb';
return ['code' => $code, 'source' => 'mmdb'];
}
/**
* @param string $ip
* @return string|null ISO 3166-1 alpha-2
*/
public static function resolve($ip)
{
$result = self::resolveWithMeta($ip);
return $result['code'];
}
public static function lastSource()
{
return self::$lastSource ?? '';
}
public static function isAvailable()
{
return self::getReader() !== null;
}
/**
* @param string $ip
* @return string|null
*/
private static function lookupMmdb($ip)
{
$reader = self::getReader();
if ($reader === null) {
return null;
}
try {
$record = $reader->country($ip);
$isoCode = $record->country->isoCode ?? null;
$name = $record->country->name ?? null;
$code = CountryCodeNormalizer::toAlpha2($isoCode);
if ($code === null && $name !== null && $name !== '') {
$code = CountryCodeNormalizer::toAlpha2($name);
}
return $code;
} catch (GeoIp2\Exception\AddressNotFoundException $e) {
return null;
} catch (Throwable $e) {
GeoIpCountryCache::logError('mmdb lookup failed: ' . $e->getMessage());
return null;
}
}
/**
* @return GeoIp2\Database\Reader|null
*/
private static function getReader()
{
if (self::$reader !== null) {
return self::$reader;
}
if (!class_exists('GeoIp2\\Database\\Reader')) {
return null;
}
if (!defined('CLOAK_GEOIP_DB_PATH') || !is_file(CLOAK_GEOIP_DB_PATH)) {
return null;
}
try {
self::$reader = new GeoIp2\Database\Reader(CLOAK_GEOIP_DB_PATH);
return self::$reader;
} catch (Throwable $e) {
GeoIpCountryCache::logError('Reader init failed: ' . $e->getMessage());
return null;
}
}
}