2010-05-02 37 views
29

我想在我的數據庫中存儲IP地址,但我也需要在我的應用程序中使用它們。我讀到了在我的MySQL查詢中使用INET_ATON()INET_NTOA()從IP地址獲取32位無符號整數,這正是我想要的,因爲它將比使用char(15)更快地搜索數據庫。PHP中的INET_ATON()和INET_NTOA()?

事情是,我找不到在PHP中執行相同類型的功能的函數。我遇到的唯一的事情是:

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

所以我測試了它:

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

並將其輸出什麼。在他們的例子中,它似乎可以工作,但是我再次不確定ip2long()是否與INET_ATON()做同樣的事情。

有人知道一個PHP函數會這樣做嗎?甚至是一個全新的解決方案來存儲IP地址到數據庫中?

謝謝。

+0

忘了補充,我工作在本地主機上,所以也許這就是爲什麼ip2long()不返回任何東西? – blerh 2010-05-02 17:46:34

+0

本地主機的IPv4仍然是127.0.0.1,它應該工作,除非你使用IPv6 - 檢查我的答案。 – 2010-05-02 18:40:15

回答

34

ip2long()long2ip()函數應該可以正常工作。

注意:你應該使用那些IPv4地址 - 確保在你的情況下,$_SERVER['REMOTE_ADDR']實際上包含有效的IPv4地址(而不是一些IPv6的東西)


嘗試在谷歌的IP地址:

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

我得到以下輸出:

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

ip2long相當於INET_ATON()。

ip2long只適用於IPv4。我懷疑你的系統使用IPv6進行環回。嘗試打印REMOTE_ADDR。

+1

啊我可以看到爲什麼它現在不工作,$ _SERVER ['REMOTE_ADDR']'返回:':: 1'。可能是因爲我在本地主機上。有沒有辦法來防止這種情況?或者我必須檢查它是否返回':: 1'? – blerh 2010-05-02 17:52:14

+1

:: 1是用於回送的IPv6。您需要禁用IPv6。對於Linux,請遵循以下說明:http://blog.taragana.com/index.php/archive/how-to-disable-ipv6-on-fedora-linux-why/ – 2010-05-02 18:07:47

11

對於IPv4和IPv6支持,請使用inet_pton()inet_ntop(),這些都是可用的,因爲PHP 5.1+和模仿完全相同的MySQL功能。

否則只需使用ip2long()long2ip()

+0

我一直無法模仿此操作。 – Artistan 2015-02-26 13:31:26

29

ip2long,long2ip與MySQL函數之間有一個重要的區別。

PHP的ip2longlong2ip涉及有符號整數。

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

「因爲PHP的整數類型是有符號的,很多IP地址會導致在32位架構負整數,你需要使用‘%U’的sprintf的格式()或printf()獲取未簽名IP地址的字符串表示。「

MySQL的INET_ATON()INET_NTOA()處理無符號整數

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

」),由INET_ATON(產生的存儲值,使用INT UNSIGNED列,而不是INT,這是簽署。如果你使用一個簽名欄,值對應於這第一個字節大於127不能被正確存儲的IP地址。」

這裏有一些功能,你可以使用這兩個之間的工作。

如果您插入MySQL數據庫,使用INET_ATON()的IP,則可以使用下面的轉換回在PHP中:

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

而且你可以將它用這個將其保存在從PHP數據庫:

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

(同樣重要的,不要類型轉換的$ip_addressint,因爲這通過包裝數量,如果它比MAX_INT大可能會導致問題。如果你必須投它,把它投到longfloat

+0

工程就像一個魅力。非常感謝小費。我從來沒有意識到這一點。 – 2013-09-20 10:24:05

+3

在64位系統上'ip2long'會給出一個無符號的結果。不過,「%u」在這種情況下仍然會做正確的事情。 – Brilliand 2014-01-28 17:25:33

14

你不應該在PHP內部處理,這就是MySQL本地功能。看到這個例子:

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 | 
+----------+------------------+ 

如果你想同時處理IPv4和IPv6在同一領域,以及你正在使用MySQL 5.6或更高版本,您可以用VARBINARY(16)和inet6_aton的功能和inet6_ntoa。這就是爲什麼你應該使用MySQL的功能,而不是處理內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 | 
+--------------------------+---------------------------------+ 

你可以看到,通過這樣做,你可以真正避免,以評估在不同格式的IPv6地址,因爲MySQL將它們轉換爲二進制文件並返回到它們最簡單的表達式。

我知道這個問題已經有2年多了,但我想讓這些信息對其他人有用。

HTH

舊金山Zarabozo

+0

如果您必須將它們與準備好的聲明一起插入,該怎麼辦?你不能綁定一個參數到mysql函數'INET_ATON(?)',所以你必須使用php – 2016-07-07 10:41:51

+0

@the_nuts你在說什麼?是的你可以。自己嘗試一下。 – 2016-07-07 15:04:17

+0

是的,我解決了它對不起:) – 2016-07-07 15:54:54

3

這裏PHP替代功能(簡單的複製/粘貼在你的程序) -

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