ip2long

(PHP 4, PHP 5, PHP 7, PHP 8)

ip2long将包含 (IPv4) Internet 协议点分十进制地址的字符串转换为长整型

描述

ip2long(string $ip): int|false

函数 ip2long() 从其 Internet 标准格式(点分十进制字符串)表示中生成 IPv4 Internet 网络地址的长整型表示。

ip2long() 也适用于不完整的 IP 地址。阅读 » http://ps-2.kev009.com/wisclibrary/aix52/usr/share/man/info/en_US/a_doc_lib/libs/commtrf2/inet_addr.htm 获取更多信息。

参数

ip

标准格式地址。

返回值

返回长整型,如果 ip 无效,则返回 false

范例

范例 #1 ip2long() 范例

<?php
$ip
= gethostbyname('www.example.com');
$out = "以下 URL 相当于:<br />\n";
$out .= 'http://www.example.com/, http://' . $ip . '/, and http://' . sprintf("%u", ip2long($ip)) . "/<br />\n";
echo
$out;
?>

范例 #2 显示 IP 地址

第二个范例展示了如何使用 printf() 函数打印转换后的地址

<?php
$ip
= gethostbyname('www.example.com');
$long = ip2long($ip);

if (
$long == -1 || $long === FALSE) {
echo
'无效 IP,请重试';
} else {
echo
$ip . "\n"; // 192.0.34.166
echo $long . "\n"; // 3221234342 (-1073732954 on 32-bit systems, due to integer overflow)
printf("%u\n", ip2long($ip)); // 3221234342
}
?>

注释

注意:

由于 PHP 的 int 类型是有符号的,并且许多 IP 地址在 32 位架构上会导致负整数,因此您需要使用 sprintf()printf() 的 "%u" 格式化程序来获取无符号 IP 地址的字符串表示。

注意:

ip2long() 在 32 位系统上会为 IP 255.255.255.255 返回 -1,因为整数值溢出了。

参见

  • long2ip() - 将长整型地址转换为 (IPv4) Internet 标准点分十进制格式的字符串
  • sprintf() - 返回格式化的字符串

添加备注

用户贡献备注 25 个备注

32
joe at joeceresini dot com
14 年前
将网络掩码(例如:255.255.255.240)转换为 CIDR 掩码(例如:/28)的快速方法

<?php
function mask2cidr($mask){
$long = ip2long($mask);
$base = ip2long('255.255.255.255');
return
32-log(($long ^ $base)+1,2);

/* 异或运算将为您提供反向掩码,
该值的以 2 为底的对数 + 1 将返回
掩码中关闭的位数,从
32 中减去得到 CIDR 表示 */

}
?>
19
Mike B
6 年前
<?php
/*
给定一个 IP 地址和子网掩码,
通过使用按位运算符确定子网地址、广播地址和通配符掩码

参考: https://php.net/manual/en/language.operators.bitwise.php
*/

$ip='10.10.10.7';
$mask='255.255.255.0';
$wcmask=long2ip( ~ip2long($mask) );
$subnet=long2ip( ip2long($ip) & ip2long($mask) );
$bcast=long2ip( ip2long($ip) | ip2long($wcmask) );
echo
"给定地址 $ip 和掩码 $mask, \n" .
"子网是 $subnet 广播是 $bcast \n" .
"通配符掩码是 $wcmask";

/*
给定地址 10.10.10.7 和掩码 255.255.255.0,
子网是 10.10.10.0 广播是 10.10.10.255
通配符掩码是 0.0.0.255
*/

?>
14
php dot net at kenman dot net
16 年前
致 nate,他建议在 MySQL 数据库中使用 IP 的无符号版本没有理由

我认为这取决于您的应用程序,但我个人认为将 IP 存储为无符号数是有用的,因为 MySQL 有两个本机函数,INET_ATON() 和 INET_NTOA(),它们的工作方式与 ip2long()/long2ip() 相同,_除了_它们生成无符号的对应部分。所以如果你想,你可以这样做

