Question

Je suis en train de stocker les adresses IPv6 dans MySQL 5.0 de manière efficace. J'ai lu les autres questions à ce sujet, tels que celui-ci . L'auteur de cette question a choisi finalement pour deux champs BIGINT. Mes recherches ont également tourné un autre mécanisme souvent utilisé: DECIMAL (39,0) pour stocker l'adresse IPv6. J'ai deux questions à ce sujet.

  1. Quels sont les avantages et les inconvénients de l'utilisation DECIMAL (39,0) par rapport aux autres méthodes telles que 2 * BIGINT?
  2. Comment puis-je convertir (en PHP) à partir du format binaire retourné par inet_pton () un format de chaîne décimale utilisable par MySQL, et comment puis-je reconvertir si je peux jolie imprimer avec inet_ntop ()?
Était-ce utile?

La solution 2

Voici les fonctions que j'utilise maintenant pour convertir les adresses IP à partir et au format DECIMAL (39,0). Ils sont nommés inet_ptod et inet_dtop pour « présentation à la décimale » et « décimale à la présentation ». Il a besoin du soutien IPv6 et bcmath en PHP.

/**
 * Convert an IP address from presentation to decimal(39,0) format suitable for storage in MySQL
 *
 * @param string $ip_address An IP address in IPv4, IPv6 or decimal notation
 * @return string The IP address in decimal notation
 */
function inet_ptod($ip_address)
{
    // IPv4 address
    if (strpos($ip_address, ':') === false && strpos($ip_address, '.') !== false) {
        $ip_address = '::' . $ip_address;
    }

    // IPv6 address
    if (strpos($ip_address, ':') !== false) {
        $network = inet_pton($ip_address);
        $parts = unpack('N*', $network);

        foreach ($parts as &$part) {
            if ($part < 0) {
                $part = bcadd((string) $part, '4294967296');
            }

            if (!is_string($part)) {
                $part = (string) $part;
            }
        }

        $decimal = $parts[4];
        $decimal = bcadd($decimal, bcmul($parts[3], '4294967296'));
        $decimal = bcadd($decimal, bcmul($parts[2], '18446744073709551616'));
        $decimal = bcadd($decimal, bcmul($parts[1], '79228162514264337593543950336'));

        return $decimal;
    }

    // Decimal address
    return $ip_address;
}

/**
 * Convert an IP address from decimal format to presentation format
 *
 * @param string $decimal An IP address in IPv4, IPv6 or decimal notation
 * @return string The IP address in presentation format
 */
function inet_dtop($decimal)
{
    // IPv4 or IPv6 format
    if (strpos($decimal, ':') !== false || strpos($decimal, '.') !== false) {
        return $decimal;
    }

    // Decimal format
    $parts = array();
    $parts[1] = bcdiv($decimal, '79228162514264337593543950336', 0);
    $decimal = bcsub($decimal, bcmul($parts[1], '79228162514264337593543950336'));
    $parts[2] = bcdiv($decimal, '18446744073709551616', 0);
    $decimal = bcsub($decimal, bcmul($parts[2], '18446744073709551616'));
    $parts[3] = bcdiv($decimal, '4294967296', 0);
    $decimal = bcsub($decimal, bcmul($parts[3], '4294967296'));
    $parts[4] = $decimal;

    foreach ($parts as &$part) {
        if (bccomp($part, '2147483647') == 1) {
            $part = bcsub($part, '4294967296');
        }

        $part = (int) $part;
    }

    $network = pack('N4', $parts[1], $parts[2], $parts[3], $parts[4]);
    $ip_address = inet_ntop($network);

    // Turn IPv6 to IPv4 if it's IPv4
    if (preg_match('/^::\d+.\d+.\d+.\d+$/', $ip_address)) {
        return substr($ip_address, 2);
    }

    return $ip_address;
}

Autres conseils

Nous sommes allés pour une colonne de VARBINARY(16) au lieu et utiliser inet_pton() et inet_ntop() pour faire les conversions:

https://github.com/skion/mysql-udf-ipv6

Les fonctions peuvent être chargées dans un serveur MySQL en cours d'exécution et vous donnera INET6_NTOP et INET6_PTON dans SQL, tout comme les fonctions familières de INET_NTOA et INET_ATON pour IPv4.

Edit: Il y a des fonctions compatibles dans MySQL maintenant, juste avec href="http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_inet6-ntoa" rel="nofollow noreferrer"> noms . Utilisez uniquement ce qui précède si vous êtes pré-MySQL 5.6 et recherchez un chemin de mise à niveau future pratique.

DECIMAL (39)

Avantages:

  • Fonctionne avec les opérateurs arithmétiques de base (tels que + et -).
  • Fonctionne avec l'indexation de base (exacte ou la plage).
  • Le format est affichage convivial.

