网络函数

目录

添加笔记

用户贡献笔记 14 个笔记

claudiu at cnixs dot com
17 年前
一个简单且非常快速的函数来检查 CIDR。

您之前的示例过于复杂,涉及许多函数调用。

这是它(只有算术运算符,并且只调用 ip2long() 和 split())
<?php
function ipCIDRCheck ($IP, $CIDR) {
list (
$net, $mask) = split ("/", $CIDR);

$ip_net = ip2long ($net);
$ip_mask = ~((1 << (32 - $mask)) - 1);

$ip_ip = ip2long ($IP);

$ip_ip_net = $ip_ip & $ip_mask;

return (
$ip_ip_net == $ip_net);
}
?>
调用示例:<?php echo ipCheck ("192.168.1.23", "192.168.1.0/24"); ?>
Anton Avramov - lukav at lukav dot com
7 年前
claudiu at cnixs dot com 的改进版本,不使用 split 并且使用以下内容
ip: 192.168.101.123, CIRD: 192.168.101.144/24

<?php
function ipCIDRCheck ($IP, $CIDR) {
list (
$net, $mask) = explode ('/', $CIDR);

$ip_net = ip2long ($net);
$ip_mask = ~((1 << (32 - $mask)) - 1);

$ip_ip = ip2long ($IP);

return ((
$ip_ip & $ip_mask) == ($ip_net & $ip_mask));
}
?>
匿名
8 年前
philippe-at-cyberabuse.org 答案的改进版本

<?php
function cidrconv($net) {
$start = strtok($net,"/");
$n = 3 - substr_count($net, ".");
if (
$n > 0)
{
for (
$i = $n;$i > 0; $i--)
$start .= ".0";
}
$bits1 = str_pad(decbin(ip2long($start)), 32, "0", STR_PAD_LEFT);
$net = (1 << (32 - substr(strstr($net, "/"), 1))) - 1;
$bits2 = str_pad(decbin($net), 32, "0", STR_PAD_LEFT);
$final = "";
for (
$i = 0; $i < 32; $i++)
{
if (
$bits1[$i] == $bits2[$i]) $final .= $bits1[$i];
if (
$bits1[$i] == 1 and $bits2[$i] == 0) $final .= $bits1[$i];
if (
$bits1[$i] == 0 and $bits2[$i] == 1) $final .= $bits2[$i];
}
return array(
$start, long2ip(bindec($final)));
}
?>
David GASTALDIN
17 年前
这是一个我为填充我的 Postfix client.cidr 而编写的 IP 范围到 CIDR 的函数,用于使用 ripe-ncc 数据阻止来自无用国家的垃圾邮件。Strcmp 函数旨在解决 PHP 愚蠢的字符串比较问题,这种比较在可能的情况下不可避免地会尝试将字符串作为数字进行比较。关于这一点我不会发表任何评论......但我必须紧紧地咬住自己的舌头。

function PlageVersCIDRs($ip_min, $ip_max) {
$cidrs = array();
$ip_min_bin = sprintf('%032b', $ip_min);
$ip_max_bin = sprintf('%032b', $ip_max);
$ip_cour_bin = $ip_min_bin;
while (strcmp($ip_cour_bin, $ip_max_bin) <= 0) {
$lng_reseau = 32;
$ip_reseau_bin = $ip_cour_bin;
while (($ip_cour_bin[$lng_reseau - 1] == '0') && (strcmp(substr_replace($ip_reseau_bin, '1', $lng_reseau - 1, 1), $ip_max_bin) <= 0)) {
$ip_reseau_bin[$lng_reseau - 1] = '1';
$lng_reseau--;
}
$cidrs[] = long2ip(bindec($ip_cour_bin)).'/'.$lng_reseau;
$ip_cour_bin = sprintf('%032b', bindec($ip_reseau_bin) + 1);
}
return $cidrs;
}
philippe-at-cyberabuse.org
22 年前
PHP 缺少 CIDR 函数。

这个函数将转换像这样的 CIDR:
0.0.0.0/16 -> 0.0.0.0 - 0.0.255.255
127.0/16 -> 127.0.0.0 - 127.0.255.255
等等...

function cidrconv($net) {
$start=strtok($net,"/");
$n=3-substr_count($net, ".");
if ($n>0) { for ($i=$n;$i>0;$i--) $start.=".0"; }
$bits1=str_pad(decbin(ip2long($start)),32,"0","STR_PAD_LEFT");
$net=pow(2,(32-substr(strstr($net,"/"),1)))-1;
$bits2=str_pad(decbin($net),32,"0","STR_PAD_LEFT");
for ($i=0;$i<32;$i++) {
if ($bits1[$i]==$bits2[$i]) $final.=$bits1[$i];
if ($bits1[$i]==1 and $bits2[$i]==0) $final.=$bits1[$i];
if ($bits1[$i]==0 and $bits2[$i]==1) $final.=$bits2[$i];
}
return $start." - ".long2ip(bindec($final));
}
nexxer at rogers dot com
19 年前
在 Trevor Hemsley 的 perl range2cidr 函数的翻译中,