-- IANA Class-B 保留/专用
SELECT * FROM `servers`
WHERE `ip` >= INET_ATON('192.168.0.0')
AND `ip` <= INET_ATON('192.168.255.255');

在我的当前应用程序中,我发现使用 MySQL 内置函数比 PHP 对应函数更容易。

如果您想知道 ATON 和 NTOA 的名称

ATON = 地址到数字,即 ip2long
NTOA = 数字到地址,即 long2ip
6
ir on ir id is at gm ai ld ot co m
16 年前
请记住,在数据库中将 IP 地址存储为整数(而不是十进制格式的 15 个字符的字符串,或十六进制格式的 8 个字符的字符串)要快数百倍。

以 MySQL 数据库对数千(或数百万!)行中的 IP 地址进行搜索为例;您要么对每个条目进行字符串比较,要么进行整数运算。如果您正确地建立索引,使用 INT 而不是 VARCHAR 进行查找速度将快 100 倍。

另请注意,整数在传递到数据库时不需要转义。:)
10
david dot schueler at tel-billig dot de
14 年前
要从广播地址和网络掩码中获取网络地址,只需对其进行 AND 运算。

<?php
// 简单示例
$bcast = ip2long("192.168.178.255");
$smask = ip2long("255.255.255.0");
$nmask = $bcast & $smask;
echo
long2ip($nmask); // 将返回 192.168.178.0
?>

使用此示例,您能够检查给定主机是否在您自己的本地网络中(在 Linux 上)。

<?php
/**
* 检查客户端 IP 是否在我们的服务器子网中
*
* @param string $client_ip
* @param string $server_ip
* @return boolean
*/
function clientInSameSubnet($client_ip=false,$server_ip=false) {
if (!
$client_ip)
$client_ip = $_SERVER['REMOTE_ADDR'];
if (!
$server_ip)
$server_ip = $_SERVER['SERVER_ADDR'];
// 从 ifconfig 中提取广播地址和网络掩码
if (!($p = popen("ifconfig","r"))) return false;
$out = "";
while(!
feof($p))
$out .= fread($p,1024);
fclose($p);
// 这是因为 php.net 的注释功能不允许长行。
//
$match = "/^.*".$server_ip;
$match .= ".*Bcast:(\d{1,3}\.\d{1,3}i\.\d{1,3}\.\d{1,3}).*";
$match .= "Mask:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/im";
if (!
preg_match($match,$out,$regs))
return
false;
$bcast = ip2long($regs[1]);
$smask = ip2long($regs[2]);
$ipadr = ip2long($client_ip);
$nmask = $bcast & $smask;
return ((
$ipadr & $smask) == ($nmask & $smask));
}
?>
3
spinyn at gmail dot com
15 年前
只是想对 kaputt 对将主机与 IP 范围有效匹配的任务的宝贵贡献添加一条评论。如果 IP 的二进制表示形式不包含前导零,则脚本可以正常工作。不幸的是,decbin() 的工作方式似乎是,第一个 IP 四字节的二进制表示形式中的前导零会丢失。如果您尝试匹配清单中的所有可能候选者,这将是一个严重的问题。在这些情况下,需要添加回前导零,才能获得 0-127(或二进制等效值,0-01111111)之间的第一个四字节中的值的准确匹配。

我提出解决此问题的解决方案是以下函数

<?php
function addLeadingZero($ip) {
if ((
$result = (32 - strlen($ip))) > 0)
return
str_repeat("0", $result).$ip;
}
?>
3
one tiger one at gee mail dot comm
17 年前
我编写了一个小函数来验证网络掩码(我们有一个表格,其中输入了给定服务器的网络掩码,我想确保它有效)。希望这有用。

