我有一个用户表,每个用户都有ID
(自动增量)存储在表中。我试图“重新计算”(编码/解码/散列)这个数字到7个数字长的另一个数字(UID
)(我不知道这个术语被称为此操作)。可以猜到,我只需要将ID的长度“增长”到int(7),我不想在数据库中将自动修正设置为100000
。
我并非试图从ID
获取UID
我正在尝试实现此目标
id -> calculation -> unique id for user
8 -> calculation -> 1234567
8 -> calculation -> 1234567
9 -> calculation -> 2569845
1234567 -> calculation -> "not possible" (not necessary just it is not needed)
我尝试过这样有趣的事情(我已经尝试了md5
,sha
各种不同的派生,我认为这不是方法)是否有任何原生的php功能会这样做吗? (!uniqid()
)
$new = substr(preg_replace("/[^0-9]/", "", md5(sha1($i))), 0, 7);
这个很棒,但它有冲突(对于循环1到10k)
Already in array new: $filled[4268] = 1050014 array old: $filled[2742] = 1050014
Already in array new: $filled[7278] = 3309143 array old: $filled[1682] = 3309143
Already in array new: $filled[9676] = 1785301 array old: $filled[8310] = 1785301
这意味着ID
与4268和2742将具有相同的UID
答案 0 :(得分:2)
正如其他人所说,这是一个荒谬的要求。任何理智的系统都只使用透明的1:1映射。但我想你必须做你被告知的事情,所以......
我们将其展开以考虑65535个ID。这是无符号短路的上限,需要2个字节--16位 - 作为整数存储。所需的输出是7个字节,因此通过移动一些位,我们可以生成直接从原始输入数字导出的唯一可逆ID,在它的表面上,与输入无关。
但是......我们仍然需要ASCII表示为数字。没问题 - 我们只是将数字编码为3位块,并将其编码为0x30 - 这意味着每个编码字节的ASCII码点都在0到7之间。
一旦我们意识到这一点,我们所需要做的就是选择一个系统。为了简单起见,我将逐步通过位1-16并将它们均匀地分布在7个输出字节中。这仍然会产生看起来相当可预测的东西 - 尤其是在低端它会有很多零,所以我会通过用已知的密钥对结果进行异或来增加它的味道。
<?php
// Produces a key of the supplied length
// This will always produce the same result, it just alternates
// the least significant 3 bits of every output byte
function generate_xor_key($length)
{
$result = array_fill(0, $length, 0);
for ($i = 0, $bit = 1; $i < $length; $i++) {
for ($j = 0; $j < 3; $j++, $bit++) {
$result[$i] |= ($bit % 2) << $j;
}
}
return implode('', array_map('chr', $result));
}
// Encode an ID
// If using a custom key this can be supplied in the 4th argument
// Keys must always be strings with all the bytes in the range 0x00 - 0x08
function encode_id($id, $encodedLength = 7, $rawBits = 16, $key = null)
{
// Because we are encoding the number into the least significant 3 bits,
// it doesn't make sense for $rawBits > $encodedLength * 3
$maxRawBits = $encodedLength * 3;
if ($rawBits > $maxRawBits) {
trigger_error('encode_id(): $rawBits must be no more than 3 times greater than $encodedLength');
return false;
}
// Get a usable key
if ($key === null) {
$key = generate_xor_key($encodedLength);
}
// Start with all bytes at ASCII 0
$result = array_fill(0, $encodedLength, 0x30);
// Extract each relevant bit from the input and store it in the output bytes
for ($position = 0; $position < $rawBits; $position++) {
$bit = (($id >> $position) & 0x01) << floor($position / $encodedLength);
$index = $position % $encodedLength;
$result[$index] |= $bit;
}
// Pad the remaining bits with alternation
// This is purely cosmetic for the output
for (; $position < $maxRawBits; $position++) {
$index = $position % $encodedLength;
$bit = ($position % 2) << floor($position / $encodedLength);
$result[$index] |= $bit;
}
// Convert the result to an ascii string
return implode('', array_map('chr', $result)) ^ $key;
}
function decode_id($id, $encodedLength = 7, $rawBits = 16, $key = null)
{
// Get a usable key
if ($key === null) {
$key = generate_xor_key($encodedLength);
}
// Convert the string to our original bytes array
$bytes = array_map(
'ord',
str_split(
str_pad($id, $encodedLength, '0', STR_PAD_LEFT) ^ $key,
1
)
);
$result = 0;
// Put the number back together
for ($position = 0; $position < $rawBits; $position++) {
$index = $position % $encodedLength;
$bit = (($bytes[$index] >> floor($position / $encodedLength)) & 0x01) << $position;
$result |= $bit;
}
return $result;
}
每个连续的ID都与前一个非常相似 - 通常只有1位数字已经改变 - 但是对于未经训练的人来说,距离标准的垂直计数器还有很长的路要走。
如上所述,这种机制实际上可以解释21位熵,因此可以生成2097152个唯一ID(包括零)。
答案 1 :(得分:0)
我现有的所有ID都小于8999999,然后只需将1000000添加到现有IDS中。