生成随机且唯一的字符串

时间:2013-02-03 16:03:24

标签: php unique

我需要一种有效的方法来获取随机唯一字符串,并且重复的可能性为零(或可忽略不计)。

我需要[0-9A-z]范围内的字符。

这是我到目前为止所做的:

substr(sha1(mt_rand().uniqid()),0,22);  

5 个答案:

答案 0 :(得分:8)

最近对PHP的更改

因为我知道这实际上是在谈论bcrypt和密码salting现在我真的可以只是将人们读到这个应该使用的功能,而不是手动滚动他们自己的盐系统。

使用password_hash($input, PASSWORD_DEFAULT);生成适合插入数据库的哈希。这将为你取盐。

插入:

$hash = password_hash($_POST["password"], PASSWORD_DEFAULT, ["cost" => 16]);
DB::table("users")->insert(["username" => $user, "password" => $hash]);
// or whatever database method you use to insert data

验证

$hash = DB::table("users")->fetchByName($username)->select("password");
$input = $_POST["password"];

$verified = password_verify($input, $hash); // true if the password matches

在PHP 5.5之前的版本中,使用https://github.com/ircmaxell/password_compat作为插入 1


当随机生成盐时,碰撞的几率是

1 / [number of possible letters/numbers] ** [length]

对于22个字符的字符串,这个字符串是不可能的(好吧,不是不可能,但是 可忽略

1 / (22 ** 60) = 1 / (3.51043 x 10**80)

请参阅?的


数学谬误

如果你需要一个真正的随机字符串(注意:这些字符串只是一行映射到字母的数字),那么你就有点不走运了。
您正在寻找的是CSPRNG(密码安全伪随机数发生器)。不需要独特性。

正如 @Guarav 在他的回答中指出的那样,您可以使用时间戳作为种子,然后对其进行哈希处理。这称为UUID(唯一通用标识符,如果它是128位时间戳)是可预测的,并且可能由于多种原因而变坏:

  1. 你采用这个时间戳的准确性成为这种盐可预测程度的决定因素。
  2. 如果你把时间用秒作为一个整数并哈希,那么你最终得到非常明确且容易猜到的盐
  3. 尽管如此,如果准确度足够高,您仍然可以将时间戳用作唯一盐。不是随机(除非你将它用作随机种子并将其转换为base10,这仍然是一个坏主意)。如果您可以在纳秒内计算时间并将其用作唯一ID,那么请考虑这一点。 PHP无法快速处理以提供两个碰撞的亚纳秒ID 1 (但这并不意味着您不应该验证!)


    1:它与作曲家合作!

答案 1 :(得分:4)

这是我正在做的事情......

// chars
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-+';

// convert to array
$arr = str_split($chars, 1);

// shuffle the array
shuffle($arr);

// array to chars with 22 chars
echo substr(implode('', $arr), 0, 22);

输出

xd*thKM$B#13^)9!QkD@gU

ixXYL0GEHRf+SNn#gcJIq-

$0LruRlgpjv1XS8xZq)hwY

$G-MKXf@rI3hFwT4l9)j0u

要确保它是唯一的,您可以随时登记数据库。如果重复,则重新生成KEY。

答案 2 :(得分:2)

您可以查看我自己问题的答案。 How to generate Unique Order Id (just to show touser) with actual Order Id?

您可以使用 TimeStamp 代替任意随机字符串。

关于你的解决方案,有可能发生碰撞,但其处于非常低的水平。

答案 3 :(得分:1)

您不会保证这将始终返回唯一值,但它会显着降低风险。使用随机数生成算法时,总是存在重复的可能性。

为了保证只生成唯一值,您可以搜索以前生成的值并丢弃重复项。

一些建议可以减少公式中重复的可能性:

  • 不要使用sha1。这是一种为任何给定输入返回一致输出的方法。它不会影响重复的可能性。
  • 考虑将随机数转换为不同的基数(例如,基数36中的数字可以使用字符0-9和AZ,而不是sha1,您可以使用字符0-9和AZ,您可以将它们存储在数据库中39;重做随机字符串输出)。但我不会在这里找到36,也许是256 +?
  • 由于您使用substr将字符串限制为22个字符,因此实际上会增加重复次数的可能性。使用我在上一个项目符号中写的内容将随机数转换为少于22个字符且不需要截断的字符串。
  • 此外,您可以通过substr函数返回原始值来删除对sha1的需求,该函数只有20个字符。
  • 或者,只是不要将字符串限制为22个字符(除非你真的需要出于任何原因)。

答案 4 :(得分:-1)

为什么不使用time()函数。

我需要做类似的事情,一个保持唯一ID的解决方案,我最终得到了一个使用PHP函数time()的解决方案,就像这样$reference_number = 'BFF-' . time();你可以将BFF更改为更有意义的东西对你的业务逻辑。这样我就不必担心是否因为时间永远是唯一的,所以正在生成新的id

我希望这会有所帮助