<?php
// 网络掩码验证器 //
function checkNetmask($ip) {
if (!
ip2long($ip)) {
return
false;
} elseif(
strlen(decbin(ip2long($ip))) != 32 && ip2long($ip) != 0) {
return
false;
} elseif(
ereg('01',decbin(ip2long($ip))) || !ereg('0',decbin(ip2long($ip)))) {
return
false;
} else {
return
true;
}
}
?>
5
Karl Rixon
9 年前
手册中指出“ip2long() 也适用于不完整的 IP 地址”,但这是系统相关的,因此不可靠。例如,在我的系统上,ip2long() 会对不完整的地址返回 FALSE

<?php
var_dump
(ip2long("255.255")); // bool(false)
?>

这是因为 ip2long 会使用 inet_pton(如果可用),而 inet_pton 不支持不完整的地址。如果您的系统上没有 inet_pton,则会使用 inet_addr,并且不完整的地址将按说明工作。
2
jpmarcotte at gmail dot com
16 年前
在使用 jbothe 下面的代码和一些“$mask = 0xFFFFFFFF << (32 - $bits)” 类型的代码的组合时,我在 64 位机器上遇到了一些错误。

请记住,当您分析旨在作为 32 位宽(如 IP 地址)的数字时,您可能希望截断它们。不依赖其他库,只需用“& 0xFFFFFFFF”跟踪任何可能导致 64 位机器上结果不同的计算就足够了。

尽管在许多情况下,似乎直接使用“~0 << …” 用于初始移位以创建网络掩码,而不是“0xFFFFFFFF << …” 可能更简单。但是,我不知道它是否能保证进一步的操作按预期工作。
3
Aleksey Kuznetsov
12 年前
不幸的是,sprintf('%u', ...) 级别很低,返回整数值的字符串表示形式而不是整数。
以下是我用来将 IP 转换为与 MySQL 兼容的有符号整数的函数

function ip2int($ip) {
if (!$r = ip2long($ip)) return 0; // 我们希望返回 0 而不是 false,即使在 IP 不正确的情况下
if ($r > 2147483647)
$r-= 4294967296;
return $r; // 正常
}
4
replay111 at tlen dot pl
12 年前
您好,
基于上面的示例,我将 IPFilter 类与 netMatch 函数混合在一起,该函数为我提供了完整的类,用于检查 IP4,包括 CIDR IP 格式

<?php
class IP4Filter {

private static
$_IP_TYPE_SINGLE = 'single';
private static
$_IP_TYPE_WILDCARD = 'wildcard';
private static
$_IP_TYPE_MASK = 'mask';
private static
$_IP_TYPE_CIDR = 'CIDR';
private static
$_IP_TYPE_SECTION = 'section';
private
$_allowed_ips = array();

public function
__construct($allowed_ips) {
$this->_allowed_ips = $allowed_ips;
}

public function
check($ip, $allowed_ips = null) {
$allowed_ips = $allowed_ips ? $allowed_ips : $this->_allowed_ips;

foreach (
$allowed_ips as $allowed_ip) {
$type = $this->_judge_ip_type($allowed_ip);
$sub_rst = call_user_func(array($this, '_sub_checker_' . $type), $allowed_ip, $ip);

if (
$sub_rst) {
return
true;
}
}

return
false;
}

private function
_judge_ip_type($ip) {
if (
strpos($ip, '*')) {
return
self :: $_IP_TYPE_WILDCARD;
}

if (
strpos($ip, '/')) {
$tmp = explode('/', $ip);
if (
strpos($tmp[1], '.')) {
return
self :: $_IP_TYPE_MASK;
} else {
return
self :: $_IP_TYPE_CIDR;
}
}

if (
strpos($ip, '-')) {
return
self :: $_IP_TYPE_SECTION;
}

if (
ip2long($ip)) {
return
self :: $_IP_TYPE_SINGLE;
}

return
false;
}

private function
_sub_checker_single($allowed_ip, $ip) {
return (
ip2long($allowed_ip) == ip2long($ip));
}

private function
_sub_checker_wildcard($allowed_ip, $ip) {
$allowed_ip_arr = explode('.', $allowed_ip);
$ip_arr = explode('.', $ip);
for (
$i = 0; $i < count($allowed_ip_arr); $i++) {
if (
$allowed_ip_arr[$i] == '*') {
return
true;
} else {
if (
false == ($allowed_ip_arr[$i] == $ip_arr[$i])) {
return
false;
}
}
}
}

private function
_sub_checker_mask($allowed_ip, $ip) {
list(
$allowed_ip_ip, $allowed_ip_mask) = explode('/', $allowed_ip);
$begin = (ip2long($allowed_ip_ip) & ip2long($allowed_ip_mask)) + 1;
$end = (ip2long($allowed_ip_ip) | (~ ip2long($allowed_ip_mask))) + 1;
$ip = ip2long($ip);
return (
$ip >= $begin && $ip <= $end);
}

private function
_sub_checker_section($allowed_ip, $ip) {
list(
$begin, $end) = explode('-', $allowed_ip);
$begin = ip2long($begin);
$end = ip2long($end);
$ip = ip2long($ip);
return (
$ip >= $begin && $ip <= $end);
}

private function
_sub_checker_CIDR($CIDR, $IP) {
list (
$net, $mask) = explode('/', $CIDR);
return (
ip2long($IP) & ~((1 << (32 - $mask)) - 1) ) == ip2long($net);
}

}
?>

