2013-08-16 31 views
11

Trong IPv4 chúng ta có thể sử dụng ip2long để chuyển nó sang số,Php chuyển đổi ipv6 lên vị trí số

Làm thế nào để chuyển đổi ipv6 nén để số trong PHP?

Tôi đã thử inet_pton và nó không hoạt động.

$ip_1='2001:0db8:85a3:0000:0000:8a2e:0370:7334'; 
$ip_2='2001:11ff:ffff:f';//Compressed 
echo inet_pton($ip_1); 
//OUTPUT ИЃ.ps4 
echo inet_pton($ip_2); 
//OUTPUT Warning: inet_pton(): Unrecognized address 2001:11ff:ffff:f 
+0

đầu ra bạn đang nhận được, bất kỳ lỗi gì? – Halcyon

+3

PHP có một kiểu dữ liệu 128-bit không? – SLaks

+0

Lần đầu tiên tôi nhận được văn bản lạ thứ hai một nén tôi nhận được lỗi – Ben

Trả lời

7

$ ip_2 không phải là một địa chỉ IPv6 hợp lệ. Bạn cần "::" ở đâu đó trong đó, để chỉ ra điểm không thiếu sót.

Nếu bạn có nó là một trong những

$ip_2='2001::11ff:ffff:f'; 
$ip_2='2001:11ff::ffff:f'; 
$ip_2='2001:11ff:ffff::f'; 

sau đó inet_pton() nên hoạt động tốt.

Như đã gợi ý, PHP không có loại 128 nguyên, do đó, tốt nhất bạn có thể nhận được là một chuỗi số trong số chuỗi nhị phân inet_pton() cung cấp cho bạn ... vâng, đó là nó là gì, và đó là lý do tại sao nó trông kỳ lạ. Nếu bạn nhìn vào các bit của chuỗi đó, bạn sẽ thấy chúng chính xác như những gì bạn mong đợi.

Dưới đây là làm thế nào để mở rộng chuỗi nhị phân thành một chuỗi số (argument "0" đã mất tích từ str_pad() ban đầu):

/** 
* @param string $ip A human readable IPv4 or IPv6 address. 
* @return string Decimal number, written out as a string due to limits on the size of int and float. 
*/ 
function ipv6_numeric($ip) { 
    $binNum = ''; 
    foreach (unpack('C*', inet_pton($ip)) as $byte) { 
     $binNum .= str_pad(decbin($byte), 8, "0", STR_PAD_LEFT); 
    } 
    return base_convert(ltrim($binNum, '0'), 2, 10); 
} 
+0

vì vậy tôi nên lưu trữ điều này trong cơ sở dữ liệu? Tôi cố gắng tìm vị trí ip từ db, một cái gì đó như INET_ATON ("123.243.51.83") GIỮA INET_ATON (ip_start) VÀ INET_ATON (ip_end) – Ben

+0

@Ben Vâng, nó phụ thuộc. Bạn chỉ có thể lưu trữ chuỗi nhị phân từ inet_pton(). Chuỗi số thực sự chỉ hữu ích nếu bạn cần sau này thực hiện một số "toán" trên địa chỉ. Nếu bạn chỉ đơn giản là chuẩn hóa các ký hiệu IP, việc so sánh đầu ra của hai ký hiệu inet_pton() là đủ. –

+0

@Ben Oh, vì vậy bạn muốn kiểm tra phạm vi ... tốt, đó là một loại "toán học", do đó, yeah. Bạn có thể muốn sử dụng một chức năng như trên, và sau đó chuyển kết quả cho một cái gì đó giống như các chức năng GMP để làm toán. –

0

Hãy thử điều này

function inet6_to_int64($addr) 
{ 
    /* Expand the address if necessary */ 
    if (strlen($addr) != 39) { 
     $addr = inet6_expand($addr); 
     if ($addr == false) return false; 
    } // if 
    $addr = str_replace(':', '', $addr); 
    $p1 = '0x' . substr($addr, 0, 16); 
    $p2 = '0x' . substr($addr, 16); 
    $p1 = gmp_init($p1); 
    $p2 = gmp_init($p2); 
    $result = array(gmp_strval($p1), gmp_strval($p2)); 
    return $result; 
} // inet6_to_int64() 

Để biết thêm các chức năng hoặc các chi tiết vui lòng truy cập http://www.soucy.org/project/inet6/

+0

gặp lỗi nghiêm trọng: Gọi hàm không xác định gmp_init() – Ben

+1

http://www.php.net/manual/en/gmp.installation.php –

+0

kiểm tra hỗ trợ GMP được bật –

1

OK, một số tiết lộ từ cuộc trò chuyện với Ben Wong ... Các REAL vấn đề là tối ưu hóa tra cứu trong DB về dịch vụ geoIP.

