1
maemual 2018-01-15 17:43:08 +08:00
自增 ID 改成随机自增 x
|
2
Sypher 2018-01-15 18:00:56 +08:00
丢 list 里啊,生成的时候检查下 list.contains(newStr)。
|
3
Keyes 2018-01-15 18:01:36 +08:00 via Android 1
生成订单号吗?参考京东做法,订单号有一个用户 id 作为 parent,随便猜,没有用,而且订单号可以做很短,客服和客户可以很容易识别
|
4
bearice 2018-01-15 18:03:37 +08:00
XTEA 加密
|
6
porrat 2018-01-15 18:07:12 +08:00
sha1(random_chars)
|
7
scriptB0y 2018-01-15 18:07:20 +08:00
uuid.uuid4()
|
8
porrat 2018-01-15 18:07:57 +08:00
看错了,以为是 40 位,可以再编码一次
|
9
xfund4 OP |
10
chinvo 2018-01-15 18:09:10 +08:00
ksuid K-Sortable Globally Unique IDs 长度太长不符合楼主要求
shortid 7-14 位,位数不固定 hashids 同位数不固定(非传统意义 ID,而是将数字 ID 加密,可逆算法 |
11
lululau 2018-01-15 18:10:51 +08:00
邀请码兑换码肯定要存库的,这个直接随机就好了吧,随机完了查下库里是不是有这个数了,有的话就重新随机一个,一个 alphanum 字符可以编码 5 位,就按 4 位算,8 个字符可以编码 4 个字节了,4 个字节怎么还不够千万;还是说不知道怎么把一个整数转换成 alphanum 字符串?
|
13
honeycomb 2018-01-15 18:13:43 +08:00 via Android
最笨的一个办法是用 csprng 导出二进制数,再转换成楼主需要的 36 进制
|
14
tabris17 2018-01-15 18:14:24 +08:00
根据自增 ID,用 skip32 加密,然后 base62 编码
|
15
moult 2018-01-15 18:14:28 +08:00
自增 ID 从 10 进制转到 62 进制。然后再追加随机字符串补全 8 位。这样可以不用去数据库校验是否重复,虽然前面几位有规律,但是后面是随机的,也能做到猜不出。
http://php.net/manual/en/function.random-bytes.php |
16
chinvo 2018-01-15 18:14:41 +08:00
@xfund4 hashids 可以控制最短位数,如果你的数据(数值型 id )没有超过一定限制,那么你固定最短 8 位就可以保证输出的字符串时 8 位的。另外 hashids 字符串范围可控,在初始化的时候传入一个 string 就好。
我也没有其他更好的方案了,你可以先试一下这个。 |
18
lululau 2018-01-15 18:19:11 +08:00
要随机就免不了碰撞,要不想检查碰撞就不可能随机。。。
|
19
Magnus1k 2018-01-15 18:24:23 +08:00 3
不想碰撞就把所有符合的字符串全部生成了,然后随机挑一点出来用。
|
20
daodao 2018-01-15 18:26:16 +08:00
hash
|
21
zjp 2018-01-15 18:31:46 +08:00 via Android
我用的是时间戳加 4 位随机数,限制 8 个字符的话时间戳范围取小一点不知道够不够
|
22
toan 2018-01-15 18:44:48 +08:00 via Android
@Magnus1k 赞同。不想碰撞的话,先生成,后随机挑。
目前我这做过一个实例,先生成可用数据池数据,比如先生出 2 万,生成的时候进行唯一检验,使用的时候从该池子里随机挑选,增加使用取数的效率。当池子数据量低于某个阈值了,就重新生成补满池子。 |
23
ylsc633 2018-01-15 18:48:45 +08:00
用这个吧 hashids
我用过,感觉还不错,没有应用到大项目里,所以 测不出性能消耗 这个只需要你保管好自己的 salt 就行了! 用的 这个包 https://github.com/ivanakimov/hashids.php 具体实践 类似于 https://www.g9zz.com/post/6ravkEd7bx 这种吧 后面是定长的,且没有特殊字符,还可反解出来 |
24
xfund4 OP |
26
l1093178 2018-01-15 19:01:03 +08:00
完全随机的话,到 sqrt(62 ^ 8) ~= 14, 000, 000 这个数量级就会出现冲突( https://zh.wikipedia.org/wiki/生日問題),所以说只能考虑除了完全随机之外的方案
可以考虑用这个库: https://github.com/c2h5oh/hide |
27
Kilerd 2018-01-15 19:03:07 +08:00
sha3
|
28
moult 2018-01-15 19:03:11 +08:00
@xfund4 不想数据库查询的话,肯定要基于一个现有的 ID 来生成了。
1、基于数据库的自增 ID 来生成,就我#15 给你的办法,比如 1-5 位由自增 ID 转到 62 进制,不够 5 位就补 0,后面三位随机生成来避免猜测性。这样肯定不会重复的。 2、基于时间戳+用户 ID,也是将随机串的其中几位来保存时间戳和用户 ID。虽然无法避免统一秒同一用户发多个请求,但是后面还有随机串在,生成重复的概率可以忽略不计。另外时间戳没必要 1970 开始,就从 2018 开始就好了,这样时间戳会小很多。 |
29
SunnyMeow 2018-01-15 19:05:24 +08:00 via iPad
|
30
kaneg 2018-01-15 19:08:04 +08:00 via iPhone
我的一个不成熟的想法:A-Z,0-9,共 36 位,每个 ID8 位,则共有 36^8 种可能,而你的需求只要千万数量级,那么可以把总的取值范围等分为千万块,每一块大概有上万个值。使用的时候先用你的自增 ID 取一个块,然后在这一块里随机取一个值。这样的结果是每个值都不会重复,每个值是万分之一的随机,所以被猜测的可能性也很小
|
31
xupefei 2018-01-15 19:14:29 +08:00
8 位千万数据量不算很大,直接 rand 然后查重就可以做到。
查重有很多办法可以用。不过上千万的数据,普通的哈希表已经慢到不行了。可以用 bloom filter 和各种 data sketch 算法。 |
33
geelaw 2018-01-15 19:17:27 +08:00
用安全的随机置换即可。
|
34
owenliang 2018-01-15 19:35:40 +08:00 via Android
随机生成字节系列,转 16 进制,去重保存
|
35
renyijiu 2018-01-15 19:40:25 +08:00
时间戳加一定长度字符串
|
36
viko16 2018-01-15 19:49:45 +08:00
实际应用上还得考虑把 "iIl1" 这类不易辨识的字母组合移除..
|
37
innoink 2018-01-15 20:08:20 +08:00
既然已经知道总数,那么预先生成存起来,然后随用随取
|
38
innoink 2018-01-15 20:09:25 +08:00
检查的时候用 bloomfilter
|
39
qfdk 2018-01-15 20:35:32 +08:00 via iPhone
md5 (数据+ 随便)取指定长度
|
40
julyclyde 2018-01-15 20:36:29 +08:00
固定长度就不可能唯一啊
|
41
yingfengi 2018-01-15 21:05:34 +08:00
非程序员,写过一些小东西,我记得 php 有个获取当前时间戳生成一个 ID 的函数还是啥,生成的这个 ID 会是毫秒级的,反正是这么一个东西,之前用过,生成 ID 后 md5 作为一个 key,当初是这样只玩的。
你可以,md5 之后随机取 8 位啥的 以上,仅供参考 |
42
billlee 2018-01-15 21:52:46 +08:00
block_ciper(counter())
|
43
fuyufjh 2018-01-15 21:56:46 +08:00
最科学的方法:把输出看成一个(26+26+10)进制、8 位的数
random.randint(0, (26+26+10)**8) |
44
nccer 2018-01-15 22:41:01 +08:00 1
生成个池子,用的时候在里面选一个.
|
45
zhx1991 2018-01-16 00:13:40 +08:00
用上面说的某种碰撞很低但不是没有的随机策略
然后在库里把这个字段设成唯一 插入重复数据会报错(非常罕见), 捕获相应异常重来 |
46
janxin 2018-01-16 11:05:06 +08:00
提前生成随机字母数字池,过滤清洗重复数据。这段时间不占用业务响应时间。使用的时候取出任意(从头部或尾部取出),销毁之。
|
48
janxin 2018-01-16 11:32:26 +08:00
刚刚说的还是比较业务偷懒了,其实技术一点的方法是设计一个映射算法即可。随便想了一个简单的:保证安全性前提下可以使用带校验位方式,可以占一个字母;为了混淆,可随机生成 2 位随机位,也可以用于后续 ID 的运算随机位可重复没关系,占用两个字节,不要求安全就随机三个字节;自增 ID 占用 5 位即可满足现有数量级需求,可按位或其他方式进行运算得到一个,还可以带入之前取到的随机数进行,凯撒之类的简单算法就可以。顺序还可以随机排序组合,能识别的前提下 XD
|
49
raptor 2018-01-16 11:53:40 +08:00
千万级就是小于 1 亿,对应二进制不到 27 位。
A-Z1-9 8 位,相当于 35 进制的 8 位,对应二进制 41 位多点。 生成一个 14 位的随机数,左移 27 位,和 ID 组成一个 41 位二进制数。 自己设置一个密钥,再用 RC4 加密这个 41 位二进制数。 最后把这个加密后的二进制数转为 35 进制的 A-Z1-9。 这样可以保证唯一,猜不到,不用查数据库三个要求。 解出 ID 的方法: 字符串转成二进制,RC4 解密,把 41 位二进制最高 14 位填充成 0,再补 23 位 0 填充成 64 位,转成整数即是 ID。 |
50
mingl0280 2018-01-16 12:23:36 +08:00
SHA1/MD5 一个随机值(真随机值)取其中随意八位,然后查库有没有碰撞到的……
其实讲道理这个碰撞在千万量级应该是不可能的…… |
51
chuhemiao 2018-01-16 13:10:45 +08:00
是时候上区块链思想了
|
52
lbp0200 2018-01-16 15:10:28 +08:00
从老外那,抄来的
od -x /dev/urandom | head -1 | awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}' |
54
mengzhuo 2018-01-16 17:10:27 +08:00
总空间只有 = 218,340,105,584,896
你的要求是 = 000,000,0xx,xxx,xxx 正好对半开 把时间填在前面,唯一 id 填到后面,然后随便位移,置换,异或一下就好了(反正没人会真的看你的算法) |
55
SooHoo 2018-01-16 17:54:33 +08:00
这两天公司业务需求,提现码(不能重复,不能被猜测到,不能太长,最多 6 位)
大概说下生成规则 先将数字小写字母大写字母打乱 然后左边取 20 个字符作为 randomKey 剩下右边给 numKey 将用户 id 进行 numKey.length 进制换算,生成字符串 result 长度不足 6 个,从 randomKey 随机取 6 个字符,插入 result 字符串 随机位置 |
56
SooHoo 2018-01-16 17:57:40 +08:00
@SooHoo
接上 ,没发完 不小心发出来了 ---------- 大概思想就是把 uid 放入到串里面,然后,随机插入 不包括 uid 的字符 为了让用户稍微难些分析。就加入了进制转换,然后随机插入位置。 可能有 BUG,欢迎指正。哈哈 ----------------------------------------- /** * * @param count 字符个数 * @param uid 用户 id * @return */ public static String randomString(int count, int uid) { String randomKey = CODE.substring(0, 20); String numKey = CODE.substring(20); StringBuilder result = new StringBuilder(); while (uid > 0) { //转成 numKey.length 进制 int p = uid % numKey.length(); result.append(numKey.substring(p, p + 1)); uid = uid / numKey.length(); } if (result.length() < count) {//字数不足,随机字符补全 Random random = new Random(); int size = count - result.length(); for (int i = 0; i < size; i++) { int r = random.nextInt(randomKey.length()); //随机取一个字符 int p = random.nextInt(result.length() + 1);//随机一个位置 result.insert(p, randomKey.substring(r, r + 1)); } } return result.toString(); } |
57
wwhc 2018-01-17 05:00:43 +08:00
md6sum -d32 用户 ID/随机数
|