我正在寻找一种将字符串编码为尽可能 短 的长度并使其可 解码 的方法(纯 PHP,无 SQL)。我有工作脚本,但我对编码字符串的长度不满意。
设想
链接到图像(这取决于我想向用户显示的文件分辨率):
编码链接(因此用户无法猜测如何获得更大的图像):
所以,基本上我只想对 URL 的搜索查询部分进行编码:
- img=/dir/dir/hi-res-img.jpg&w=700&h=500
我现在使用的方法会将上述查询字符串编码为:
- y8xNt9VPySwC44xM3aLUYt3M3HS9rIJ0tXJbcwMDtQxbUwMDAA
我使用的方法是:
$raw_query_string = 'img=/dir/dir/hi-res-img.jpg&w=700&h=500';
$encoded_query_string = base64_encode(gzdeflate($raw_query_string));
$decoded_query_string = gzinflate(base64_decode($encoded_query_string));
如何缩短编码结果并仍然可以 仅 使用 PHP 对其进行解码?
原文由 Artur Filipiak 发布,翻译遵循 CC BY-SA 4.0 许可协议
我怀疑如果您不希望它被用户解码,您将需要更多地考虑您的散列方法。 Base64 的问题是 Base64 字符串 看起来 像 base64 字符串。很有可能,精明的人会查看您的页面源代码,也可能会认出它。
第一部分:
如果您的 URL 词汇/字符灵活,这将是一个很好的起点。由于 gzip 使用反向引用获得了很多收益,因此字符串太短没有什么意义。
考虑你的例子——你在压缩中只保存了 2 个字节,这些字节在 Base64 填充中再次丢失:
非 gzip 压缩:
string(52) "aW1nPS9kaXIvZGlyL2hpLXJlcy1pbWcuanBnJnc9NzAwJmg9NTAw"
压缩:
string(52) "y8xNt9VPySwC44xM3aLUYt3M3HS9rIJ0tXJbcwMDtQxbUwMDAA=="
如果你减少你的词汇量,这自然会让你更好的压缩。假设我们删除了一些冗余信息。
看一下功能:
和
它基本上是去除冗余信息,然后将 4 个字节压缩为 3 个字节。这是通过有效地拥有 ASCII 表的 6 位子集来实现的。此窗口已移动,因此偏移量从有用的字符开始,并包括您当前使用的所有字符。
使用我使用的偏移量,您可以使用从 ASCII 38 到 102 的任何内容。这为您提供了 30 字节 的结果字符串,即 9 字节 (24%) 压缩!不幸的是,您需要使其成为 URL 安全的(可能使用 base64),这使它回到 40 个字节。
我认为在这一点上,您可以很安全地假设您已经达到阻止 99.9% 的人所需的“通过默默无闻的安全”级别。让我们继续,你的问题的第二部分
可以说这已经用上面的方法解决了,但是你需要通过服务器上的秘密来传递它,最好是使用 PHP 的 OpenSSL 接口。以下代码展示了上述函数的完整使用流程和加密:
该脚本的输出如下:
你会看到整个循环:压缩→加密→Base64编码/解码→解密→解压。这个输出将尽可能接近你真正能得到的,接近你能得到的最短长度。
撇开一切不谈,我觉得有必要得出这样的结论:它只是理论上的,这是一个很好的思考挑战。肯定有更好的方法可以达到您想要的结果 - 我会第一个承认我的解决方案有点荒谬!