这段代码对我来说非常有效,所以我要感谢你们所有人!
1
schat
5 年前
抱歉,我刚写错了,抱歉。这是正确的版本。谢谢。

<?php
/**
* 将 CIDR 转换为 IP 范围
* 来自: <https://github.com/www-schat-top>
* @param string $cidr "192.168.0.0/23"
* @return array ["192.168.0.0", "192.168.1.255"]
*/
function cidr2range($cidr){
list(
$subnet, $mask ) = explode( '/', $cidr );
return [
$subnet, long2ip(ip2long($subnet ) | (pow(2,( 32 - $mask ))-1))];
}
?>
3
jwadhams1 at yahoo dot com
15 年前
我想在 kaputt 和 spinyn 的贡献基础上进行构建,我认为它更直观(例如,让 sprintf 处理所有二进制转换和填充,并让 substr_compare 处理修剪和比较)。

<?php
function ip_in_network($ip, $net_addr, $net_mask){
if(
$net_mask <= 0){ return false; }
$ip_binary_string = sprintf("%032b",ip2long($ip));
$net_binary_string = sprintf("%032b",ip2long($net_addr));
return (
substr_compare($ip_binary_string,$net_binary_string,0,$net_mask) === 0);
}

ip_in_network("192.168.2.1","192.168.2.0",24); //true
ip_in_network("192.168.6.93","192.168.0.0",16); //true
ip_in_network("1.6.6.6","128.168.2.0",1); //false
?>
2
rasmus at mindplay dot dk
10 年前
正如其他人所指出的,此函数的返回值在 32 位和 64 位平台上不一致。

在 32 位/64 位平台(以及 Windows)上获得一致的行为的最佳方法是使用最低公分母:将 ip2long() 的返回值强制转换为带符号的 32 位整数,例如:

var_dump(unpack('l', pack('l', ip2long('255.255.255.0'))));

这看起来很愚蠢,但它在所有平台上都提供了始终一致的带符号整数值。

(pack() 和 unpack() 的参数都是小写字母“L”,而不是数字“1”,以防它在您的屏幕上看起来像那样...)
1
oo dot para at gmail dot com
10 年前
如果您想使用此函数验证 IP,请小心
应改用 filter_var 函数来验证 IP。

<?php
$ip
= '192.168.0355.24';
var_dump(ip2long($ip) !== false); // true (预期 false)
var_dump(filter_var($ip, FILTER_VALIDATE_IP) !== false); // false

