2011-02-08 17 views
15

Có cách nào (hoặc hàm/lớp) để lấy danh sách địa chỉ IP từ ký pháp CIDR không? Ví dụ, tôi có 73.35.143.32/27 CIDR và ​​muốn nhận danh sách tất cả các IP trong ký hiệu này. Bất kỳ đề xuất?Lấy các danh sách IP từ ký hiệu CIDR trong PHP

Cảm ơn bạn.

+0

xem [khớp IP với mặt nạ CIDR trong php5?] (Http://stackoverflow.com/questions/594112/matching-an-ip-to-a-cidr-mask-in-php5) – Distdev

Trả lời

18

Tôi sẽ chỉnh sửa aforementionedclass để chứa phương pháp cho điều đó. Đây là mã tôi nghĩ ra có thể giúp bạn cho đến lúc đó.

function cidrToRange($cidr) { 
    $range = array(); 
    $cidr = explode('/', $cidr); 
    $range[0] = long2ip((ip2long($cidr[0])) & ((-1 << (32 - (int)$cidr[1])))); 
    $range[1] = long2ip((ip2long($range[0])) + pow(2, (32 - (int)$cidr[1])) - 1); 
    return $range; 
} 
var_dump(cidrToRange("73.35.143.32/27")); 

//////////////////OUTPUT//////////////////////// 
// array(2) { 
// [0]=> 
// string(12) "73.35.143.32" 
// [1]=> 
// string(12) "73.35.143.63" 
// } 
///////////////////////////////////////////////// 

Trả về kết thúc thấp của dải ip làm mục nhập đầu tiên trong mảng, sau đó trả về kết thúc cao làm mục nhập thứ hai.

+0

Tôi đã chỉnh sửa [lớp CIDR] (http://snipplr.com/view/15557/ cidr-class-for-ipv4 /) để chứa phương thức sẽ cung cấp cho bạn kết quả bạn đang tìm kiếm. Tôi nghĩ bạn cũng có thể muốn xem xét phương thức IPisWithinRange(). – jonavon

+1

Tôi không thấy câu trả lời đúng như thế nào. OP yêu cầu 'danh sách tất cả IP trong ký hiệu này', hàm này chỉ trích xuất kết thúc cao + thấp. –

+1

Nó trả lời câu hỏi, Dr.GZZ, bởi vì nó cung cấp kết thúc thấp và cao của một phạm vi, mà sau đó cho phép bất cứ ai biết whats giữa. Việc trả về một mảng IP đầy đủ là không thực tế và có thể dễ dàng phá vỡ PHP với mặt nạ mạng thấp. – IncredibleHat

2

Tôi không tin this class sẽ trả về danh sách IP, nhưng nó cung cấp một số phương pháp hữu ích để làm việc với các khối CIDR.

9

Vâng, đó là một bitmask - 73.35.143.32/27 có nghĩa là 27 bit là mặt nạ mạng, và phần còn lại là dành cho gán cho các nút trong mạng:

73.35.143.32 

trong hệ nhị phân là thế này (chấm hiển thị cho mức độ dễ đọc):

01001001.00100011.10001111.00100000 

Các netmask là 27 bit:

11111111.11111111.11111111.11100000 

vì vậy, bạn có thể chỉ AN D chúng lại với nhau và có được điều này:

01001001.00100011.10001111.001 00000 
network prefix (27 bits)  | node address (5 bits) 

Từ đây, bạn có thể chỉ cần liệt kê tất cả các kết hợp trong địa chỉ nút (00000 là 0, 11111 là 31, do đó, một vòng lặp đơn giản là đủ), và bạn sẽ có tất cả các máy chủ có sẵn.

Chuyển đổi giả này để PHP là trái như một bài tập cho người đọc;)

Oh, và cảnh báo deprecation bắt buộc: IPv4 hiện giờ đã đầy, hãy xem xét cũng IPv6.

+1

Nếu bạn không muốn bao gồm địa chỉ mạng và địa chỉ quảng bá, sau đó đảm bảo loại trừ 0 (địa chỉ mạng) và 31 (địa chỉ quảng bá) –

-1

Hej. Tôi cũng cần chức năng này và tôi chỉnh sửa 1 hàm khác để trả về danh sách tất cả các địa chỉ IP trong phạm vi. Điều này sẽ trả về danh sách địa chỉ IP từ Ký hiệu CIDR. Thưởng thức nó;)

