discourse-legacysite-perl/site/slowtwitch.com/cgi-bin/articles/GT/IPCountry.pm
2024-06-17 21:49:12 +10:00

173 lines
4.7 KiB
Perl

# ====================================================================
# Gossamer Threads Module Library - http://gossamer-threads.com/
#
# GT::IPCountry
# Author: Jason Rhinelander
# CVS Info : 087,071,086,086,085
# $Id: IPCountry.pm,v 1.1 2006/01/31 00:45:04 jagerman Exp $
#
# Copyright (c) 2006 Gossamer Threads Inc. All Rights Reserved.
# ====================================================================
#
# Description:
# Attempts to look up an IP's country using a variety of common CPAN modules.
#
package GT::IPCountry;
use strict;
require Exporter;
use vars qw/@EXPORT @ISA %MODULE/;
@ISA = 'Exporter';
@EXPORT = 'ip_to_country';
sub lookup_possible () {
_load_module() if not defined $MODULE{loaded};
return $MODULE{loaded};
}
sub ip_to_country ($) {
my $ip = shift;
lookup_possible or return (undef, undef);
my $country;
if ($MODULE{geoip}) { # Geo::IP
$country = $MODULE{geoip}->country_name_by_addr($ip);
}
elsif ($MODULE{ipc}) { # IP::Country & Geography::Countries
$country = $MODULE{ipc}->inet_ntocc(Socket::inet_aton($ip));
my %special = ( # Special codes returned that G::C can't handle:
AP => 'non-specific Asia-Pacific location',
CS => 'Czechoslovakia (former)',
EU => 'non-specific European Union location',
FX => 'France, Metropolitan',
PS => 'Palestinian Territory, Occupied',
'**' => 'Intranet address'
);
if ($special{$country}) { $country = $special{$country} }
elsif ($MODULE{geoc}) {
$country = Geography::Countries::country($country) || $country;
}
}
elsif ($MODULE{geoipfree}) { # Geo::IPfree
$country = ($MODULE{geoipfree}->LookUp($ip))[1];
}
return wantarray ? ($country, 1) : $country;
}
# Attempts to load various CPAN modules capable of going the IP -> country
# lookup. Sets $MODULE{loaded} to 1 if at least one of the modules was found,
# sets to 0 if none were loadable.
sub _load_module {
if (!defined $MODULE{geoip}) {
$MODULE{geoip} = eval { require Geo::IP; Geo::IP->new(Geo::IP::GEOIP_STANDARD()) } || 0;
if (!$MODULE{geoip}) {
$MODULE{geoipfree} = 0 && eval { require Geo::IPfree; Geo::IPfree->new } || 0;
}
if (!$MODULE{geoip}) {
$MODULE{ipc} = eval { require IP::Country::Fast; IP::Country::Fast->new } || 0;
}
if ($MODULE{ipc}) {
require Socket;
$MODULE{geoc} = eval { require Geography::Countries } || 0;
}
if (!$MODULE{ipc} and !$MODULE{geoipfree}) {
$MODULE{geoipfree} = 0 && eval { require Geo::IPfree; Geo::IPfree->new } || 0;
}
}
$MODULE{loaded} = $MODULE{geoip} || $MODULE{geoipfree} || $MODULE{ipc} ? 1 : 0;
}
1;
__END__
=head1 NAME
GT::IPCountry - Attempts to look up an IP's country using a variety of common
CPAN modules.
=head1 SYNOPSIS
use GT::IPCountry;
my $country = ip_to_country("209.139.239.160");
my ($country, $lookup_okay) = ip_to_country("209.139.239.160");
my $can_lookup = GT::IPCountry::lookup_possible();
=head1 DESCRIPTION
This module takes an IP address and returns the country name the IP is reserved
for. This module itself does no actual lookup, but is simply a wrapper around
serveral CPAN modules. If none of the modules are available, it simply returns
the value C<undef>.
=head1 FUNCTIONS
=head2 ip_to_country
This method takes a country name and returns two elements: the country name,
and a true/false value indicating whether one of the lookup modules was
available. In scalar context just the country name is returned. A country
name of C<undef> indicates that either the IP wasn't found, or no lookup module
was available.
C<ip_to_country> is exported by default.
=head2 lookup_possible
This method returns a true/false value indicating whether or not an IP ->
Country lookup can be done. It corresponds directly to the second return value
of C<ip_to_country>.
=head1 MODULES
GT::IPCountry attempts to use the following modules, in order, to perform a
country lookup:
=over 4
=item Geo::IP
Uses Geo::IP for the lookup.
=item IP::Country
Uses IP::Country for the lookup. Note that because IP::Country only returns a
country code, this module will attempt to use Geography::Countries to determine
the country name. If Geography::Countries isn't installed, you'll just get a
country code.
=item Geo::IPfree
Uses Geo::IPfree for the lookup.
=back
=head1 SEE ALSO
L<Geo::IP>
L<Geo::IPfree>
L<IP::Country>
=head1 COPYRIGHT
Copyright (c) 2006 Gossamer Threads Inc. All Rights Reserved.
http://www.gossamer-threads.com/
=head1 VERSION
Revision: $Id: IPCountry.pm,v 1.1 2006/01/31 00:45:04 jagerman Exp $
=cut