请教 PHP 高效生成简短唯一随机数方法

2019-04-18 22:06:44 +08:00
 VKMEPR

兼顾高效、尽量不重复。md5 最短 16 位数,uniqid 13 位(这样长度其实也可以,就是重复概率能不能再减低,不要求绝对唯一)

打算时间戳+截取几个 uniqid 字符,有比这更好方法吗?

5697 次点击
所在节点    PHP
19 条回复
newmind
2019-04-18 22:10:38 +08:00
hashids
gz911122
2019-04-18 22:29:43 +08:00
各种开源的随机数生成器都可以啊
MetalCore
2019-04-18 23:16:53 +08:00
雪花算法
flyingghost
2019-04-18 23:42:30 +08:00
hashids + snowflake + GUID 简直绞杀我所有关于 id 的需求。
wdlth
2019-04-19 00:55:53 +08:00
openssl_random_pseudo_bytes
random_bytes
可以试试
vibbow
2019-04-19 01:36:17 +08:00
不要用 uniqid()

当 CPU 足够快的时候,uniqid() 必重复
lihongjie0209
2019-04-19 10:27:12 +08:00
md5 是 hash 算法,不是随机数算法
lihongjie0209
2019-04-19 10:28:11 +08:00
时间戳在分布式环境中不太好维护吧, 要保证所有机器的时间都一致
lihongjie0209
2019-04-19 10:29:49 +08:00
uniqid ([ string $prefix = "" [, bool $more_entropy = false ]] ) : string
获取一个带前缀、基于当前时间微秒数的唯一 ID。

uniqid 本来就是基于时间戳的, 所以你说的

打算时间戳+截取几个 uniqid 字符

不成立
caoyouming
2019-04-19 10:30:54 +08:00
拿去,之前写的一个。
function genToken( $len = 32, $md5 = true ) {
# Seed random number generator
# Only needed for PHP versions prior to 4.2
mt_srand( (double)microtime()*1000000 );
# Array of characters, adjust as desired
$chars = array(
'Q', '@', '8', 'y', '%', '^', '5', 'Z', '(', 'G', '_', 'O', '`',
'S', '-', 'N', '<', 'D', '{', '}', '[', ']', 'h', ';', 'W', '.',
'/', '|', ':', '1', 'E', 'L', '4', '&', '6', '7', '#', '9', 'a',
'A', 'b', 'B', '~', 'C', 'd', '>', 'e', '2', 'f', 'P', 'g', ')',
'?', 'H', 'i', 'X', 'U', 'J', 'k', 'r', 'l', '3', 't', 'M', 'n',
'=', 'o', '+', 'p', 'F', 'q', '!', 'K', 'R', 's', 'c', 'm', 'T',
'v', 'j', 'u', 'V', 'w', ',', 'x', 'I', '$', 'Y', 'z', '*'
);
# Array indice friendly number of chars;
$numChars = count($chars) - 1; $token = '';
# Create random token at the specified length
for ( $i=0; $i<$len; $i++ )
$token .= $chars[ mt_rand(0, $numChars) ];
# Should token be run through md5?
if ( $md5 ) {
# Number of 32 char chunks
$chunks = ceil( strlen($token) / 32 ); $md5token = '';
# Run each chunk through md5
for ( $i=1; $i<=$chunks; $i++ )
$md5token .= md5( substr($token, $i * 32 - 32, 32) );
# Trim the token
$token = substr($md5token, 0, $len);
} return $token;
}
DavidNineRoc
2019-04-19 11:31:08 +08:00
26 小写 + 26 大写 + 10 个数字 = 62. 直接排列字符串, 然后要生成几位直接生成一个下标数组
$randoms = 'xxxxxxxx'
$wants = [1, 14, 15, 11, 11, 10];
$randoms{1} . $randoms{14} . $randoms{15} . xxxxx

62 的 6 次方大约是 568 亿
62 的 7 次方大约是 3 5216 亿
所以, 10 次方肯定不用想.
mamahaha
2019-04-19 11:33:07 +08:00
```php
function genToken( $len = 32, $md5 = true ) {
# Seed random number generator
# Only needed for PHP versions prior to 4.2
mt_srand( (double)microtime()*1000000 );
# Array of characters, adjust as desired
$chars = array(
'Q', '@', '8', 'y', '%', '^', '5', 'Z', '(', 'G', '_', 'O', '`',
'S', '-', 'N', '<', 'D', '{', '}', '[', ']', 'h', ';', 'W', '.',
'/', '|', ':', '1', 'E', 'L', '4', '&', '6', '7', '#', '9', 'a',
'A', 'b', 'B', '~', 'C', 'd', '>', 'e', '2', 'f', 'P', 'g', ')',
'?', 'H', 'i', 'X', 'U', 'J', 'k', 'r', 'l', '3', 't', 'M', 'n',
'=', 'o', '+', 'p', 'F', 'q', '!', 'K', 'R', 's', 'c', 'm', 'T',
'v', 'j', 'u', 'V', 'w', ',', 'x', 'I', '$', 'Y', 'z', '*'
);
# Array indice friendly number of chars;
$numChars = count($chars) - 1; $token = '';
# Create random token at the specified length
for ( $i=0; $i<$len; $i++ )
$token .= $chars[ mt_rand(0, $numChars) ];
# Should token be run through md5?
if ( $md5 ) {
# Number of 32 char chunks
$chunks = ceil( strlen($token) / 32 ); $md5token = '';
# Run each chunk through md5
for ( $i=1; $i<=$chunks; $i++ )
$md5token .= md5( substr($token, $i * 32 - 32, 32) );
# Trim the token
$token = substr($md5token, 0, $len);
} return $token;
}
```
最近在学 markdown,帮 10 楼整理下看看是啥效果
lihongjie0209
2019-04-19 14:15:10 +08:00
@caoyouming 还真有人使用自制的随机数生成器?
caoyouming
2019-04-19 15:31:10 +08:00
@lihongjie0209 我在之前写一个系统使用邮箱重置密码的时候用的这个生成 token。觉得还不错。
lihongjie0209
2019-04-19 15:56:15 +08:00
@caoyouming 随机数和加密算法一样,最好不要用自制的,使用全球公开并且认可的算法
windgreen
2019-04-19 17:33:05 +08:00
唯一性,拿雪花来精简一下好了。
1.如果没有分布式,机器 id 可以省掉了
2.时间戳可以精简成从现在的一个时间开始,而不是从 1970 年开始,算下用几年,能省下几个字节
3.自增部分看自己要求的每秒生成的最大数量,如果小的话也能省几个字节
最后可以用 base58 而不用 hex,又可以省下几个字符
muchengxue
2019-04-19 18:52:50 +08:00
4ark
2019-04-20 09:59:20 +08:00
session_create_id
chouqiu
2019-05-05 11:11:44 +08:00
uniqid() . mt_rand(1000000, 9999999)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/556584

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX