1
votes

I'm developing an open source plugin for use 3rd party sites. It includes this snippet to obtain a visitors country code:

$visitorIP = $_SERVER['REMOTE_ADDR'];

if( filter_var($visitorIP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ) {
    $geoIPdb = 'GeoIP.dat';
} elseif ( filter_var($visitorIP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ) {
    $geoIPdb = 'GeoIPv6.dat';
} else return 'something';

include_once($this->maxmindDirectory . 'geoip.inc');
$gi = geoip_open($this->maxmindDirectory . $geoIPdb, GEOIP_STANDARD);

if($geoIPdb == 'GeoIP.dat') {
    $ISOcode = geoip_country_code_by_addr($gi, $visitorIP); }
else {
    $ISOcode = geoip_country_code_by_addr_v6($gi, $visitorIP);
}

My server and ISP both use IPv4 and the code works for IPv4 addresses; but I can't test real visitor IPv6 addresses.

However, if I test by hard coding $visitorIP as an IPv6 address I get an "inet_pton() [function.inet-pton]: Unrecognized address" warning.

  1. Is this an error in my code, or down to my server/PHP configuration? (When I checked AF_INET6 was undefined.)

  2. If its not my error, will this code work correctly on servers where $_SERVER['REMOTE_ADDR'] contains an IPv6 address, or do I still need to add additional checks?

Thanks for any advice.

1
@Andre thanks for the quick response: full error msg including IPV6 addy Warning: inet_pton(): Unrecognized address 2001:4860:0:1001::68 in /home/betatrav/public_html/wptest/wp/wp-content/plugins/ajwtextwidget/maxmind/geoip.inc on line 1615 Warning: unpack(): Type C: not enough input, need 1, have 0 in /home/betatrav/public_html/wptest/wp/wp-content/plugins/ajwtextwidget/maxmind/geoip.inc on line 1678 Warning: array_merge(): Argument #1 is not an array in /home/betatrav/public_html/wptest/wp/wp-content/plugins/ajwtextwidget/maxmind/geoip.inc on line 1678scytale
Can you check if your PHP supports IPv6 with this code ?user2629998
The server doesn't support IPv6. The code you linked was how I found AF_INET6 was undefined and made me suspect on my server inet_pton may be unable to handle an IPv6 string. I guess this is leading to yes it is an issue with PHP on my server? In which case, can I assume that when this code runs on other servers and the value of $_SERVER['REMOTE_ADDR'] is a valid IPv6 address, it means that server MUST be correctly implemented for IPv6 and the code will run without errors/warnings and there is no need for any additional checking?scytale
Yes your code is mostly correct, just make sure that you put this in a function since you're returning something.user2629998
Thanks Andre, if you want to add an answer about it being a server issue then I'm happy to mark it as accepted.scytale

1 Answers

4
votes

Your server's PHP is compiled without IPv6 support (using the --disable-ipv6) so your code fails, however it should work fine on a server on which PHP supports IPv6.

Here's how to check if IPv6 is supported on your PHP installation, taken from here :

if (defined('AF_INET6')) {
  echo "PHP was compiled without --disable-ipv6 option";
} else {
  echo "PHP was compiled with --disable-ipv6 option";
}

By the way, here's how I would rewrite your code, it looks better to me but I'm far from being a PHP expert so use it at your own risk.

function getISOcode($visitorIP) {
    if(filter_var($visitorIP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
        $geoIPdb = "GeoIP.dat";

        include_once($this->maxmindDirectory."geoip.inc");
        $gi = geoip_open($this->maxmindDirectory.$geoIPdb, GEOIP_STANDARD);

        return geoip_country_code_by_addr($gi, $visitorIP);
    } elseif (filter_var($visitorIP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
        $geoIPdb = "GeoIPv6.dat";

        include_once($this->maxmindDirectory."geoip.inc");
        $gi = geoip_open($this->maxmindDirectory.$geoIPdb, GEOIP_STANDARD);

        return geoip_country_code_by_addr($gi, $visitorIP);
    } else {
        return false; // or throw an exception about the address being invalid
    }
}