This post has already been read 2576 times!

This is a simple PHP script I wrote for detecting whether a visitor to a page is connected via IPv4 or IPv6, matching the remote address server variable or an address passed as a query parameter to a regular expression and returning the address and protocol as JSON.
I found the IPv6 regular expression through a Google search; and yes, I know it doesn’t check to see if the address is valid. No need for that, I say, when it’ll mostly be using server-side values for the visitor’s address. A basic implementation using jQuery (replacing, of course, the URL of the script with wherever you choose to host it) would look something like this:

<?php
header('Content-type: application/json');
if ( array_key_exists('addr', $_GET) )
     $ip = $_GET['addr'];
else
     $ip = $_SERVER['REMOTE_ADDR'];
$v6 = preg_match("/^[0-9a-f]{1,4}:([0-9a-f]{0,4}:){1,6}[0-9a-f]{1,4}$/", $ip);
$v4 = preg_match("/^([0-9]{1,3}\.){3}[0-9]{1,3}$/", $ip);
if ( $v6 != 0 )
    $type = "IPv6";
elseif ( $v4 != 0 )
    $type = "IPv4";
else
$type = "unknown";
echo json_encode(array("ip" => $ip, "type" => $type));
?> 

$(function() {
$.get("http://pub.jbhannah.net/v6.php", function(d) {
if( d.type != "unknown" )
$("#remote_ip").html("Connected via " + d.type + " from " + d.ip);
}, "json");
});

A span id="remote_ip" or div id="remote_ip" (remember the closing /, or closing tag to stay HTML5-valid) would be replaced with Connected via IPv6 from 2000:4000:aaa:22bb::dead:b33f so that a visitor can see what protocol and address they’re connected with. You can also use the script to track how many visitors to your site use IPv6. It may be trivial, but it’s just something I threw together on a whim because I felt like it and thought it’d be a fun exercise in regular expressions, JSON, and jQuery.

Validating IP-Addresses in PHP

Using PHP functions can be surprising at times. Validating IP-Addresses using Validate Filters seems to be one of those. There are several flags you can set to specify what kind of IP-Addresses you wan’t to consider as valid, namely:

  • FILTER_FLAG_IPV4 : Validates only IPv4 Addresses
  • FILTER_FLAG_IPV6 : Validates only IPv6 Addresses
  • FILTER_FLAG_NO_PRIV_RANGE : Consider IPs from the private range as invalid
  • FILTER_FLAG_NO_RES_RANGE : Consider IPs from the reserved range as invalid

In the PHP docs, the explanation for those flags says as follows:

Validates value as IP address, optionally only IPv4 or IPv6 or not from private or reserved ranges.

Uhm, yeah. Okay so just to make it clear how that works, here are a few examples (first the surprising one):

$ip = "2001:db8:0:8d3:0:8a2e:70:7344";
$flags = FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6;
filter_var( $ip, FILTER_VALIDATE_IP, $flags );
=> false$ip = "30.17.132.147";
$flags = FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6;
filter_var( $ip, FILTER_VALIDATE_IP, $flags );
=> false

If FILTER_FLAG_IPV4 and FILTER_FLAG_IPV6 are specified together, FILTER_VALIDATE_IP seems to always return false, which was rather unexpected for me. The rest is quite understandable, though:

$ip = "2001:db8:0:8d3:0:8a2e:70:7344";
filter_var( $ip, FILTER_VALIDATE_IP );
=> "2001:db8:0:8d3:0:8a2e:70:7344"$ip = "30.17.132.147";
filter_var( $ip, FILTER_VALIDATE_IP );
=> "30.17.132.147"

These both validate, as FILTER_VALIDATE_IP defaults to allowing both IPv4 and IPv6.

For an explanation on what the private range and reserved range flags do, check out the Wikipedia page on Reserved IP addresses.

Leave a Reply

Post Navigation