3

I've been reading about how to determine whether an IP is IPv4 or IPv6 and it seems obvious to me that the thing to look for is whether there is a colon. However, then you have IPv4–mapped IPv6 addresses and IPv4–compatible IPv6 addresses. It seems to me that these types of addresses have both colons and periods, so instead of solutions that look for whether there is no ::ffff at the beginning of the string, why not just do this:

function isIPv6($ip) {
  if(strpos($ip, ":") !== false && strpos($ip, ".") === false) {
     return true;
  }
  return false;
}

EDIT: Am I missing something or would this function work properly in all cases?

J Johnson
  • 168
  • 3
  • 11
  • is it a question ? you seem provided a function that detects IPv6 . – Raptor Mar 28 '13 at 06:14
  • Could look at the length of the IP? – Class Mar 28 '13 at 06:15
  • 2
    Or you could make it easy on yourself and use [`FILTER_FLAG_IPV4` or `FILTER_FLAG_IPV6` with `filter_var()`](http://php.net/manual/en/function.filter-var.php). – Jared Farrish Mar 28 '13 at 06:15
  • *sidenote:* `filter_var()` requires PHP 5.2.0 – Raptor Mar 28 '13 at 06:20
  • 1
    Shivan, My question is whether the above function would work properly in all cases. Class, the length of the IP doesn't seem like the best solution, especially when the shorthand notation is used. http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzai2%2Frzai2ipv6addrformat.htm Jared, that seems more expensive than a simple function like the one above - if it works properly. – J Johnson Mar 28 '13 at 06:22
  • 1
    *If it works properly?* You believe what you want to believe. – Jared Farrish Mar 28 '13 at 06:24
  • @JJohnson your function does not _work properly_, check my comment on my answer. – Ares Mar 28 '13 at 06:36

3 Answers3

5

PHP => 5.2 has a "built-in" approach to do this using filter_var

Your function could look like this:

function isIPv6($ip) {

   if(filter_var($ip, FILTER_VALIDATE_IP)) {

       if(filter_var($ip, FILTER_FLAG_IPV6)) {
          //It is IPv6 indeed.
        } else {
          //It is IPv4
       }

   } else {
      // NOT VALID IP
   }

}
glglgl
  • 89,107
  • 13
  • 149
  • 217
Ares
  • 5,905
  • 3
  • 35
  • 51
  • 2
    The problem is that `12:29 AM` would actually return true. Your evaluation is way too simplistic. If you want to implement it your self then you should look into doing it using regular expressions. – Ares Mar 28 '13 at 06:30
  • 1
    Well, that's assuming the function is used on just about any input. This function is intended to be used with valid IP addresses. We already assume the input to be either an IPv4 IP or an IPv6 IP. Not every function needs to super validate everything to make sure the input is valid to begin with. The programmer using the function needs to have some common sense too... – J Johnson Mar 28 '13 at 06:38
  • 2
    Sigh . . . Check this [answer on security](http://stackoverflow.com/a/2794089/547144). Look at the very first item. – Ares Mar 28 '13 at 06:50
  • 1
    It wouldn't be user input in this case. It would be the $_SERVER["REMOTE_ADDR"] variable. By "input", I meant the input into the function. I don't see why any validation needs to be done in this specific case. – J Johnson Mar 28 '13 at 06:58
  • @JJohnson Depending on how the server is set up, `$_SERVER['REMOTE_ADDR']` could very well be something other than the remote user's IP address. And your code will end up getting reused in some other context, where it should be validated more stringently. Best to do it right the first time. – Michael Hampton Apr 14 '13 at 19:00
3

From IBM:

An IPv6 address can have two formats:

    Normal - Pure IPv6 format
    2001 : db8: 3333 : 4444 : 5555 : 6666 : 7777 : 8888
    Dual - IPv6 plus IPv4 formats
    2001 : db8: 3333 : 4444 : 5555 : 6666 : 1 . 2 . 3 . 4

You function only validating Pure format of IPv6. I also suggest to use FILTER_FLAG_IPV4 or FILTER_FLAG_IPV6

function isIPv6($ip) {
  if(strpos($ip, ":") !== false && strpos($ip, ".") === false) {
     return true; //Pure format
  }
  elseif(strpos($ip, ":") !== false && strpos($ip, ".") !== false){
    return true; //dual format
  }
  else{
  return false;
  }
}
1

Assuming the IP address is valid and knowing you can have IPv6 mapped IPv4 addresses, e.g. ::ffff:127.0.0.1, just checking the existence of : should be enough.

function isIPv6($address) 
{
    return strpos($address, ':') !== false;
}

If it may not be valid, you should first validate it:

function isIPv6($address) 
{
    return filter_var($address, FILTER_VALIDATE_IP) && 
        strpos($address, ':') !== false;
}

Btw, this is how PHP handles IPv6 as well, as you can see from the source.

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309