HiveBrain v1.2.0
Get Started
← Back to all entries
patternphpMinor

Representing IPv6 addresses with PHP per RFC 5952

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
per5952withphpaddressesrfcipv6representing

Problem

I wrote the following function in PHP to represent IPv6 addresses as short as possible:

function ipv6_compress($ip){
    // Shorten first group of zeros
    if(substr($ip, 0, 4) == 0000) $ip = substr_replace($ip, '0', 0, 4);
    // Shorten full groups of zeros
    $ip = str_replace('0000:', '0:', $ip);
    // Remove leading zeros
    $ip = preg_replace('/:0{1,3}(?=\w)/', ':', $ip);
    // Remove longest extra group of zeros per [RFC 5952](https://www.rfc-editor.org/rfc/rfc5952)
    if(strpos('::') !== false) return $ip; // But don't if a :: is already present as entered
    $pos = strpos($ip, '0:0:0:0:0:0:0:');
    if($pos !== false) return $ip = substr_replace($ip, '::', $pos, 14);
    $pos = strpos($ip, '0:0:0:0:0:0:');
    if($pos !== false) return $ip = substr_replace($ip, '::', $pos, 12);
    $pos = strpos($ip, '0:0:0:0:0:');
    if($pos !== false) return $ip = substr_replace($ip, '::', $pos, 10);
    $pos = strpos($ip, '0:0:0:0:');
    if($pos !== false) return $ip = substr_replace($ip, '::', $pos, 8);
    $pos = strpos($ip, '0:0:0:');
    if($pos !== false) return substr_replace($ip, '::', $pos, 6);
    $pos = strpos($ip, '0:0:');
    if($pos !== false) return substr_replace($ip, '::', $pos, 4);
    return $ip;
}


I attempt to adhere to RFC 5952.

  • Do I violate the standard in any way?



  • Can I do anything more efficiently?



As you can probably tell, I am not concerned with validating the addresses.

Solution

You seem to adhere to the RFC from what I can tell. What I feel is missing in your code is just a little more bracing and a way to drop these repeating if-statements.

What do you think of the following for the :: replacing (pseudocode)

const $zero_chain = '0:0:0:0:0:0:0:';

// zero shortening already happened by now    
$zero_chain_copy = $zero_chain;
while (strpos($ip, '::') === false && strlen($zero_chain) >= 4) {
    $pos = strpos($ip, $zerochain);
    if ($pos !== false) {
        // early return, because no further shortenings can be applied anyways
        return $ip = substr_replace($ip, ::, $pos, strlen($zero_chain));
    }
    // cut away one '0:' to shorten the chain
    $zero_chain = substr($zerochain, 0, strlen($zero_chain) - 2);
}
return $ip; // no zero-chains at all

Code Snippets

const $zero_chain = '0:0:0:0:0:0:0:';

// zero shortening already happened by now    
$zero_chain_copy = $zero_chain;
while (strpos($ip, '::') === false && strlen($zero_chain) >= 4) {
    $pos = strpos($ip, $zerochain);
    if ($pos !== false) {
        // early return, because no further shortenings can be applied anyways
        return $ip = substr_replace($ip, ::, $pos, strlen($zero_chain));
    }
    // cut away one '0:' to shorten the chain
    $zero_chain = substr($zerochain, 0, strlen($zero_chain) - 2);
}
return $ip; // no zero-chains at all

Context

StackExchange Code Review Q#90430, answer score: 4

Revisions (0)

No revisions yet.