<?php 

    $ip_addr_cidr = "192.256.0.0/16"; 
    $ip_arr = explode('/', $ip_addr_cidr); 

    $bin = ''; 
    for($i=1;$i<=32;$i++) { 
     $bin .= $ip_arr[1] >= $i ? '1' : '0'; 
    } 
    $ip_arr[1] = bindec($bin); 

    $ip = ip2long($ip_arr[0]); 
    $nm = ip2long($ip_arr[1]); 
    $nw = ($ip & $nm); 
    $bc = $nw | (~$nm); 

    echo "Number of Hosts: " . ($bc - $nw - 1) . "<br/>"; 
    echo "Host Range:   " . long2ip($nw + 1) . " -> " . long2ip($bc - 1) . "<br/>". "<br/>"; 

    for($zm=1;($nw + $zm)<=($bc - 1);$zm++) 
     { 
     echo long2ip($nw + $zm). "<br/>"; 
     } 

    ?> 
+0

trên dòng này, có lỗi của phương pháp chưa biết, hãy kiểm tra $ bc = $ nw | (~ $ nm); –

+0

Có vẻ như có lỗi cú pháp với tập lệnh này. –

-1

cố định phiên bản của Kosmonaft kịch bản:

function get_list_ip($ip_addr_cidr){ 

     $ip_arr = explode("/", $ip_addr_cidr);  
     $bin = ""; 

     for($i=1;$i<=32;$i++) { 
      $bin .= $ip_arr[1] >= $i ? '1' : '0'; 
     } 

     $ip_arr[1] = bindec($bin); 

     $ip = ip2long($ip_arr[0]); 
     $nm = $ip_arr[1]; 
     $nw = ($ip & $nm); 
     $bc = $nw | ~$nm; 
     $bc_long = ip2long(long2ip($bc)); 

     echo "Number of Hosts: " . ($bc_long - $nw - 1) . "<br/>"; 
     echo "Host Range:   " . long2ip($nw + 1) . " -> " . long2ip($bc - 1) . "<br/>". "<br/>"; 

     for($zm=1;($nw + $zm)<=($bc_long - 1);$zm++) 
     { 
      echo long2ip($nw + $zm). "<br/>"; 
     } 
    } 
0

này trả về một mảng của ip:

function get_list_ip($ip_addr_cidr){ 
    $ip_arr = explode("/", $ip_addr_cidr);  
    $bin = ""; 

    for($i=1;$i<=32;$i++) { 
     $bin .= $ip_arr[1] >= $i ? '1' : '0'; 
    } 

    $ip_arr[1] = bindec($bin); 

    $ip = ip2long($ip_arr[0]); 
    $nm = $ip_arr[1]; 
    $nw = ($ip & $nm); 
    $bc = $nw | ~$nm; 
    $bc_long = ip2long(long2ip($bc)); 

    for($zm=1;($nw + $zm)<=($bc_long - 1);$zm++) 
    { 
     $ret[]=long2ip($nw + $zm); 
    } 
    return $ret; 
} 
0

tôi đưa ra một ý tưởng tốt hơn

$ip_from= long2ip(ip2long($ip)& (-1<<(32-$net_mask))); 
$ip_to= long2ip(ip2long($ip)| (~(-1<<(32-$net_mask)))); 

PS: $ ip là địa chỉ ipv4 như 60.12.34.5; $ net_mas k là mặt nạ mạng int như 25;

nó rất nhanh vì hoạt động dịch chuyển bit

0

Mở rộng đến câu trả lời của @jonavon.Nếu bạn cần danh sách IP tĩnh. Bạn có thể chuyển đổi chức năng của mình như dưới đây.