$ip = '192.168.355.24';
var_dump(ip2long($ip) !== false); // false
var_dump(filter_var($ip, FILTER_VALIDATE_IP) !== false); // false
?>
1
PandoraBox2007 at gmail dot com
12 年前
通用 ip4/ip6

<?php
// 编码 --
function encode_ip ($ip)
{
$d = explode('.', $ip);
if (
count($d) == 4) return sprintf('%02x%02x%02x%02x', $d[0], $d[1], $d[2], $d[3]);

$d = explode(':', preg_replace('/(^:)|(:$)/', '', $ip));
$res = '';
foreach (
$d as $x)
$res .= sprintf('%0'. ($x == '' ? (9 - count($d)) * 4 : 4) .'s', $x);
return
$res;
}

// 解码
function decode_ip($int_ip)
{
function
hexhex($value) { return dechex(hexdec($value)); };

if (
strlen($int_ip) == 32) {
$int_ip = substr(chunk_split($int_ip, 4, ':'), 0, 39);
$int_ip = ':'. implode(':', array_map("hexhex", explode(':',$int_ip))) .':';
preg_match_all("/(:0)+/", $int_ip, $zeros);
if (
count($zeros[0]) > 0) {
$match = '';
foreach(
$zeros[0] as $zero)
if (
strlen($zero) > strlen($match))
$match = $zero;
$int_ip = preg_replace('/'. $match .'/', ':', $int_ip, 1);
}
return
preg_replace('/(^:([^:]))|(([^:]):$)/', '$2$4', $int_ip);
}
$hexipbang = explode('.', chunk_split($int_ip, 2, '.'));
return
hexdec($hexipbang[0]). '.' . hexdec($hexipbang[1]) . '.' . hexdec($hexipbang[2]) . '.' . hexdec($hexipbang[3]);
}
?>

DB
`user_ip` varchar(32) DEFAULT NULL
2
f dot wiessner at smart-weblications dot net
14 年前
这里有一些可用的 ip2long6 和 long2ip6 函数 - 请记住这需要 php gmp-lib

<?php

$ipv6
= "2001:4860:a005::68";

function
ip2long6($ipv6) {
$ip_n = inet_pton($ipv6);
$bits = 15; // 16 x 8 bit = 128bit
while ($bits >= 0) {
$bin = sprintf("%08b",(ord($ip_n[$bits])));
$ipv6long = $bin.$ipv6long;
$bits--;
}
return
gmp_strval(gmp_init($ipv6long,2),10);
}

function
long2ip6($ipv6long) {

$bin = gmp_strval(gmp_init($ipv6long,10),2);
if (
strlen($bin) < 128) {
$pad = 128 - strlen($bin);
for (
$i = 1; $i <= $pad; $i++) {
$bin = "0".$bin;
}
}
$bits = 0;
while (
$bits <= 7) {
$bin_part = substr($bin,($bits*16),16);
$ipv6 .= dechex(bindec($bin_part)).":";
$bits++;
}
// 压缩

return inet_ntop(inet_pton(substr($ipv6,0,-1)));
}

print
$ipv6long = ip2long6($ipv6)."\n";
print
$ipv6 = long2ip6($ipv6long)."\n";

?>

输出

42541956150894553250710573749450571880
2001:4860:a005::68
1
Ian B
17 年前
注意:ip2long() 不应该用于 CIDR 计算。
相反,您应该使用类似以下内容

<?php
/* 从数据库中的禁用项获取基数和位数 */
list($base, $bits) = explode('/', $CIDR);

/* 现在将其拆分为其类别 */
list($a, $b, $c, $d) = explode('.', $base);

/* 现在执行一些位移位/切换操作以转换为整数 */
$i = ($a << 24) + ($b << 16) + ($c << 8) + $d;
$mask = $bits == 0 ? 0 : (~0 << (32 - $bits));

/* 这是我们的最低整数 */
$low = $i & $mask;

