2010-05-02 25 views
29

Tôi muốn lưu trữ địa chỉ IP trong cơ sở dữ liệu của mình, nhưng tôi cũng cần sử dụng chúng trong toàn bộ ứng dụng của mình. Tôi đọc về cách sử dụng INET_ATON()INET_NTOA() trong các truy vấn MySQL để lấy số nguyên không dấu 32 bit ra khỏi địa chỉ IP, chính xác là những gì tôi muốn vì nó sẽ tìm kiếm thông qua cơ sở dữ liệu nhanh hơn sử dụng char (15).INET_ATON() và INET_NTOA() bằng PHP?

Vấn đề là, tôi không thể tìm thấy chức năng thực hiện cùng một loại điều trong PHP. Điều duy nhất tôi đi qua là:

http://php.net/manual/en/function.ip2long.php

Vì vậy, tôi đã thử nghiệm nó:

$ip = $_SERVER['REMOTE_ADDR']; 
echo ip2long($ip); 

Và nó ra gì. Trong ví dụ họ đã cho nó có vẻ làm việc, nhưng sau đó một lần nữa tôi không chính xác chắc chắn nếu ip2long() không giống như INET_ATON().

Có ai đó biết một hàm PHP sẽ thực hiện việc này không? Hoặc thậm chí là một giải pháp hoàn toàn mới để lưu trữ địa chỉ IP trong cơ sở dữ liệu?

Cảm ơn.

+0

Quên để thêm, tôi đang làm việc trên localhost, như vậy có lẽ đó là lý do tại sao ip2long() không trả lại bất cứ điều gì? – blerh

+0

IPv4 của localhost vẫn là 127.0.0.1, nó sẽ hoạt động trừ khi bạn đang sử dụng IPv6 - kiểm tra câu trả lời của tôi. –

Trả lời

34

Các chức năng ip2long()long2ip() sẽ hoạt động tốt.

Lưu ý: bạn nên sử dụng chúng cho địa chỉ IPv4 - đảm bảo rằng, trong trường hợp của bạn, $_SERVER['REMOTE_ADDR'] thực sự chứa địa chỉ IPv4 hợp lệ (và không phải một số thứ IPv6).


Đang cố gắng trên một địa chỉ IP google:

var_dump(ip2long('209.85.227.147')); 
var_dump(long2ip(3512066963)); 

tôi nhận được kết quả như sau:

int(3512066963) 
string(14) "209.85.227.147" 
1

ip2long tương đương với inet_aton().

ip2long chỉ hoạt động với IPv4. Tôi nghi ngờ hệ thống của bạn đang sử dụng IPv6 cho loopback. Hãy thử in REMOTE_ADDR.

+1

Tôi có thể thấy tại sao nó không hoạt động, '$ _SERVER ['REMOTE_ADDR']' trả về: ':: 1'. Có lẽ vì tôi đang trên localhost. Có cách nào để ngăn chặn điều này? Hoặc tôi phải làm một kiểm tra để xem nếu nó trở về ':: 1'? – blerh

+1

:: 1 là IPv6 cho loopback. Bạn cần tắt IPv6. Đối với Linux, hãy làm theo hướng dẫn này: http://blog.taragana.com/index.php/archive/how-to-disable-ipv6-on-fedora-linux-why/ –

11

Để sử dụng hỗ trợ IPv4 và IPv6 inet_pton()inet_ntop(), chúng sẵn có kể từ PHP 5.1 trở lên và bắt chước chính xác các hàm MySQL tương đương.

Nếu không, chỉ sử dụng ip2long()long2ip().

+0

tôi đã không thể bắt chước được điều này. – Artistan

29

Có một sự khác biệt quan trọng giữa ip2long, long2ip và các chức năng của MySQL.

PHP ip2longlong2ip đối phó với các số nguyên đã ký.

Xem http://php.net/manual/en/function.ip2long.php

"Bởi vì loại nguyên của PHP được ký kết, và nhiều địa chỉ IP sẽ cho kết quả số nguyên âm trên kiến ​​trúc 32-bit, bạn cần phải sử dụng '% u' formatter của sprintf() hoặc printf() để lấy biểu diễn chuỗi của địa chỉ IP chưa ký."

MySQL của INET_ATON()INET_NTOA() thỏa thuận với số nguyên unsigned

Xem http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_inet-aton

" Để giá trị lưu trữ được tạo ra bởi INET_ATON(), sử dụng một INT cột UNSIGNED hơn INT, được ký kết. Nếu bạn sử dụng một cột có chữ ký, giá trị tương ứng với địa chỉ IP mà octet đầu tiên lớn hơn 127 không thể được lưu trữ một cách chính xác."

Dưới đây là một số chức năng bạn có thể sử dụng để làm việc giữa hai người.

Nếu bạn đưa vào cơ sở dữ liệu MySQL, một IP sử dụng INET_ATON(), bạn có thể chuyển đổi nó trở lại trong PHP sử dụng như sau:

