-
Notifications
You must be signed in to change notification settings - Fork 26
Home
IPv4/IPv6 manipulation library for PHP. This library is inspired by Python ipaddress.
Feel free to read the source code for more info.
This documentation applies to version >= 3.0.
The IPv4
and IPv6
objects provide a way to create and manipulate IP Addresses. They both inherit from IP
.
+------+ | IP | +------+ | | +---+ +---+ | | +------+ +------+ | IPv4 | | IPv6 | +------+ +------+
IP
instances can be created from many different base types and representations. Each method is available for IPv4
and IPv6
class.
The most common use case is to create an instance from a human-readable string representation of an IP address.
$ip = IPv4::createFromString('192.168.0.1');
$ip = IPv6::createFromString('2001:db8::');
A InvalidArgumentException
will be thrown in the value provided cannot be converted into an IP address.
$ip = IPv4::createFromString('2001:db8::');
// InvalidArgumentException: The string "2001:db8::" is not a valid IPv4 address.
It is/was relatively common to represent IP addresses as integer, for example using ip2long
, especially for storage of IPv4 in a database.
However is isn't as practical with IPv6, because there is a risk to go over the max int value even on 64-bits systems (PHP_INT_MAX
).
When this happens PHP will implicitely convert the integer to a float or double, but this leads to a loss of precision. Read more about Floating point precision on the official doc.
Therefore when using numeric representation, it highly recommended to use numeric strings instead of integers or floats.
-
createFromNumericString
creates an instance from a numeric string containing an positive decimal integer value (a string containing a negative integer will not be accepted). -
createFromInt
creates an instance from an signed decimal integer (such as the result ofip2long
). This method is safe to use on a 64-bit systems with IPv4, but is not recommended for IPv6 as most IPv6 can't fit into an integer. On 32-bit systems, IPv4 will overflow into a negative integer. Negative integers will be converted to unsigned positive. -
createFromFloat
creates an instance from a float/double containing an positive decimal integer value (a negative float/double will not be considered valid). This method exists for backwards compatibility with 32-bit systems and some fringe use cases, but is dangerous for most use cases, especially with IPv6, due to the loss of precision of big float/double numbers.
$ip = IPv4::createFromNumericString('2130706433'); // 127.0.0.1
$ip = IPv4::createFromInt(2130706433); // 127.0.0.1
$ip = IPv6::createFromNumericString('55835404833073476206743540170770874368'); // 2a01:8200::
$ip = IPv6::createFromInt(55835404833073476206743540170770874368); // will not work because it'll be converted to a float
// TypeError: Argument 1 passed to PhpIP\IPv6::createFromInt() must be of the type int, float given
$ip = IPv6::createFromFloat(55835404833073476206743540170770874368); // might or might not work depending on your system - use at your own risk
-
createFromBinaryString
creates an instance from a binary string, such as the result ofinet_pton
. Binary strings must be exactly 4 chars (32 bits) for IPv4 and 16 chars (128 bits) for IPv6. -
createFromGmp
creates from a GMP object
IP addresses can be created auto-magically either by calling directly the constructor of IPv4
or IPv6
, or using the convenience factory method IP::create($ip)
.
In this case the library will attempt to guess the type of the input parameter and generate the appropriate IP
instance.
$ip = new IPv4('192.168.0.1');
$ip = new IPv6('2001:db8::');
$ip = new IPv6('::192.168.0.0'); // IPV4-mapped IPv6
$ip = new IPv6('::ffff:192.168.0.0'); // IPV4-mapped IPv6
$ip = IP::create('192.168.0.1'); // return IPv4
$ip = IP::create('2001:db8::'); // return IPv6
The implicit creation with create
and constructor methods are safe and convenient to use as long as you work with a string representing a human readable IP address.
This is equivalent to createFromString
.
However with every other types, there are some caveats with makes the auto-detection not recommended unless you are sure what you are doing.
-
IP::create()
will returnIPv4
by default for integers less than 2^32. If you work withIPv6
or both versions, you might want to useIPv6
constructors or an explicit create method. - Binary strings (such as the result of
inet_pton
) will only work withIPv4
. Auto-detection of binary string are not supported with IPv6 due to the risk of confusion with regular string representation of an abbreviated IPv6. See bug #57 for more in-depth info on this topic.
$ip = IP::create(294967295); // 17.148.215.255
$ip = IP::create("\000\000\000*"): // 0.0.0.42
Additionally, the same warning as for the explicit create methods apply:
- With an integer there is a risk of overflow, particularly with IPv6. (same warning as
createFromInt
) - With a float/double containing there is a risk of loss of precision and unpredictable results, particularly with IPv6. (same warning as
createFromFloat
).
A InvalidArgumentException
will be thrown in the value provided cannot be converted into an IP address.
IPv4 and IPv6 objects are convertible to string by default. You can also explicitly generate a string representation with humanReadable($short_form)
method.
The parameter $short_form
(default true
) indicates whether or not to display a short version of the address.
$ip = new IPv4(294967295);
echo $ip; // 17.148.215.255
echo $ip->humanReadable(false); // 017.148.215.255
$ip = new IPv6('2a01:8200::');
echo $ip; // 2a01:8200::
echo $ip->humanReadable(false); // 2a01:8200:0000:0000:0000:0000:0000:0000
Note: IPv4-mapped IPv6 will be displayed as plain IPv6 in uncompressed mode.
$ip = new IPv6('::ffff:192.168.0.0');
echo $ip; // ::ffff:192.168.0.0
echo $ip->humanReadable(false),"\n"; // but 0000:0000:0000:0000:0000:ffff:c0a8:0000
Conversion to integer is done with the numeric()
method. Due the limits of the integer type in PHP, this method will return a numeric string, not an actual integer.
This method accepts an optional parameter $base
. Default is to return in base 10 (decimal).
$ip = new IPv4('127.0.0.0');
echo $ip->numeric(); // '2130706432'
echo $ip->numeric(2); // '1111111000000000000000000000000'
echo $ip->numeric(16); // '7f000000'
$ip = new IPv6('2a01:8200::');
echo $ip->numeric(); // '55835404833073476206743540170770874368'
echo $ip->numeric(2); // '101010000000011000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
echo $ip->numeric(16); // '2a018200000000000000000000000000'
The binary()
method returns the IP address as a binary string, identical to what inet_pton
would return. This could be used to insert into a MySQL VARBINARY
field for example.
$ip = new IPv6('2a01:8200::');
$ip->binary(); // this is a binary string
PHP doesn't support overloading of operators, so you have to call the methods directly. All methods accepts any data type that can be converted into a IP address.
$ip = new IPv4('127.0.0.0');
echo $ip->plus(1); // 127.0.0.1
echo $ip->minus(1); // 126.255.255.255
Operators will throw a OutOfBoundException
if you reach the boundaries of the given IP address (for example, trying to add 1
to 255.255.255.255
).
$ip = new IPv4('127.0.0.0');
echo $ip->bit_or('255.255.0.0'); // 255.255.0.0
echo $ip->bit_and('255.255.0.0'); // 127.0.0.0
echo $ip->bit_xor('255.255.0.0'); // 128.255.0.0
echo $ip->bit_negate(); // 128.255.255.255
Name | Description |
---|---|
getVersion() |
Return the IP version (4 or 6) |
isReserved() |
Return true if the address is reserved in the IANA special-purpose address registry |
isPrivate() |
Return true if the address is specifically reserved for private (forwardable, non globally routable) networks |
isPublic() |
Return true if the address is allocated for public networks |
reversePointer() |
The name of the reverse DNS PTR record for the IP address. Example IP::create('212.212.204.85')->reversePointer(); // '85.204.212.212.in-addr.arpa.
|
isLinkLocal() |
Return true if the address is a link-local addresses |
isLoopback() |
Return true if the address is a loopback addresses |
matches($ip, $mask) |
Perform wildcard mask matching common in network Access Control Lists and OSPF dynamic routing. |
The IPv4Block
and IPv6Block
objects provide a way to create and manipulate IP networks. They use the CIDR block notation (e.g. 192.168.0.0/24
).
They both inherit from IPBlock
.
+-----------+ | IPBlock | +-----------+ | | +------+ +------+ | | +-----------+ +-----------+ | IPv4Block | | IPv6Block | +-----------+ +-----------+
Like IP addresses, blocks can be created either by instantiating directly IPv4Block
or IPv6Block
, or by using the convenience factory method IPBlock::create()
.
$block = new IPv4Block('128.0.0.0/16');
$block = new IPv4Block('128.0.0.0', '16'); // alternate way of calling the constructor
$block = new IPv6Block('2001:0db8::/32');
$block = new IPv6Block('2001:0db8::', '32'); // alternate way of calling the constructor
$block = IPBlock::create('128.0.0.0/16'); // IPv4Block
- The IP parameter can be anything that can be converted into an IP address (string, integer, etc.)
- The prefix must be an integer between 0 and 32 (IPv4) or 0 and 128 (IPv6)
These methods are available statically on IPv4Block
and IPv6Block
classes.
Name | Description |
---|---|
getReservedBlocks() |
Return an array containing all the reserved blocks defined in this version of the IP protocol as per the IANA special-purpose address registry |
getPrivateBlocks() |
Return an array containing all only the private (forwardable, non globally routable) blocks defined in this version of the IP protocol |
getLoopbackBlock() |
Return the loopback block of this version of the IP protocol |
getLinkLocalBlock() |
Return the link-local block of this version of the IP protocol. |
Example:
echo IPv6Block::getLinkLocalBlock(); // fe80::/10
Name | Description |
---|---|
getFirstIp() , getNetworkAddress()
|
Return the first IP of the block, also known as the network address |
getLastIp() , getBroadcastAddress()
|
Return the last IP of the block, also known as the broadcast address |
getNetmask() |
Return the netmask as an IP object |
getDelta() |
Return the delta to last IP of the block, also known as "host mask" as an IP object |
getNbAddresses() , count()
|
Return the number of IP addresses in the block. Because this number can be huge, this returns a numeric string, not an actual integer. |
getGivenIp() |
Return the IP that was used to create the block |
getPrefixLength() |
Return the prefix length of the bloc |
getMaxPrefixLength() |
Return the maximum allowed prefix length for this type of block based on the IP version (constant) |
getVersion() |
Return the IP version of the block (4 or 6) |
Example:
$block = new IPv4Block('128.0.0.0/16');
echo $block->getNetmask(); // 255.255.0.0
echo $block->getDelta(); // 0.0.255.255
echo $block->getFirstIp(); // 128.0.0.0
echo $block->getLastIp(); // 128.0.255.255
echo $block->getNbAddresses(); // '65536'
$block = new IPv6Block('2001:0db8::/32');
echo $block->getNetmask(); // ffff:ffff::
echo $block->getDelta(); // ::ffff:ffff:ffff:ffff:ffff:ffff
echo $block->getFirstIp(); // 2001:db8::
echo $block->getLastIp(); // 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff
echo $block->getNbAddresses(); // '79228162514264337593543950336'
Like IP addresses, you can make addition and subtractions with blocks. You cannot however do bitwise operations.
$block = new IPv4Block('192.168.0.0/24');
echo $block->plus(42); // 192.168.42.0/24
echo $block->minus(42); // 192.167.214.0/24
Operators will throw a OutOfBoundException
if you reach the boundaries of the given IP version (for example, if you try to add 256
to 255.255.255.0/24
).
IP blocks are containers for IP addresses or other IP blocks. You can test whether a block contains another block or IP, or
is contained by another block using contains
(or containsIP()
/containsBlock()
) and isIn
. The method isIn
is also available for IP objects, to test if a given IP is in a given block.
The method overlaps
returns true if the block overlaps another block, whether is is bigger or smaller.
Example:
$block = IPBlock::create('192.168.0.0/24');
$block->contains('192.168.0.42'); // true
$block->contains('192.168.1.0/24'); // false
$block->isIn('192.168.0.0/16'); // true
$block->overlaps('192.168.0.0/16'); // true
$ip = IP::create('192.168.0.42');
$ip->isIn($block); // true
IP addresses contained in a block can be iterated with foreach
directly using the block object.
$block = IPBlock::create('192.168.0.0/24');
foreach ( $block as $ip ) {
echo $ip,"\n";
}
// outputs:
// 192.168.0.0
// 192.168.0.1
// 192.168.0.2
// ...
// 192.168.0.255
It's also possible to access an IP address directly using array notation.
$block = IPBlock::create('192.168.0.0/24');
echo $block[0]; // 192.168.0.0
echo $block[42]; // 192.168.0.42
$block = IPBlock::create('2001:db8::/32');
echo $block['79228162514264337543950335']; // 2001:db8:41:8937:4bc6:a7ef:9abd:6fff
Trying to access an offset outside of the block will throw a OutOfBoundsException
.
Note: It's not possible to use array notation to set values inside the block.
Blocks can be split into smaller blocks with the getSubblocks($prefix)
method. This method returns a IPBlockIterator
object, so you can loop with foreach
. The value of $prefix
must be greater than the current block prefix. For example, you can split a /16 into /24, but not the other way around. Note that $prefix
accepts an optional leading '/', e.g. you can pass "/24" instead of "24" if you find it clearer.
$blocks = IPBlock::create('192.168.0.0/16')->getSubBlocks('/24');
echo $blocks->count(),"\n"; // 256
foreach ( $blocks as $block ) {
echo $block,"\n";
}
// outputs:
// 192.168.0.0/24
// 192.168.1.0/24
// 192.168.2.0/24
// ...
// 192.168.255.0/24
The block containing the current block can be obtained with getSuperBlock($prefix)
.
$block = IPBlock::create('192.168.42.0/24');
echo $block->getSuperBlock('/16'); // 192.168.0.0