/* 这是我们的最高整数 */
$high = $i | (~$mask & 0xFFFFFFFF);

/* 现在将我们正在检查的 IP 拆分为类别 */
list($a, $b, $c, $d) = explode('.', $iptocheck);

/* 现在将我们正在检查的 IP 转换为整数 */
$check = ($a << 24) + ($b << 16) + ($c << 8) + $d;

/* 如果 IP 在范围内,包括
最高/最低值,那么它就在 CIDR 范围内 */
if ($check >= $low && $check <= $high)
return
1;
else
return
0;
?>

这意味着您应该检查以确保 IP
地址每次都具有正确的格式。
2
pink at pink dot art dot pl
12 年前
请注意,当您运行 64 位系统时,ip2long 将生成 64 位整数,该整数不适合 MySQL INT,您可以使用 BIGINT 或 INT UNSIGNED,因为在 64 位系统上,ip2long 永远不会返回负整数。另请参阅 https://bugs.php.net/bug.php?id=54338
1
Anonymous
19 年前
我重新编写了 jbothe at hotmail dot com 中的函数,作为面向对象的一点练习,并添加了几个额外的函数。

<?php

//--------------
// IPv4 类
class ipv4
{
var
$address;
var
$netbits;

//--------------
// 创建新类
function ipv4($address,$netbits)
{
$this->address = $address;
$this->netbits = $netbits;
}

//--------------
// 返回 IP 地址
function address() { return ($this->address); }

//--------------
// 返回网络位数
function netbits() { return ($this->netbits); }

//--------------
// 返回网络掩码
function netmask()
{
return (
long2ip(ip2long("255.255.255.255")
<< (
32-$this->netbits)));
}

//--------------
// 返回地址所在的网络
function network()
{
return (
long2ip((ip2long($this->address))
& (
ip2long($this->netmask()))));
}

//--------------
// 返回地址所在的广播
function broadcast()
{
return (
long2ip(ip2long($this->network())
| (~(
ip2long($this->netmask())))));
}

//--------------
// 返回网络掩码的反掩码
function inverse()
{
return (
long2ip(~(ip2long("255.255.255.255")
<< (
32-$this->netbits))));
}

}

$ip = new ipv4("192.168.2.1",24);
print
"Address: $ip->address()\n";
print
"Netbits: $ip->netbits()\n";
print
"Netmask: $ip->netmask()\n";
print
"Inverse: $ip->inverse()\n";
print
"Network: $ip->network()\n";
print
"Broadcast: $ip->broadcast()\n";
?>
2
admin at wudimei dot com
12 年前
<?php

/**
*
* 从 cidr(网络 ID 和掩码长度)获取第一个 IP 和最后一个 IP
* 我会将此函数集成到“Rong Framework”中 :)
* @author [email protected]
* @param string $cidr 56.15.0.6/16 , [网络 ID]/[掩码长度]
* @return array $ipArray = array( 0 =>"网络的第一个 IP", 1=>"网络的最后一个 IP" );
* $ipArray 的每个元素的类型都是长整型,使用 long2ip( $ipArray[0] ) 将其转换为 IP 字符串。
* 例如:
* list( $long_startIp , $long_endIp) = getIpRange( "56.15.0.6/16" );
* echo "起始 IP:" . long2ip( $long_startIp );
* echo "<br />";
* echo "结束 IP:" . long2ip( $long_endIp );
*/

