为此,我考虑使用一个对用户隐藏的自动递增值,并向他们呈现一个从该值生成唯一字符串的MD5或其他方法。生成的字符串不应该呈现线性,因此简单地将自动递增ID转换为base 36 [0-9A-Z]有点过于简单,但类似于该函数的功能是我正在考虑的方向。
编辑:安全性不是问题,因为这不会用于保护信息。它只是一个到较长字符串的快捷方式。 谢谢。感谢您的建议,对延迟表示歉意。牙医...
$i=($input+97) & 0xf;
$result=((($i&0x1) << 3) + (($i&0xe) >> 1)) ^ 0x5;
编辑
更简单的方法是使用线性同余生成器(LCG,通常用于生成随机数),其定义为以下形式的公式:
X_n+1 = (a * X_n + c) mod m
a = 16807, c = 0, m = 2147483647
substr(base64_encode(pack("l", (16807 * $index) % 2147483647)), 0, 6)
你可以生成当前日期/随机数的MD5哈希值,并将其截断为所需长度(5-8个字符),然后将其存储为ID字段。
如果你要将这些信息存储在数据库中,你不需要使用for循环来进行冲突检查,而是可以使用select语句 - 类似于
SELECT count(1) c FROM Table WHERE id = :id
其中 :id 将是新生成的 id。如果 c 大于 0,则表示它已经存在。
编辑
这可能不是最好的方法。但我会尝试一下,所以我猜你需要的是将数字转换为唯一的短字符串的方法,并且不是按顺序排列的。
我想,正如你所说,base64 编码已经将数字转换为短字符串了。为了避免序列问题,您可以在自动生成的 id 和某个“随机”值(唯一映射)之间建立一些映射。然后,您可以对此唯一值进行 base64 编码。
您可以按以下方式生成此映射。创建一个临时表,存储从 1 到 10,000,000 的值。以随机顺序排序并将其存储到 Map 表中。
INSERT INTO MappingTable (mappedId) SELECT values FROM TemporaryTable ORDER BY RAND()
MappingTable应该有2个字段:id(您的自动生成的ID将针对此进行查找)和mappedId(这是您将为其生成base64编码的内容)。
当您接近1000万时,可以再次运行上述代码,并使用10,000,001-20,000,000之类的临时表中的值更改值。
你可以使用按位异或来混淆一些比特:
select thefield ^ 377 from thetable;
+-----+---------+
| a | a ^ 377 |
+-----+---------+
| 154 | 483 |
| 152 | 481 |
| 69 | 316 |
| 35 | 346 |
| 72 | 305 |
| 139 | 498 |
| 96 | 281 |
| 31 | 358 |
| 11 | 370 |
| 127 | 262 |
+-----+---------+
我认为这永远不会真正安全,因为你只需要找到短唯一字符串背后的加密方法就可以劫持一个ID。在您的设置中循环检查冲突是否真的有那么棘手吗?
一个递增数字的MD5应该是可以的,但我担心如果你将MD5(通常为128位)截断为5-8个字符,你几乎肯定会破坏它作为唯一签名的能力...