-1

我有一个大字符串$string,当应用于时md5(),给我

c4ca4238a0b923820dcc509a6f75849b

长度是32,我想减少它,所以

base64_encode(md5($string, true));

xMpCOKC5I4INzFCab3WEmw==

删除最后两个==它给了我一个长度= 22的字符串。

还有其他更好的算法吗?

4

8 回答 8

3

我不确定您是否意识到这md5是一个哈希函数,因此是不可逆的。如果您不关心可逆性,您也可以将md5哈希(或您喜欢的任何哈希*)修剪为任意数量的字符。所有这一切都会增加碰撞的可能性(我觉得这不会产生均匀的分布)。

如果您正在寻找可逆(即非破坏性)压缩,那么不要重新发明轮子。使用内置函数,例如gzdeflate()orgzcompress()其他类似函数


*这是哈希函数列表(维基百科)及其输出的大小。我想最小可能的“哈希函数”将是奇偶校验位:)

于 2013-06-26T12:52:34.927 回答
2

一种更好的方法是,不是将二进制转换为十六进制(如 md5 那样),然后将字符串转换为 base64,而是从十六进制 md5 直接转换为 base64。

由于十六进制是每个字符 16 位,而 base64 是每个字符 64 位,因此每 2 个十六进制字符将组成一个 base64 字符。

要执行转换,您可以执行以下操作:

  • 将字符串拆分为 16 个 2 个字符的块
  • 第一个字符应乘以 2 并添加到第二个字符(记住 AF = 10-15)。
  • 可以使用此处的表格将此数字与 base64 方案匹配:https ://en.wikipedia.org/wiki/Base64

这将产生一个 16 字符的 base64 字符串,其值与 md5 字符串的十六进制表示形式相同。

理论上,你可以对任何基地做同样的事情。如果我们有办法用 ASCII 编码 base128 字符串,我们可以得到一个 8 个字符的字符串。但是,由于字符集有限,我认为base64是常用的最高基数。

于 2013-06-23T14:03:11.503 回答
2

length您想要的字符串越小.. 的数量越小possible combination

有声望的可能性总数

总可能性 = n r

由于我们正在处理base64具有可打印的输出,这意味着我们只有 64 个字符

 n = 64 

如果您正在查看 22 个字母的长度

n r = 64 22 = 5,444,517,870,735,015,415,413,993,718,908,291,383,296 种可能性

回到你的问题:有没有更好的算法?

将具有良好哈希的字符串截断为所需的长度,因为总的可能性和冲突是固定的

$string = "the fox jumps over the lazy brown dog";
echo truncateHash($string, 8);

输出

9TWbFjOl

使用的功能

function truncateHash($str, $length) {
    $hash = hash("sha256", $str, true);
    return substr(base64_encode($hash), 0, $length);
} 
于 2013-06-27T13:53:01.477 回答
1

不确定 MD5 是否适合您,但我会假设您有理由坚持使用此算法并正在寻找更短的表示。有几种可能性可以生成具有不同字母的较短字符串:

选项 1:二进制字符串

MD5 的最短可能形式是它的二进制表示,要获得这样的字符串,您可以简单地调用:

$binaryMd5 = md5($input, true);

这个字符串可以像数据库中的任何其他字符串一样存储,它只需要 16 个字符。只需确保使用mysqli_real_escape_string()或使用参数化查询 (PDO) 进行正确的转义。

选项 2:Base64 编码

Base64 编码将生成一个带有以下字母的字符串:[0-9 AZ az + /] 并使用 '=' 作为填充。这种编码非常快,但有时会包含不需要的字符“+/=”。

$base64Md5 = base64_encode(md5($input, true));

MD5 哈希的输出长度始终为 24 个字符。

选项 3:Base62 编码

base62 编码仅使用字母表 [0-9 AZ az]。这样的字符串可以安全地用于任何目的,例如 URL 中的标记,而且它们非常紧凑。我写了一个base62 编码器,它能够将二进制字符串转换为 base62 字母表。这可能不是最快的实现,但我的目标是编写可理解的代码。同一个类可以很容易地适应不同的字母。

$base62Md5 = StoBase62Encoder::base62encode(md5($input, true));

MD5 散列的输出长度从 16 到 22 个字符不等。

于 2013-07-01T22:41:50.450 回答
1

这种编码生成较短的字符串,

print base64_encode(hash("crc32b",$string,1));

输出

qfQIdw==
于 2013-06-25T23:11:21.217 回答
0

我从您的帖子中读到您正在搜索散列算法而不是压缩。

php中有各种标准的散列算法。看看 PHP散列函数。根据您要散列的内容,有不同的方法。小心并计算平均碰撞概率。

但是,您似乎正在搜索“压缩”,它输出给定字符串的最小可能大小的字符。如果你这样做了,那么看看Lempel-Ziv-Welch ( php implementation ) 或其他

于 2013-07-02T12:57:24.370 回答
0

Base 91看起来是最节省空间的二进制到 ASCII 可打印编码算法(这似乎是您想要的)。

我还没有看到 PHP 实现,但是如果您的软件必须与其他软件一起使用,我会坚持使用 Base 64;它是众所周知的,闪电般的速度,随处可用。

于 2013-06-29T17:19:27.773 回答
0

首先,回答您的问题:是的,有更好的算法(如果“更好”是指“更短”)。

将该hash()函数(它是 PHP 核心的一部分,自 PHP 5.1.2 起默认启用)与任何、adler32fnv132crc32crc32b算法一起使用。fnv132joaat

如果对您当前的情况没有更深入的了解,您不妨选择您认为听起来最酷的那个。

这是一个例子:

hash('crc32b', $string)

我设置了一个在线示例,您可以使用它。

其次,我想指出,您所问的问题几乎与 stackoverflow 上的另一个问题完全相同。

于 2013-06-30T20:53:15.793 回答