这是我的解决方案。
有一个三部分的x-y-z,其中x是时间戳,y是随机代码,z是由x和y连接产生的检查数字。但为了简化(使其更小),x和y以自定义基数给出,而不是数字基数10,但z仍以基数10给出。
以下是您可以使用此方法获取的ID示例:
- LP9NTX-8D41-QW6R-9
- LP9NTY-5H3L-BFS7-5
- LP9NTZ-RWL3-D619-8
- LP9NVB-BW74-788W-6
- LP9NVW-G17D-4911-8
因此,您可以按时间戳排序(如果您不知道数字基数的确切含义,请注意它以“递增字母数字”顺序进行)。
为此,我使用了base58的数字和大写字母(最后使用小写或大写都没关系),这是没有一些混淆字符的base62。Flickr、bit.ly等网站使用base58制作Twitter“友好”链接等。
下面的Verhoeff::calcsum是Dahnielson的Verhoeff的Dihedral Group D5 Check。我所做的唯一编辑就是将他的代码放在一个类里面,所以它完全相同。
这里有一些代码:(从上面的行中略微修改)
<?php
$time_divisor = 3;
$base = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
$lower_limit = 50000;
$upper_limit = 1291467968;
$ptime = (int)($_SERVER['REQUEST_TIME']/$time_divisor);
$rand1 = mt_rand($lower_limit, $upper_limi);
$rand2 = mt_rand($lower_limit, $upper_limi);
$ptime_b = base_encode($time, $base);
$rand1_b = base_encode($rand1, $base);
$rand2_b = base_encode($rand2, $base);
$order_id = $ptime_b.$rand1_b.$rand2_b.Verhoeff::calcsum($time.$rand1.$rand2);
echo $order_id;
?>
我刚写完这篇文章,又想到了可能出错的另一种情况。我记得你不希望消费者感到被侮辱。所以即使像'f?ck'或'4ss'这样的脏话最终出现可能是可以接受的(而且几乎肯定会出现),但明确的脏话(例如将前一个单词中的'4'换成'a')绝对不行。因此,我建议你使用以下备用的基础/上限:
<?php
$lower_limit = 27000;//=2111
$upper_limit = 809999;//=ZZZZ
$base = "123456789BCDFGHJKLMNPQRSTVWXYZ";//erased -a -e -u
?>
请注意,如果您尝试使用更大的数字,您将达到PHP的上限和mt_rand限制,可以通过mt_getrandmax()查看。此外,我想说的是,就我所见,mt_rand的熵已足够。
如果您需要更大的随机数,我建议只需添加第三部分,例如mt_rand(i, j);其中i和j是您的基数的最小和最大值,这将增加您的订单号长度$num-chars(实际上我已经做到了,使用上述配置)。
在数据库方面,它是一个唯一字段,以避免冲突。
谢谢大家。