App-geoip

 view release on metacpan or  search on metacpan

geoip  view on Meta::CPAN

    $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 )