0

There are lots of posts here and elsewhere about how to handle IP4 and IP6 addresses in PHP.

I want to write code which will normalise all IP addresses, regardless of their representation, to IP6 format.

I can do that by piecing together various bits of advice and doing some string hacking, but has best practice moved on from that?

Are there built-in functions in modern PHP which will do this correctly for all cases, without any conditional logic in my application code?

Community
  • 1
  • 1
spraff
  • 32,570
  • 22
  • 121
  • 229
  • http://stackoverflow.com/questions/14445582/change-ipv4-to-ipv6-string – ceejayoz Apr 05 '16 at 20:35
  • 1
    **NOT** a duplicate. *ahem*: "There are lots of posts here and elsewhere..." saw that, wanted to know "has best practice moved on from that?" – spraff Apr 05 '16 at 21:48
  • @spraff That doesn't stop it from being a duplicate. – ceejayoz Apr 06 '16 at 04:32
  • The question there was "how do I do this?" The question here is "how do I do this without doing that?" – spraff Apr 06 '16 at 11:31
  • "I want to write code without conditionals" doesn't make it non-duplicate. It just makes you weirdly picky. – ceejayoz Apr 06 '16 at 12:53
  • Not at all. Another way of phrasing this question would be "are there library functions for this now?" so that there is a **canonical** solution that doesn't require further testing, and also future-proofs application code against e.g. the IP spec being extended to introduce another notation/encoding. This question is about the existence of a certain quality of solution, not "any hack which will do the job", which is what the others were. You seem to be saying the questions are equivalent as long as the observable output of the programs is the same. – spraff Apr 06 '16 at 22:43

1 Answers1

2

No, you can't do this without any conditional logic. On the other hand, the necessary code isn't very difficult:

function normalise_ip($address, $force_ipv6=false) {
    # Parse textual representation
    $binary = inet_pton($address);
    if ($binary === false) {
        return false;
    }

    # Convert back to a normalised string
    $normalised = inet_ntop($binary);

    # Add IPv4-Mapped IPv6 Address prefix if requested
    if ($force_ipv6 && strlen($binary) == 4) {
        $normalised = '::ffff:' . $normalised;
    }

    return $normalised;
}

You can test it like this:

$addresses = array(
    '192.000.002.001',
    '2001:0db8:0000:0000:0000:0000:0000:0001',
);

foreach ($addresses as $original) {
    $normalised = normalise_ip($original);
    $normalised_ipv6 = normalise_ip($original, true);

    echo "Original: $original; ";
    echo "Normalised: $normalised; ";
    echo "As IPv6: $normalised_ipv6\n";
}

If you force the result to IPv6 you get IPv4-Mapped IPv6 Addresses instead of IPv4 addresses.

Sander Steffann
  • 9,509
  • 35
  • 40