我需要一种有效的方法来获取随机和唯一的字符串,重复的机会为零(或可忽略不计)。
我需要[0-9A-z]
范围内的字符。
这是我到目前为止所拥有的:
substr(sha1(mt_rand().uniqid()),0,22);
因为我知道这实际上是在谈论 bcrypt 和密码加盐,所以我现在真的可以将阅读本文的人指向他们应该使用的功能,而不是手动滚动他们自己的加盐系统。
用于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 位时间戳)是可预测的,并且由于多种原因可能会很糟糕:
尽管如此,只要有足够的准确性,您仍然可以使用时间戳作为唯一盐。不是随机的(除非您将其用作随机种子并将其基本转换为 base10,这仍然是一个坏主意)。如果您可以在纳秒以下计算时间并喜欢将其用作唯一 ID,请考虑这一点。PHP 无法以足够快的速度处理以提供两个冲突的亚纳秒 ID 1(但这并不意味着您不应该验证!)
1:它适用于作曲家!
这就是我有时正在做的方式......
// 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。
您不能保证这将始终返回一个唯一值,但它会显着降低风险。当您使用随机数生成算法时,总是有重复的可能性。
为了保证只生成唯一值,您可以搜索以前生成的值并丢弃重复项。
一些减少公式中重复机会的建议:
sha1
. 这是一种为任何给定输入返回一个一致输出的方法。它不会影响重复的可能性。sha1
,请考虑将随机数转换为不同的基数(例如,以 36 为基数的数字可以使用字符 0-9 和 AZ,您可以将其存储在数据库中或您对随机字符串输出所做的任何事情) . 但是我真的不会在这里选择36,也许是256+?substr
因此实际上增加了重复的机会。使用我在上一个项目符号中所写的内容将随机数转换为不需要截断的少于 22 个字符的字符串。substr
此外,您可以通过使用该函数返回一个原始值来消除对的需求sha1
,该值只有 20 个字符。为什么不直接使用该time()
功能。
我需要做类似的事情,一个保持唯一 id 的解决方案,我最终得到了一个使用 PHP 函数的解决方案,time()
你$reference_number = 'BFF-' . time();
可以将 BFF 更改为对你的业务逻辑更有意义的东西。这样我就不必担心是否正在生成的新 id 之前被占用,因为时间总是唯一的
我希望这有帮助