将MD5转换为base62以用于URL

12

我有一个将脚本转换为基数62(A-Za-z0-9)的脚本,但是如何从MD5中获取数字?

我已经在许多地方阅读到,因为MD5中的数字比PHP可以处理的整数要大,所以它会不准确...由于我需要一个短的URL,而且不打算使用整个哈希值,只使用其中的8个字符...

所以我的问题是如何获取MD5哈希的部分数字?

此外,仅使用MD5哈希的一部分是否是一个坏主意?


5
MD5是一个用base36编码表示的数字,我认为... - Mark
1
你说得有一半是对的,md5哈希是以16进制(a-f0-9)表示的十六进制数字。 - Alix Axel
10
MD5哈希是一个128位的数字,通常以十六进制表示,但这并非必须。 - Georg Schölly
1
好的,那么我该如何将十六进制转换为数字呢?我知道这个数字对于 PHP 来说太大了,所以我应该使用 substr 和 hexdec 吗? - Mark
我知道这一点,但我不认为他在这里谈论哈希的原始表示。 - Alix Axel
显示剩余9条评论
9个回答

9

我在这里提出了一个不同的建议。既然您只对使用md5哈希的十进制块感兴趣,为什么不使用其他短数字哈希,如CRC32Adler?以下是一个示例:

$hash = sprintf('%u', crc32('your string here'));

这将生成一个8位数的哈希值。 编辑:我想我误解了你,这里有一些函数提供了转换到和从62进制的基数的功能 再次编辑:要处理任意长度的数字,您必须使用bc_math或GMP扩展,这是一个使用bc_math扩展的函数,也可以从2进制转换为62进制。您应该像这样使用它:
echo bc_base_convert(md5('your url here'), 16, 62); // public base 62 hash

以及反向操作:

echo bc_base_convert('base 62 encoded value here', 62, 16); // private md5 hash

希望有所帮助。=)


有没有可能推断出哈希函数中输入的内容?我在想,如果我只显示哈希值的一部分,那么推断生成它的方式会更加困难……对吗? - Mark
没错,但这样它就不是真正意义上的哈希了,而且冲突更有可能发生。 - Alix Axel

4
如果可能的话,我建议不要在URL中使用哈希。最终你会遇到冲突……特别是如果你截断了哈希值。如果你实现一个基于ID的系统,每个项目都有一个唯一的ID,那么就会少很多麻烦。第一个项目将是1,第二个将是2等等——如果你正在使用MySQL,只需添加一个自增列即可。
为了生成短ID:
//the basic example
$sid = base_convert($id, 10, 36);

//if you're going to be needing 64 bit numbers converted 
//on a 32 bit machine, use this instead
$sid = gmp_strval(gmp_init($id, 10), 36);

将短id转换为十进制id的方法:

//the basic example
$id = base_convert($id, 36, 10);

//if you're going to be needing 64 bit numbers
//on a 32 bit machine, use this instead
$id = gmp_strval(gmp_init($shortid, 36));

希望这可以帮到你!

如果你真的想要使用基数62(无法使用gmpbase_convert实现),请查看以下内容:http://snipplr.com/view/22246/base62-encode--decode/


抱歉,也许我没有表达清楚,md5并不作为ID的功能...只是一种防止用户猜测下一个URL的方法...所以URL是id=1&md5=dsf213sfe。无论如何,谢谢。 - Mark

1

你可以这样做:(并非所有步骤都是用php编写的,我已经很久没有使用它了。)

仅使用md5的几个位数没有风险。唯一改变的是碰撞的危险性。


1

实际上有一个Java实现,你可能可以提取它。这是一个名为Pulse的开源CMS解决方案。

在这里查看toBase62()fromBase62()的代码。

http://pulse.torweg.org/javadoc/src-html/org/torweg/pulse/util/StringUtils.java.html

StringUtils 中唯一的依赖是 LifeCycle 类,它提供了一种获取字符串的盐哈希值的方法,你甚至可以完全省略它,或者将该方法复制到你自己的 StringUtils 中。就这样。


0
截至 PHP 5.3.2,GMP 支持最大进制数为 62(之前只有 36),因此 brianreavis 的建议非常接近。我认为对你的问题最简单的答案是:
function base62hash($source, $chars = 22) {
  return substr(gmp_strval(gmp_init(md5($source), 16), 62), 0, $chars);
}

将十六进制转换为六十二进制显然具有空间优势。一个普通的128位MD5哈希在十六进制中是32个字符,但在六十二进制中只有22个字符。如果您要将哈希存储在数据库中,可以将它们转换为原始二进制并节省更多的空间(对于MD5,仅需16字节)。

由于生成的哈希值只是一个字符串表示,因此如果您只想使用其中一部分(如函数所做的那样),则可以使用substr。


0

您可以尝试使用base62x来获得安全且兼容的编码表示。

这里提供有关base62x的更多信息, 或者在-NatureDNS中简单地使用-base62x

shell> ./base62x -n 16 -enc 16AF 
1Ql
shell> ./base62x -n 16 -dec 1Ql 
16AF

shell> ./base62x 
Usage: ./base62x [-v] [-n <2|8|10|16|32>] <-enc|dec> string 
Version: 0.60 

0
你可以像这样做:
$hash = md5("The data to be hashed", true);
$ints = unpack("L*num", $hash);

$hash_str = base62($ints['num1']) . base62($ints['num2']) . base62($ints['num3']) . base62($ints['num4'])

0

这里有一个开源的Java库,可以将MD5字符串转换为Base62字符串 https://github.com/inder123/base62

Md5ToBase62.toBase62("9e107d9d372bb6826bd81d3542a419d6") ==> cbIKGiMVkLFTeenAa5kgO4

Md5ToBase62.fromBase62("4KfZYA1udiGCjCEFC0l") ==> 0000bdd3bb56865852a632deadbc62fc

这个转换是双向的,所以如果你将它转换回MD5,你将得到原始的MD5:

Md5ToBase62.fromBase62(Md5ToBase62.toBase62("9e107d9d372bb6826bd81d3542a419d6")) ==> 9e107d9d372bb6826bd81d3542a419d6

Md5ToBase62.toBase62(Md5ToBase62.fromBase62("cbIKGiMVkLFTeenAa5kgO4")) . ==> cbIKGiMVkLFTeenAa5kgO4

的翻译内容为:

```


-1

您可以使用稍微修改过的 Base 64,将+/替换为-_

function base64_url_encode($str) {
    return strtr(base64_encode($str), array('+'=>'-', '/'=>'_'));
}
function base64_url_decode($str) {
    return base64_decode(strtr($str, array('-'=>'+', '_'=>'/')));
}

此外,您可以删除尾部填充的 = 字符。

要获取原始的 MD5 值(二进制字符串),请将第二个参数(在手册中命名为 $raw_output)设置为 true

$raw_md5 = md5($str, true);

请查看此链接:https://dev59.com/n0XRa4cB1Zd3GeqPv_b9#1743486 - Alix Axel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接