465 lines
14 KiB
PHP
465 lines
14 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Class to provide IPv4 calculations
|
||
|
*
|
||
|
* PHP versions 4 and 5
|
||
|
*
|
||
|
* LICENSE: This source file is subject to version 3.01 of the PHP license
|
||
|
* that is available through the world-wide-web at the following URI:
|
||
|
* http://www.php.net/license/3_01.txt. If you did not receive a copy of
|
||
|
* the PHP License and are unable to obtain it through the web, please
|
||
|
* send a note to license@php.net so we can mail you a copy immediately.
|
||
|
*
|
||
|
* @category Net
|
||
|
* @package Net_IPv4
|
||
|
* @author Eric Kilfoil <edk@ypass.net>
|
||
|
* @author Marco Kaiser <bate@php.net>
|
||
|
* @author Florian Anderiasch <fa@php.net>
|
||
|
* @copyright 1997-2005 The PHP Group
|
||
|
* @license http://www.php.net/license/3_01.txt PHP License 3.01
|
||
|
* @version CVS: $Id: IPv4.php,v 1.11 2005/11/29 12:56:35 fa Exp $
|
||
|
* @link http://pear.php.net/package/Net_IPv4
|
||
|
*/
|
||
|
|
||
|
require_once 'PEAR.php';
|
||
|
|
||
|
// {{{ GLOBALS
|
||
|
/**
|
||
|
* Map of bitmasks to subnets
|
||
|
*
|
||
|
* This array contains every valid netmask. The index of the dot quad
|
||
|
* netmask value is the corresponding CIDR notation (bitmask).
|
||
|
*
|
||
|
* @global array $GLOBALS['Net_IPv4_Netmask_Map']
|
||
|
*/
|
||
|
$GLOBALS['Net_IPv4_Netmask_Map'] = array(
|
||
|
0 => "0.0.0.0",
|
||
|
1 => "128.0.0.0",
|
||
|
2 => "192.0.0.0",
|
||
|
3 => "224.0.0.0",
|
||
|
4 => "240.0.0.0",
|
||
|
5 => "248.0.0.0",
|
||
|
6 => "252.0.0.0",
|
||
|
7 => "254.0.0.0",
|
||
|
8 => "255.0.0.0",
|
||
|
9 => "255.128.0.0",
|
||
|
10 => "255.192.0.0",
|
||
|
11 => "255.224.0.0",
|
||
|
12 => "255.240.0.0",
|
||
|
13 => "255.248.0.0",
|
||
|
14 => "255.252.0.0",
|
||
|
15 => "255.254.0.0",
|
||
|
16 => "255.255.0.0",
|
||
|
17 => "255.255.128.0",
|
||
|
18 => "255.255.192.0",
|
||
|
19 => "255.255.224.0",
|
||
|
20 => "255.255.240.0",
|
||
|
21 => "255.255.248.0",
|
||
|
22 => "255.255.252.0",
|
||
|
23 => "255.255.254.0",
|
||
|
24 => "255.255.255.0",
|
||
|
25 => "255.255.255.128",
|
||
|
26 => "255.255.255.192",
|
||
|
27 => "255.255.255.224",
|
||
|
28 => "255.255.255.240",
|
||
|
29 => "255.255.255.248",
|
||
|
30 => "255.255.255.252",
|
||
|
31 => "255.255.255.254",
|
||
|
32 => "255.255.255.255"
|
||
|
);
|
||
|
// }}}
|
||
|
// {{{ Net_IPv4
|
||
|
|
||
|
/**
|
||
|
* Class to provide IPv4 calculations
|
||
|
*
|
||
|
* Provides methods for validating IP addresses, calculating netmasks,
|
||
|
* broadcast addresses, network addresses, conversion routines, etc.
|
||
|
*
|
||
|
* @category Net
|
||
|
* @package Net_IPv4
|
||
|
* @author Eric Kilfoil <edk@ypass.net>
|
||
|
* @author Marco Kaiser <bate@php.net>
|
||
|
* @author Florian Anderiasch <fa@php.net>
|
||
|
* @copyright 1997-2005 The PHP Group
|
||
|
* @license http://www.php.net/license/3_01.txt PHP License 3.01
|
||
|
* @version CVS: @package_version@
|
||
|
* @link http://pear.php.net/package/Net_IPv4
|
||
|
* @access public
|
||
|
*/
|
||
|
class Net_IPv4
|
||
|
{
|
||
|
// {{{ properties
|
||
|
var $ip = "";
|
||
|
var $bitmask = false;
|
||
|
var $netmask = "";
|
||
|
var $network = "";
|
||
|
var $broadcast = "";
|
||
|
var $long = 0;
|
||
|
|
||
|
// }}}
|
||
|
// {{{ validateIP()
|
||
|
|
||
|
/**
|
||
|
* Validate the syntax of the given IP adress
|
||
|
*
|
||
|
* Using the PHP long2ip() and ip2long() functions, convert the IP
|
||
|
* address from a string to a long and back. If the original still
|
||
|
* matches the converted IP address, it's a valid address. This
|
||
|
* function does not allow for IP addresses to be formatted as long
|
||
|
* integers.
|
||
|
*
|
||
|
* @param string $ip IP address in the format x.x.x.x
|
||
|
* @return bool true if syntax is valid, otherwise false
|
||
|
*/
|
||
|
static function validateIP($ip)
|
||
|
{
|
||
|
if ($ip == long2ip(ip2long($ip))) {
|
||
|
return true;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ check_ip()
|
||
|
|
||
|
/**
|
||
|
* Validate the syntax of the given IP address (compatibility)
|
||
|
*
|
||
|
* This function is identical to Net_IPv4::validateIP(). It is included
|
||
|
* merely for compatibility reasons.
|
||
|
*
|
||
|
* @param string $ip IP address
|
||
|
* @return bool true if syntax is valid, otherwise false
|
||
|
*/
|
||
|
function check_ip($ip)
|
||
|
{
|
||
|
return $this->validateIP($ip);
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ validateNetmask()
|
||
|
|
||
|
/**
|
||
|
* Validate the syntax of a four octet netmask
|
||
|
*
|
||
|
* There are 33 valid netmask values. This function will compare the
|
||
|
* string passed as $netmask to the predefined 33 values and return
|
||
|
* true or false. This is most likely much faster than performing the
|
||
|
* calculation to determine the validity of the netmask.
|
||
|
*
|
||
|
* @param string $netmask Netmask
|
||
|
* @return bool true if syntax is valid, otherwise false
|
||
|
*/
|
||
|
function validateNetmask($netmask)
|
||
|
{
|
||
|
if (! in_array($netmask, $GLOBALS['Net_IPv4_Netmask_Map'])) {
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ parseAddress()
|
||
|
|
||
|
/**
|
||
|
* Parse a formatted IP address
|
||
|
*
|
||
|
* Given a network qualified IP address, attempt to parse out the parts
|
||
|
* and calculate qualities of the address.
|
||
|
*
|
||
|
* The following formats are possible:
|
||
|
*
|
||
|
* [dot quad ip]/[ bitmask ]
|
||
|
* [dot quad ip]/[ dot quad netmask ]
|
||
|
* [dot quad ip]/[ hex string netmask ]
|
||
|
*
|
||
|
* The first would be [IP Address]/[BitMask]:
|
||
|
* 192.168.0.0/16
|
||
|
*
|
||
|
* The second would be [IP Address] [Subnet Mask in dot quad notation]:
|
||
|
* 192.168.0.0/255.255.0.0
|
||
|
*
|
||
|
* The third would be [IP Address] [Subnet Mask as Hex string]
|
||
|
* 192.168.0.0/ffff0000
|
||
|
*
|
||
|
* Usage:
|
||
|
*
|
||
|
* $cidr = '192.168.0.50/16';
|
||
|
* $net = Net_IPv4::parseAddress($cidr);
|
||
|
* echo $net->network; // 192.168.0.0
|
||
|
* echo $net->ip; // 192.168.0.50
|
||
|
* echo $net->broadcast; // 192.168.255.255
|
||
|
* echo $net->bitmask; // 16
|
||
|
* echo $net->long; // 3232235520 (long/double version of 192.168.0.50)
|
||
|
* echo $net->netmask; // 255.255.0.0
|
||
|
*
|
||
|
* @param string $ip IP address netmask combination
|
||
|
* @return object true if syntax is valid, otherwise false
|
||
|
*/
|
||
|
static function parseAddress($address)
|
||
|
{
|
||
|
$myself = new Net_IPv4;
|
||
|
if (strchr($address, "/")) {
|
||
|
$parts = explode("/", $address);
|
||
|
if (! $myself->validateIP($parts[0])) {
|
||
|
return PEAR::raiseError("invalid IP address");
|
||
|
}
|
||
|
$myself->ip = $parts[0];
|
||
|
|
||
|
// Check the style of netmask that was entered
|
||
|
/*
|
||
|
* a hexadecimal string was entered
|
||
|
*/
|
||
|
//if (eregi("^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$", $parts[1], $regs)) {
|
||
|
if (preg_match("/^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i", $parts[1], $regs)) {
|
||
|
// hexadecimal string
|
||
|
$myself->netmask = hexdec($regs[1]) . "." . hexdec($regs[2]) . "." .
|
||
|
hexdec($regs[3]) . "." . hexdec($regs[4]);
|
||
|
|
||
|
/*
|
||
|
* a standard dot quad netmask was entered.
|
||
|
*/
|
||
|
} else if (strchr($parts[1], ".")) {
|
||
|
if (! $myself->validateNetmask($parts[1])) {
|
||
|
return PEAR::raiseError("invalid netmask value");
|
||
|
}
|
||
|
$myself->netmask = $parts[1];
|
||
|
|
||
|
/*
|
||
|
* a CIDR bitmask type was entered
|
||
|
*/
|
||
|
} else if ($parts[1] >= 0 && $parts[1] <= 32) {
|
||
|
// bitmask was entered
|
||
|
$myself->bitmask = $parts[1];
|
||
|
|
||
|
/*
|
||
|
* Some unknown format of netmask was entered
|
||
|
*/
|
||
|
} else {
|
||
|
return PEAR::raiseError("invalid netmask value");
|
||
|
}
|
||
|
$myself->calculate();
|
||
|
return $myself;
|
||
|
} else if ($myself->validateIP($address)) {
|
||
|
$myself->ip = $address;
|
||
|
return $myself;
|
||
|
} else {
|
||
|
return PEAR::raiseError("invalid IP address");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ calculate()
|
||
|
|
||
|
/**
|
||
|
* Calculates network information based on an IP address and netmask.
|
||
|
*
|
||
|
* Fully populates the object properties based on the IP address and
|
||
|
* netmask/bitmask properties. Once these two fields are populated,
|
||
|
* calculate() will perform calculations to determine the network and
|
||
|
* broadcast address of the network.
|
||
|
*
|
||
|
* @return mixed true if no errors occured, otherwise PEAR_Error object
|
||
|
*/
|
||
|
function calculate()
|
||
|
{
|
||
|
$validNM = $GLOBALS['Net_IPv4_Netmask_Map'];
|
||
|
|
||
|
if (! is_a($this, "net_ipv4")) {
|
||
|
$myself = new Net_IPv4;
|
||
|
return PEAR::raiseError("cannot calculate on uninstantiated Net_IPv4 class");
|
||
|
}
|
||
|
|
||
|
/* Find out if we were given an ip address in dot quad notation or
|
||
|
* a network long ip address. Whichever was given, populate the
|
||
|
* other field
|
||
|
*/
|
||
|
if (strlen($this->ip)) {
|
||
|
if (! $this->validateIP($this->ip)) {
|
||
|
return PEAR::raiseError("invalid IP address");
|
||
|
}
|
||
|
$this->long = $this->ip2double($this->ip);
|
||
|
} else if (is_numeric($this->long)) {
|
||
|
$this->ip = long2ip($this->long);
|
||
|
} else {
|
||
|
return PEAR::raiseError("ip address not specified");
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check to see if we were supplied with a bitmask or a netmask.
|
||
|
* Populate the other field as needed.
|
||
|
*/
|
||
|
if (strlen($this->bitmask)) {
|
||
|
$this->netmask = $validNM[$this->bitmask];
|
||
|
} else if (strlen($this->netmask)) {
|
||
|
$validNM_rev = array_flip($validNM);
|
||
|
$this->bitmask = $validNM_rev[$this->netmask];
|
||
|
} else {
|
||
|
return PEAR::raiseError("netmask or bitmask are required for calculation");
|
||
|
}
|
||
|
$this->network = long2ip(ip2long($this->ip) & ip2long($this->netmask));
|
||
|
$this->broadcast = long2ip(ip2long($this->ip) |
|
||
|
(ip2long($this->netmask) ^ ip2long("255.255.255.255")));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getNetmask()
|
||
|
|
||
|
function getNetmask($length)
|
||
|
{
|
||
|
if (! PEAR::isError($ipobj = Net_IPv4::parseAddress("0.0.0.0/" . $length))) {
|
||
|
$mask = $ipobj->netmask;
|
||
|
unset($ipobj);
|
||
|
return $mask;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getNetLength()
|
||
|
|
||
|
function getNetLength($netmask)
|
||
|
{
|
||
|
if (! PEAR::isError($ipobj = Net_IPv4::parseAddress("0.0.0.0/" . $netmask))) {
|
||
|
$bitmask = $ipobj->bitmask;
|
||
|
unset($ipobj);
|
||
|
return $bitmask;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ getSubnet()
|
||
|
|
||
|
function getSubnet($ip, $netmask)
|
||
|
{
|
||
|
if (! PEAR::isError($ipobj = Net_IPv4::parseAddress($ip . "/" . $netmask))) {
|
||
|
$net = $ipobj->network;
|
||
|
unset($ipobj);
|
||
|
return $net;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ inSameSubnet()
|
||
|
|
||
|
function inSameSubnet($ip1, $ip2)
|
||
|
{
|
||
|
if (! is_object($ip1) || strcasecmp(get_class($ip1), 'net_ipv4') <> 0) {
|
||
|
$ipobj1 = Net_IPv4::parseAddress($ip1);
|
||
|
if (PEAR::isError($ipobj)) {
|
||
|
return PEAR::raiseError("IP addresses must be an understood format or a Net_IPv4 object");
|
||
|
}
|
||
|
}
|
||
|
if (! is_object($ip2) || strcasecmp(get_class($ip2), 'net_ipv4') <> 0) {
|
||
|
$ipobj2 = Net_IPv4::parseAddress($ip2);
|
||
|
if (PEAR::isError($ipobj)) {
|
||
|
return PEAR::raiseError("IP addresses must be an understood format or a Net_IPv4 object");
|
||
|
}
|
||
|
}
|
||
|
if ($ipobj1->network == $ipobj2->network &&
|
||
|
$ipobj1->bitmask == $ipobj2->bitmask) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ atoh()
|
||
|
|
||
|
/**
|
||
|
* Converts a dot-quad formatted IP address into a hexadecimal string
|
||
|
* @param string $addr IP-adress in dot-quad format
|
||
|
* @return mixed false if invalid IP and hexadecimal representation as string if valid
|
||
|
*/
|
||
|
function atoh($addr)
|
||
|
{
|
||
|
if (! Net_IPv4::validateIP($addr)) {
|
||
|
return false;
|
||
|
}
|
||
|
$ap = explode(".", $addr);
|
||
|
return sprintf("%02x%02x%02x%02x", $ap[0], $ap[1], $ap[2], $ap[3]);
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ htoa()
|
||
|
|
||
|
/**
|
||
|
* Converts a hexadecimal string into a dot-quad formatted IP address
|
||
|
* @param string $addr IP-adress in hexadecimal format
|
||
|
* @return mixed false if invalid IP and dot-quad formatted IP as string if valid
|
||
|
*/
|
||
|
function htoa($addr)
|
||
|
{
|
||
|
//if (eregi("^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$",
|
||
|
if (preg_match("/^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i",
|
||
|
$addr, $regs)) {
|
||
|
return hexdec($regs[1]) . "." . hexdec($regs[2]) . "." .
|
||
|
hexdec($regs[3]) . "." . hexdec($regs[4]);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ ip2double()
|
||
|
|
||
|
/**
|
||
|
* Converts an IP address to a PHP double. Better than ip2long because
|
||
|
* a long in PHP is a signed integer.
|
||
|
* @param string $ip dot-quad formatted IP adress
|
||
|
* @return float IP adress as double - positive value unlike ip2long
|
||
|
*/
|
||
|
static function ip2double($ip)
|
||
|
{
|
||
|
return (double)(sprintf("%u", ip2long($ip)));
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
// {{{ ipInNetwork()
|
||
|
|
||
|
/**
|
||
|
* Determines whether or not the supplied IP is within the supplied network.
|
||
|
*
|
||
|
* This function determines whether an IP address is within a network.
|
||
|
* The IP address ($ip) must be supplied in dot-quad format, and the
|
||
|
* network ($network) may be either a string containing a CIDR
|
||
|
* formatted network definition, or a Net_IPv4 object.
|
||
|
*
|
||
|
* @param string $ip A dot quad representation of an IP address
|
||
|
* @param string $network A string representing the network in CIDR format or a Net_IPv4 object.
|
||
|
* @return bool true if the IP address exists within the network
|
||
|
*/
|
||
|
static function ipInNetwork($ip, $network)
|
||
|
{
|
||
|
if (! is_object($network) || strcasecmp(get_class($network), 'net_ipv4') <> 0) {
|
||
|
$network = Net_IPv4::parseAddress($network);
|
||
|
}
|
||
|
|
||
|
if ( !is_object($network) OR ( is_object($network) AND ( !isset($network->network) OR !isset($network->broadcast) ) ) ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$net = Net_IPv4::ip2double($network->network);
|
||
|
$bcast = Net_IPv4::ip2double($network->broadcast);
|
||
|
$ip = Net_IPv4::ip2double($ip);
|
||
|
unset($network);
|
||
|
if ($ip >= $net && $ip <= $bcast) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
}
|
||
|
|
||
|
// }}}
|
||
|
|
||
|
/*
|
||
|
* vim: sts=4 ts=4 sw=4 cindent fdm=marker
|
||
|
*/
|
||
|
?>
|