我之前already answered这样的问题。我更新了我的代码,为生成的 id 添加了更多随机性(熵)。
此类生成伪唯一、非连续、非数字 ID。
class IdGenerator {
static private function _nextChar() {
return base_convert(mt_rand(0, 35), 10, 36);
}
static public function generate() {
$parts = explode('.', uniqid('', true));
$id = str_pad(base_convert($parts[0], 16, 2), 56, mt_rand(0, 1), STR_PAD_LEFT)
. str_pad(base_convert($parts[1], 10, 2), 32, mt_rand(0, 1), STR_PAD_LEFT);
$id = str_pad($id, strlen($id) + (8 - (strlen($id) % 8)), mt_rand(0, 1), STR_PAD_BOTH);
$chunks = str_split($id, 8);
$id = array();
foreach ($chunks as $key => $chunk) {
if ($key & 1) { // odd
array_unshift($id, $chunk);
} else { // even
array_push($id, $chunk);
}
}
// add random seeds
$prefix = str_pad(base_convert(mt_rand(), 10, 36), 6, self::_nextChar(), STR_PAD_BOTH);
$id = str_pad(base_convert(implode($id), 2, 36), 19, self::_nextChar(), STR_PAD_BOTH);
$suffix = str_pad(base_convert(mt_rand(), 10, 36), 6, self::_nextChar(), STR_PAD_BOTH);
return $prefix . self::_nextChar() . $id . $suffix;
}
}
如果你执行这个脚本
header('Content-type: text/plain; charset=utf-8');
for ($i=0; $i<10; $i++) {
$uid = IdGenerator::generate();
echo $uid . " = " . strlen($uid) . "\n";
}
你会得到这样的东西:
x0i8eea3c8kw4lgudmoss4c4w03db6wl = 32
byqrfgc6hilr9d1ot4wow8gw4syugtvz = 32
ta075al22zp3v6awtlw4kgkk446mjbiv = 32
hqqa90p27e9desx99q8skokcc46fujx4 = 32
uqc000q7g20l1k9zlwko80gsow5e59e7 = 32
gxx2r5d5oa0p8iykvc4ckgc4kc0teekv = 32
ayysoos5ltfua3d0m80ccocc0kcfhqyb = 32
dtj31vi4tzmh6lhk1iccc0os4cgsze1e = 32
fvn41hh2gnk6lbrq4w0wwgko8k5ihda8 = 32
oxamsba3qh0ro6xehkw8cg400s10tiyq = 32
** 编辑 **
那么,为什么这一切?为什么不直接使用uniqid()?因为uniqid() 是连续的并且是可预测的。因为你需要增加更多的熵。这个类不仅使用uniqid()“更多熵”参数,它还使用mt_rand()来填充生成的值。此处提供的类也将始终生成一个 32 字节(256 位)的字符串。
这个函数有多随机?要拥有重复的 ID,需要同时调用uniqid()准确,而mt_rand() 需要在同一时间返回准确相同的随机值订购......连续七次。底线是它是相当随机的。
** 编辑 2 **
您可能还对pure PHP UUID 实现感兴趣。
** 编辑 3 **
使用主键 (PK) 作为唯一文件名的问题在于它是可预测的。如果您打算直接从 URI 路由提供这些文件,则生成的非顺序值更安全。如果您打算以其他方式提供这些文件,那么无论如何都必须为这些文件分配一些唯一的密钥......并且由于完全相同的原因,这个密钥不能是连续的。因此,无论用例如何,使用非顺序唯一键作为文件名都是一个好主意。