Pregunta

Estoy tratando de almacenar direcciones IPv6 en MySQL 5.0 de una manera eficiente. He leído las otras preguntas relacionadas con esta, como éste . El autor de la pregunta, finalmente, optó por dos campos BIGINT. Mis búsquedas también han aparecido otro mecanismo de uso frecuente: El uso de un decimal (39,0) para almacenar la dirección IPv6. Tengo dos preguntas al respecto.

  1. ¿Cuáles son las ventajas y desventajas del uso de DECIMAL (39,0) sobre los otros métodos tales como 2 * BIGINT?
  2. ¿Cómo se convierte (en PHP) desde el formato binario tal como lo devuelve inet_pton () para un formato utilizable por cadena decimal de MySQL, y cómo puedo convertir de nuevo para que pueda imprimir con bastante-inet_ntop ()?
¿Fue útil?

Solución 2

Estas son las funciones que ahora utilizo para convertir las direcciones IP desde y hacia el formato decimal (39,0). Se llaman inet_ptod y inet_dtop para "presentación-a-decimal" y "decimal-a-presentación". Se necesita el apoyo IPv6 y 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;
}

Otros consejos

Fuimos para una columna VARBINARY(16) lugar y usar inet_pton() y inet_ntop() para hacer las conversiones:

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

Las funciones se pueden cargar en un servidor MySQL corriendo y le dará INET6_NTOP y INET6_PTON en SQL, así como las funciones y INET_NTOA INET_ATON familiares para IPv4.

Edit: Hay funciones compatibles en MySQL ahora, sólo con href="http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_inet6-ntoa" rel="nofollow noreferrer"> nombres . Sólo utilice el anterior si se encuentra en pre-5.6 MySQL y busca un futuro conveniente actualizar camino.

DECIMAL (39)

Pros:

  • Funciona con operadores aritméticos básicos (como + y -).
  • funciona con la indexación básica (exacta o rango).
  • El formato es mostrar usar.

Contras:

  • ¿Puede aceptar valores fuera de rango para IPv6.
  • No es un mecanismo de almacenamiento muy eficiente.
  • Puede causar confusión en cuanto a que los operadores o funciones matemáticas funcionan y cuáles no.

binario (16) ...

Pros:

  • formato más eficiente para la representación exacta.
  • funciona con la indexación básica (exacta y la gama).
  • funciona con la indexación de prefijo para los prefijos que son múltiplos de 8 bits.
  • Tiendas de IPv6 sólo valores válidos (aunque no garantiza la validez direccionamiento).
  • MySQL en versiones posteriores tiene funciones que soportan las conversiones para este formato a y a partir de representaciones IPv6 (pero no 4in6).

Contras:

  • No es muy agradable para su visualización.
  • No es amigable con operadores o funciones que sirven para los números.

binario (39) ...

Esto es para direcciones completas (utilizando hexdec incluso para 4in6). También puede ser ASCII en lugar de binario.

Pros:

  • legible (si se puede llamar IPv6).
  • Compatible con la indexación básica (exacta y la gama).
  • Soporta indexación prefijo para múltiplo de 4 bits.
  • directamente compatibles con IPv6. Sin necesidad de conversión.

Contras:

  • No funciona bien con las funciones u operadores matemáticos.
  • almacenamiento más ineficiente.
  • ¿Puede permitir que las representaciones no válidos.

Rarezas:

  • Obtiene compleja si quieres que las cosas tales como entre mayúsculas y minúsculas.
  • IPv6 tiene otros formatos de visualización, aunque el uso de dichas marcas para más complejidades, como se puede tener dos representaciones de la misma dirección o perder las búsquedas de rango. Incluso puede llegar a tener para que sea 45 bytes de longitud o el uso de varchar / varbinary.
  • Las variaciones de esto se puede apoyar la preservación de la dirección como se recibió originalmente. Que rara vez puede desear, pero cuando se pierde una gran cantidad de beneficios.
  • Eliminar los separadores con formato completo y justo tienda es como una cadena hexadecimal para menos molestias y un poco más eficiencia. Puede llevar esto un largo camino si la indexación prefijo es importante (binario (128)).

BIGINT sin signo * 2

Pros:

  • Funciona con operadores matemáticos y funciones con la salvedad de tener que hacer cosas adicionales alrededor de ella siendo dos columnas.
  • eficiente, pero de nuevo con la advertencia de que siendo dos columnas añadirá algo de sobrecarga.
  • Funciona con índices básicos (exactas, rango).
  • Funciona con índice de prefijo cuando prefijo es de 64 bits.
  • formato amigable de visualización.

Contras:

  • Dos columnas hace que no atómica y los medios de duplicación de una gran cantidad de operaciones en él.

Rarezas:

  • Muchos lenguajes y sistemas modernos dan 64 bits enteros, pero no sin signo. Firmado es problemático. Los números negativos se presentan como más bajo que positiva, pero sus secuencias de bits son más elevados. Por esta razón es común en lugar de utilizar 4 * unsigned int.
  • Del mismo modo la gente podría romperlo para la indexación de prefijo y se puede ir por lo menos tan lejos como 8 bits (TINYINT signo). Algunas personas también pueden hacer uso del TBI (1) de tipo para la indexación prefijo completo, asumiendo MySQL co índices posit sobre los tipos de bits correctamente.
  • de nuevo de manera similar con cuatro columnas algunas operaciones que requieren cosas como llevar de encendido a otro son irónicamente más fácil debido a aflojar los bits durante los cálculos (valores intermedios en los cálculos todavía puede ser 64 bits).

Resumen

La gente va a utilizar diferentes formatos para diferentes razones. Compatibilidad hacia atrás puede ser una razón y que depende de lo que se estaba haciendo para IPv4. Otros dependen de cómo se utilizan las direcciones y OPtimisations alrededor de eso. Usted puede ver más de un enfoque que se utilice.

B16 es un buen método por defecto, ya que es el más eficiente y sin problemas.

Para las conversiones en PHP que puede hacer a mano si la investigación:

  • gmp o bcmath
  • operadores
  • manejo número de PHP y bit a bit, ser especialmente conscientes de las limitaciones de int o float, así como las funciones que dependen de ellos que de otro modo podrían parecer útil
  • Los formatos IPv6
  • paquete / descomprimir, bin2hex / hex2bin.

Yo recomendaría sin embargo con una biblioteca común para hacer frente a diversos formatos de visualización de IPv6.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top