App-geoip
view release on metacpan or search on metacpan
$sth->execute;
while (my $i = $sth->fetchrow_hashref) {
$i->{provider} = $prov;
$i->{ip} = $ip;
$i->{ip_n} = $in;
$i->{hostname} = $host // "(hostname not found)";
foreach my $tp ("reg", "rep") {
if (my $cid = delete $i->{"${tp}_country_id"}) {
$stc->execute ($cid);
my $c = $stc->fetchrow_hashref or next;
$i->{"${tp}_ctry_$_"} = $c->{$_} for keys %$c;
delete $i->{"${tp}_ctry_id"};
}
else {
$i->{"${tp}_ctry_$_"} = "" for qw( iso name continent );
}
$i->{"${tp}_continent"} = $cont{delete $i->{"${tp}_ctry_continent"}} || "";
}
$st4->execute;
if (my $c = $st4->fetchrow_hashref) {
$stc->execute (delete $c->{reg_country_id});
if (my $ctry = $stc->fetchrow_hashref) {
$c->{country} = $ctry->{name};
}
$i->{$_} = $c->{$_} for qw( postal_code latitude longitude accuracy );
$stC->execute (delete $c->{id});
if (my $city = $stC->fetchrow_hashref) {
$i->{"city_$_"} = $city->{$_} for qw( name tz metro_code );
}
$stC->finish;
}
$st4->finish;
$found{$ip} //= $i;
}
$stc->finish;
}
my $here;
if (($conf{local_location} // "") =~ m{^(-?\d+\.\d+)\s*[,/]\s*(-?\d+\.\d+)\s*$}) {
$here = { Latitude => $1, Longitude => $2 };
}
elsif ($conf{distance} and eval { require LWP::UserAgent; require HTML::TreeBuilder; }) {
my $ua = LWP::UserAgent->new (
max_redirect => 2,
agent => "geoip/$VERSION",
parse_head => 0,
timeout => 10,
cookie_jar => {},
);
$ua->env_proxy;
warn "Using GeoIP to determine own location\n";
$here = {};
my %cls = (
lat => "Latitude",
lng => "Longitude",
ip => "IP",
city => "City",
company => "Provider",
);
foreach my $url (qw( https://iplocation.com https://geoiptool.com )) {
my $rsp = $ua->request (HTTP::Request->new (GET => $url));
if ($rsp->is_success) {
$opt_v > 1 and warn "$url: OK\n";
my $tree = HTML::TreeBuilder->new ();
if ($tree->parse_content ($rsp->content)) {
foreach my $e ($tree->look_down (_tag => "div", class => "data-item")) {
my $di = $e->as_text or next;
$di =~ m/^\s*(\S[^:]+?)\s*:\s*(.*?)\s*$/ and $here->{$1} //= $2;
}
foreach my $e ($tree->look_down (_tag => "td",
class => qr{^(?:lat|lng|ip|city|company)$})) {
my $di = $e->as_text =~ s/^\s+//r =~ s/\s+$//r or next;
my $cl = $cls{$e->attr ("class")} or next;
$here->{$cl} //= $di;
}
}
}
elsif ($opt_v) {
printf STDERR "%-25s : %s\n", $url, $rsp->status_line;
}
defined $here->{Longitude} and last;
}
unless (exists $here->{Longitude}) {
# If I did not get info, use the database:
# 1: dig -4 a +short myip.opendns.com @resolver1.opendns.com
# 2: https://tools.tracemyip.org - only returns IP, no coordinates
# <div class="tsTxt14 txtBld"><span class="txtBld tsTxt14 sModPrW"><a href="/lookup/1.2.3.4">1.2.3.4</a></span></div>
}
defined $here->{Longitude} or $here = undef;
$opt_v > 4 and _dump ("Here", $here);
}
my @json;
for (sort { $a->{ip_from_n} <=> $b->{ip_to_n} ||
$a->{ip_n} <=> $b->{ip_n}
} values %found) {
$opt_v > 6 and _dump ("Processing", $_);
my ($lat, $lon, $acc) = ($_->{latitude}, $_->{longitude}, $_->{accuracy});
$_->{city} = join ", " => grep m/\S/ => map { $_ || "" }
$_->{city_name}, $_->{city_metro_code}, $_->{postal_code};
$_->{city_tz} ||= "";
my %json = %$_;
unless ($conf{json}) {
say "GeoIP data for $_->{ip} - $_->{hostname}:";
say " CIDR : $_->{cidr}";
say " IP range : $_->{ip_from} - $_->{ip_to}";
say " Provider : $_->{provider}";
say " City : $_->{city}";
say " Country : $_->{reg_ctry_iso} $_->{reg_ctry_name}";
say " Continent : $_->{reg_continent}";
say " Timezone : $_->{city_tz}";
}
if (!$conf{short} && ($lat || $lon)) {
my ($lat_dms, $lon_dms) = map { dec2dms ($_) } $lat, $lon;
@json{qw( latitude_dms longitude_dms )} = ($lat_dms, $lon_dms);
$conf{json} or printf " Location : %9.4f / %9.4f %-6s %14s / %14s\n",
$lat, $lon, "($acc)", $lat_dms, $lon_dms;
# OSM max zoom = 19, Google Maps max zoom = 21
my $z = 16 - int log $acc;
( run in 0.671 second using v1.01-cache-2.11-cpan-97f6503c9c8 )