Mysql
 sql >> Base de données >  >> RDS >> Mysql

Impossible de sélectionner où ip=inet_pton($ip)

Tout d'abord, le correctif, qui est assez simple :si vous souhaitez stocker à la fois les adresses IPv4 et IPv6, vous devez utiliser VARBINARY(16) au lieu de BINARY(16) .

Passons maintenant au problème :pourquoi cela ne fonctionne-t-il pas comme prévu avec BINARY(16) ?

Considérons que nous avons une table ips avec une seule colonne ip BINARY(16) PRIMARY KEY .Nous stockons l'adresse IPv4 locale par défaut avec

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

et trouvez la valeur suivante dans la base de données :

0x7F000001000000000000000000000000

Comme vous le voyez - C'est une valeur binaire de 4 octets (0x7F000001 ) rempli à droite avec des zéros pour s'adapter à la colonne de longueur fixe de 16 octets.

Lorsque vous essayez maintenant de le trouver avec

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

ce qui suit se produit :PHP envoie la valeur 0x7F000001 comme paramètre qui est ensuite comparé avec la valeur stockée 0x7F000001000000000000000000000000 .Mais comme deux valeurs binaires de longueurs différentes ne sont jamais égales, la condition WHERE retournera toujours FAUX. Vous pouvez essayer avec

SELECT 0x00 = 0x0000

qui renverra 0 (FAUX).

Remarque :Le comportement est différent pour les chaînes non binaires de longueur fixe (CHAR(N) ).

Nous pourrions utiliser la diffusion explicite comme solution de contournement :

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

et il trouvera la ligne. Mais si nous regardons ce que nous obtenons

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

nous verrons

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

Mais ce n'est pas (vraiment) ce que nous avons essayé de stocker.Et quand nous essayons maintenant de stocker 7f00:1:: , nous obtiendrons une erreur de clé en double , même si nous n'avons encore jamais stocké d'adresse IPv6.

Donc encore une fois :utilisez VARBINARY(16) , et vous pouvez conserver votre code intact. Vous économiserez même de l'espace de stockage si vous stockez de nombreuses adresses IPv4.