Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Kann nicht auswählen wo ip=inet_pton($ip)

Zuerst die Lösung, die ganz einfach ist:Wenn Sie sowohl IPv4- als auch IPv6-Adressen speichern möchten, sollten Sie VARBINARY(16) verwenden statt BINARY(16) .

Nun zum Problem:Warum funktioniert es mit BINARY(16) nicht wie erwartet ?

Stellen Sie sich vor, wir haben eine Tabelle ips mit nur einer Spalte ip BINARY(16) PRIMARY KEY .Wir speichern die standardmäßige lokale IPv4-Adresse mit

$stmt = $db->prepare("INSERT INTO ips(ip) VALUES(?)");
$stmt->execute([inet_pton('127.0.0.1')]);

und finden Sie den folgenden Wert in der Datenbank:

0x7F000001000000000000000000000000

Wie Sie sehen, handelt es sich um einen 4-Byte-Binärwert (0x7F000001 ) rechts mit Nullen aufgefüllt, um in die 16-Byte-Spalte mit fester Länge zu passen.

Wenn Sie jetzt versuchen, es mit

zu finden
$stmt = $db->prepare("SELECT * FROM ips WHERE ip = ?");
$stmt->execute([inet_pton('127.0.0.1')]);

Folgendes passiert:PHP sendet den Wert 0x7F000001 als Parameter, der dann mit dem gespeicherten Wert 0x7F000001000000000000000000000000 verglichen wird .Aber da zwei Binärwerte unterschiedlicher Länge niemals gleich sind, wird die WHERE-Bedingung immer FALSE zurückgeben.Sie können es mit

versuchen
SELECT 0x00 = 0x0000

was 0 zurückgibt (FALSCH).

Hinweis:Das Verhalten ist anders für nicht binäre Zeichenfolgen mit fester Länge (CHAR(N) ).

Wir könnten explizites Casting als Problemumgehung verwenden:

$stmt = $db->prepare("SELECT * FROM ips WHERE ip = CAST(? as BINARY(16))");
$stmt->execute([inet_pton('127.0.0.1')]);

und es wird die Zeile finden. Aber wenn wir uns ansehen, was wir bekommen

var_dump(inet_ntop($stmt->fetch(PDO::FETCH_OBJ)->ip));

wir werden sehen

string(8) "7f00:1::"

Aber das ist (wirklich) nicht das, was wir zu speichern versucht haben. Und wenn wir jetzt versuchen, 7f00:1:: zu speichern , erhalten wir einen Fehler wegen doppeltem Schlüssel ,obwohl wir noch nie eine IPv6-Adresse gespeichert haben.

Also nochmal:Verwenden Sie VARBINARY(16) , und Sie können Ihren Code unverändert lassen. Sie sparen sogar Speicherplatz, wenn Sie viele IPv4-Adressen speichern.