$status, 'data' => $data, 'error' => $error ], JSON_PRETTY_PRINT); exit; } if (!isset($_GET['ip']) || trim($_GET['ip']) === '') { respond(false, null, 'IP parameter is required'); } $ip = trim($_GET['ip']); if (!filter_var($ip, FILTER_VALIDATE_IP)) { respond(false, null, 'Invalid IP address'); } try { $cityReader = new Reader(__DIR__ . '/../.hta_lib/data/GeoLite2-City.mmdb'); $asnReader = new Reader(__DIR__ . '/../.hta_lib/data/GeoLite2-ASN.mmdb'); $cityData = $cityReader->get($ip); $asnData = $asnReader->get($ip); $cityReader->close(); $asnReader->close(); $response = [ 'ip' => $ip, 'continent' => [ 'name' => $cityData['continent']['names']['en'] ?? null, 'code' => $cityData['continent']['code'] ?? null ], 'country' => [ 'name' => $cityData['country']['names']['en'] ?? null, 'code' => $cityData['country']['iso_code'] ?? null ], 'state' => [ 'name' => $cityData['subdivisions'][0]['names']['en'] ?? null, 'code' => $cityData['subdivisions'][0]['iso_code'] ?? null ], 'city' => $cityData['city']['names']['en'] ?? null, 'timezone' => $cityData['location']['time_zone'] ?? null, 'location' => [ 'latitude' => $cityData['location']['latitude'] ?? null, 'longitude' => $cityData['location']['longitude'] ?? null ], 'postal_code' => $cityData['postal']['code'] ?? null, 'asn' => [ 'number' => $asnData['autonomous_system_number'] ?? null, 'org' => $asnData['autonomous_system_organization'] ?? null ], ]; $anycastASN = [15169, 13335, 36692]; $response['is_anycast'] = in_array($response['asn']['number'], $anycastASN); $response['note'] = $response['is_anycast'] ? 'Anycast IP detected. Location may vary.' : 'IP-based location is approximate.'; respond(true, $response); } catch (Exception $e) { respond(false, null, $e->getMessage()); }