Representing IPv6 addresses with PHP per RFC 5952
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 &amp;&amp; strlen($zero_chain) &gt;= 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