这是我的解决方案。
有一个 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 and others use base58 for making Twitter 'friendly' links and the like.
下面的 Verhoeff::calcsum 是 Verhoeff’s Dihedral Group D5 Check by Dahnielson. 我所做的唯一编辑是将他的代码放在一个类中,所以它是一样的。
这是一些代码:(*与我在上面的行中承诺的有所修改^)
<?php
$time_divisor = 3;
$base = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ";//consider using another base **see note below**
$lower_limit = 50000;//just to avoiding to confuse the user with a lower number
$upper_limit = 1291467968;//1291467968 == ZZZZZZ in this base I used
//you can check the limit with base_decode("ZZZZZZ", $base);
$ptime = (int)($_SERVER['REQUEST_TIME']/$time_divisor);//or time();
$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”)绝对不是.因此,我建议您改用以下备用 base/upper_limit:
<?php
$lower_limit = 27000;//=2111
$upper_limit = 809999;//=ZZZZ
$base = "123456789BCDFGHJKLMNPQRSTVWXYZ";//erased -a -e -u
?>
请注意,如果您尝试使用更大的数字,您将达到 PHP 的 int 上限以及 mt_rand 限制,这可以通过 mt_getrandmax() 看到。另外,我想说的是,就我所见,mt_rand 的熵就足够了。
如果您需要更大的随机部分数字,我建议您仅在其中附加第三部分,例如 mt_rand(i, j);其中 i 和 j 是您的基数的最小值和最大值,它将以 $num-chars 长度增加您的订单 ID(实际上是我做了这个,使用上面的配置)。
在数据库方面,它是一个独特的字段,可以避免冲突。
谢谢大家。