2010-05-02 3 views
29

Ich möchte IP-Adressen in meiner Datenbank speichern, aber ich muss sie auch in meiner gesamten Anwendung verwenden. Ich lese über INET_ATON() und INET_NTOA() in meinen MySQL-Abfragen, um eine 32-Bit-Ganzzahl ohne Vorzeichen aus einer IP-Adresse zu erhalten, was genau das ist, was ich schneller durch die Datenbank suchen werde als mit char (15).INET_ATON() und INET_NTOA() in PHP?

Die Sache ist, ich kann eine Funktion nicht finden, die die gleiche Sache in PHP tut. Das einzige, was ich kam über ist:

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

So testete ich es:

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

Und es gibt nichts. In dem Beispiel, das sie gaben, scheint es zu funktionieren, aber dann bin ich mir nicht sicher, ob ip2long() dasselbe tut wie INET_ATON().

Kennt jemand eine PHP-Funktion, die dies tun wird? Oder sogar eine völlig neue Lösung zum Speichern einer IP-Adresse in einer Datenbank?

Danke.

+0

hinzuzufügen vergessen, ich bin auf localhost arbeiten, so vielleicht deshalb ip2long() gibt nichts zurück? – blerh

+0

Das IPv4 von localhost ist immer noch 127.0.0.1, es sollte funktionieren, außer Sie verwenden IPv6 - überprüfen Sie meine Antwort. –

Antwort

34

Die Funktionen ip2long() und long2ip() sollten gut funktionieren.

Hinweis: Sie sollten die für IPv4-Adressen verwenden - stellen Sie sicher, dass in Ihrem Fall $_SERVER['REMOTE_ADDR'] enthält tatsächlich eine gültige IPv4-Adresse (und nicht einen IPv6-stuff).


Der Versuch, auf einer Google-IP-Adresse:

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

ich die folgende Ausgabe:

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

ip2long zu INET_ATON entspricht().

ip2long funktioniert nur mit IPv4. Ich vermute, dass Ihr System IPv6 für Loopback verwendet. Versuchen Sie, REMOTE_ADDR zu drucken.

+1

Ah Ich kann sehen, warum es jetzt nicht funktioniert, '$ _SERVER ['REMOTE_ADDR']' gibt zurück: ':: 1'. Wahrscheinlich, weil ich auf localhost bin. Gibt es einen Weg dies zu verhindern? Oder muss ich überprüfen, ob es ':: 1 'zurückgibt? – blerh

+1

:: 1 ist die IPv6 for Loopback. Sie müssen IPv6 deaktivieren. Für Linux, folgen Sie dieser Anweisung: http://blog.taragana.com/index.php/archive/how-to-disable-ipv6-on-fedora-linux-why/ –

11

Verwenden Sie für die Unterstützung von IPv4 und IPv6 inet_pton() und inet_ntop(), diese sind seit PHP 5.1 verfügbar und entsprechen genau den entsprechenden MySQL-Funktionen.

Ansonsten verwenden Sie einfach ip2long() und long2ip().

+0

Ich konnte dies nicht nachahmen. – Artistan

29

Es gibt eine wichtige Unterscheidung zwischen ip2long, long2ip und den MySQL-Funktionen.

PHP's ip2long und long2ip befassen sich mit vorzeichenbehafteten Ganzzahlen.

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

„Weil PHP Integer-Typ signiert ist, und viele IP-Adressen in negativen ganzen Zahlen auf 32-Bit-Architekturen führen wird, können Sie die '% u' Formatierer von sprintf verwenden müssen() oder printf(), um die Zeichenfolgendarstellung der nicht signierten IP-Adresse zu erhalten."

MySQL INET_ATON() und INET_NTOA() Deal mit unsignierten ganzen Zahlen

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

" Zum Speichern von Werten, die durch INET_ATON(), verwenden Sie eine INT UNSIGNED Spalte statt INT, die signiert ist. Wenn Sie eine signierte Spalte verwenden, Werte entsprechend IP-Adressen, für die das erste Oktett größer als 127 ist nicht korrekt gespeichert werden.“

Hier sind einige Funktionen, die Sie verwenden können, zwischen den beiden zu arbeiten.

Wenn Sie in die MySQL-Datenbank eingefügt, eine IP-INET_ATON() verwenden, können Sie es zurück in PHP mit dem folgenden konvertieren:

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

Und Sie können es wandeln es in der Datenbank von PHP speichern diese mit:

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

(auch wichtig, nicht die $ip_address zu int, da dies zu Problemen führen, durch das Einwickeln der Anzahl nicht typ werfen, wenn es größer als MAX_INT. Wenn Sie es umwandeln müssen, werfen Sie es auf eine long oder float)

+0

Funktioniert wie ein Charme. Vielen Dank für den Tipp. Das war mir nie bewusst. –

+3

'ip2long' auf einem 64-Bit-System ergibt ein vorzeichenloses Ergebnis. "% u" wird aber in diesem Fall immer noch das Richtige tun. – Brilliand

14

Sie sollten nicht mit dem innerhalb von PHP beschäftigen, das ist, was MySQL native Funktionen sind. Sehen Sie folgendes Beispiel:

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

Wenn Sie mit beiden umgehen wollen IPv4- und IPv6 im gleichen Feld, und Sie verwenden Mysql 5.6 oder höher, können Sie varbinary (16) und die Funktionen inet6_aton und inet6_ntoa. Dies ist ein besseres Beispiel dafür, warum Sie MySQL-Funktionen verwenden sollten und nicht mit binären Daten in PHP beschäftigen:

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

Sie können sehen, dass dadurch, man kann eigentlich mit vermeiden IPv6-Adressen in verschiedenen Formaten zu bewerten, da MySQL konvertiert sie in Binärdateien und zurück zu ihrem einfachsten Ausdruck.

Ich weiß, dass diese Frage mehr als 2 Jahre bereits hat, aber ich möchte diese Informationen für andere nützlich sein, die rüberkommen.

HTH

Francisco Zarabozo

+0

Was ist, wenn Sie sie mit einer vorbereiteten Anweisung einfügen müssen? Sie können einen Parameter nicht an mysql Funktionen, 'INET_ATON (?)', Binden, also müssen Sie php verwenden –

+0

@the_nuts Wovon redest du? Ja, du kannst. Probieren Sie es selbst aus. –

+0

ja ich habe es entschuldigt :) –

3

PHP Hier alternative Funktionen (einfaches Kopieren/Einfügen in Ihrem Programm) -

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