|
<?php
/**
* IPv6 Address Functions for PHP
*
* Functions to manipulate IPv6 addresses for PHP
*
* Copyright (C) 2009, 2011 Ray Patrick Soucy
*
* LICENSE:
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package inet6
* @author Ray Soucy <rps@soucy.org>
* @version 1.0.2
* @copyright 2009, 2011 Ray Patrick Soucy
* @link http://www.soucy.org/
* @license GNU General Public License version 3 or later
* @since File available since Release 1.0.1
*/
/**
* Expand an IPv6 Address
*
* This will take an IPv6 address written in short form and expand it to include all zeros.
*
* @param string $addr A valid IPv6 address
* @return string The expanded notation IPv6 address
*/
function inet6_expand($addr)
{
/* Check if there are segments missing, insert if necessary */
if (strpos($addr, '::') !== false) {
$part = explode('::', $addr);
$part[0] = explode(':', $part[0]);
$part[1] = explode(':', $part[1]);
$missing = array();
for ($i = 0; $i < (8 - (count($part[0]) + count($part[1]))); $i++)
array_push($missing, '0000');
$missing = array_merge($part[0], $missing);
$part = array_merge($missing, $part[1]);
} else {
$part = explode(":", $addr);
} // if .. else
/* Pad each segment until it has 4 digits */
foreach ($part as &$p) {
while (strlen($p) < 4) $p = '0' . $p;
} // foreach
unset($p);
/* Join segments */
$result = implode(':', $part);
/* Quick check to make sure the length is as expected */
if (strlen($result) == 39) {
return $result;
} else {
return false;
} // if .. else
} // inet6_expand
/**
* Compress an IPv6 Address
*
* This will take an IPv6 address and rewrite it in short form.
*
* @param string $addr A valid IPv6 address
* @return string The address in short form notation
*/
function inet6_compress($addr)
{
/* PHP provides a shortcut for this operation */
$result = inet_ntop(inet_pton($addr));
return $result;
} // inet6_compress
/**
* Generate an IPv6 mask from prefix notation
*
* This will convert a prefix to an IPv6 address mask (used for IPv6 math)
*
* @param integer $prefix The prefix size, an integer between 1 and 127 (inclusive)
* @return string The IPv6 mask address for the prefix size
*/
function inet6_prefix_to_mask($prefix)
{
/* Make sure the prefix is a number between 1 and 127 (inclusive) */
$prefix = intval($prefix);
if ($prefix < 0 || $prefix > 128) return false;
$mask = '0b';
for ($i = 0; $i < $prefix; $i++) $mask .= '1';
for ($i = strlen($mask) - 2; $i < 128; $i++) $mask .= '0';
$mask = gmp_strval(gmp_init($mask), 16);
for ($i = 0; $i < 8; $i++) {
$result .= substr($mask, $i * 4, 4);
if ($i != 7) $result .= ':';
} // for
return inet6_compress($result);
} // inet6_prefix_to_mask
/**
* Convert an IPv6 address and prefix size to an address range for the network.
*
* This will take an IPv6 address and prefix and return the first and last address available for the network.
*
* @param string $addr A valid IPv6 address
* @param integer $prefix The prefix size, an integer between 1 and 127 (inclusive)
* @return array An array with two strings containing the start and end address for the IPv6 network
*/
function inet6_to_range($addr, $prefix)
{
$size = 128 - $prefix;
$addr = gmp_init('0x' . str_replace(':', '', inet6_expand($addr)));
$mask = gmp_init('0x' . str_replace(':', '', inet6_expand(inet6_prefix_to_mask($prefix))));
$prefix = gmp_and($addr, $mask);
$start = gmp_strval(gmp_add($prefix, '0x1'), 16);
$end = '0b';
for ($i = 0; $i < $size; $i++) $end .= '1';
$end = gmp_strval(gmp_add($prefix, gmp_init($end)), 16);
for ($i = 0; $i < 8; $i++) {
$start_result .= substr($start, $i * 4, 4);
if ($i != 7) $start_result .= ':';
} // for
for ($i = 0; $i < 8; $i++) {
$end_result .= substr($end, $i * 4, 4);
if ($i != 7) $end_result .= ':';
} // for
$result = array(inet6_compress($start_result), inet6_compress($end_result));
return $result;
} // inet6_to_range
/**
* Convert an IPv6 address to two 64-bit integers.
*
* This will translate an IPv6 address into two 64-bit integer values for storage in an SQL database.
*
* @param string $addr A valid IPv6 address
* @return array An array with two strings containing the 64-bit interger values
*/
function inet6_to_int64($addr)
{
/* Expand the address if necessary */
if (strlen($addr) != 39) {
$addr = inet6_expand($addr);
if ($addr == false) return false;
} // if
$addr = str_replace(':', '', $addr);
$p1 = '0x' . substr($addr, 0, 16);
$p2 = '0x' . substr($addr, 16);
$p1 = gmp_init($p1);
$p2 = gmp_init($p2);
$result = array(gmp_strval($p1), gmp_strval($p2));
return $result;
} // inet6_to_int64()
/**
* Convert two 64-bit integer values into an IPv6 address
*
* This will translate an array of 64-bit integer values back into an IPv6 address
*
* @param array $val An array containing two strings representing 64-bit integer values
* @return string An IPv6 address
*/
function int64_to_inet6($val)
{
/* Make sure input is an array with 2 numerical strings */
$result = false;
if ( ! is_array($val) || count($val) != 2) return $result;
$p1 = gmp_strval(gmp_init($val[0]), 16);
$p2 = gmp_strval(gmp_init($val[1]), 16);
while (strlen($p1) < 16) $p1 = '0' . $p1;
while (strlen($p2) < 16) $p2 = '0' . $p2;
$addr = $p1 . $p2;
for ($i = 0; $i < 8; $i++) {
$result .= substr($addr, $i * 4, 4);
if ($i != 7) $result .= ':';
} // for
return inet6_compress($result);
} // int64_to_inet6()
// trailing PHP tag omitted to prevent accidental whitespace
|