function getIpRang( $cidr) {

list(
$ip, $mask) = explode('/', $cidr);

$maskBinStr =str_repeat("1", $mask ) . str_repeat("0", 32-$mask ); // 网络掩码二进制字符串
$inverseMaskBinStr = str_repeat("0", $mask ) . str_repeat("1", 32-$mask ); // 反掩码

$ipLong = ip2long( $ip );
$ipMaskLong = bindec( $maskBinStr );
$inverseIpMaskLong = bindec( $inverseMaskBinStr );
$netWork = $ipLong & $ipMaskLong;

$start = $netWork+1;// 去掉网络号 ,ignore network ID(eg: 192.168.1.0)

$end = ($netWork | $inverseIpMaskLong) -1 ; // 去掉广播地址 ignore brocast IP(eg: 192.168.1.255)
return array( $start, $end );
}
?>
2
alex at alex-at dot ru
7 年前
以下是我的前缀到掩码和掩码到前缀转换版本。如果不需要理智预检查,您可以删除每个函数中的第一行(if/preg)。

function prefix2Mask($prefix)
{
if (!preg_match('#^(?:0*[0-2]?[0-9]|3[0-2])$#', $prefix)) return false; # 错误的前缀
return long2ip(0xffffffff << (32 - $prefix));
}

function mask2Prefix($mask)
{
if (!preg_match('#^(?:(?:[0-1][0-9][0-9]|2[0-4][0-9]|25[0-5]|[0-9][0-9]|[0-9])\.){3}'.
'(?:[0-1][0-9][0-9]|2[0-4][0-9]|25[0-5]|[0-9][0-9]|[0-9])$#', $mask))
return false; # 错误的掩码
$m2p = str_pad(substr(decbin(ip2long($mask)), -32, 32), 32, '0', STR_PAD_LEFT);
if (!preg_match('#^(1*)0*$#', $m2p, $m)) return false; # 错误的掩码
return strlen($m[1]);
}
2
laacz at php dot net
17 年前
只是为了节省您的时间。

请注意,IP 地址中的八位字节被视为数字。因此,“10.0.0.11” 不等于“10.0.0.011”。“011” 是八进制数(以 8 为基数),因此它转换为“9”。您甚至可以进一步了解“10.0.0.0xa” 也有效(等于“10.0.0.16”)。

但这并非 PHP 的问题。
0
chrisp-phpnet at inventivedingo dot com
16 年前
我在 lighttpd 服务器上使用 REMOTE_ADDR 调用此函数时遇到了问题。事实证明,此服务器上安装了 IPv6,因此即使 REMOTE_ADDR 是 IPv4 地址,它也使用 IPv6 的 IPv4 兼容模式进行格式化。例如,10.0.0.1 变成了 ::ffff:10.0.0.1,这导致 iplong 报告地址无效而不是正确解析。

当然,正确的解决方法是更新我的基础设施使其与 IPv6 兼容;但在我的特定情况下,这将涉及大量的重新设计。因此,作为权宜之计,我使用这个快速而肮脏的技巧来解决这个问题。

<?php
$ip
= htmlspecialchars($_SERVER['REMOTE_ADDR']);
if (
strpos($ip, '::') === 0) {
$ip = substr($ip, strrpos($ip, ':')+1);
}
$host = ip2long($ip);
?>

丑陋但实用。
0
ken at expitrans dot com
18 年前
下面是所有各种笔记的合并形式,以及一个更好的(也是正确的)网络匹配函数。

<?php

function net_match($network, $ip) {
// 确定以 192.168.17.1/16 或
// 127.0.0.1/255.255.255.255 或 10.0.0.1 格式的网络是否与给定 IP 匹配
$ip_arr = explode('/', $network);
$network_long = ip2long($ip_arr[0]);

$x = ip2long($ip_arr[1]);
$mask = long2ip($x) == $ip_arr[1] ? $x : 0xffffffff << (32 - $ip_arr[1]);
$ip_long = ip2long($ip);

// echo ">".$ip_arr[1]."> ".decbin($mask)."\n";
return ($ip_long & $mask) == ($network_long & $mask);
}

echo
net_match('192.168.17.1/16', '192.168.15.1')."\n"; // 返回 true
echo net_match('127.0.0.1/255.255.255.255', '127.0.0.2')."\n"; // 返回 false
echo net_match('10.0.0.1', '10.0.0.1')."\n"; // 返回 true

?>
To Top