检查 CIDR 子网是否包含 IP 地址
我正在寻找快速/简单的方法来将给定的 IP4 点分四 IP 与 CIDR 表示法掩码进行匹配。
我有一堆 IP,我需要看看它们是否与一系列 IP 匹配。
示例:
$ips = array('10.2.1.100', '10.2.1.101', '10.5.1.100', '1.2.3.4');
foreach ($ips as $IP) {
if (cidr_match($IP, '10.2.0.0/16') == true) {
print "you're in the 10.2 subnet\n";
}
}
cidr_match()
会是什么样子?
它并不一定要简单,但速度快就更好了。 任何仅使用内置/通用函数的东西都是一种奖励(因为我可能会让一个人向我展示 pear 中的一些东西来执行此操作,但我不能依赖 pear 或安装在我的代码所在的位置的软件包部署)。
I'm looking for quick/simple method for matching a given IP4 dotted quad IP to a CIDR notation mask.
I have a bunch of IPs I need to see if they match a range of IPs.
example:
$ips = array('10.2.1.100', '10.2.1.101', '10.5.1.100', '1.2.3.4');
foreach ($ips as $IP) {
if (cidr_match($IP, '10.2.0.0/16') == true) {
print "you're in the 10.2 subnet\n";
}
}
What would cidr_match()
look like?
It doesn't really have to be simple, but fast would be good. Anything that uses only built-in/common functions is a bonus (as I'm likely to get one person to show me something in pear that does this, but I can't depend on pear or that package being installed where my code is deployed).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
如果仅使用 IPv4:
ip2long()
将 IP 和子网范围转换为长整数类似这样的东西应该有效:
If only using IPv4:
ip2long()
to convert the IPs and the subnet range into long integerssomething like this should work:
在类似的情况下,我最终使用了 symfony/http-foundation。
使用此包时,您的代码将如下所示:
它还处理 IPv6。
链接:https://packagist.org/packages/symfony/http-foundation
In a similar situation, I ended up using symfony/http-foundation.
When using this package, your code would look like:
It also handles IPv6.
Link: https://packagist.org/packages/symfony/http-foundation
我发现许多这些方法在 PHP 5.2 之后就被破坏了。 但是,以下解决方案适用于版本 5.2 及更高版本:
结果示例
来源 http://www.php.net/manual/en/function.ip2long.php#82397。
I found many of these methods breaking after PHP 5.2. However the following solution works on versions 5.2 and above:
Example results
Source http://www.php.net/manual/en/function.ip2long.php#82397.
一些功能发生了变化:
Some function changed:
这是一个快速的 64 位函数来完成此操作,请注释掉您不需要的返回行。 接受带有或不带有有效 CIDR 路由前缀的任何有效 Ipv4,例如 63.161.156.0/24 或 63.161.156.0
要快速检查给定 ipv4 是否与给定 CIDR 匹配,您可以像本例一样内联执行
要获取完整范围作为给定 IP(有或没有 CIDR 路由前缀)的数组,您可以使用以下代码,但要小心,因为例如 25.25.25.25/ 16 返回一个包含 65536 个元素的数组,使用较小的路由前缀很容易耗尽内存
给定的 IP 数组匹配(带或不带 CIDR 路由前缀)
快速检查给定的 ipv4 是否与 运行速度快,该函数不检查输入,但形式上它应该是与以下正则表达式匹配的字符串
如果您想在使用该函数之前验证输入
那么正式问题的答案如下
Here is one fast 64bits function to do it, please comment the return line you don't need. Accepting any valid Ipv4 with or without valid CIDR Routing Prefix for example 63.161.156.0/24 or 63.161.156.0
To fast check if a given ipv4 is matching a given CIDR you can do it inline like in this example
To get the full range as an array for a given IP (with or without CIDR Routing Prefix) you can use the following code but be carefull because for example 25.25.25.25/16 return an array with 65536 elements and you can easily run out of memory using a smaller Routing Prefix
To fast check if a given ipv4 is matching a given array of IP (with or without CIDR Routing Prefix)
To run fast the function don't check input but formally it should be a string matching the following regex
If you want to verify the input before using the function
Then the formal answer to your question is the following
我的技术使用子网和掩码进行位对位匹配。
My technique uses bit to bit matching using subnet and mask.
我还需要根据 CIDR 掩码测试 IP。 我发现一个网站有很好的解释和源代码,运行得很好。
网站 http://pgregg.com/blog/2009/04/php-algorithms-determining-if-an-ip-is-within-a-specific-range/
因为该网站有一天可能不复存在,这是代码
(我没有开发这个;这是由 Paul Gregg 开发的(http://pgregg.com/ )
I also needed to test IP's against CIDR masks. I've found a website with excellent explanation and sourcecode which works perfectly well.
The website http://pgregg.com/blog/2009/04/php-algorithms-determining-if-an-ip-is-within-a-specific-range/
Because the website can one day cease to exist, here is the code
(I did not develop this; this is developed by Paul Gregg (http://pgregg.com/)
我最近需要将 IP 地址与 CIDR 掩码进行匹配,并看到了这篇文章。 下面是基于上述想法的稍微不同的方法,包括对 CIDR 输入的检查。 如果提交的 CIDR 格式不正确,该函数将返回 false。
我为任何需要经过测试的交钥匙功能的人发布了此解决方案。
测试数据如下图所示:
I recently needed to match an IP address to a CIDR mask and came across this article. Below is a slightly different approach based on the ideas above and includes a check on the CIDR input. The function returns false if an incorrect CIDR format is submitted.
I posted this solution for anyone who needs a turn-key function that has been tested.
Test data is shown in the image below:
请注意,Alnitak 的答案适用于 32/64 位。
这是它的熟版,可根据随处可见的国家/地区 IP 列表进行快速垃圾邮件防护。 google 查找国家/地区 ip 列表或国家/地区 ip 块(这里必须给出一个,在该网站的页面导航中很难找到它:国家 ip 块生成器)
将您的 cidr ip 列表复制粘贴到字符串 $cidrs。 将此代码放在页面 html 之前,可能放在 header.php 文件中。
还可用于根据国家/地区过滤页面模板中的 AdSense 使用情况。
这只是一个半夜紧急的解决方案。 有时,昨天需要快速为客户想出这样的东西,所以就在这里。
Just a note, Alnitak's answer works 32/64 bit.
Here is a cooked version of it, for quick spam protection based on country IP lists that you can get everywhere. google for country ip list or country ip block (Have to give one here, really difficult to find it in that sites page navigation:Country ip block generator)
Copy-paste your cidr ip list to string $cidrs. And put this code just before page html, possibly in the header.php file.
Can also be used to filter adsense use in page templates based on country.
This is only a in-the-middle-of-the-night-urgency solution. Sometimes one needs to come up with something like this for a client quickly yesterday, so here it is.
您还可以使用 Net_IPv4 PEAR 库。
You also can use Net_IPv4 PEAR library.
也许它对某人有用。
将位掩码转换为 IP 掩码:
将 IP 掩码转换为位掩码:
Perhaps it is useful to someone.
Convert bit mask into IP mask:
Convert IP mask into bit mask:
我最终使用了 @ARNasirQureshi 的解决方案,该解决方案具有逐位匹配的子网和掩码,我也将其扩展为处理 IPv6,因为没有提到其他解决方案 inet_pton 有效地处理一些奇怪的情况,如 "2006:BCAA:64FF::104.121.140.212" ,而不是用 "." 分割。 或“:”,这可能很复杂!
因为比较总是使用“128 位”(又名 128 个 1 和 0)进行,所以无论 IP 和范围是相同类型(IPv4 还是 IPv6),甚至当它们的类型不同(IPv4 与 IPv6 或反之亦然)。
I ended up using @A.R.NasirQureshi's solution with bit to bit matching subnet and mask, which I expanded to deal with IPv6 as well since no other solution mentioned inet_pton that effectively takes care of some odd cases like "2006:BCAA:64FF::104.121.140.212" , instead of splitting by "." or ":" which may be complicated !
Because the comparison always takes place with "128 bits" (aka 128 1s & 0s), this works whether both the IP and Range are the same type (IPv4 or IPv6), and even when their type is different (IPv4 vs IPv6 or vice-versa).
我最近需要将 IP 地址与网络列表进行匹配,并发现了这个问题。 下面是一个变体,集成了之前发布的所有想法以及 IPv6 支持和地址、子网和掩码验证。 如果提交了不正确的 CIDR 格式或尝试将 IPv4 地址与 IPv6 网络匹配(反之亦然),则该函数返回 false。
I recently needed to match IP addresses to a network list and found this question. Below is a variant integrating all the ideas posted earlier plus IPv6 support and validation of address, subnet and mask. The function returns false if an incorrect CIDR format is submitted or when attempt to match IPv4 address to IPv6 network (or vice versa) is made.
使用输入验证检查和 php8 重写塞缪尔帕金森代码
rewriting samuel parkinsons code with input validation checks and php8
我想让你看看我的几行字。 人们在我之前提出的例子似乎不起作用。 据我了解,原因之一是 CIDR 掩码位是二进制数,因此位移必须在二进制数上完成。 我尝试过将长 IP 转换为二进制文件,但遇到了最大二进制数限制。
好的,这是我的几行:
I want to have you look at my few lines. The examples that people suggested before me don't seem to work. One reason being, as far as I understand it, is that CIDR mask bits are binary numbers, so the bit shift must be done on a binary number. I have tried converting the long IP's into binaries, but ran into a max binary number limit.
OK, here my few lines: