生成随机且唯一的字符串

San*_*cci 5 php unique

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

我需要[0-9A-z]范围内的角色.

这是我到目前为止:

substr(sha1(mt_rand().uniqid()),0,22);  
Run Code Online (Sandbox Code Playgroud)

Ame*_*lia 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
Run Code Online (Sandbox Code Playgroud)

验证:

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

$verified = password_verify($input, $hash); // true if the password matches
Run Code Online (Sandbox Code Playgroud)

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


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

1 / [number of possible letters/numbers] ** [length]
Run Code Online (Sandbox Code Playgroud)

这对于一个22个字符的字符串来说是不可能的低(好吧,不可能,但可忽略不计)

1 / (22 ** 60) = 1 / (3.51043 x 10**80)
Run Code Online (Sandbox Code Playgroud)

看到?很小.


数学谬误

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

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

  1. 您采用此时间戳的准确性成为该盐可预测程度的决定因素.
  2. 如果你以秒为单位将时间作为一个整数并对其进行哈希处理,那么最终会得到非常明确且容易猜到的盐

然而,只要准确度足够,您仍然可以使用时间戳作为唯一的盐.不随机(除非你将它用作随机种子并将其转换为base10,这仍然是一个坏主意).如果您可以在纳秒内计算时间并将其用作唯一ID,那么请考虑这一点.PHP无法快速处理以提供两个冲突的亚纳秒ID 1(但这并不意味着您不应该验证!)


1:它与作曲家合作!