V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
DavidNineRoc
V2EX  ›  问与答

优秀的生成防伪码的代码应该如何写?百万千万量级别的。

  •  
  •   DavidNineRoc · 2018-03-23 10:01:53 +08:00 · 3231 次点击
    这是一个创建于 2463 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求:

    • 生成的防伪码长度大概在 12~18 位
    • 有可能是纯数字,或者字母+数字
    • 绝对不能重复 某 cms 防伪系统的生成防伪码的源码;
    function genRandomString($len, $t = 0)
    {
    	$chars = array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "2", "3", "4", "5", "6", "7", "8", "9");
    	$chars1 = array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z");
    	$chars2 = array("1", "2", "0", "3", "4", "5", "6", "7", "8", "9");
    	$chars3 = array("A", "B", "C", "D", "E", "F", "G", "O", "H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z");
    
    	if ($t == 1) {
    		$charsLen = count($chars1) - 1;
    		shuffle($chars1);
    		$output = "";
    
    		for ($i = 0; $i < $len; $i++) {
    			$output .= $chars1[mt_rand(0, $charsLen)];
    		}
    	}
    	else if ($t == 2) {
    		$charsLen = count($chars2) - 1;
    		shuffle($chars2);
    		$output = "";
    
    		for ($i = 0; $i < $len; $i++) {
    			$output .= $chars2[mt_rand(0, $charsLen)];
    		}
    	}
    	else if ($t == 3) {
    		$charsLen = count($chars3) - 1;
    		shuffle($chars3);
    		$output = "";
    
    		for ($i = 0; $i < $len; $i++) {
    			$output .= $chars3[mt_rand(0, $charsLen)];
    		}
    	}
    	else {
    		$charsLen = count($chars) - 1;
    		shuffle($chars);
    		$output = "";
    
    		for ($i = 0; $i < $len; $i++) {
    			$output .= $chars[mt_rand(0, $charsLen)];
    		}
    	}
    
    	return $output;
    }
    

    1 基本就是金刚葫芦娃,一股脑生成,插入数据库。连判断都没有。虽然重复的概率小,但还是有可能呀。怎么做到一个优秀一点的?

    • 我想的就只是插入的时候返回 0 或者 1,循环结束计算返回 1 的集合,是否等于要生成的防伪码数量,如果不等于,(这时候,数量级已经下降了很多)
    • 来一个死循环,一次生成一个插入数据库,知道成功的条数弥补上一次重复的数量,跳出循环。

    有没有更好的方法?

    第 1 条附言  ·  2018-03-23 16:13:06 +08:00

    是防伪码呀 >_<

    17 条回复    2018-03-24 23:01:59 +08:00
    ryd994
        1
    ryd994  
       2018-03-23 10:11:51 +08:00 via Android
    验证码这种使用场景,难道不该上 redis 么?重启就重启,反正丢几个验证码有没什么大事,用户只会怀疑自己打错了
    arron
        2
    arron  
       2018-03-23 10:28:28 +08:00
    如果是批量,你就加两个干扰项:time, index 至于放进去怎么变化看需求,可以保证你生成的字符串不会重复。如果是用的时候再生成,那么 time + rand 基本就可以了,保证重复概率低。
    whileFalse
        3
    whileFalse  
       2018-03-23 11:08:44 +08:00
    uuid 不行吗
    oott123
        4
    oott123  
       2018-03-23 11:41:17 +08:00 via Android
    数据库做个唯一性索引,插崩了就重新插一下
    loveCoding
        5
    loveCoding  
       2018-03-23 11:53:43 +08:00
    生成的防伪码长度大概在 12~18 位
    有可能是纯数字,或者字母+数字

    楼上说的 uuid 满足需求的
    DavidNineRoc
        6
    DavidNineRoc  
    OP
       2018-03-23 13:05:48 +08:00
    @ryd994 不是验证码,是防伪码 >_<
    @arron 真的不是验证码,是防伪码
    @whileFalse 给客户使用的,就是验证是否是正品的防伪码
    @oott123 这个,每次都插入,不如我的第二个方法

    * 我想的就只是插入的时候返回 0 或者 1,循环结束计算返回 1 的集合,是否等于要生成的防伪码数量,如果不等于,(这时候,数量级已经下降了很多)
    * 来一个死循环,一次生成一个插入数据库,知道成功的条数弥补上一次重复的数量,跳出循环。


    @loveCoding uuid 肯定不符合要求,长度太长,而且总是英文数字混合的。想要纯数字根本不可能
    prolic
        7
    prolic  
       2018-03-23 13:12:45 +08:00 via Android
    这需求数字加盐散列不就够了么,信不过 md5 你可以再去一次重
    rrfeng
        8
    rrfeng  
       2018-03-23 13:15:26 +08:00 via Android
    防伪:
    发出去的存起来
    算法自验证

    楼上都在说什么...
    DavidNineRoc
        9
    DavidNineRoc  
    OP
       2018-03-23 16:12:09 +08:00
    @prolic 我真的再说防伪码 >_<
    @rrfeng 生成是问题
    l12ab
        10
    l12ab  
       2018-03-23 16:30:53 +08:00 via iPhone
    类似于卖软件的生成序列号
    LukeChien
        11
    LukeChien  
       2018-03-23 19:56:51 +08:00 via Android
    时间戳+aes(时间戳,秘钥)
    chinvo
        12
    chinvo  
       2018-03-23 19:59:41 +08:00
    Sonyflake-like 的串号,加上校验位
    DavidNineRoc
        13
    DavidNineRoc  
    OP
       2018-03-23 23:13:53 +08:00
    @l12ab 对,差不多就是这样
    @LukeChien 不行,会重复
    @chinvo 能生成纯数字?
    chinvo
        14
    chinvo  
       2018-03-23 23:19:44 +08:00
    @DavidNineRoc #13 你的范例代码不是字母数字混合的么……

    如果要纯数字,那就用时间戳+自增,配合一到两位校验
    DavidNineRoc
        15
    DavidNineRoc  
    OP
       2018-03-24 08:25:35 +08:00
    @chinvo 看 $chars3,时间戳都有十位了,再加自增?一次生成十万百万级别的,基本就出现重复了
    xml123
        16
    xml123  
       2018-03-24 09:25:03 +08:00 via Android
    时间戳是唯一的,就算占了全部的位数,也不会重复啊
    DavidNineRoc
        17
    DavidNineRoc  
    OP
       2018-03-24 23:01:59 +08:00
    @xml123 你还年轻,来点并发,就会重复了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2365 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 16:09 · PVG 00:09 · LAX 08:09 · JFK 11:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.