php 将MD5哈希表示为整数

gzjq41n4  于 2023-02-03  发布在  PHP
关注(0)|答案(9)|浏览(343)

在我的用户数据库表中,我将用户电子邮件地址的MD5散列作为id。
示例:email(example@example.org) = id(d41d8cd98f00b204e9800998ecf8427e)
不幸的是,我现在必须将id表示为整数值--以便能够使用id只能为整数的API。
现在我正在寻找一种方法来将id编码成一个整数,以便在接收时再次解码。我该怎么做呢?
我目前的想法是:

  1. convert_uuencode()convert_uudecode()用于MD5哈希
    1.将MD5散列的每个字符替换为其ord()
    哪种方法更好?你知道更好的方法吗?
    我希望你能帮助我。先谢谢你!
xxslljrj

xxslljrj1#

要小心。将MD5转换为整数需要支持big(128位)整数。很有可能你使用的API只支持32位整数--或者更糟,可能处理浮点数。无论哪种方式,你的ID都会被删除。如果是这种情况,与试图将MD5转换为整数相比,仅任意分配第二个ID是更好的处理方式。
然而,如果你确信API可以处理任意大的整数,你可以把MD5从十六进制转换成整数,PHP很可能不支持这个内置函数,因为它会试图把它表示成32位整数或浮点数;您可能需要使用PHP GMP library

tmb3ates

tmb3ates2#

其他人指出,以不同的方式这样做是有充分理由的。
但是如果你想把一个md5哈希转换成一个 * 十进制数字串 *(我认为这就是你所说的"用整数表示"的真正含义,因为md5已经是一个字符串形式的整数了),然后再把它转换回同样的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);
}

演示:

$md5 = md5('example@example.com');
echo $md5 . '<br />';  // 23463b99b62a72f26ed677cc556c44e8
$dec = md5_hex_to_dec($md5);
echo $dec . '<br />';  // 0903015257466342942628374306682186817640
$hex = md5_dec_to_hex($dec);
echo $hex;             // 23463b99b62a72f26ed677cc556c44e8

当然,使用这两个字符串都要小心,比如确保只将它们用作字符串类型以避免丢失前导零,确保字符串的长度正确等等。

7qhs6swi

7qhs6swi3#

一个简单的解决方案可以通过指定base 16作为第二个参数来使用intval()
支持64位整数的系统可以将128位/16字节的md5()散列拆分为两个8字节的部分,然后进行转换。每个十六进制对代表1个字节,因此在本例中使用16个字符的块:

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

对于32位整数,十六进制块为8个字符:

foreach (str_split($hash, 8) as $chunk) {
    $int_hashes[] = intval($chunk, 16);
}
q9rjltbz

q9rjltbz4#

为什么ord()?md5生成的是16字节的值,为了更好的可读性,它是以十六进制的形式呈现的。所以你不能将16字节的值转换成4或8字节的整数。你必须修改你的算法的某些部分,才能将其用作id。

rsl1atfo

rsl1atfo5#

您可以使用hexdec来解析十六进制字符串并将数字存储在数据库中。

w1jd8yoj

w1jd8yoj6#

你不能添加另一个自动递增的整型字段吗?

k2fxgqgv

k2fxgqgv7#

关于:

$float = hexdec(md5('string'));

$int = (integer) (substr(hexdec(md5('string')),0,9)*100000000);

碰撞的机会肯定更大,但仍然很好,足以使用,而不是散列在数据库虽然?

mbzjlibv

mbzjlibv8#

将这两列添加到表中。

`email_md5_l` bigint(20) UNSIGNED GENERATED ALWAYS AS (conv(left(md5(`email`),16),16,10)) STORED,
`email_md5_r` bigint(20) UNSIGNED GENERATED ALWAYS AS (conv(right(md5(`email`),16),16,10)) STORED,

在这两列上创建一个PK可能会有帮助,也可能没有帮助,因为它可能会连接两个字符串表示并散列结果。这可能会挫败你的目的,完全扫描可能会更快,但这取决于列数和记录数。不要试图在php中读取这些bigint,因为它没有无符号整数,只是停留在SQL中,并执行如下操作:

select email 
into result 
from `address`
where url_md5_l = conv(left(md5(the_email), 16), 16, 10)
  and url_md5_r = conv(right(md5(the_email), 16), 16, 10) 
limit 1;

MD5确实会碰撞btw。

9rnv2umw

9rnv2umw9#

使用电子邮件地址作为共享文件夹(如/var/myprocess/ www.example.com)中的空临时文件的文件名example@example.org
然后,对文件名调用ftok。ftok将返回一个唯一的整数ID。
虽然不能保证它是唯一的,但它可能足以满足您的API。

相关问题