729 lines
24 KiB
PHP
729 lines
24 KiB
PHP
<?php
|
|
|
|
/** DomFramework
|
|
* @package domframework
|
|
* @author Dominique Fournier <dominique@fournier38.fr>
|
|
* @license BSD
|
|
*/
|
|
|
|
namespace Domframework;
|
|
|
|
/** Manage the IP addresses conversions */
|
|
class Ipaddresses
|
|
{
|
|
/** Return true if the provided IP address is valid (IPv4 or IPv6)
|
|
* @param string $ip The IP Address to validate
|
|
*/
|
|
public function validIPAddress($ip)
|
|
{
|
|
if (!is_string($ip) || $ip === "") {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IP address"),
|
|
500
|
|
);
|
|
}
|
|
$rc = $this->validIPv4Address($ip);
|
|
if ($rc === true) {
|
|
return true;
|
|
}
|
|
$rc = $this->validIPv6Address($ip);
|
|
return $rc;
|
|
}
|
|
|
|
/** Return true if the provided IP address is valid and is IPv4
|
|
* @param string $ip The IP Address to validate
|
|
*/
|
|
public function validIPv4Address($ip)
|
|
{
|
|
if (!is_string($ip) || $ip === "") {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IPv4 address"),
|
|
500
|
|
);
|
|
}
|
|
$rc = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
|
|
if ($rc === false) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** Return true if the provided IP address is valid and is IPv6
|
|
* @param string $ip The IP Address to validate
|
|
*/
|
|
public function validIPv6Address($ip)
|
|
{
|
|
if (!is_string($ip) || $ip === "") {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IPv6 address"),
|
|
500
|
|
);
|
|
}
|
|
$rc = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
|
|
if ($rc === false) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** Return true if the provided IP address is valid (IPv4 or IPv6) and the
|
|
* provided CIDR is valid too
|
|
* @param string $ip The IP Address to validate with a CIDR
|
|
*/
|
|
public function validIPAddressWithCIDR($ip)
|
|
{
|
|
if (!is_string($ip) || $ip === "") {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IP address"),
|
|
500
|
|
);
|
|
}
|
|
$rc = $this->validIPv4AddressWithCIDR($ip);
|
|
if ($rc === true) {
|
|
return true;
|
|
}
|
|
$rc = $this->validIPv6AddressWithCIDR($ip);
|
|
return $rc;
|
|
}
|
|
|
|
/** Return true if the provided IP address is valid and is IPv4 and the
|
|
* provided CIDR is valid too
|
|
* @param string $ip The IP Address to validate with a CIDR
|
|
*/
|
|
public function validIPv4AddressWithCIDR($ip)
|
|
{
|
|
if (!is_string($ip) || $ip === "") {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IPv4 address"),
|
|
500
|
|
);
|
|
}
|
|
$tmp = explode("/", $ip);
|
|
$ip = $tmp{0};
|
|
$cidr = (isset($tmp{1})) ? $tmp{1} : null;
|
|
if ($cidr === null) {
|
|
return false;
|
|
}
|
|
$rc = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
|
|
if ($rc === false) {
|
|
return false;
|
|
}
|
|
if ($this->validIPv4CIDR($cidr) === false) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** Return true if the provided IP address is valid and is IPv6 and the
|
|
* provided CIDR is valid too
|
|
* @param string $ip The IP Address to validate with a CIDR
|
|
*/
|
|
public function validIPv6AddressWithCIDR($ip)
|
|
{
|
|
if (!is_string($ip) || $ip === "") {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IPv6 address"),
|
|
500
|
|
);
|
|
}
|
|
$tmp = explode("/", $ip);
|
|
$ip = $tmp{0};
|
|
$cidr = (isset($tmp{1})) ? $tmp{1} : null;
|
|
if ($cidr === null) {
|
|
return false;
|
|
}
|
|
$rc = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
|
|
if ($rc === false) {
|
|
return false;
|
|
}
|
|
if ($this->validIPv6CIDR($cidr) === false) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** Return true if the provided CIDR is valid. The CIDR can be valid in IPv4
|
|
* or IPv6
|
|
* @param integer $cidr The CIDR to test
|
|
* @return boolean The CIDR is valid
|
|
*/
|
|
public function validCIDR($cidr)
|
|
{
|
|
if (! is_integer($cidr) && ! is_integer($cidr)) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid CIDR provided"),
|
|
500
|
|
);
|
|
}
|
|
if (strspn($cidr, "0123456879") !== strlen($cidr)) {
|
|
return false;
|
|
}
|
|
if ($cidr < 0 || $cidr > 128) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** Return true if the provided CIDR is valid. The CIDR can be valid in IPv4.
|
|
* @param integer $cidr The CIDR to test
|
|
* @return boolean The CIDR is valid
|
|
*/
|
|
public function validIPv4CIDR($cidr)
|
|
{
|
|
if (! is_integer($cidr) && ! is_string($cidr)) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid CIDR provided"),
|
|
500
|
|
);
|
|
}
|
|
if (strspn($cidr, "0123456879") !== strlen($cidr)) {
|
|
return false;
|
|
}
|
|
if ($cidr < 0 || $cidr > 32) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** Return true if the provided CIDR is valid. The CIDR can be valid in IPv6.
|
|
* @param integer $cidr The CIDR to test
|
|
* @return boolean The CIDR is valid
|
|
*/
|
|
public function validIPv6CIDR($cidr)
|
|
{
|
|
if (! is_integer($cidr) && ! is_string($cidr)) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid CIDR provided"),
|
|
500
|
|
);
|
|
}
|
|
if (strspn($cidr, "0123456879") !== strlen($cidr)) {
|
|
return false;
|
|
}
|
|
if ($cidr < 0 || $cidr > 128) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** Return the IPv6 to compressed (or compact) form.
|
|
* Remove the 0 when they are placed on the begin of the nibble.
|
|
* Remove all the blocks only zero to convert them to :: (but only one time)
|
|
* Example: 2001:0660:530d:0201:0000:0000:0000:0124 => 2001:660:530d:201::124
|
|
* If an IPv4 is provided, return it without modification
|
|
* @param string $ip The IP to compress
|
|
*/
|
|
public function compressIP($ip)
|
|
{
|
|
if (strpos($ip, ":") === false) {
|
|
return $ip;
|
|
}
|
|
$ip = $this->uncompressIPv6($ip);
|
|
$ipArr = explode(":", $ip);
|
|
if (count($ipArr) !== 8) {
|
|
return $ip;
|
|
}
|
|
// Remove the 0 if they are at the beginning of the nibble
|
|
foreach ($ipArr as &$ip) {
|
|
$ip = sprintf("%x", hexdec($ip));
|
|
}
|
|
// Remove the 0 nibble if there is an other 0 nibble after
|
|
$cleanLoop = false;
|
|
$ipCompArr = array();
|
|
foreach ($ipArr as $key => $val) {
|
|
// echo "VAL=".var_export ($val, true).
|
|
// ", cleanLoop=".var_export ($cleanLoop, true);
|
|
if ($val !== "0") {
|
|
// echo " => In NOT zero\n";
|
|
if ($cleanLoop) {
|
|
$cleanLoop = false;
|
|
}
|
|
} elseif ($cleanLoop) {
|
|
// echo " => In CleanLoop\n";
|
|
unset($ipArr[$key]);
|
|
} else {
|
|
// echo " => In ZERO\n";
|
|
if (key_exists($key + 1, $ipArr) && $ipArr[$key + 1] === "0") {
|
|
// echo " ===> NEXT ZERO : CleanLoop Start\n";
|
|
$cleanLoop = true;
|
|
$ipArr[$key] = "";
|
|
}
|
|
}
|
|
}
|
|
$ipArr = array_values($ipArr);
|
|
if (end($ipArr) === "") {
|
|
array_pop($ipArr);
|
|
$ipArr[] = ":";
|
|
}
|
|
if (reset($ipArr) === "") {
|
|
$ipArr[0] = ":";
|
|
}
|
|
if (count($ipArr) === 1) {
|
|
$ipArr[] = "";
|
|
}
|
|
$ipHex = implode(":", $ipArr);
|
|
return $ipHex;
|
|
}
|
|
|
|
/** Return the IPv6 uncompressed (all the fields exists). They are not filled
|
|
* by zeros
|
|
* If the provided IP is IPv4, there is no change applied
|
|
* Return False if the parameter is invalid
|
|
* Based on http://www.weberdev.com/get_example.php3?ExampleID=3921
|
|
* @param string $ip The IP address to uncompress
|
|
* Example : $ip="::" => return "0:0:0:0:0:0:0:0"
|
|
* Example : $ip = "::ffff:127.0.0.1",
|
|
* return "0:0:0:0:0:0:ffff:7f00:1"
|
|
*/
|
|
public function uncompressIPv6($ip)
|
|
{
|
|
if (
|
|
! is_string($ip) || $ip === "" ||
|
|
$this->validIPAddress($ip) === false
|
|
) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IP address"),
|
|
500
|
|
);
|
|
}
|
|
if (strstr($ip, "::")) {
|
|
$e = explode(":", $ip);
|
|
// Case where :: is in start
|
|
if ($e[0] === "") {
|
|
$e[0] = "0";
|
|
}
|
|
// Case where :: is in end
|
|
if ($e[count($e) - 1] === "") {
|
|
$e[count($e) - 1] = "0";
|
|
}
|
|
$s = 8 - count($e);
|
|
foreach ($e as $key => $val) {
|
|
if ($val === "") {
|
|
for ($i = 0; $i <= $s; $i++) {
|
|
$newipv6[] = 0;
|
|
}
|
|
} else {
|
|
$newipv6[] = $val;
|
|
}
|
|
}
|
|
$ip = implode(":", $newipv6);
|
|
if (substr_count($ip, ":") !== 7) {
|
|
throw new \Exception("uncompressIPv6: Invalid IP provided", 500);
|
|
}
|
|
}
|
|
if (substr($ip, 0, 17) === "0:0:0:0:0:0:ffff:") {
|
|
// Manage the IPv4 blocks in IPv6 : ::ffff:192.168.1.2
|
|
// If the IP is already in valid IPv6 (without dots), skip this part
|
|
$ipv4Block = substr($ip, 17);
|
|
if (strpos($ipv4Block, ".") !== false) {
|
|
@list($ip1, $ip2, $ip3, $ip4) = @explode(".", $ipv4Block);
|
|
// remove the first 0: as there is 2 nibbles for the IPv4 address
|
|
$ip = substr($ip, 2, 15);
|
|
$ip .= sprintf("%x:%x", $ip1 * 256 + $ip2, $ip3 * 256 + $ip4);
|
|
}
|
|
}
|
|
return $ip;
|
|
}
|
|
|
|
/** Get an IPv6 address with the format
|
|
* x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x
|
|
* and return it with format
|
|
* xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
|
|
* Return false if the IP provided is not complete
|
|
* @param string $ipv6 The IPv6 to group
|
|
*/
|
|
public function groupIPv6($ipv6)
|
|
{
|
|
if (! is_string($ipv6) || $ipv6 === "") {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IPv6 address"),
|
|
500
|
|
);
|
|
}
|
|
if (substr_count($ipv6, ".") !== 31) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IPv6 address"),
|
|
500
|
|
);
|
|
}
|
|
$ipv6 = str_replace(".", "", $ipv6);
|
|
$new = "";
|
|
for ($i = 0; $i < 32; $i++) {
|
|
if ($i % 4 === 0 && $i !== 0) {
|
|
$new .= ":";
|
|
}
|
|
$new .= $ipv6[$i];
|
|
}
|
|
return $new;
|
|
}
|
|
|
|
/** Return the IP adddress with filling the fields with the missing zeros.
|
|
* Valid only on IPv6 (but don't change anything if the provided address is
|
|
* IPv4)
|
|
* @param string $ip The IP to complete
|
|
* @return string The address in nibbles
|
|
* Example : $ip = "::", return "0000:0000:0000:0000:0000:0000:0000:0000"
|
|
* Example : $ip = "::ffff:127.0.0.1",
|
|
* return "0000:0000:0000:0000:0000:0000:ffff:7f00:0001"
|
|
*/
|
|
public function completeAddressWithZero($ip)
|
|
{
|
|
if (! is_string($ip) || $ip === "") {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IP address"),
|
|
500
|
|
);
|
|
}
|
|
$ip = $this->uncompressIPv6($ip);
|
|
if (substr_count($ip, ":") === 7) {
|
|
// IPv6
|
|
$ips = explode(":", $ip);
|
|
$ipnew = array();
|
|
foreach ($ips as $iptmp) {
|
|
$ipnew[] = sprintf("%04x", hexdec($iptmp));
|
|
}
|
|
return implode(":", $ipnew);
|
|
} elseif (substr_count($ip, ".") === 31) {
|
|
// Full IPv6 with dots
|
|
return $ip;
|
|
} elseif (substr_count($ip, ".") === 3) {
|
|
// IPv4
|
|
return $ip;
|
|
}
|
|
throw new \Exception(dgettext("domframework", "Invalid IP address"), 500);
|
|
}
|
|
|
|
/** Return the provided CIDR in binary. Length must be in bytes.
|
|
* Return FALSE if the parameters are invalid
|
|
* @param integer $cidr The CIDR to convert
|
|
* @param integer $length The length to use
|
|
*/
|
|
public function cidrToBin($cidr, $length)
|
|
{
|
|
if (! is_numeric($cidr) || $cidr < 0 || $cidr > 128) {
|
|
throw new \Exception(dgettext("domframework", "Invalid CIDR"), 500);
|
|
}
|
|
if (! is_numeric($length) || $length < 1 || $length > 16) {
|
|
throw new \Exception(dgettext("domframework", "Invalid length"), 500);
|
|
}
|
|
$val = "";
|
|
for ($i = 0; $i < $length * 8; $i++) {
|
|
if ($i < $cidr) {
|
|
$val .= "1";
|
|
} else {
|
|
$val .= "0";
|
|
}
|
|
}
|
|
return pack('H*', $this->str_base_convert($val, 2, 16));
|
|
}
|
|
|
|
/** Base conversion with 128 bits support for IPv6
|
|
* Based on http://fr2.php.net/manual/en/function.base-convert.php#109660
|
|
* @param string $str The string to convert
|
|
* @param integer|null $frombase The base of the provided string (10 by
|
|
* default)
|
|
* @param integer|null $tobase The base of the returned string (36 by
|
|
* default)
|
|
*/
|
|
public function str_base_convert($str, $frombase = 10, $tobase = 36)
|
|
{
|
|
$str = trim($str);
|
|
if (intval($frombase) != 10) {
|
|
$len = strlen($str);
|
|
$q = 0;
|
|
for ($i = 0; $i < $len; $i++) {
|
|
$r = base_convert($str[$i], $frombase, 10);
|
|
$q = bcadd(bcmul($q, $frombase), $r);
|
|
}
|
|
} else {
|
|
$q = $str;
|
|
}
|
|
|
|
if (intval($tobase) != 10) {
|
|
$s = '';
|
|
while (bccomp($q, '0', 0) > 0) {
|
|
$r = intval(bcmod($q, $tobase));
|
|
$s = base_convert($r, 10, $tobase) . $s;
|
|
$q = bcdiv($q, $tobase, 0);
|
|
}
|
|
} else {
|
|
$s = $q;
|
|
}
|
|
|
|
return $s;
|
|
}
|
|
|
|
/** Reverse the provided IP address
|
|
* The IPv6 are returned in format :
|
|
* x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x
|
|
* @param string $ipReverse The IPv6 to reverse
|
|
*/
|
|
public function reverseIPAddress($ipReverse)
|
|
{
|
|
if (!is_string($ipReverse) || $ipReverse === "") {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IP address"),
|
|
500
|
|
);
|
|
}
|
|
$ipReverse = $this->completeAddressWithZero($ipReverse);
|
|
if (substr_count($ipReverse, ":") === 7 && strlen($ipReverse) == 39) {
|
|
// Complete IPv6 with quadruplets and colon
|
|
$ip = str_replace(":", "", $ipReverse);
|
|
$tmp2 = array_reverse(str_split($ip));
|
|
return implode(".", $tmp2);
|
|
} elseif (substr_count($ipReverse, ".") === 31) {
|
|
// IPv6 with dots
|
|
$tmp2 = explode(".", $ipReverse);
|
|
$tmp2 = array_reverse($tmp2);
|
|
$ipnew = implode(".", $tmp2);
|
|
return $ipnew;
|
|
} elseif (substr_count($ipReverse, ".") === 3) {
|
|
// IPv4
|
|
$tmp2 = explode(".", $ipReverse);
|
|
$tmp2 = array_reverse($tmp2);
|
|
$ipnew = implode(".", $tmp2);
|
|
return $ipnew;
|
|
}
|
|
throw new \Exception(dgettext("domframework", "Invalid IP address"), 500);
|
|
}
|
|
|
|
/** This function return the CIDR associated to the provided netmask
|
|
* Ex. Return 24 for a mask 255.255.255.0 in direct
|
|
* Ex. Return 24 for a mask 0.0.0.255 in wildcard
|
|
* Work only in IPv4
|
|
* Return FALSE if the provided mask is invalid (155.0.0.0 by example)
|
|
* Throw an exception if the provided IP is invalid
|
|
* @param string $netmask The mask to convert in CIDR
|
|
* @param boolean|null $maskdirect If true check a direct mask, if false
|
|
* check a wildcard mask
|
|
*/
|
|
public function netmask2cidr($netmask, $maskdirect = true)
|
|
{
|
|
$maskdirect = "" . ($maskdirect + 0);
|
|
$maskrevert = ($maskdirect === "0") ? "1" : "0";
|
|
$netmask = ip2long($netmask);
|
|
if ($netmask === false) {
|
|
throw new \Exception(dgettext("domframework", "Invalid netmask"), 500);
|
|
}
|
|
$netmask = decbin($netmask);
|
|
$netmask = sprintf("%032s", $netmask);
|
|
$res = -1;
|
|
for ($i = 0; $i < 32; $i++) {
|
|
if ($res === -1 && $netmask[$i] === $maskdirect) {
|
|
} elseif ($res === -1 && $netmask[$i] === $maskrevert) {
|
|
$res = $i;
|
|
} elseif ($res !== -1 && $netmask[$i] === $maskdirect) {
|
|
return false;
|
|
} else {
|
|
}
|
|
}
|
|
if ($res === -1 && $i === 32) {
|
|
return 32;
|
|
}
|
|
if ($res === -1 && $i === 1) {
|
|
return 32;
|
|
}
|
|
return $res;
|
|
}
|
|
|
|
/** This function return the netmask associated to a CIDR.
|
|
* Work only on IPv4 addresses (CIDR between 0 and 32)
|
|
* @param string $cidr The CIDR to convert in netmask
|
|
* @param boolean|null $maskdirect If true return a direct mask, if false
|
|
* return a wildcard mask
|
|
* @return the mask
|
|
* @return false if the CIDR is not between 0 and 32
|
|
*/
|
|
public function cidr2netmask($cidr, $maskdirect = true)
|
|
{
|
|
if ($cidr < 0 || $cidr > 32) {
|
|
return false;
|
|
}
|
|
$maskdirect = "" . ($maskdirect + 0);
|
|
$maskrevert = ($maskdirect === "0") ? "1" : "0";
|
|
$bin = "";
|
|
for ($i = 0; $i < 32; $i++) {
|
|
if ($i < $cidr) {
|
|
$bin .= $maskdirect;
|
|
} else {
|
|
$bin .= $maskrevert;
|
|
}
|
|
}
|
|
$res = "";
|
|
for ($i = 0; $i < 32; $i = $i + 8) {
|
|
$block = substr($bin, $i, 8);
|
|
if ($i > 0) {
|
|
$res .= ".";
|
|
}
|
|
$res .= bindec($block);
|
|
}
|
|
return $res;
|
|
}
|
|
|
|
/** This function return true if the provided address is in the provided
|
|
* network with the associated cidr
|
|
* @param string $ip The IPv4 or IPv6 to test
|
|
* @param string $network The IPv4 or IPv6 network base
|
|
* @param string $cidr The CIDR to apply
|
|
* @return boolean True if $ip is in $network/$cidr
|
|
*/
|
|
public function ipInNetwork($ip, $network, $cidr)
|
|
{
|
|
if ($this->validIPAddress($ip) === false) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IP address"),
|
|
500
|
|
);
|
|
}
|
|
if ($this->validIPAddress($network) === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Invalid Network address"
|
|
), 500);
|
|
}
|
|
$ipv4 = $this->validIPv4Address($ip);
|
|
$networkv4 = $this->validIPv4Address($network);
|
|
if ($ipv4 !== $networkv4) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Network and IP address are not compatible"
|
|
), 500);
|
|
}
|
|
if ($ipv4 === true) {
|
|
if ($this->validIPv4CIDR($cidr) === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"CIDR is not IPv4 compatible"
|
|
), 500);
|
|
}
|
|
} else {
|
|
if ($this->validIPv6CIDR($cidr) === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"CIDR is not IPv6 compatible"
|
|
), 500);
|
|
}
|
|
}
|
|
return ($this->networkFirstIP($ip, $cidr) ===
|
|
$this->networkFirstIP($network, $cidr));
|
|
}
|
|
|
|
/** Get the first IP of a network.
|
|
* IPv4 and IPv6 compatible
|
|
* @param string $ip The IPv4 or IPv6 in the network
|
|
* @param string $cidr The CIDR to apply
|
|
* @return string the network base
|
|
* Example : $ip="192.168.1.2", $cidr=24 => return "192.168.1.0"
|
|
*/
|
|
public function networkFirstIP($ip, $cidr)
|
|
{
|
|
return $this->networkFirstLastIP($ip, $cidr, "0");
|
|
}
|
|
|
|
/** Get the last IP of a network.
|
|
* IPv4 and IPv6 compatible
|
|
* @param string $ip The IPv4 or IPv6 in the network
|
|
* @param string $cidr The CIDR to apply
|
|
* @return string the network base
|
|
* Example : $ip="192.168.1.2", $cidr=24 => return "192.168.1.255"
|
|
*/
|
|
public function networkLastIP($ip, $cidr)
|
|
{
|
|
return $this->networkFirstLastIP($ip, $cidr, "1");
|
|
}
|
|
|
|
/** Get the network first IP.
|
|
* IPv4 and IPv6 compatible
|
|
* @param string $ip The IPv4 or IPv6 in the network
|
|
* @param string $cidr The CIDR to apply
|
|
* @param string $map if "0", get the first address of the network,
|
|
* if "1" get the last address of the network
|
|
* @return string the network base
|
|
* Example : $ip="192.168.1.2", $cidr=24 => return "192.168.1.0"
|
|
*/
|
|
private function networkFirstLastIP($ip, $cidr, $map)
|
|
{
|
|
if ($this->validIPAddress($ip) === false) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Invalid IP address"),
|
|
500
|
|
);
|
|
}
|
|
$ipv4 = $this->validIPv4Address($ip);
|
|
if ($ipv4 === true) {
|
|
if ($this->validIPv4CIDR($cidr) === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"CIDR is not IPv4 compatible"
|
|
), 500);
|
|
}
|
|
} else {
|
|
if ($this->validIPv6CIDR($cidr) === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"CIDR is not IPv6 compatible"
|
|
), 500);
|
|
}
|
|
}
|
|
// Convert the IP and CIDR to binary string
|
|
if ($ipv4) {
|
|
list($ip1, $ip2, $ip3, $ip4) = explode(".", $ip);
|
|
$ipBin = sprintf("%08b%08b%08b%08b", $ip1, $ip2, $ip3, $ip4);
|
|
$cidrBin = "";
|
|
for ($i = 0; $i < $cidr; $i++) {
|
|
$cidrBin .= "1";
|
|
}
|
|
for ($i = $cidr; $i < 32; $i++) {
|
|
$cidrBin .= "0";
|
|
}
|
|
} else {
|
|
$ip = $this->completeAddressWithZero($ip);
|
|
$ip = str_replace(":", "", $ip);
|
|
$ipArr = str_split($ip, 2);
|
|
$ipBin = "";
|
|
foreach ($ipArr as $ip) {
|
|
$ipBin .= sprintf("%08b", hexdec($ip));
|
|
}
|
|
$cidrBin = "";
|
|
for ($i = 0; $i < $cidr; $i++) {
|
|
$cidrBin .= "1";
|
|
}
|
|
for ($i = $cidr; $i < 128; $i++) {
|
|
$cidrBin .= "0";
|
|
}
|
|
}
|
|
// Get the binary value of IP if the mask is 1 or put $map if the mask is 0
|
|
$ipBaseBin = "";
|
|
for ($i = 0; $i < strlen($ipBin); $i++) {
|
|
if ($cidrBin[$i] === "1") {
|
|
$ipBaseBin .= $ipBin[$i];
|
|
} else {
|
|
$ipBaseBin .= "$map";
|
|
}
|
|
}
|
|
// Convert ipBaseBin from binary to decimal if IPv4 and to hexa for IPv6
|
|
if ($ipv4) {
|
|
$ipBase = "";
|
|
for ($i = 0; $i < 32; $i = $i + 8) {
|
|
$block = substr($ipBaseBin, $i, 8);
|
|
if ($i > 0) {
|
|
$ipBase .= ".";
|
|
}
|
|
$ipBase .= bindec($block);
|
|
}
|
|
} else {
|
|
$ipBase = "";
|
|
for ($i = 0; $i < 128; $i = $i + 8) {
|
|
$block = substr($ipBaseBin, $i, 8);
|
|
if ($i > 0 && $i % 16 == 0) {
|
|
$ipBase .= ":";
|
|
}
|
|
$ipBase .= sprintf("%02x", bindec($block));
|
|
}
|
|
$ipBase = $this->compressIP($ipBase);
|
|
}
|
|
return $ipBase;
|
|
}
|
|
}
|