gpt4 book ai didi

php - 搜索存储为整数的部分 IP 地址

转载 作者:行者123 更新时间:2023-11-30 21:22:32 26 4
gpt4 key购买 nike

我目前有一个包含 IP 地址的 MySQL 数据库。在搜索表单上,客户端想要搜索部分 IP 地址并弹出(可能)许多结果。我目前将 IP 地址作为 unsigned int 存储在 mysql 中。我使用的是 PHP 5.2,因此无法访问 PHP 5.7 及其 INET6_NTOA 函数。

当前数据库有超过 50,000 条记录并且还在继续增长,所以我不想将所有 IP 转换为点分符号,然后进行匹配 - 这似乎有点笨拙。

有没有更好的方法来搜索部分 IP 地址?

最佳答案

实际上,无符号整数列已经是搜索部分 ip 地址匹配项的最有效方法!请不要将您的精力和 CPU 时间浪费在转换回点分符号或对某种字符串列进行 LIKE 搜索上。

有几种记录部分 IP 地址的方法,但最终,它们都归结为带有网络掩码的基本 IP。另外,假设partial是指所有具有共同前缀的IP,那么这也相当于指定了一个IP范围。

无论哪种方式,部分 IP 地址规范最终被描述为两个 32 位无符号整数,编码格式与您的数据库列相同。要么你有一个起始 ip 和结束 ip,要么你有一个基本 ip 和一个掩码。这些整数可以直接在您的 SQL 查询中使用,以有效地获得匹配。更好的是,如果您使用 ip 范围方法,那么引擎将能够利用 ip 列上的有序索引。您不能期望更好。

那么如何建立IP范围呢?我们将首先取决于您的部分地址是如何指定的,但是假设您确实知道网络掩码,那么起始地址等于(基本 ip 和网络掩码),结束地址是((基本 ip & 掩码) | (~netmask)), 其中 &, |和~分别表示按位与、按位或、按位非。

更新

这是应用我描述的策略的示例代码。

自从我上次编写 PHP 代码以来已经有很长时间了,并且从未执行过以下内容,所以请原谅我可能引入的任何错误。我还特意选择“扩展”每个符号场景,以使它们更易于理解,而不是将它们全部压缩在一个非常复杂的正则表达式中。

if (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [/] (\d{1,2}) $/x', $input, $r)) {
// Four-dotted IP with number of significant bits: 123.45.67.89/24

$a = intval($r[1]);
$b = intval($r[2]);
$c = intval($r[3]);
$d = intval($r[4]);
$mask = intval($r[5]);

} elseif (preg_match(' /^ (\d{1,3}) (?: [.] [*0] [.] [*0] [.] [*0] )? $/x', $input, $r)) {
// Four-dotted IP with three-last numbers missing, or equals to 0 or '*':
// 123.45, 123.45.0.0, 123.45.*.* (assume netmask of 8 bits)

$a = intval($r[1]);
$b = 0;
$c = 0;
$d = 0;
$mask = 8;

} elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) (?: [.] [*0] [.] [*0] )? $/x', $input, $r)) {
// Four-dotted IP with two-last numbers missing, or equals to 0 or '*':
// 123.45, 123.45.0.0, 123.45.*.* (assume netmask of 16 bits)

$a = intval($r[1]);
$b = intval($r[2]);
$c = 0;
$d = 0;
$mask = 16;

} elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) (?: [.] [*0] )? $/x', $input, $r)) {
// Four-dotted IP with last number missing, or equals to 0 or *:
// 123.45.67, 123.45.67.0, 123.45.67.* (assume netmask of 24 bits)

$a = intval($r[1]);
$b = intval($r[2]);
$c = intval($r[3]);
$d = 0;
$mask = 24;

} elseif (preg_match(' /^ (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) $/x', $input, $r)) {
// Four-dotted IP: 123.45.67.89 (assume netmask of 32 bits)

$a = intval($r[1]);
$b = intval($r[2]);
$c = intval($r[3]);
$d = intval($r[4]);
$mask = 32;

} else {
throw new Exception('...');
}

if ($a < 0 || $a > 255) { throw new Exception('...') };
if ($b < 0 || $b > 255) { throw new Exception('...') };
if ($c < 0 || $c > 255) { throw new Exception('...') };
if ($d < 0 || $d > 255) { throw new Exception('...') };
if ($mask < 1 || $mask > 32) { throw new Exception('...') };

$baseip = ($a << 24) + ($b << 16) + ($c << 8) + ($d);
$netmask = (1 << (32 - $mask)) - 1;

$startip = $baseip & netmask;
$endip = ($baseip & netmask) | (~netmask);

// ...

doSql( "SELECT ... FROM ... WHERE ipaddress >= ? && ipaddress <= ?", $startip, $endip);

// or

doSql( "SELECT ... FROM ... WHERE ((ipaddress & ?) = ?)", $netmask, $startip);

关于php - 搜索存储为整数的部分 IP 地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26508008/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com