long2ip(sprintf("%d", $ip_address)); 

Và bạn có thể chuyển đổi nó để lưu nó trong cơ sở dữ liệu từ PHP sử dụng này:

sprintf("%u", ip2long($ip_address)); 

(Cũng rất quan trọng, đừng gõ-cast $ip_address để int vì điều này có thể gây ra các vấn đề bằng cách gói số nếu nó lớn hơn MAX_INT. Nếu bạn phải bỏ nó, hãy đưa nó vào một số long hoặc float)

+0

Làm việc như một sự quyến rũ. Cảm ơn rất nhiều về mẹo. Tôi chưa bao giờ biết điều đó. –

+3

'ip2long' trên hệ thống 64 bit sẽ cho kết quả không dấu. Tuy nhiên, "% u" vẫn sẽ làm điều đúng trong trường hợp đó. – Brilliand

14

Bạn không cần phải đối phó với điều đó bên trong PHP, đó là những gì mà funcion gốc của MySQL dành cho. Xem ví dụ sau:

create table iptable (
    ip int(32) unsigned not null, 
    comment varchar(32) not null 
); 

insert into iptable (ip, comment) values (inet_aton('10.0.0.3'), 'This is 10.0.0.3'); 

select * from iptable; 

+-----------+------------------+ 
| ip  | comment   | 
+-----------+------------------+ 
| 167772163 | This is 10.0.0.3 | 
+-----------+------------------+ 

select inet_ntoa(ip) as ip, comment from iptable; 

+----------+------------------+ 
| ip  | comment   | 
+----------+------------------+ 
| 10.0.0.3 | This is 10.0.0.3 | 
+----------+------------------+ 

Nếu bạn muốn để đối phó với cả IPv4 và IPv6 trong cùng lĩnh vực, và bạn đang sử dụng Mysql 5.6 hoặc cao hơn, bạn có thể sử dụng varbinary (16) và các chức năng inet6_aton và inet6_ntoa. Đây là một ví dụ tốt hơn về lý do tại sao bạn nên sử dụng chức năng MySQL và không đối phó với dữ liệu nhị phân bên trong PHP:

create table iptable2 (
    ip varbinary(16) not null, 
    comment varchar(32) not null 
); 

insert into iptable2 (ip, comment) values 
    (inet6_aton('192.168.1.254'), 'This is router 192.168.1.254'), 
    (inet6_aton('::1'), 'This is ipv6 localhost ::1'), 
    (inet6_aton('FE80:0000:0000:0000:0202:B3FF:FE1E:8329'), 'This is some large ipv6 example') 
; 

select * from iptable2; 
+------------------+---------------------------------+ 
| ip    | comment       | 
+------------------+---------------------------------+ 
| +¿?¦    | This is router 192.168.1.254 | 
|    ? | This is ipv6 localhost ::1  | 
| ¦Ç  ??¦ ¦?â) | This is some large ipv6 example | 
+------------------+---------------------------------+ 

select inet6_ntoa(ip) as ip, comment from iptable2; 
+--------------------------+---------------------------------+ 
| ip      | comment       | 
+--------------------------+---------------------------------+ 
| 192.168.1.254   | This is router 192.168.1.254 | 
| ::1      | This is ipv6 localhost ::1  | 
| fe80::202:b3ff:fe1e:8329 | This is some large ipv6 example | 
+--------------------------+---------------------------------+ 

Bạn có thể thấy rằng bằng cách làm này, bạn thực sự có thể tránh được việc phải đánh giá các địa chỉ ipv6 trong các định dạng khác nhau, kể từ MySQL chuyển đổi chúng thành nhị phân và trở lại biểu thức đơn giản nhất của chúng.

Tôi biết câu hỏi này đã có hơn 2 năm rồi, nhưng tôi muốn để thông tin này hữu ích cho những người khác gặp phải.

HTH

Francisco Zarabozo

+0

Điều gì xảy ra nếu bạn phải chèn chúng với một tuyên bố đã chuẩn bị? Bạn không thể liên kết một tham số với các hàm mysql, 'INET_ATON (?)', Vì vậy bạn phải sử dụng php –

+0

@the_nuts Bạn đang nói về cái gì? Có, bạn có thể. Hãy thử nó cho chính mình. –

+0

vâng tôi đã giải quyết nó xin lỗi :) –

3

Đây PHP chức năng thay thế (đơn giản copy/paste trong chương trình của bạn) -

function inet_aton($ip) 
{ 
    $ip = trim($ip); 
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) return 0; 
    return sprintf("%u", ip2long($ip)); 
} 


function inet_ntoa($num) 
{ 
    $num = trim($num); 
    if ($num == "0") return "0.0.0.0"; 
    return long2ip(-(4294967295 - ($num - 1))); 
} 
Các vấn đề liên quan