while ($end > $start)

条件应该是

while ($end >= $start)

否则它将无法处理 /32,例如如果你输入 range2cidr("1.2.3.4", "1.2.3.4")。

-- nex
-dR
8 年前
这个小函数可能很有用

<?php
function cidr_range( $cidr, $chkip=null )
{
// 分配 IP / 掩码
list($ip,$mask) = explode("/",$cidr);

// 净化 IP
$ip1 = preg_replace( '_(\d+\.\d+\.\d+\.\d+).*$_', '$1', "$ip.0.0.0" );

// 计算范围
$ip2 = long2ip( ip2long( $ip1 ) - 1 + ( 1 << ( 32 - $mask) ) );

// 我们正在检查 CIDR 范围吗?
if ( $chkip != null && ! filter_var( $chkip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false )
{
return
ip2long( $ip1 ) <= ip2long( $chkip ) && ip2long( $ip2 ) >= ip2long( $chkip ) ? true : false;
} else {
return
"$ip1 - $ip2";
}
}

var_dump( cidr_range( "127.0/16", "127.0.0.1" ) ); // bool(true)
var_dump( cidr_range( "127.0/16", "192.168.0.1" ) ); // bool(false)
var_dump( cidr_range( "192.168.0.0/24" ) ); // string(27) "192.168.0.0 - 192.168.0.255"

?>
Anonymous
21 年前
cidr_conv 函数的另一种选择 - 稍微容易理解一些

function cidr_conv($cidr_address) {
$first = substr($cidr_address, 0, strpos($cidr_address, "/"));
$netmask = substr(strstr($cidr_address, "/"), 1);

$first_bin = str_pad(decbin(ip2long($first)), 32, "0", STR_PAD_LEFT);
$netmask_bin = str_pad(str_repeat("1", (integer)$netmask), 32, "0", STR_PAD_RIGHT);

for ($i = 0; $i < 32; $i++) {
if ($netmask_bin[$i] == "1")
$last_bin .= $first_bin[$i];
else
$last_bin .= "1";
}

$last = long2ip(bindec($last_bin));

return "$first - $last";
}
samuele at norsam dot org
20 年前
要查找某个 IP 是否在某个 net/mask 中(非常快)
<?php
function isIPIn($ip,$net,$mask) {
$lnet=ip2long($net);
$lip=ip2long($ip);
$binnet=str_pad( decbin($lnet),32,"0","STR_PAD_LEFT" );
$firstpart=substr($binnet,0,$mask);
$binip=str_pad( decbin($lip),32,"0","STR_PAD_LEFT" );
$firstip=substr($binip,0,$mask);
return(
strcmp($firstpart,$firstip)==0);
}
?>

这个函数可以进行压缩,避免一些变量设置,但函数的可读性会降低...
示例代码,用于构建一种基于网络的定位服务

<?php
$n
= array ( "192.168.0.0/16" => "TUSCANY",
"192.168.1.0/24" => "- Florence",
"192.168.2.0/24" => "- Pisa",
"192.168.3.0/24" => "- Siena",
"192.168.64.0/21" => "- Tuscan Archipelago",
"192.168.64.0/23" => "--- Elba Island",
"192.168.66.0/24" => "--- Capraia Island",
"192.168.67.0/24" => "--- Giannutri Island");

// 通常情况下,应该使用以下代码行
$myip = $HTTP_SERVER_VARS['REMOTE_ADDR'];
// 这是第一个例子:返回 Tuscany/Pisa
$myip = "192.168.2.33";
// 这是第二个例子:返回 Tuscany/T.Arch./Elba
$myip = "192.168.65.34";

echo
"您的位置:<br />\n";
foreach (
$n as $k=>$v ) {
list(
$net,$mask)=split("/",$k);
if (
isIPIn($myip,$net,$mask)) {
echo
$n[$k]."<br />\n"; }
}
?>

等等...
metator at netcabo dot pt
19 年前
关于 samuele 的笔记

您可以通过直接应用网络设备(如路由器)中的操作来获得更快的代码。如果您将远程 IP 与本地网络掩码进行与运算(逻辑运算),结果将是远程 IP 来自本地网络的网络 IP。例如

192.168.0.16 = 11000000.10101000.00000000.00010000
& 255.255.255.0 = 11111111.11111111.11111111.00000000
--------------------------------------------------------------
192.168.0.0 = 11000000.10101000.00000000.00000000

现在是代码。我的示例使用了一个 HTML 表单,您可以在其中放置要测试的值

<HTML><HEAD><TITLE>检查 IP</TITLE>
</HEAD><BODY>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST">

希望您觉得这有用。
要检查的 IP:<input type="text" name="ip"> <br>
本地网络 IP:<input type="text" name="net"> <br>
本地网络掩码:<input type="text" name="mask"> <br>
<input type="submit" name="check" value="检查它!">
</form>
<?php

/**
* @param string $ip 要以点分十进制格式检查的 IP
* @param string $net 网络 IP 以点分十进制格式
* @param string $mask 网络掩码以点分十进制格式
* @returns 如果 IP 属于网络,则返回 true,否则返回 false
**/
function isIPIn($ip, $net, $mask) {
// 不检查 ip2long 的返回值
$ip = ip2long($_POST['ip']);
$rede = ip2long($_POST['net']);
$mask = ip2long($_POST['mask']);

//与运算
$res = $ip & $mask;

return (
$res == $rede);
}

if (isset(
$_POST['check'])) {
echo
isIPIn($_POST['ip'], $_POST['net'], $_POST['mask']) ? "IP 在内.": "IP 在外.";
}
?>
</BODY><HTML>
dand at ddchosting.com
18 年前
当我参与一个项目时,我遇到了这个重定向问题。我的解决方案如下
header("Refresh: 5; url=../main/main.php?".session_id()."");

这使我能够传递 session_id(),它在整个站点中使用以确保用户已登录。
希望这有帮助!
anderson at piq dot com dot br
21 年前
如果您想根据本地路由表获取 IP 的接口,请使用此方法。

function GetIfaceforIP($user_ip)
{
$route = "/bin/netstat -rn";

exec($route, $aoutput);
foreach($aoutput as $key => $line)
{
if($key > 1)
{
$line = ereg_replace("[[:space:]]+",",",$line);
list($network, $gateway, $mask, $flags, $mss, $window, $irtt, $iface) = explode(",", $line)
if((ip2long($user_ip) & ip2long($mask)) == ip2long($network))
{
return $iface;
}
}
}
}
trevor-hemsley at nospam dot dial dot pipex dot com
21 年前
前面的 IP 范围到 CIDR 列表的示例无法像 perl Net::Netmask range2cidrlist() 函数那样很好地处理范围。在 PHP 中,它看起来像这样

<?
function imask($this)
{
// 使用 base_convert 而不是 dechex,因为 dechex 已损坏,返回 0x80000000 而不是 0xffffffff
return base_convert((pow(2,32) - pow(2, (32-$this)))), 10, 16);
}

