2009-09-14 31 views
14

En mi tabla de base de datos de usuario, tomo el hash MD5 de la dirección de correo electrónico de un usuario como id.Representar hash MD5 como un número entero

Ejemplo: email([email protected]) = id(d41d8cd98f00b204e9800998ecf8427e)

desgracia, he para representar los ids como valores enteros ahora - con el fin de ser capaz de utilizar un API donde el ID sólo puede ser un número entero.

Ahora estoy buscando una forma de codificar el ID en un entero para enviar una decodificación de nuevo al recibir. ¿Cómo podría hacer esto?

Mis ideas hasta ahora:

  1. convert_uuencode() y convert_uudecode() para el hash MD5
  2. reemplazar cada carácter del hash MD5 de su valor ord()

¿Qué método es mejor? ¿Conoces formas aún mejores de hacer esto?

Espero que me puedan ayudar. ¡Muchas gracias por adelantado!

+1

¿Tiene ningún otro, posiblemente interno, valor para identificar a tus usuarios? Bueno, deberías tener al menos un PK para tu tabla de usuarios. – Malax

+0

@Malax: Sí, la clave principal es el campo de identificación que contiene el hash MD5. ¿Es esta una mala solución? – caw

+3

El uso de un hash MD5 como la clave principal de su tabla de usuario generalmente no es una gran idea. Un ID de autoincremento/entero de serie es de 4 a 8 bytes. Un hash md5 tiene 32 bytes. Comparaciones en valores enteros (p.cada vez que se UNE a esa tabla, o SELECCIONE una fila) será mucho más rápido que comparar cadenas de 32 bytes, y los valores enteros requerirán menos almacenamiento. Y realmente ... si quieres usar un valor de cadena, ¿por qué no usar la dirección de correo electrónico en sí? Va a ser de 32 bytes o menos, la mayoría de las veces. –

Respuesta

16

Ten cuidado. La conversión de los MD5 a un entero requerirá soporte para enteros grandes (128 bits). Lo más probable es que la API que está utilizando solo admita números enteros de 32 bits, o peor, podría tratarse del número en coma flotante. De cualquier forma, tu identificación será mordida. Si este es el caso, simplemente asignar un segundo ID arbitrariamente es una forma mucho mejor de tratar las cosas que tratar de convertir el MD5 en un número entero.

Sin embargo, si es seguro que la API puede tratar números enteros arbitrariamente grandes sin problemas, puede convertir el MD5 de hexadecimal a un número entero. Es muy probable que PHP no admita esta función incorporada, ya que tratará de representarlo como un entero de 32 bits o un punto flotante; probablemente necesite usar el PHP GMP library para ello.

+3

+1 para dar a entender que el valor resultante puede ser demasiado grande para la API incluso cuando se usan los bytes desnudos como número entero. Debería encontrar otra solución para su problema de "dirección de correo electrónico a entero". – Malax

+0

¡Muchas gracias! ¿Esta sería la solución mejor que mis dos ideas? $ id_integer = base_convert ($ id_string, 16, 10); – caw

+0

Lea la advertencia en los documentos de base_convert (http://www.php.net/manual/en/function.base-convert.php) - NO es adecuado para números grandes. Y los MD5 son números muy grandes. Debes usar una biblioteca bigint, y la API a la que estás accediendo también debe hacerlo, pero dudo que lo haga. Simplemente agregue otra columna y asigne identificaciones arbitrarias a cada usuario, será mucho más fácil. – bdonlan

1

Puede usar hexdec para analizar la cadena hexadecimal y almacenar el número en la base de datos.

+1

¿Eso maneja enteros de 160 bits sin cortarlos? – bdonlan

+2

respuesta: no, se convierte en flotante, según la documentación. Por lo tanto, perderá alrededor de 120 bits de datos y no podrá recuperar el MD5 original más tarde. – bdonlan

+2

Tiene razón, la suma de MD5 es demasiado grande para almacenarla como un entero de 32 bits. Ignora mi respuesta. ;-) – Malax

1

¿No podría simplemente agregar otro campo que fuera un campo int de incremento automático?

1

¿Por qué ord()? md5 produce un valor normal de 16 bytes, que se presenta en hexadecimal para una mejor legibilidad. Por lo tanto, no puede convertir un valor de 16 bytes en un entero de 4 u 8 bytes sin pérdida. Debe cambiar alguna parte de sus algoritmos para usar esto como id.

+0

MD5 produce un valor de 20 bytes. – bdonlan

+2

