PHP Regex IPv6 with preg_match

Edit: There is a better way of doing this, please see PHP Regex IPv6 with preg_match – Revisited. Thanks for the comments.

IPv6 regex with preg_match

IPv6 is coming, I hope you are all ready for it! This function should help you out when developing software that needs to be IPv6 aware.

function valid_ipv6_address( $ipv6 )
{
        $pattern1 = '([A-Fa-f0-9]{1,4}:){7}[A-Fa-f0-9]{1,4}';
        $pattern2 = '[A-Fa-f0-9]{1,4}::([A-Fa-f0-9]{1,4}:){0,5}[A-Fa-f0-9]{1,4}';
        $pattern3 = '([A-Fa-f0-9]{1,4}:){2}:([A-Fa-f0-9]{1,4}:){0,4}[A-Fa-f0-9]{1,4}';
        $pattern4 = '([A-Fa-f0-9]{1,4}:){3}:([A-Fa-f0-9]{1,4}:){0,3}[A-Fa-f0-9]{1,4}';
        $pattern5 = '([A-Fa-f0-9]{1,4}:){4}:([A-Fa-f0-9]{1,4}:){0,2}[A-Fa-f0-9]{1,4}';
        $pattern6 = '([A-Fa-f0-9]{1,4}:){5}:([A-Fa-f0-9]{1,4}:){0,1}[A-Fa-f0-9]{1,4}';
        $pattern7 = '([A-Fa-f0-9]{1,4}:){6}:[A-Fa-f0-9]{1,4}';

        $full = "/^($pattern1)$|^($pattern2)$|^($pattern3)$|^($pattern4)$|^($pattern5)$|^($pattern6)$|^($pattern7)$/";

        if(!preg_match($full, $ipv6))
        return (0); // is not a valid IPv6 Address

    return (1);
}

Basic example usage of this function

$addr6 = "2001:2d12:c4fe:5afe::1";
if ( valid_ipv6_address( $addr6 ) )
{
    printf ( "%s is a valid IPv6 Address!n", $addr6 );
}
else
{
    printf ( "%s is *NOT* a valid IPv6 Address!n", $addr6 );
}

$addr6 = "4d4x:3daz:rdc2:23sd::1";
if ( valid_ipv6_address( $addr6 ) )
{
    printf ( "%s is a valid IPv6 Address!n", $addr6 );
}
else
{
    printf ( "%s is *NOT* a valid IPv6 Address!n", $addr6 );
}

Gives us this output

2001:2d12:c4fe:5afe::1 is a valid IPv6 Address!
4d4x:3daz:rdc2:23sd::1 is *NOT* a valid IPv6 Address!

That’s it!

You may also like...

  • Aeron

    Try:
    /^(((?=(?>.*?(::))(?!.+3)))3?|([dA-F]{1,4}(3|:(?!$)|$)|2))(?4){5}((?4){2}|(25[0-5]|(2[0-4]|1d|[1-9])?d)(.(?7)){3})z/i

    From:
    http://home.deds.nl/~aeron/regex/

    • http://www.mebsd.com/ Jake Smith

      Although your regex is much smaller, which is always nice, it does not work with short hand IPv6 addresses. E.g. in the, post 2001:2d12:c4fe:5afe::1 is a valid IPv6 address, however your regex would not match this unless the input was something like 2001:2d12:c4fe:5afe:0:0:0:1

      Would be interested to see any improvements you could make on it, maybe one that would even accept ::1

      • Aeron

        This regex works with the latest version of PCRE, as PHP implements PCRE for regex validation this should work; which version of PCRE do you have installed in PHP?

        You can try the regex out with use of http://regex.larsolavtorvik.com/

        • Jake Smith

          Useful link thanks, and thanks for the regex.

          Just re-ran my test with your regex, and it works perfectly :) Silly me had used double quotes ( ” ) not single ( ‘ ) surrounding the pattern so the backslash escape sequences weren’t being interpreted correctly. Even works for ::1

  • Aeron

    Try:
    /^(((?=(?>.*?(::))(?!.+3)))3?|([dA-F]{1,4}(3|:(?!$)|$)|2))(?4){5}((?4){2}|(25[0-5]|(2[0-4]|1d|[1-9])?d)(.(?7)){3})z/i

    From:
    http://home.deds.nl/~aeron/regex/

    • http://mebsd.com/ Jake Smith

      Although your regex is much smaller, which is always nice, it does not work with short hand IPv6 addresses. E.g. in the, post 2001:2d12:c4fe:5afe::1 is a valid IPv6 address, however your regex would not match this unless the input was something like 2001:2d12:c4fe:5afe:0:0:0:1

      Would be interested to see any improvements you could make on it, maybe one that would even accept ::1

      • Aeron

        This regex works with the latest version of PCRE, as PHP implements PCRE for regex validation this should work; which version of PCRE do you have installed in PHP?

        You can try the regex out with use of http://regex.larsolavtorvik.com/

        • Jake Smith

          Useful link thanks, and thanks for the regex.

          Just re-ran my test with your regex, and it works perfectly :) Silly me had used double quotes ( ” ) not single ( ‘ ) surrounding the pattern so the backslash escape sequences weren’t being interpreted correctly. Even works for ::1