search

Home  >  Q&A  >  body text

php - 12位纯数字兑换码的生成算法,如何尽可能保证不重复?

在只有PHP和mysql的环境下,做一个简单的发券、核销程序。其中券的兑换码必须为12位数字,数据量不会超过千万。如何生成不重复且乱序的券码?

最糟糕的方案是纯随机,然后到表里查一遍是否重复,重复则重新生成;不重复则插入

一个自认为好点的方案是用户id加一位随机数加截取时间戳后x位
例如用户ID为123,则是3位,加随机数4位。此时剩余8位则截取时间戳后8位补上。重复概率应该就很低了

在尽可能不遍历表的情况下,还有更难以重复的生成算法吗?求不吝赐教

迷茫迷茫2791 days ago2174

reply all(5)I'll reply

  • 伊谢尔伦

    伊谢尔伦2017-04-10 18:07:05

    考虑用户的ID和时间进行消息摘要算法,比如最简单内置的MD5或者SHA1,然后对于结果进行一定的压缩或者提取,转化成12位的

    reply
    0
  • 怪我咯

    怪我咯2017-04-10 18:07:05

    如果是按照用户ID和时间戳等生成md5摘要的方式的话,可以用base_convert将哈希后的md5值转为10进制,不过这样转出来的结果值长度肯定就不止12位了,还需要用字符串截取函数截取一下,但原本几十位的十进制数只截取12位那么唯一性就无法保证了,可能还不如直接截取ID加时间戳,看你的描述应该是在用户请求的时候才生成码,那么一个用户同一秒不能生成多张的情况下组合部分时间戳和用户ID还是没问题的。

    reply
    0
  • 迷茫

    迷茫2017-04-10 18:07:05

    我感觉你的想法挺好啊,还可以还原进行验证兑换码的合法性。

    reply
    0
  • 怪我咯

    怪我咯2017-04-10 18:07:05

    消息摘要算法太混沌了,压缩到12位后效果和随机没有区别,多了还是会碰撞。

    楼主的做法(id + 时间戳 + 随机数)基本能满足不碰撞的要求了,问题在于乱序。

    可以仿效线性同余生成伪随机数的方法,找个大素数a和常数b,把id + 时间戳 + 随机数生成的数字输入函数f(x) = a * x + b (mod 1,000,000,000,000)里,只要a足够大(数量级跟1,000,000,000,000相近)就很随机了。而且由于a是素数,f是可逆的,这也保证了只要输入不重复,输出也不会重复。

    另外建议拼接数字时把随机数放在高位,这样运算后输出的差别更大。

    reply
    0
  • PHPz

    PHPz2017-04-10 18:07:05

    我的卡券类号码都是一位特定大写随机英文字典中抽一位+uid+time()+rand(十位数),然后截取16位出来生成比如T132-0161-2052-3091,有些超市用户一个月就分发百万张出去,没有重复的反馈.
    之所以加英文,主要还是增加接口查询被随机碰撞破解的难度.

    reply
    0
  • Cancelreply