Hmmm ... puede ser que estoy completamente estúpida, pero ... Fred Fred @-desktop: ~ $ md5sum citycode.sql 734e4d6f039a81c8a196db588e1cb002 citycode.sql 73 4e 4d 6f 03 9a 81 c8 a1 96 db 58 8e 1c b0 02 aquí un marco92w (pregunta propietario) valor d4 1d 8c D9 8f 00 b2 04 e9 80 09 98 ec f8 42 7e lo que está mal ¿conmigo? ¿Dónde está adicionalmente cuatro bytes? –

+0

@bdonlan: No, 128 bits es igual a 16 bytes, ¿no es así? – caw

10

Existen buenas razones, según otros, para hacerlo de otra manera.

Pero si lo que quieres hacer es convertir un hash MD5 en una cadena de dígitos decimales(que es lo que creo que realmente quieren decir por "representar por un entero", ya que un MD5 ya es un número entero en forma de cadena), y transformar de nuevo en la misma cadena md5:

function md5_hex_to_dec($hex_str) 
{ 
    $arr = str_split($hex_str, 4); 
    foreach ($arr as $grp) { 
     $dec[] = str_pad(hexdec($grp), 5, '0', STR_PAD_LEFT); 
    } 
    return implode('', $dec); 
} 

function md5_dec_to_hex($dec_str) 
{ 
    $arr = str_split($dec_str, 5); 
    foreach ($arr as $grp) { 
     $hex[] = str_pad(dechex($grp), 4, '0', STR_PAD_LEFT); 
    } 
    return implode('', $hex); 
} 

demostración:

$md5 = md5('[email protected]'); 
echo $md5 . '<br />'; // 23463b99b62a72f26ed677cc556c44e8 
$dec = md5_hex_to_dec($md5); 
echo $dec . '<br />'; // 0903015257466342942628374306682186817640 
$hex = md5_dec_to_hex($dec); 
echo $hex;    // 23463b99b62a72f26ed677cc556c44e8 

por supuesto, tendría que ser Caref ul usando alguna de las cadenas, como asegurándose de usar sólo como tipo de cadena para evitar perder los ceros iniciales, asegurando las cuerdas son las longitudes correctas, etc.

+0

Muchas gracias. Así es como funcionaría. Pero ahora puedo ver lo que todos los demás querían decir: el nuevo entero es muy largo. Y el cero inicial también es un problema. – caw

+0

Me alegra ayudar.Tenga en cuenta que la cadena de dígitos decimales y la cadena de dígitos hexadecimales (la cadena de md5) no son iguales matemáticamente; son meramente "traducciones" entre sí, producidas por estas funciones complementarias, en sus respectivos conjuntos de símbolos de dígitos. – GZipp

1

qué pasa:

$ float = hexdec (MD5 (' cuerda'));

o

$ int = (número entero) (substr (hexdec (md5 ('cadena')), 0,9) * 100 000 000);

Definitivamente mayores posibilidades de colisión, pero aún así es bueno usar en lugar de hash en DB.

aplausos,

/Marcin

+0

este es aún mejor: sprintf ("% u", crc32 (md5 ('cadena'))); – Marcin

+0

bien, déjame calcular 32 * 16 bit ... necesitarás 64bytes. no se puede flotar ni duplicar ese largo;) su número perderá precisión por truncamiento o redondeo –

0

utilizar la dirección de correo electrónico como nombre de archivo de un archivo en blanco, temporal en una carpeta compartida, como /var/myprocess/[email protected]

Luego, llame a ftok sobre el nombre del archivo. ftok devolverá una identificación entera única.

No se garantiza que sea único, pero probablemente sea suficiente para su API.

6

Para una condensación de 32 bits, se puede hacer una solución simple seleccionando 4 pares hexadecimales (8 caracteres) del hash MD5, donde cada par representa un byte, y luego convirtiéndolo con intval().

Para un sin signo de 32 bits Int:

$inthash = intval(substr(md5($str), 0, 8), 16); 

Para el valor positivo solamente de un signo de 32 bits Int:

$inthash = intval(substr(md5($str), 0, 8), 16) >> 1; 

Esto es probable que sólo funciona para valores de hasta 64- bit (8 bytes o 16 caracteres) para la mayoría de los sistemas modernos como se indica en los documentos.

En un sistema que puede acomodar Entrs de 64 bits, una estrategia de división que consume todo el hash MD5 de 128 bits como 2 Entrs podría ser:

$hash = md5($str); 
$inthash1 = intval(substr($hash, 0, 16), 16); 
$inthash2 = intval(substr($hash, 16, 16), 16);