Reputation: 10581
Currently I have two ways of calculating IPv4 long-form integers:
//IPv4 format: w.x.y.z
$ip_number = (16777216 * $w) + (65536 * $x) + (256 * $y) + $z;
$ip_number = ip2long($ip);
But how do I calculate IPv6 into a long-form integer?
I'm looking for a function or something that doesn't require me to install any extensions to PHP.
Edit:
I need the long form integer so I can compare it for an IP range query. Here's an example row for a IPv6 range query:
"58569075684585412230123897272863293440","58569076873007849944088961176022548479","MU","Mauritius"
Upvotes: 1
Views: 1410
Reputation: 10581
Ok, here's how I eventually solved it:
function ipaddress_to_ipnumber($ipaddress) {
$pton = @inet_pton($ipaddress);
if (!$pton) { return false; }
$number = '';
foreach (unpack('C*', $pton) as $byte) {
$number .= str_pad(decbin($byte), 8, '0', STR_PAD_LEFT);
}
return base_convert(ltrim($number, '0'), 2, 10);
}
https://inkplant.com/code/ipv6-to-number
Upvotes: 0
Reputation: 40156
Storing in long is not a proper way for that. Use,
string inet_ntop ( string $in_addr )
This function converts a 32bit IPv4, or 128bit IPv6 address (if PHP was built with IPv6 support enabled) into an address family appropriate string representation.
You should also see,
string inet_pton ( string $address )
<?php
$packed = chr(127) . chr(0) . chr(0) . chr(1);
$expanded = inet_ntop($packed);
/* Outputs: 127.0.0.1 */
echo $expanded;
$packed = str_repeat(chr(0), 15) . chr(1);
$expanded = inet_ntop($packed);
/* Outputs: ::1 */
echo $expanded;
?>
The following two functions were introduced in PHP 5.1.0, inet_pton
and inet_pton
. Their purpose is to convert human readable IP addresses into their packed in_addr
representation. Since the result is not pure binary, we need to use the unpack
function in order to apply bitwise operators.
Both functions support IPv6 as well as IPv4. The only difference is how you unpack the address from the results. With IPv6, you will unpack with contents with A16, and with IPv4, you will unpack with A4.
To put the previous in a perspective here is a little sample output to help clarify:
// Our Example IP's
$ip4= "10.22.99.129";
$ip6= "fe80:1:2:3:a:bad:1dea:dad";
// ip2long examples
var_dump( ip2long($ip4) ); // int(169239425)
var_dump( ip2long($ip6) ); // bool(false)
// inet_pton examples
var_dump( inet_pton( $ip4 ) ); // string(4)
var_dump( inet_pton( $ip6 ) ); // string(16)
We demonstrate above that the inet_* family supports both IPv6 and v4. Our next step will be to translate the packed result into an unpacked variable.
// Unpacking and Packing
$_u4 = current( unpack( "A4", inet_pton( $ip4 ) ) );
var_dump( inet_ntop( pack( "A4", $_u4 ) ) ); // string(12) "10.22.99.129"
$_u6 = current( unpack( "A16", inet_pton( $ip6 ) ) );
var_dump( inet_ntop( pack( "A16", $_u6 ) ) ); //string(25) "fe80:1:2:3:a:bad:1dea:dad"
Note : The current function returns the first index of an array. It is equivelant to saying $array[0].
After the unpacking and packing, we can see we achieved the same result as input. This is a simple proof of concept to ensure we are not losing any data.
Finally use,
if ($ip <= $high_ip && $low_ip <= $ip) {
echo "in range";
}
Reference: php.net
Upvotes: 2