从整数生成一个伪随机的6个字符字符串

8
我正在尝试通过PHP解决以下问题。目标是基于整数种子生成一个唯一的6个字符的字符串,其中包含预定义范围内的字符。第二个要求是该字符串必须看起来是随机的(因此,如果代码1为100000,则不接受代码2为100001,3 100002)。
字符范围如下:
大写字母A-Z,不包括:B,I,O,S和Z
数字0-9,不包括:0,1,2,5,8
如果我没记错的话,总共有26个字符。我的第一个想法是从10进制转换为24进制,从数字7962624开始。所以做7962624 + 种子,然后将该数字编码为24进制。
这给我带来了0-N的字符。如果我以以下方式替换结果字符串,则满足第一个条件:
B=P, I=Q, 0=R, 1=T, 2=U, 5=V, 8=W

所以现在,我的代码大致如下:
1=TRRRR, 2=TRRRT, 3=TRRRU

我的问题是:各位大师们,我该如何编写一个行为一致(即给定整数的返回字符串始终相同)且符合上述两个要求的方法?我已经花了两天时间,除了将700,000,000个代码存入数据库并随机检索它们之外,我已经没有更多的想法了。 - Stephen

1
出于好奇,你用这个字符串做什么?你考虑过碰撞吗? - Gray
1
这将是一种以可读方式访问由整数标识的资源的方法。不幸的是,我受到保密协议的限制,无法告诉您确切的原因,但它与短网址并不相似。 - Stephen Groom
1
关于碰撞问题,我的原始解决方案是基于编码的,因为我认为使用该方法是不可能发生碰撞的。 - Stephen Groom
2
没问题,我理解不说具体细节。我只是想知道你是否在做自己的家庭加密。如果数字必须保密,我认为6个字符是不够的。有人可以随机尝试,几次后他们很容易得到一个有效的数字,更不用说你没有对这个数字进行哈希,而是编码/加密它。区别在于可逆性,这听起来可能是一个问题,对吗?我问碰撞的原因是,使用真正的哈希方法,这可能是一个问题。 - Gray
1
啊,没问题。它并不是一个密码,也许我标记了错误的OP,它只是使用一个6位数字字符串来引用一个整数的方法。函数(int)必须始终返回相同的值,但它不必是可逆的,如果它不可逆也不是问题。 - Stephen Groom
1个回答

7
您只需将输入序列1、2、3...应用于模质数的线性映射,就可以得到一个相当随机的序列。唯一代码数量限制在该质数中,因此应选择一个较大的质数。只要选择的乘数不可被该质数整除,生成的代码就是唯一的。
以下是一个示例:使用6个字符,您可以创建266=308915776个唯一字符串,因此适当的质数可能是308915753。因此,此函数将生成超过3亿个唯一代码:
function encode($num) {
    $scrambled = (240049382*$num + 37043083) % 308915753;
    return base_convert($scrambled, 10, 26);
}

请确保在64位PHP上运行此代码,否则乘法将会溢出。在32位上,您需要使用bcmath。生成数字1至9的代码如下:

n89a2d
hdh4jo
biopb9
5o6k2k
3eek5
k8m9aj
ee4424
8jbojf
2ojjb0

所有剩下的就是填写有时缺失的初始0并替换字母和数字,以便不产生任何禁止字符。如您所见,没有明显的模式,但有些时间、足够的动力和访问一些这些代码的人将能够找出发生了什么。更安全的选择是使用具有小块大小的加密算法,例如Skip32

1
也许我漏掉了一些显而易见的东西。我明白你在线性映射中使用了240049382和37043083,但是你是如何选择它们的呢?不过,我理解你为模数选择了一个素数。 - Gray
3
随意输入数字。 - Joni
1
哈,我得说我有点失望于那个回答,但我接受了它。我原以为它们会使用高级数学仔细选择,但答案基本上是:“在键盘上猛敲一通”。不过这也是个好答案。 - Gray
1
这几乎肯定是被接受的答案,但是否可能解释一下算法中3个数字的影响是什么。第三个数字显然是一个大质数,但其他两个数字的目的是什么?将它们变得更大/更小的影响是什么,为什么选择了这些数字? - Stephen Groom
2
给定 (a*x+b)%p,其中 a 是相邻数字之间的差。使其变大可以确保您不会看到像 xxxxxx、xxxxxy、xxxxxz 这样的代码。b 是必需的,以使序列的起始点难以猜测;如果没有它,x=0 的代码将为 0,而 x=1 的代码将给出 a。使用两者可以得到一个看起来难以预测和随机的东西。 - Joni
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接