function cidrToRange($value) { 
    $range = array(); 
    $split = explode('/', $value); 
    if (!empty($split[0]) && is_scalar($split[1]) && filter_var($split[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { 
     $rangeStart = ip2long($split[0]) & ((-1 << (32 - (int)$split[1]))); 
     $rangeEnd = ip2long($split[0]) + pow(2, (32 - (int)$split[1])) - 1; 

     for ($i = $rangeStart; $i <= $rangeEnd; $i++) { 
      $range[] = long2ip($i); 
     } 
     return $range; 
    } else { 
     return $value; 
    } 
} 
0

này lặp trên mỗi địa chỉ IP trong một khối CIDR sử dụng một chức năng ẩn danh:

cidrl('194.168.0.1/28', $error_code, function($address) { 
    // Do something. 
    print "$address\n"; 
}); 

Hoặc, như một mảng:

$addresses = cidrl('194.168.0.1/28', $error_code); 

Nguồn:

function cidrl($cidr, &$error_code = 0, $callback = null) { 
    $error_code = 0; 
    sscanf($cidr, "%[^/]/%u", $network, $bits); 
    $addr = ip2long($network); 
    if ($addr === false) { 
     $error_code = 2; 
     return false; 
    }  

    if ($bits == 32) { 
     if (is_callable($callback)) { 
      $callback(long2ip($addr)); 
      return array(); 
     }   
     return array(long2ip($addr)); 
    }  

    if ($bits > 32) { 
     $error_code = 3; 
     return false; 
    }  

    $mask = ~(0xFFFFFFFF >> $bits); 

    $addr_start = $addr & $mask; 
    $addr_end = ($addr & $mask) | ~$mask; 

    $addresses = array(); 
    for ($i = $addr_start; $i <= $addr_end; $i++) { 
     if (is_callable($callback)) $callback(long2ip($i)); 
     else $addresses[] = long2ip($i); 
    }  
    return $addresses; 
} 

Mã số: https://github.com/emden-norfolk/cidrl/tree/master/php

3

Có sửa chữa nhỏ - khi ai đó đặt tiền tố ip như: 127.0.0.15/26 chức năng này trả về địa chỉ IP cuối cùng xấu. Trong chức năng này ở dòng 4 (bắt đầu: $ range [1] ...) đã thay đổi $ cidr [0] thành $ range [0] - bây giờ trở về địa chỉ IP cuối cùng tốt cho mọi IP trong phạm vi.

function cidrToRange($cidr) { 
    $range = array(); 
    $cidr = explode('/', $cidr); 
    $range[0] = long2ip((ip2long($cidr[0])) & ((-1 << (32 - (int)$cidr[1])))); 
    $range[1] = long2ip((ip2long($range[0])) + pow(2, (32 - (int)$cidr[1])) - 1); 
    return $range; 
} 
var_dump(cidrToRange("127.0.0.15/26")); 

Trước khi sửa chữa:

array(2) { 
    [0]=> 
    string(9) "127.0.0.0" 
    [1]=> 
    string(10) "127.0.0.78" 
} 
string(41) "127.0.0.15/26 >> 2130706432 -> 2130706510" 

Sau khi sửa chữa:

array(2) { 
    [0]=> 
    string(9) "127.0.0.0" 
    [1]=> 
    string(10) "127.0.0.63" 
} 
string(41) "127.0.0.15/26 >> 2130706432 -> 2130706495" 
+1

Đây là mã viết, nếu chúng ta kiểm tra mã được chấp nhận ở trên với ví dụ này, nó sẽ không hoạt động. 110.143.0.55/16. Cảm ơn bạn Flip :) –

+0

Đây là giải pháp đúng. Đã khắc phục giải pháp được chấp nhận để tránh phổ biến lỗi. – Toto

2

Đây là một chức năng 64bits nhanh để làm điều đó, hãy bình luận dòng trở lại bạn không cần. Chấp nhận bất kỳ IPv4 hợp lệ có hoặc không có giá trị CIDR Routing Prefix ví dụ 63.161.156.0/ hoặc 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; 
} 

Để chạy nhanh các chức năng không kiểm tra đầu vào nhưng chính thức nó phải là một chuỗi phù hợp với sau regex

#^(?:((?: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]))))?)$# 

Nếu bạn muốn xác minh các đầu vào trước khi sử dụng chức năng

<?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); 
} 