Moins:

  • peut-il accepter de valeurs de la plage pour IPv6.
  • est pas un mécanisme de stockage très efficace.
  • Peut causer de la confusion à laquelle les opérateurs mathématiques ou des fonctions de travail et qui ne le font pas.

BINARY (16) ...

Avantages:

  • format le plus efficace pour la représentation exacte.
  • Fonctionne avec l'indexation de base (exacte et plage).
  • Fonctionne avec indexation préfixe pour les préfixes qui sont des multiples de 8 bits.
  • ne stocke que les valeurs IPv6 valides (bien que ne garantit pas valable adressage).
  • MySQL dans les versions ultérieures a des fonctions qui prennent en charge les conversions pour ce format et des représentations IPv6 (mais pas 4in6).

Moins:

  • Contenu non pour l'affichage.
  • est pas facile avec des opérateurs ou des fonctions destinées pour les nombres.

BINARY (39) ...

Ceci est pour les adresses complètes (en utilisant hexdec même pour 4in6). Peut aussi être ascii plutôt que binaire.

Avantages:

  • Texte lisible (si vous pouvez appeler IPv6).
  • Prise en charge de l'indexation de base (exacte et plage).
  • Supports indexation de préfixe pour multiple de 4 bits.
  • directement compatibles avec IPv6. Aucune conversion nécessaire.

Moins:

  • ne fonctionne pas bien avec des fonctions mathématiques ou opérateurs.
  • stockage les plus inefficaces.
  • peut permettre à des représentations non valides.

Bizarreries:

  • Obtient complexe si vous voulez que les choses telles que la casse.
  • IPv6 a d'autres formats d'affichage bien l'utilisation de ces marques pour plus complexes, comme vous pouvez avoir deux représentations de la même adresse ou vous perdez de gamme lookups. Peut même finir par avoir à le rendre 45 octets ou en utilisant varchar / varbinary.
  • Variances de ce qui peut soutenir la préservation de l'adresse initialement reçue. Cela peut rarement être désiré, mais quand il vous perdez beaucoup d'avantages.
  • Retirez les séparateurs avec format complet et juste magasin est sous forme de chaîne hexagonale pour moins de tracas et un peu plus d'efficacité. Vous pouvez prendre ce un long chemin si l'indexation de préfixe est important (BINARY (128)).

UNSIGNED BIGINT * 2

Avantages:

  • travaille avec des opérateurs mathématiques et fonctions avec la mise en garde d'avoir à faire des choses supplémentaires autour étant deux colonnes.
  • efficace mais encore une fois la mise en garde qu'il étant deux colonnes ajoutera certains frais généraux.
  • Fonctionne avec des index de base (exactes, gamme).
  • Fonctionne avec index de préfixe lorsque le préfixe est de 64 bits.
  • Format d'affichage convivial.

Moins:

  • Deux colonnes rend non atomique et signifie doubler d'un grand nombre d'opérations sur elle.

Bizarreries:

  • Beaucoup de langues modernes et des systèmes donnent 64 ints bit mais pas non signé. Signé est problématique. Les nombres négatifs présents comme plus faible que positif, mais leurs séquences de bits sont plus élevés. Pour cette raison, il est plutôt courant d'utiliser 4 * unsigned int.
  • De même les gens pourraient le casser pour l'indexation de préfixe et vous pouvez aller au moins aussi loin que 8 bits (TINYINT non signé). Certaines personnes peuvent également utiliser le BIT (1) de type pour l'indexation préfixe complet, en supposant des index de POSIT MySQL co sur les types de bits correctement.
  • Encore une fois de même avec quatre colonnes des opérations qui nécessitent des choses comme porter de à une autre sont paradoxalement plus facile en raison de relâcher les bits au cours de calculs (valeurs intermédiaires dans les calculs peuvent être encore 64 bits).

Résumé

Les gens vont utiliser différents formats pour des raisons différentes. rétrocompatibilité peut être une raison et cela dépend de ce qui était fait pour IPv4. D'autres dépendent de la façon dont les adresses sont utilisées et optimisations autour de cela. Vous pouvez voir plus d'une approche utilisée.

B16 est une bonne approche par défaut car il est le plus efficace et sans tracas.

Pour les conversions en PHP, vous pouvez les faire à la main si vous la recherche:

  • ou gmp bcmath
  • manipulation de numéro PHP et les opérateurs de bits, être particulièrement conscient des limites sur int ou flottent ainsi que des fonctions qui dépendent de ceux qui pourraient sembler par ailleurs utile
  • Les formats IPv6
  • Pack / déballer, bin2hex / HEX2BIN.

Je recommande cependant l'utilisation d'une bibliothèque commune pour faire face aux différents formats d'affichage de IPv6.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top