long2ip php cidr

php - long2ip()



¿Coincidencia de una IP a una máscara CIDR en PHP 5? (12)

Alguna función modificada:

  • dividir con explotar

function cidr_match($ip, $range) { list ($subnet, $bits) = explode(''/'', $range); $ip = ip2long($ip); $subnet = ip2long($subnet); $mask = -1 << (32 - $bits); $subnet &= $mask; return ($ip & $mask) == $subnet; }

Estoy buscando un método rápido / simple para unir un IP de cuatro puntos IP determinado a una máscara de notación CIDR.

Tengo un montón de direcciones IP que necesito ver si coinciden con un rango de direcciones IP.

ejemplo:

$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"; } }

¿Cómo se vería cidr_match() ?

Realmente no tiene que ser simple, pero rápido sería bueno. Cualquier cosa que use solo funciones incorporadas / comunes es una ventaja (ya que es probable que haga que una persona me muestre algo en pera que hace esto, pero no puedo depender de pera o de que ese paquete esté instalado donde mi código es desplegada).


Aquí hay una función rápida de 64 bits para hacerlo, por favor comente la línea de retorno que no necesita. Aceptando cualquier Ipv4 válido con o sin Prefijo de enrutamiento CIDR válido, por ejemplo 63.161.156.0/ 24 o 63.161.156.0

