具有固定位数的唯一代码

时间:2013-12-19 07:51:02

标签: php mysql sql

在我的mysql数据库中,我存储了可以在我的PHP Web应用程序中显示的商品。每个商品都有自己独特的自动增量数据库ID,我不想向用户显示。但是,我需要一些公共唯一标识符。

为什么我不想显示真实身份

  • 位数可能会有所不同,经过一段时间后数字可能会太长
  • 如果有人减去两个所选优惠的ID,他将收到这两个优惠之间发布的优惠数

我想要的公共ID

  • 独一无二
  • 具有固定的位数(最佳5或6)

我所知道的

  • 有效报价的最长持续时间为6个月(未来可能会更长,但不会超过一年)

我在想:

问题:

  1. 最后一个选项最适合您吗?或者你能否提出任何其他常用的方法/技巧。
  2. 是否可以为所有6位数字保留900 000行表格?
  3. 如果(理论上)我的有效报价数量超过900 000(我知道如果发生这种情况,第2点无关紧要),我该如何处理情况?
  4. 拥有可能相同ID的更多非活动商品是否正确?例如,某些用户可能会想要参考他的旧报价。
  5. 将数字与数字一起使用以扩大可能的组合数量会更好吗?

3 个答案:

答案 0 :(得分:2)

假设您的公共ID是从64个字符的字母表中提取的任何6个字符的字符串(例如英文字母的26个字母,大写和小写;印度 - 阿拉伯数字系统的10个十进制数字;以及另外两个字符,例如+/)。

可以用这种方式表达的可能ID的数量是64 6 ,或接近690亿。把它放在上下文中,这个星球上的每个人几乎都有10个ID;或者每年一个身份证,直到公元4191年。我想你在申请退休或更换之前不会用尽所有可能性。

那么,如何获得这样一个6个字符的字符串呢?值得注意的是,Base-64编码一个4字节的值,少了任何填充,将产生6个字符(尽管它将只产生8个 4 ×40亿个可能的值,因为最后的字符将被绘制来自64种可能性中的4种。

然后问题变成“我应该使用什么4字节值?”你提出的建议是:

  •   

    “真实”ID的单一转换

    MySQL INT是4个字节。如果您的“真实身份”是INT UNSIGNED AUTO_INCREMENT,也许您可​​以使用:*

    SELECT TRIM(TRAILING '=' FROM TO_BASE64(LPAD(CHAR(id),4,CHAR(0))))
    FROM   my_table
    WHERE  ...;
    
    SELECT *
    FROM   my_table
    WHERE  id = CONV(HEX(FROM_BASE64(CONCAT(?, '=='))),16,10);
    

    但是请注意,您只需要一个可以轻松解码的id编码:对于其他任何人来说,转换回数字并击败本练习的对象并不会太难。可以通过bitwise XOR id针对已知秘密来缓解此类攻击,或者更好地使用单向加密哈希函数。

  •   

    时间戳的转换

    MySQL TIMESTAMP也是4字节。您可以类似地使用它(只需在上述示例中应用UNIX_TIMESTAMP()FROM_UNIXTIME())。请注意,如果两个时间戳相同(到第二个),则会发生冲突:您可能会使用最后一个字符中的额外4位来处理此类冲突,尽管这只会将问题延迟到有16个记录时同一时间戳。)

  •   

    生成未使用的号码列表,如下所示:Generate 6 Digit unique number

    当然这是一种可能性,但确实是一张非常大的桌子。更多信息如下。

所以,回答你的问题:

  1.   

    最后一个选项最适合您吗?或者你可以建议任何其他常用的方法/技术。

    这取决于威胁模型。由于它的简单性,我可能会使用Base {64编码id(可能与已知秘密进行异或)。

  2.   

    是否可以为所有6位数字保留900 000行表格?

    即使它是6位十进制数字,你也会谈论超过900,000行(事实上是100万行)。如上所示,通过使用比十进制数字更大的字母表,可以考虑更大的空间。

    “OK”并不清楚你的意思。如果有一个存储空间可供使用,我不知道会出现什么问题。虽然我们谈论的是几千兆字节的存储空间,但它的价格相当便宜。

  3.   

    如果(理论上)我的有效报价数量超过900 000(我知道如果发生这种情况,第2点将无关紧要),我该如何处理情况?

    这就是为什么允许变长是很方便的原因。目前尚不清楚为什么要反对变长。

  4.   

    拥有可能相同ID的更多非活动商品是否正确?例如,某些用户可能会想要参考他的旧报价。

    我不会重复使用ID。

  5.   

    将字母和数字一起使用以扩展可能的组合数量会更好吗?

    呃,是的。见上文。


  6. *请注意,在v5.6.1中添加了MySQL函数Base64函数;如果使用早期版本,您将需要安装suitable UDF,手动执行编码 - 例如。在stored function中 - 或者在应用程序的更高层进行。

答案 1 :(得分:1)

使用字母和数字可能更好,从可用性的角度来看,你可以得到更多的组合。

在大多数情况下,存储一百万左右这些并不会破坏太多。

是先生成还是按需生成这些都是一个使用问题 - 是否有1000人可能想要同时生成代码?如果是这样,请预先构建它们。存储空间是一个因素吗?如果是这样,请考虑动态生成它们。

您应该避免让2个商品代码具有相同的可能性,因此可以根据实际需要将它们连接起来,或者确保生成器函数为每次使用生成唯一的商品代码。

答案 2 :(得分:1)

嗯,你能做的最好的事情是: 1)从具有完整参数的日期生成变量(yyyy-MM-dd hh:mm:ss)并将其与用户电子邮件连接。 在md5中编码。

2)或者使用像MSID服务器中存在的guid生成器一样叫做NEWID(),这与c#GUID相同

你可以将它从0子串到你想要多少个字符

我不建议将未使用的号码列表作为表现的原因。

将它作为整数并不是那么好也会导致更容易从6个字符中的0到9生成一个数字来破解你的数据库(注入和类似的东西)。