Pergunta

Eu estou tentando armazenar endereços IPv6 em MySQL 5.0 de forma eficiente. Eu li as outras questões relacionadas a este, tais como esta . O autor da pergunta finalmente escolheu para dois campos BIGINT. Minhas pesquisas também apareceu outro mecanismo frequentemente usado: Usando um DECIMAL (39,0) para armazenar o endereço IPv6. Eu tenho duas perguntas sobre isso.

  1. Quais são as vantagens e desvantagens do uso DECIMAL (39,0) nos outros métodos tais como 2 * BIGINT?
  2. Como faço para converter (em PHP) a partir do formato binário como retornado por inet_pton () para um utilizável formato string decimal pelo MySQL, e como faço para converter de volta para que eu possa pretty-print com inet_ntop ()?
Foi útil?

Solução 2

Aqui estão as funções que agora usam para converter endereços IP de e para DECIMAL (39,0) formato. Eles são nomeados inet_ptod e inet_dtop para "apresentação-se decimal" e "decimal-a-apresentação". Ele precisa de apoio IPv6 e bcmath em 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;
}

Outras dicas

Nós fomos para uma coluna VARBINARY(16) vez e usar inet_pton() inet_ntop() para fazer as conversões:

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

As funções podem ser carregados em um servidor MySQL em execução e lhe dará INET6_NTOP e INET6_PTON em SQL, assim como os familiares funções INET_NTOA e INET_ATON para IPv4.

Edit: Existem funções compatíveis em MySQL agora, apenas com diferente nomes . Só use o acima, se você estiver em pré-5.6 MySQL e estão procurando um caminho de atualização futura conveniente.

DECIMAL (39)

Pros:

  • Trabalha com operadores aritméticos básicos (tais como + e -).
  • Obras com indexação básica (exata ou intervalo).
  • O formato é de exibição amigável.

Contras:

  • Pode aceitar valores fora da faixa para o IPv6.
  • Não é um mecanismo de armazenamento muito eficiente.
  • Pode causar confusão sobre qual operadores matemáticos ou funções de trabalho e quais não.

BINARY (16) ...

Pros:

  • A maioria formato eficiente para a representação exata.
  • Obras com indexação básica (exata e gama).
  • Funciona com indexação prefixo para prefixos que são múltiplos de 8 bits.
  • armazena apenas valores IPv6 válidos (embora não garante válida endereçamento).
  • MySQL em versões posteriores tem funções que as conversões de suporte para este formato de e para representações IPv6 (mas não 4in6).

Contras:

  • Não amigável para exibição.
  • Não é amigável com operadores ou funções destinados para números.

BINARY (39) ...

Isto é para endereços completos (usando hexdec mesmo para 4in6). também pode ser ascii em vez de binário.

Pros:

  • Human legível (se você pode chamar IPv6 isso).
  • Suporta indexação básica (exata e gama).
  • Suporta em prefixo indexação para múltiplo de 4 bits.
  • Diretamente compatível IPv6. necessária nenhuma conversão.

Contras:

  • não funciona bem com quaisquer funções matemáticas ou operadores.
  • A maioria de armazenamento ineficiente.
  • Pode permitir representações inválidos.

Curiosidades:

  • Obtém complexo se você quer que as coisas tais como caso insensível.
  • IPv6 tem outros formatos de exibição Embora o uso dessas marcas para mais complexidades, como você pode ter duas representações do mesmo endereço ou você perde consultas de intervalo. Pode até mesmo acabar por ter de fazê-lo 45 bytes ou usando varchar / varbinary.
  • As variações deste pode suportar preservando o endereço como originalmente recebido. Que podem raramente ser desejado, mas quando você perde um monte de benefícios.
  • Remova os separadores com formato completo e apenas loja é como uma string hexadecimal para menos aborrecimentos e um pouco mais eficiência. Você pode levar isso um longo caminho se a indexação prefixo é importante (binário (128)).

BIGINT UNSIGNED * 2

Pros:

  • Trabalha com operadores matemáticos e funções com a ressalva de ter que fazer coisas extra em torno dele sendo duas colunas.
  • Eficiente mas novamente com a ressalva de que sendo duas colunas irá adicionar alguma sobrecarga.
  • Funciona com índices básicos (exatas, intervalo).
  • Funciona com índice de prefixo quando prefixo tem 64 bits.
  • Mostrar formato amigável.

Contras:

  • Duas colunas torna não-atômica e meios de duplicação de uma série de operações sobre ele.

Curiosidades:

  • Muitas línguas e sistemas modernos dar 64 ints pouco, mas não sem sinal. Assinado é problemática. Os números negativos apresentam como mais baixos do que positivo, mas as suas sequências de bits são realmente mais elevados. Por esta razão, é comum, em vez de usar 4 * INT UNSIGNED.
  • Da mesma forma as pessoas podem quebrá-lo para a indexação prefixo e você pode ir pelo menos tanto quanto 8 bits (TINYINT não assinada). Algumas pessoas também podem fazer uso da (1) tipo BIT para a indexação prefixo completo, assumindo índices posit MySQL colegas sobre os tipos de bits corretamente.
  • Uma vez mais semelhante com quatro colunas de algumas operações que exigem coisas como carregar a partir para outra são ironicamente mais fácil devido à folga pedaços durante cálculos (valores intermediários em cálculos ainda pode ser 64 bit).

Resumo

As pessoas vão usar diferentes formatos para diferentes razões. Compatibilidade com versões anteriores pode ser uma razão e que depende do que estava sendo feito para IPv4. Outros dependem de como os endereços estão sendo usados ??e optimisations em torno disso. Você pode ver mais do que uma abordagem que está sendo usado.

B16 é uma boa abordagem padrão, já que é o mais eficiente e sem complicações.

Para conversões em PHP que você pode fazer-lhes a mão, se você pesquisar:

  • gmp ou bcmath
  • operadores de manipulação número e bit a bit do PHP, estar especialmente ciente de limitações em int ou float, bem como funções que dependem delas que poderiam parecem úteis
  • formatos O IPv6
  • embalagem / descompactação, bin2hex / HEX2BIN.

Eu recomendaria porém utilizando uma biblioteca comum para lidar com vários formatos de exibição do IPv6.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top