<?php function cidr2range($ipv4){ if ($ip=strpos($ipv4,''/'')) {$n_ip=(1<<(32-substr($ipv4,1+$ip)))-1; $ip_dec=ip2long(substr($ipv4,0,$ip)); } else {$n_ip=0; $ip_dec=ip2long($ipv4); } $ip_min=$ip_dec&~$n_ip; $ip_max=$ip_min+$n_ip; #Array(2) of Decimal Values Range return [$ip_min,$ip_max]; #Array(2) of Ipv4 Human Readable Range return [long2ip($ip_min),long2ip($ip_max)]; #Array(2) of Ipv4 and Subnet Range return [long2ip($ip_min),long2ip(~$n_ip)]; #Array(2) of Ipv4 and Wildcard Bits return [long2ip($ip_min),long2ip($n_ip)]; #Integer Number of Ipv4 in Range return ++$n_ip; }

Para comprobar rápidamente si un determinado ipv4 coincide con un CIDR determinado , puede hacerlo en línea como en este ejemplo

<?php $given_cidr=''55.55.55.0/24''; $given_ipv4=''55.55.55.55''; if(($range=cidr2range($given_cidr)) && ($check=ip2long($given_ipv4))!==false && $check>=$range[0] && $check<=$range[1]) { echo ''Yes, ''.$given_ipv4.'' is included in ''.$given_cidr; } else { echo ''No, ''.$given_ipv4.'' is not included in ''.$given_cidr; }

Para obtener el rango completo como una matriz para una IP determinada (con o sin Prefijo de enrutamiento CIDR), puede usar el siguiente código, pero tenga cuidado porque, por ejemplo, 25.25.25.25/16 devuelve una matriz con 65536 elementos y puede fácilmente quedarse sin memoria utilizando un Prefijo de enrutamiento más pequeño

<?php $result=cidr2range($ipv4); for($ip_dec=$result[0];$ip_dec<=$result[1];$ip_dec++) $full_range[$ip_dec]=long2ip($ip_dec); print_r($full_range);

Para comprobar rápidamente si un determinado ipv4 coincide con un conjunto determinado de IP (con o sin Prefijo de enrutamiento CIDR)

<?php #This code is checking if a given ip belongs to googlebot $given_ipv4=''74.125.61.208''; $given_cidr_array=[''108.59.93.43/32'',''108.59.93.40/31'',''108.59.93.44/30'',''108.59.93.32/29'',''108.59.93.48/28'',''108.59.93.0/27'',''108.59.93.64/26'',''108.59.93.192/26'',''108.59.92.192/27'',''108.59.92.128/26'',''108.59.92.96/27'',''108.59.92.0/27'',''108.59.94.208/29'',''108.59.94.192/28'',''108.59.94.240/28'',''108.59.94.128/26'',''108.59.94.16/29'',''108.59.94.0/28'',''108.59.94.32/27'',''108.59.94.64/26'',''108.59.95.0/24'',''108.59.88.0/22'',''108.59.81.0/27'',''108.59.80.0/24'',''108.59.82.0/23'',''108.59.84.0/22'',''108.170.217.128/28'',''108.170.217.160/27'',''108.170.217.192/26'',''108.170.217.0/25'',''108.170.216.0/24'',''108.170.218.0/23'',''108.170.220.0/22'',''108.170.208.0/21'',''108.170.192.0/20'',''108.170.224.0/19'',''108.177.0.0/17'',''104.132.0.0/14'',''104.154.0.0/15'',''104.196.0.0/14'',''107.167.160.0/19'',''107.178.192.0/18'',''125.17.82.112/30'',''125.16.7.72/30'',''74.125.0.0/16'',''72.14.192.0/18'',''77.109.131.208/28'',''77.67.50.32/27'',''66.102.0.0/20'',''66.227.77.144/29'',''66.249.64.0/19'',''67.148.177.136/29'',''64.124.98.104/29'',''64.71.148.240/29'',''64.68.64.64/26'',''64.68.80.0/20'',''64.41.221.192/28'',''64.41.146.208/28'',''64.9.224.0/19'',''64.233.160.0/19'',''65.171.1.144/28'',''65.170.13.0/28'',''65.167.144.64/28'',''65.220.13.0/24'',''65.216.183.0/24'',''70.32.132.0/23'',''70.32.128.0/22'',''70.32.136.0/21'',''70.32.144.0/20'',''85.182.250.128/26'',''85.182.250.0/25'',''80.239.168.192/26'',''80.149.20.0/25'',''61.246.224.136/30'',''61.246.190.124/30'',''63.237.119.112/29'',''63.226.245.56/29'',''63.158.137.224/29'',''63.166.17.128/25'',''63.161.156.0/24'',''63.88.22.0/23'',''41.206.188.128/26'',''12.234.149.240/29'',''12.216.80.0/24'',''8.34.217.24/29'',''8.34.217.0/28'',''8.34.217.32/27'',''8.34.217.64/26'',''8.34.217.128/25'',''8.34.216.0/24'',''8.34.218.0/23'',''8.34.220.0/22'',''8.34.208.128/29'',''8.34.208.144/28'',''8.34.208.160/27'',''8.34.208.192/26'',''8.34.208.0/25'',''8.34.209.0/24'',''8.34.210.0/23'',''8.34.212.0/22'',''8.35.195.128/28'',''8.35.195.160/27'',''8.35.195.192/26'',''8.35.195.0/25'',''8.35.194.0/24'',''8.35.192.0/23'',''8.35.196.0/22'',''8.35.200.0/21'',''8.8.8.0/24'',''8.8.4.0/24'',''8.6.48.0/21'',''4.3.2.0/24'',''23.236.48.0/20'',''23.251.128.0/19'',''216.239.32.0/19'',''216.252.220.0/22'',''216.136.145.128/27'',''216.33.229.160/29'',''216.33.229.144/29'',''216.34.7.176/28'',''216.58.192.0/19'',''216.109.75.80/28'',''216.74.130.48/28'',''216.74.153.0/27'',''217.118.234.96/28'',''208.46.199.160/29'',''208.44.48.240/29'',''208.21.209.0/28'',''208.184.125.240/28'',''209.185.108.128/25'',''209.85.128.0/17'',''213.200.103.128/26'',''213.200.99.192/26'',''213.155.151.128/26'',''199.192.112.224/29'',''199.192.112.192/27'',''199.192.112.128/26'',''199.192.112.0/25'',''199.192.113.176/28'',''199.192.113.128/27'',''199.192.113.192/26'',''199.192.113.0/25'',''199.192.115.80/28'',''199.192.115.96/27'',''199.192.115.0/28'',''199.192.115.128/25'',''199.192.114.192/26'',''199.192.114.0/25'',''199.223.232.0/21'',''198.108.100.192/28'',''195.16.45.144/29'',''192.104.160.0/23'',''192.158.28.0/22'',''192.178.0.0/15'',''206.160.135.240/28'',''207.223.160.0/20'',''203.222.167.144/28'',''173.255.125.72/29'',''173.255.125.80/28'',''173.255.125.96/27'',''173.255.125.0/27'',''173.255.125.128/25'',''173.255.124.240/29'',''173.255.124.232/29'',''173.255.124.192/27'',''173.255.124.128/29'',''173.255.124.144/28'',''173.255.124.160/27'',''173.255.124.48/29'',''173.255.124.32/28'',''173.255.124.0/27'',''173.255.124.64/26'',''173.255.126.0/23'',''173.255.122.128/26'',''173.255.122.64/26'',''173.255.123.0/24'',''173.255.121.128/26'',''173.255.121.0/25'',''173.255.120.0/24'',''173.255.117.32/27'',''173.255.117.64/26'',''173.255.117.128/25'',''173.255.116.192/27'',''173.255.116.128/26'',''173.255.116.0/25'',''173.255.118.0/23'',''173.255.112.0/22'',''173.194.0.0/16'',''172.102.8.0/21'',''172.253.0.0/16'',''172.217.0.0/16'',''162.216.148.0/22'',''162.222.176.0/21'',''180.87.33.64/26'',''128.177.109.0/26'',''128.177.119.128/25'',''128.177.163.0/25'',''130.211.0.0/16'',''142.250.0.0/15'',''146.148.0.0/17'']; echo ''<pre>''; $in_range=false; if (($given_ipv4_dec=ip2long($given_ipv4))!==false) { foreach($given_cidr_array as $given_cidr){ if(($range=cidr2range($given_cidr)) && $given_ipv4_dec>=$range[0] && $given_ipv4_dec<=$range[1]) { $in_range=true; echo $given_ipv4.'' matched ''.$given_cidr.'' (''.join(array_map(''long2ip'',$range),'' - '').")/n"; } } } echo $given_ipv4.'' is probably''.($in_range?'''':'' not'').'' a Googlebot IP'';

Para ejecutar rápido, la función no verifica la entrada, pero formalmente debe ser una cadena que coincida con la siguiente expresión regular

#^(?:((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))/.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))/.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))/.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))(?:/((?:(?:0)|(?:3[0-2])|(?:[1-2]?[0-9]))))?)$#

Si quiere verificar la entrada antes de usar la función

<?php if (is_string($ipv4) && preg_match(''#^(?:((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))/.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))/.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))/.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))(?:/((?:(?:0)|(?:3[0-2])|(?:[1-2]?[0-9]))))?)$#'',$ipv4)) { #This is a valid ipv4 with or without CIDR Routing Prefix $result=cidr2range($ipv4); print_r($result); }

Entonces la respuesta formal a su pregunta es la siguiente

<?php #Requiring cidr2range shown above function function cidr_match($mixed_ip,$mixed_cidr){ if (!is_array($mixed_ip)){ $string_mode=true; $mixed_ip=[$mixed_ip=>0]; } else $mixed_ip=array_fill_keys($mixed_ip,0); if (!is_array($mixed_cidr)) $mixed_cidr=[$mixed_cidr]; foreach($mixed_ip as $ip => &$result) foreach($mixed_cidr as $cidr) { if(($range=cidr2range($cidr)) && ($check=ip2long($ip))!==false && $check>=$range[0] && $check<=$range[1]){ $result=$cidr; break; } } $mixed_ip=array_filter($mixed_ip); return $string_mode?($mixed_ip?true:false):$mixed_ip; } print ''<pre>''; #Your 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"; } } #Also working with IP array and/or CIDR array #If IP array is given then return an array containing IP (keys) matching CIDR (values) $result=cidr_match($ips,[''20.2.0.0/16'',''10.2.0.0/15'']); foreach($result as $ip => $cidr){ print "$ip is in the $cidr subnet/n"; }

Puedes compilar tu propia función usando estos ejemplos, espero que estas pocas líneas te hayan ayudado ...


En una situación similar, terminé usando Symfony / http-foundation.

Cuando use este paquete, su código se verá así:

$ips = array(''10.2.1.100'', ''10.2.1.101'', ''10.5.1.100'', ''1.2.3.4''); foreach($ips as $IP) { if (/Symfony/Component/HttpFoundation/IpUtils::checkIp($_SERVER[''REMOTE_ADDR''], ''10.2.0.0/16'')) { print "you''re in the 10.2 subnet/n"; } }

También maneja IPv6.

Enlace: https://packagist.org/packages/symfony/http-foundation


Encontré muchos de estos métodos rompiendo después de PHP 5.2. Sin embargo, la siguiente solución funciona en las versiones 5.2 y superiores:

function cidr_match($ip, $cidr) { list($subnet, $mask) = explode(''/'', $cidr); if ((ip2long($ip) & ~((1 << (32 - $mask)) - 1) ) == ip2long($subnet)) { return true; } return false; }

Resultados de ejemplo

cidr_match("1.2.3.4", "0.0.0.0/0"): true cidr_match("127.0.0.1", "127.0.0.1/32"): true cidr_match("127.0.0.1", "127.0.0.2/32"): false

Fuente http://www.php.net/manual/en/function.ip2long.php#82397 .


Mi técnica utiliza la correspondencia bit a bit usando subredes y máscaras.

function cidr_match($ip, $range){ list ($subnet, $bits) = explode(''/'', $range); $ip = substr(IP2bin($ip),0,$bits) ; $subnet = substr(IP2Bin($subnet),0,$bits) ; return ($ip == $subnet) ; } function IP2Bin($ip){ $ipbin = ''''; $ips = explode(".",$ip) ; foreach ($ips as $iptmp){ $ipbin .= sprintf("%08b",$iptmp) ; } return $ipbin ; }


Quiero que mires mis pocas líneas. Los ejemplos que la gente sugirió antes que yo no parecen funcionar. Una razón de ser, por lo que yo entiendo, es que los bits de máscara CIDR son números binarios, por lo que el cambio de bit se debe hacer en un número binario. Intenté convertir los IP largos en binarios, pero encontré un límite máximo de números binarios. OK, aquí mis pocas líneas ... Espero tus comentarios.

function cidr_match($ipStr, $cidrStr) { $ipStr = explode(''.'', $ipStr); foreach ($ipStr as $key => $val) { $ipStr[$key] = str_pad(decbin($val), 8, ''0'', STR_PAD_LEFT); } $ip = ''''; foreach ($ipStr as $binval) { $ip = $ip . $binval; } $cidrArr = explode(''/'',$cidrStr); $maskIP = explode(''.'', $cidrArr[0]); foreach ($maskIP as $key => $val) { $maskIP[$key] = str_pad(decbin($val), 8, ''0'', STR_PAD_LEFT); } $maskIP = ''''; foreach ($ipStr as $binval) { $maskIP = $maskIP . $binval; } $maskBits = 32 - $cidrArr[1]; return (($ip>>$maskBits) == ($maskIP>>$maskBits)); }


Si solo usa IPv4:

  • use ip2long() para convertir las IP y el rango de subred en enteros largos
  • convierta el / xx en una máscara de subred
  • hacer un ''y'' bit a bit (es decir, ip y máscara) y comprobar que ese ''resultado = subred''

Algo como esto debería funcionar:

function cidr_match($ip, $range) { list ($subnet, $bits) = explode(''/'', $range); $ip = ip2long($ip); $subnet = ip2long($subnet); $mask = -1 << (32 - $bits); $subnet &= $mask; # nb: in case the supplied subnet wasn''t correctly aligned return ($ip & $mask) == $subnet; }


Solo una nota, la respuesta de Alnitak funciona 32/64 bit.

Aquí hay una versión cocida, para una protección rápida de spam basada en listas de IP de país que puede obtener en todas partes. google para la lista de IP del país o el bloque de IP del país (Tengo que dar uno aquí, realmente difícil de encontrar en la navegación de la página de los sitios: generador de bloque de IP del país )

Copie y pegue su lista de cidr ip a string $ cidrs. Y coloque este código justo antes de la página html, posiblemente en el archivo header.php.

También se puede usar para filtrar el uso de AdSense en las plantillas de página según el país.

Esta es solo una solución de urgencia en el medio de la noche. A veces uno tiene que encontrar algo como esto para un cliente rápidamente ayer, así que aquí está.

//++++++++++++++++++++++ //COUNTRY SPAM PROTECTOR //speed: ~5ms @ 2000 cidrs //comments start with # //++++++++++++++++++++++ $cidrs= '' #yourcountry 1.3.4.5/21 #mycountry 6.7.8.9/20 ''; //$cidrs.="/n".''123.12.12.12/32'';//test, your ip $cidrs_ar=preg_split(''//s+/'',$cidrs,-1,PREG_SPLIT_NO_EMPTY); $ip=@$_SERVER[''REMOTE_ADDR'']; $iplong=ip2long($ip); //var_export($cidrs_ar);var_export($ip);var_export($iplong); if($iplong) foreach($cidrs_ar as $cidr) { $ar=explode (''/'', $cidr); $netiplong=ip2long($ar[0]); if($netiplong===false) continue; $mask=intval(@$ar[1]); if(!$mask) continue; $bitmask=-1 <<(32-$mask); if(($iplong & $bitmask) == ($netiplong & $bitmask)) { header(''Location: http://www.someotherwebsite.com/'',true,303); exit; } }


Tal vez sea útil para alguien.

Convierte máscara de bits en máscara de IP:

// convert 12 => 255.240.0.0 // ip2long(''255.255.255.255'') == -1 $ip = long2ip((-1 << (32 - $bit)) & -1);

Convierta máscara IP en máscara de bits:

// convert 255.240.0.0 => 12 // is valid IP if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) { throw new /InvalidArgumentException(sprintf(''Invalid IP "%s".'', $ip)); } // convert decimal to binary $mask = ''''; foreach (explode(''.'', $ip) as $octet) { $mask .= str_pad(decbin($octet), 8, ''0'', STR_PAD_LEFT); } // check mask if (strpos(''01'', $mask) !== false) { // valid 11111111111111111111111100000000 -> 255.255.255.0 // invalid 11111111111111111111111100000001 -> 255.255.255.1 throw new /InvalidArgumentException(sprintf(''IP mask "%s" is not valid.'', $ip)); } $bit = substr_count($mask, ''1''); // bit mask


También necesitaba probar IP contra máscaras CIDR. Encontré un sitio web con una excelente explicación y código fuente que funciona perfectamente.

El sitio web http://pgregg.com/blog/2009/04/php-algorithms-determining-if-an-ip-is-within-a-specific-range/

Debido a que el sitio web puede algún día dejar de existir, aquí está el código

<?php /* * ip_in_range.php - Function to determine if an IP is located in a * specific range as specified via several alternative * formats. * * Network ranges can be specified as: * 1. Wildcard format: 1.2.3.* * 2. CIDR format: 1.2.3/24 OR 1.2.3.4/255.255.255.0 * 3. Start-End IP format: 1.2.3.0-1.2.3.255 * * Return value BOOLEAN : ip_in_range($ip, $range); * * Copyright 2008: Paul Gregg <[email protected]> * 10 January 2008 * Version: 1.2 * * Source website: http://www.pgregg.com/projects/php/ip_in_range/ * Version 1.2 * * This software is Donationware - if you feel you have benefited from * the use of this tool then please consider a donation. The value of * which is entirely left up to your discretion. * http://www.pgregg.com/donate/ * * Please do not remove this header, or source attibution from this file. */ // decbin32 // In order to simplify working with IP addresses (in binary) and their // netmasks, it is easier to ensure that the binary strings are padded // with zeros out to 32 characters - IP addresses are 32 bit numbers Function decbin32 ($dec) { return str_pad(decbin($dec), 32, ''0'', STR_PAD_LEFT); } // ip_in_range // This function takes 2 arguments, an IP address and a "range" in several // different formats. // Network ranges can be specified as: // 1. Wildcard format: 1.2.3.* // 2. CIDR format: 1.2.3/24 OR 1.2.3.4/255.255.255.0 // 3. Start-End IP format: 1.2.3.0-1.2.3.255 // The function will return true if the supplied IP is within the range. // Note little validation is done on the range inputs - it expects you to // use one of the above 3 formats. Function ip_in_range($ip, $range) { if (strpos($range, ''/'') !== false) { // $range is in IP/NETMASK format list($range, $netmask) = explode(''/'', $range, 2); if (strpos($netmask, ''.'') !== false) { // $netmask is a 255.255.0.0 format $netmask = str_replace(''*'', ''0'', $netmask); $netmask_dec = ip2long($netmask); return ( (ip2long($ip) & $netmask_dec) == (ip2long($range) & $netmask_dec) ); } else { // $netmask is a CIDR size block // fix the range argument $x = explode(''.'', $range); while(count($x)<4) $x[] = ''0''; list($a,$b,$c,$d) = $x; $range = sprintf("%u.%u.%u.%u", empty($a)?''0'':$a, empty($b)?''0'':$b,empty($c)?''0'':$c,empty($d)?''0'':$d); $range_dec = ip2long($range); $ip_dec = ip2long($ip); # Strategy 1 - Create the netmask with ''netmask'' 1s and then fill it to 32 with 0s #$netmask_dec = bindec(str_pad('''', $netmask, ''1'') . str_pad('''', 32-$netmask, ''0'')); # Strategy 2 - Use math to create it $wildcard_dec = pow(2, (32-$netmask)) - 1; $netmask_dec = ~ $wildcard_dec; return (($ip_dec & $netmask_dec) == ($range_dec & $netmask_dec)); } } else { // range might be 255.255.*.* or 1.2.3.0-1.2.3.255 if (strpos($range, ''*'') !==false) { // a.b.*.* format // Just convert to A-B format by setting * to 0 for A and 255 for B $lower = str_replace(''*'', ''0'', $range); $upper = str_replace(''*'', ''255'', $range); $range = "$lower-$upper"; } if (strpos($range, ''-'')!==false) { // A-B format list($lower, $upper) = explode(''-'', $range, 2); $lower_dec = (float)sprintf("%u",ip2long($lower)); $upper_dec = (float)sprintf("%u",ip2long($upper)); $ip_dec = (float)sprintf("%u",ip2long($ip)); return ( ($ip_dec>=$lower_dec) && ($ip_dec<=$upper_dec) ); } echo ''Range argument is not in 1.2.3.4/24 or 1.2.3.4/255.255.255.0 format''; return false; } } ?>

(No desarrollé esto, esto es desarrollado por Paul Gregg ( http://pgregg.com/ )


También puede usar la biblioteca Net_IPv4 PEAR .

function cidr_match($ip, $net){ include_once("Net/IPv4.php"); $objIP = new Net_IPv4(); return $objIP->ipInNetwork($ip, $net); }


function cidr_match($ipStr, $cidrStr) { $ip = ip2long($ipStr); $cidrArr = split(''/'',$cidrStr); $maskIP = ip2long($cidrArr[0]); $maskBits = 32 - $cidrArr[1]; return (($ip>>$maskBits) == ($maskIP>>$maskBits)); }