什么是电子商务解决方案或付费网络服务的良好订单ID方案?

时间:2010-10-31 04:33:26

标签: database-design e-commerce uniqueidentifier

考虑以下因素:

a)你想要一些机密性(因为没有告诉每个人你收到了多少订单)。

b)你想要一个校验位(例如,使用Verhoeff算法),这样你就可以轻松地告诉拼写错误,并在扫描条形码时帮助处理错误,如果是这样的话。

c)你要考虑时间,以便消费者可以对订单的顺序进行排序。

d)应该是全数字还是十六进制等?。

e)由于安全问题,您的消费者可以通过电话向支持团队说出的内容足以识别订单而无需工作人员要求发送电子邮件等。

我很想听听一些意见。

PS:任何为解决这个问题而设计的算法对我来说都是一个有效的答案。

4 个答案:

答案 0 :(得分:5)

这是我的解决方案。

有三个部分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'之类的坏词最终也可能出现(而且几乎肯定会出现),明确的词语(如在上一个词中改变'a'的'4')绝对不是。因此,我建议您使用以下备用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(实际上我做了这个,带上面的配置)。

在DB方面,它是一个独特的领域,以避免碰撞。

谢谢大家。

答案 1 :(得分:1)

你认为合适的随机字符串怎么样?使用不易与其他字符混淆的字符,以便通过电话阅读。因此,在每个订单上调用类似于:

    public static string GetRandomString(int length)
    {
        char[] chars = "ACDEFGHJKMNPQRTWXY34679".ToCharArray();
        var crypto = new RNGCryptoServiceProvider();
        var data = new byte[length];
        crypto.GetNonZeroBytes(data);
        var result = new StringBuilder(length);
        for (int i = 0; i < data.Length; i++)
        {
            result.Append(chars[data[i] % chars.Length]);
        }

        return result.ToString();
    }

猜测从上述方法返回的8个字符是1/282429536481。你会在数据库中保持完整性并具有唯一约束吗?

答案 2 :(得分:1)

java.util.UUID.randomUUID()

答案 3 :(得分:0)

您可以使用GUID。要将其缩小为客户友好的字符串,值得通过Base32转换器运行该值,这将导致包含26个字符的A-Z和数字2-7的字符串

为了满足您的其他标准,您可以在guid值附加一个校验位,并且您可能需要在数据库中使用单独的真正增量订单号来保证唯一性并允许自然索引/排序。