独特的,不可预测的,12位数,整数id

时间:2011-08-25 17:18:37

标签: php mysql random

我将如何生成此...我希望保持主键顺序,并为添加到数据库的每个新对象生成一个12位唯一引脚。

它不能仅仅是自动增量的原因是我不希望序列号很容易猜到。

它必须是整数,因为我将需要在电话簿上拨打验证码。

7 个答案:

答案 0 :(得分:6)

使用唯一递增数字和随机生成数字的串联。

唯一递增的数字可确保结果是唯一的,随机生成的数字使其难以猜测。

简单,保证无碰撞(1)。结果是增量,部分随机,不可预测(假设随机数部分是使用良好的PRNG生成的)。

(1):你必须用零填充idrandom,或用一些非数字字符分隔它们。

使用MySQL数据库,转换为:

CREATE TABLE foo (
    id int not null auto_increment,
    random int not null,
    ...
    primary key (id)
);

答案 1 :(得分:2)

也许你可以使用UUID_SHORT()。长度不是12位数,但仍然是一个可行的选择:

mysql> select uuid_short();
+-------------------+
| uuid_short()      |
+-------------------+
| 22048742962102272 |
+-------------------+

所以:

INSERT INTO `table` (`id`, `text`) VALUES (UUID_SHORT(), 'hello world!');

注意:如果你真的想拥有12位数,那么如果不能确保标识符的唯一性并且可能导致冲突,那么甚至不要尝试对结果进行子串。

答案 2 :(得分:1)

<?php 
$allowed_characters = array(1,2,3,4,5,6,7,8,9,0);
for($i = 1;$i <= 12; $i++){
    $pass .= $allowed_characters[rand(0, count($allowed_characters) - 1)];
}
echo $pass;
?>

演示:http://sandbox.phpcode.eu/g/c0190/4

答案 3 :(得分:0)

一种方法是获取主键值,将其与一些其他随机数据位(用户名,当前时间,进程ID,固定字符串等等)进行加密,并使用md5或sha1进行哈希处理。然后,您可以使用哈希字符串并通过基本字符串操作将其转换为数字。那会给你一个相对独特的数字代码。

当然,只有12位数字,你比使用原始字符串哈希更容易结束碰撞 - 但是因为你要求在键盘上拨打它,所以这是一个可以接受的权衡。

如果在使用后引脚无效/删除,那么碰撞几率将大大降低。

答案 4 :(得分:0)

你想要两件事

  1. 唯一性
  2. 增量
  3. 如果你想要两个相同序列的东西,你将会运气不好(字面意思) 通过大样本空间+随机+检查唯一性来保证唯一性。这意味着,实际数字可以是样本空间之间的任何位置。

    但是如果你想要唯一+增量属性,你将样本空间除以2.在64次尝试中,你会将64位int样本空间减少到1位样本空间。

    祝你好运!

答案 5 :(得分:0)

一般来说,我宁愿做一些更低技术的事情。我模糊了PHP中的值,并将它们保留为JS中的自动递增。

$seeds = array( /*series 100 of very large >= 10-digit numbers*/ );
$seedID = rand( count( $seeds ) ); // randomly choose one of those.
// a string combination which represents the ID + some hash.
$id = bcadd( $seeds[ $seedID ], /* id retrieved from database */ );
// make sure we've not accidentally passed the 10^12 point
$id = bcmod( $id, 1000000000000 );
// make sure to pad
$id = str_pad('' .  $id, 3, "0", STR_PAD_LEFT);
$outID = substr( $id, 0, 5 ) . $seedID . substr( $id, 6 );

然后,当从用户那里收到ID时:

$seedID = substr( $outID, 6, 2 );
$tmpID = substr( $outID, 0, 5 ) . substr( $outID, 8 );
$id = bcsub( $tmpID, $seeds[ $seedID ] );
// we passed the modulus se we need to add this back in.
if( $id < 0 ) $id = bcmod( bcadd( $id, 1000000000000 ), 1000000000000 );

这基本上意味着你只是模糊了你想要的任何数字 - 你可以使用auto_increment而不受惩罚!

答案 6 :(得分:0)

到目前为止,所有解决方案都缺少对您的应用至关重要的一件事:安全性

你说你将使用这些数字作为(产品)验证码 - 所以你真的,真的希望这是不可预测的,否则被利用。

MySQL的内置RANDOM函数和PHP今天提供的任何随机函数都不是安全随机函数。它们表现为伪随机,好吧,但它们都 可预测!

你唯一的机会就是在* nix机器上使用/dev/urandom或在Windows上利用Crypto API来制作自己的东西。 OpenSSL确实提供了基于这些机制的安全随机数 - 您可以在PHP的C扩展中重用它,也可以通过从PHP调用的命令行脚本读取输出。另请参阅此answer

关于您对顺序数字的要求 - 这真的非常重要吗?它确实使事情变得复杂。否则,您可以使用十六进制编码(产生12个字符的字符串)使用编码为字符串的简单安全6字节随机数。虽然我建议将10个字节和20个字符设置为更安全。

但是如果你想要顺序,我认为它是单调增加的(因为一个简单的+1可以简单地预测),这使事情变得更加复杂。而且你没有从这种复杂性中获得任何东西,唯一可能发生的是你通过发明一些容易被利用的模糊方案来破坏安全性。

我的建议:添加另一列作为普通旧的自动递增ID,并将代码添加为如上构造的随机数作为单独的列。据我所知,没有必要同时要求产品激活码作为ID。