Bố cục DB được cung cấp bởi this geoIP database quá chậm để chỉ có đồng bằng ol 'GIỮA được áp dụng khi bắt đầu và kết thúc, mặc dù bộ nhớ là thiết bị kinh tế nhất bạn có thể nhận được. Đề xuất tôi vạch ra lần đầu tiên trong cuộc trò chuyện là chia nhỏ địa chỉ IP thành 4 int được so sánh tuần tự, nhưng vào thứ hai, điều đó có thể không đủ, vì bạn vẫn đang tìm kiếm trên toàn bộ DB, đó là hơn 1 triệu hàng. Tôi cũng đã có một ý tưởng về làm khớp với mặt nạ mạng con, nhưng cho rằng một số phạm vi không phải là trong mặt nạ lớn, làm điều này có thể, một lần nữa, không đủ.

Tôi sẽ xem những gì tôi có thể làm và tôi sẽ chỉnh sửa câu trả lời này. Nhưng tôi đăng bài này trong thời gian chờ đợi cho bất kỳ ai khác sẵn lòng hỗ trợ việc này.

9

Sử dụng:

$ip = 'fe80:0:0:0:202:b3ff:fe1e:8329'; 
$dec = ip2long_v6($ip); 
$ip2 = long2ip_v6($dec); 

// $ip = fe80:0:0:0:202:b3ff:fe1e:8329 
// $dec = 338288524927261089654163772891438416681 
// $ip2 = fe80::202:b3ff:fe1e:8329 

Chức năng:

Với kích hoạt GMP hoặc BCMATH mở rộng.

function ip2long_v6($ip) { 
    $ip_n = inet_pton($ip); 
    $bin = ''; 
    for ($bit = strlen($ip_n) - 1; $bit >= 0; $bit--) { 
     $bin = sprintf('%08b', ord($ip_n[$bit])) . $bin; 
    } 

    if (function_exists('gmp_init')) { 
     return gmp_strval(gmp_init($bin, 2), 10); 
    } elseif (function_exists('bcadd')) { 
     $dec = '0'; 
     for ($i = 0; $i < strlen($bin); $i++) { 
      $dec = bcmul($dec, '2', 0); 
      $dec = bcadd($dec, $bin[$i], 0); 
     } 
     return $dec; 
    } else { 
     trigger_error('GMP or BCMATH extension not installed!', E_USER_ERROR); 
    } 
} 

function long2ip_v6($dec) { 
    if (function_exists('gmp_init')) { 
     $bin = gmp_strval(gmp_init($dec, 10), 2); 
    } elseif (function_exists('bcadd')) { 
     $bin = ''; 
     do { 
      $bin = bcmod($dec, '2') . $bin; 
      $dec = bcdiv($dec, '2', 0); 
     } while (bccomp($dec, '0')); 
    } else { 
     trigger_error('GMP or BCMATH extension not installed!', E_USER_ERROR); 
    } 

    $bin = str_pad($bin, 128, '0', STR_PAD_LEFT); 
    $ip = array(); 
    for ($bit = 0; $bit <= 7; $bit++) { 
     $bin_part = substr($bin, $bit * 16, 16); 
     $ip[] = dechex(bindec($bin_part)); 
    } 
    $ip = implode(':', $ip); 
    return inet_ntop(inet_pton($ip)); 
} 

demo

3

Lưu ý rằng tất cả các câu trả lời sẽ dẫn đến kết quả không chính xác cho các địa chỉ IP lớn hay đang trải qua một quá trình rất phức tạp để nhận được những con số thực tế. Lấy giá trị số nguyên thực tế từ một địa chỉ IPv6 đòi hỏi hai điều:

  1. hỗ trợ IPv6
  2. GMP extension (--with-gmp)

Với cả hai điều kiện tiên quyết tại chỗ chuyển đổi được đơn giản như:

$ip = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'; 
$int = gmp_import(inet_pton($ip)); 

echo $int; // 340282366920938463463374607431768211455 

Các số nhị phân được đóng gói in_addr đại diện được trả về bởi inet_pton đã là số nguyên và có thể trực tiếp b e được nhập khẩu vào GMP, như minh họa ở trên. Không cần chuyển đổi đặc biệt hay gì cả.

Lưu ý rằng cách khác xung quanh cũng không kém phần đơn giản:

$int = '340282366920938463463374607431768211455'; 
$ip = inet_ntop(str_pad(gmp_export($int), 16, "\0", STR_PAD_LEFT)); 

echo $ip; // ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 

Do đó việc xây dựng hai chức năng mong muốn là đơn giản như:

function ipv6_to_integer($ip) { 
    return (string) gmp_import(inet_pton($ip)); 
} 

function ipv6_from_integer($integer) { 
    return inet_ntop(str_pad(gmp_export($integer), 16, "\0", STR_PAD_LEFT)); 
} 
Các vấn đề liên quan