function imaxblock($ibase, $tbit)
{
while ($tbit > 0)
{
$im = hexdec(imask($tbit-1));
$imand = $ibase & $im;
if ($imand != $ibase)
{
break;
}
$tbit--;
}
return $tbit;
}

function range2cidrlist($istart, $iend)
{
// 此函数返回一个 CIDR 列表数组,这些列表映射给定的范围
$s = explode(".", $istart);
// PHP ip2long 无法处理 IP 地址的起始零!172.016 返回 172.14,似乎被视为八进制!
$start = "";
$dot = "";
while (list($key,$val) = each($s))
{
$start = sprintf("%s%s%d",$start,$dot,$val);
$dot = ".";
}
$end = "";
$dot = "";
$e = explode(".",$iend);
while (list($key,$val) = each($e))
{
$end = sprintf("%s%s%d",$end,$dot,$val);
$dot = ".";
}
$start = ip2long($start);
$end = ip2long($end);
$result = array();
while ($end > $start)
{
$maxsize = imaxblock($start,32);
$x = log($end - $start + 1)/log(2);
$maxdiff = floor(32 - floor($x));
$ip = long2ip($start);
if ($maxsize < $maxdiff)
{
$maxsize = $maxdiff;
}
array_push($result,"$ip/$maxsize");
$start += pow(2, (32-$maxsize));
}
return $result;
}
?>
philippe-at-cyberabuse.org
21 年前
... 并且这个将执行相反的操作(对于无效的网络块返回 NULL)

1.0.0.0 1.0.255.255 -> 1.0.0.0/16
1.0.0.0 1.3.255.255 -> 1.0.0.0/14
192.168.0.0 192.168.0.255 -> 192.168.0.0/24

function ip2cidr($ip_start,$ip_end) {
if(long2ip(ip2long($ip_start))!=$ip_start or long2ip(ip2long($ip_end))!=$ip_end) return NULL;
$ipl_start=(int)ip2long($ip_start);
$ipl_end=(int)ip2long($ip_end);
if($ipl_start>0 && $ipl_end<0) $delta=($ipl_end+4294967296)-$ipl_start;
else $delta=$ipl_end-$ipl_start;
$netmask=str_pad(decbin($delta),32,"0","STR_PAD_LEFT");
if(ip2long($ip_start)==0 && substr_count($netmask,"1")==32) return "0.0.0.0/0";
if($delta<0 or ($delta>0 && $delta%2==0)) return NULL;
for($mask=0;$mask<32;$mask++) if($netmask[$mask]==1) break;
if(substr_count($netmask,"0")!=$mask) return NULL;
return "$ip_start/$mask";
}
To Top