PHP - 从长md5哈希生成短字母数字字符串的好方法是什么?

Mos*_*oss 17 php random base

这是为了有一个很好的短URL,它指的是数据库中的md5哈希.我想转换这样的东西:

a7d2cd9e0e09bebb6a520af48205ced1

进入这样的事情:

hW9lM5f27

这些都包含大约相同数量的信息.该方法不必是直接的和可逆的,但这样会很好(更灵活).至少我希望随机生成的字符串以十六进制哈希作为种子,因此它是可重现的.我确信有很多可能的答案,我很想知道人们会如何以优雅的方式做到这一点.

哦,这不需要与原始哈希完美的1:1对应,但这将是一个奖励(我想我已经暗示了可逆性标准).如果可能的话,我想避免碰撞.

编辑 我意识到我的初步计算是完全错误的(感谢人们在这里回答,但我花了一些时间才知道)并且通过将所有小写字母和大写字母放入混合中,你无法真正减少字符串长度.所以我想我会想要一些不能直接从hex转换为base 62的东西.

dka*_*ins 8

这是一个需要考虑的小功能:

/** Return 22-char compressed version of 32-char hex string (eg from PHP md5). */
function compress_md5($md5_hash_str) {
    // (we start with 32-char $md5_hash_str eg "a7d2cd9e0e09bebb6a520af48205ced1")
    $md5_bin_str = "";
    foreach (str_split($md5_hash_str, 2) as $byte_str) { // ("a7", "d2", ...)
        $md5_bin_str .= chr(hexdec($byte_str));
    }
    // ($md5_bin_str is now a 16-byte string equivalent to $md5_hash_str)
    $md5_b64_str = base64_encode($md5_bin_str);
    // (now it's a 24-char string version of $md5_hash_str eg "VUDNng4JvrtqUgr0QwXOIg==")
    $md5_b64_str = substr($md5_b64_str, 0, 22);
    // (but we know the last two chars will be ==, so drop them eg "VUDNng4JvrtqUgr0QwXOIg")
    $url_safe_str = str_replace(array("+", "/"), array("-", "_"), $md5_b64_str);
    // (Base64 includes two non-URL safe chars, so we replace them with safe ones)
    return $url_safe_str;
}
Run Code Online (Sandbox Code Playgroud)

基本上,MD5哈希字符串中有16个字节的数据.这是32个字符长,因为每个字节编码为2个十六进制数字(即00-FF).所以我们将它们分解为字节并构建一个16字节的字符串.但是因为它不再是人类可读或有效的ASCII,我们base-64将其编码回可读字符.但由于base-64导致~4/3扩展(我们每8位输入仅输出6位,因此需要32位来编码24位),16字节变为22字节.但是因为base-64编码通常填充长度为4的倍数,所以我们只能获取24个字符输出的前22个字符(最后2个是填充).然后我们将base-64编码使用的非URL安全字符替换为URL安全等效字符.

这是完全可逆的,但这仍然是读者的练习.

我认为这是你能做的最好的,除非你不关心人类可读/ ASCII,在这种情况下你可以直接使用$ md5_bin_str.

如果您不需要保留所有位,也可以使用此函数的结果的前缀或其他子集.抛出数据显然是缩短事情的最简单方法!(但那时它不可逆)

PS为您输入"a7d2cd9e0e09bebb6a520af48205ced1"(32个字符),此函数将返回"VUDNng4JvrtqUgr0QwXO0Q"(22个字符).


Gum*_*mbo 5

以下是Base-16到Base-64转换的两个转换函数,以及任意输入长度的Base Base-64到Base-16的转换函数:

function base16_to_base64($base16) {
    return base64_encode(pack('H*', $base16));
}
function base64_to_base16($base64) {
    return implode('', unpack('H*', base64_decode($base64)));
}
Run Code Online (Sandbox Code Playgroud)

如果您需要具有URL和文件名安全字母的Base-64编码,则可以使用以下功能:

function base64_to_base64safe($base64) {
    return strtr($base64, '+/', '-_');
}
function base64safe_to_base64($base64safe) {
    return strtr($base64safe, '-_', '+/');
}
Run Code Online (Sandbox Code Playgroud)

如果您现在想要一个函数使用URL安全字符压缩十六进制MD5值,您可以使用:

function compress_hash($hash) {
    return base64_to_base64safe(rtrim(base16_to_base64($hash), '='));
}
Run Code Online (Sandbox Code Playgroud)

和反函数:

function uncompress_hash($hash) {
    return base64_to_base16(base64safe_to_base64($hash));
}
Run Code Online (Sandbox Code Playgroud)