Để nhận phạm vi đầy đủ làm một mảng cho một IP nhất định (có hoặc không có Tiền tố định tuyến CIDR), bạn có thể sử dụng mã sau nhưng cẩn thận vì ví dụ 25.25.25.25/16 trở lại một mảng với 65536 yếu tố và bạn có thể dễ dàng chạy ra khỏi bộ nhớ sử dụng một Routing nhỏ Prefix

<?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); 

Để tiến nhanh về kiểm tra xem một cho ipv4 là phù hợp với một CIDR cho bạn có thể làm điều đó như thế nào trong inline ví dụ này

<?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; 
} 

Để kiểm tra nhanh chóng nếu được ipv4 là phù hợp với một mảng nhất định IP (có hoặc không có CIDR Routing Prefix)

<?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'; 

hy vọng rằng những vài dòng đã giúp bạn ...

+0

Fantastic - giải thích đúng đắn và kỹ lưỡng, cảm ơn bạn. – seb835

-1

tôi đã có một số vấn đề với các phiên bản trước, các lỗi PHP khác nhau như không xác định bù đắp, vv

Tôi tìm thấy những gì tôi nghĩ là một cách tốt hơn để làm điều đó mà không có lỗi như chi tiết dưới đây.

Điều này sẽ ghi địa chỉ IP của IPV4 CIDR và ​​có thể được sử dụng để lấy địa chỉ IP bắt đầu/kết thúc của phạm vi CIDR hoặc đếm tổng số địa chỉ IP trong cơ sở dữ liệu địa chỉ IP.

$count = 0; 
    $result = $sia_db_con->query("SELECT `ip_address` FROM `ip4` WHERE `ip_ban_active`='True' ORDER BY ip4.added ASC"); 
while ($row = $result->fetch_array()) { 
    $pos = strpos($row[0], "/"); 
    $ip_arr = [0 => substr($row[0], 0, $pos), 1 => substr($row[0], $pos+1)]; 
    $start = cidr2ip($ip_arr)[0]; 
    $end = cidr2ip($ip_arr)[1]; 
    $count = $count + (ip2long($end) - ip2long($start)) + 1; 
} 
    unset($result, $row, $pos, $ip_arr, $start, $end, $range); 

function cidr2ip($cidr) { 
    $start = ip2long($cidr[0]); 
    $nm = $cidr[1]; 
    $num = pow(2, 32 - $nm); 
    $end = $start + $num - 1; 
    $range = [0 => $cidr[0], 1 => long2ip($end)]; 
    unset($start, $nm, $num, $end); 
    return $range; 
} 

Bí quyết ở đây là cách tôi tạo biến $ ip_arr. Thay vì sử dụng phát nổ PHP, tôi đặt kích thước mảng theo cách thủ công cho từng địa chỉ IP. Đây tất nhiên là một phiên bản cơ sở dữ liệu của mã và các chu kỳ thông qua tất cả các địa chỉ IP trong cơ sở dữ liệu đáp ứng các tiêu chí tìm kiếm.

+0

Để nhận tổng số máy chủ từ địa chỉ IPID CIDR của IPV4, bạn chỉ cần sử dụng: $ count = 0; $ count = $ count + pow (2, 32 - substr ($ ip, strpos ($ ip, "/") + 1)); Trong đó $ ip là địa chỉ IP CIDR IPV4. Bạn cũng có thể lặp qua nhiều địa chỉ IP, từ một cơ sở dữ liệu chẳng hạn. Điều này là ngắn gọn và đơn giản như tôi đã thấy. – AndyC

+0

Để nhận tổng số máy chủ từ địa chỉ IPV6 CIDR, bạn có thể chỉ cần sử dụng: $ count = 0; $ count = $ count + pow (2, 128 - substr ($ ip, strpos ($ ip, "/") + 1)); Trong đó $ ip là địa chỉ IP IPV6 CIDR. Bạn cũng có thể lặp qua nhiều địa chỉ IP, từ một cơ sở dữ liệu chẳng hạn. – AndyC

Các vấn đề liên quan