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

2018-03-23 10:01:53 +08:00
 DavidNineRoc

需求:

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;
}

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


有没有更好的方法?

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

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

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


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

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

如果要纯数字,那就用时间戳+自增,配合一到两位校验
DavidNineRoc
2018-03-24 08:25:35 +08:00
@chinvo 看 $chars3,时间戳都有十位了,再加自增?一次生成十万百万级别的,基本就出现重复了
xml123
2018-03-24 09:25:03 +08:00
时间戳是唯一的,就算占了全部的位数,也不会重复啊
DavidNineRoc
2018-03-24 23:01:59 +08:00
@xml123 你还年轻,来点并发,就会重复了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/440661

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX