推荐用 bin2hex(random_bytes(16)) 生成加密安全、无时间依赖、长度可控的唯一字符串;uniqid() 仅适用于短时低冲突场景,php 8.2+ 已废弃 $more_entropy 参数。

用 uniqid() 生成临时唯一字符串,但别直接当主键用
它靠微秒时间戳 + 可选前缀生成,快、轻量,但同一微秒内并发调用会重复。PHP 8.2+ 默认禁用 uniqid() 的 $more_entropy 参数(已废弃),所以别再传 true 了。
常见错误是写成 uniqid('', true) —— 这在新版 PHP 里会报 Deprecated 警告,且返回值仍是字符串,不是加密安全的。
- 只适合日志追踪 ID、临时缓存键这类“短时、低冲突容忍”场景
- 如果加前缀,比如
uniqid('order_'),前缀不能含空格或特殊符号,否则可能影响后续解析 - 注意时区不影响结果,它用的是系统 gettimeofday(),和
date()无关
要真正唯一且安全?用 random_bytes() + bin2hex()
这是目前最推荐的通用方案:加密安全、无时间依赖、长度可控。比 md5(uniqid().rand()) 更可靠,也比调用外部命令(如 /dev/urandom)更便携。
典型错误是直接 base64_encode(random_bytes(16)) —— 会带 +、/、=,不适合 URL 或文件名。必须做 URL 安全转换或转十六进制。
立即学习“PHP免费学习笔记(深入)”;
-
bin2hex(random_bytes(16))→ 得到 32 位小写十六进制字符串,兼容所有存储和传输场景 - 需要 22 位 Base64URL 字符串?用
rtrim(strtr(base64_encode(random_bytes(16)), '+/', '-_'), '=') - 别用
mt_rand()或rand()替代 —— 它们可预测,不满足唯一性保障
数据库自增 ID 不等于业务唯一 ID,别混用
MySQL 的 AUTO_INCREMENT 或 PostgreSQL 的 SERIAL 是高效可靠的主键,但它暴露顺序、可被枚举、不适合对外展示。用户看到 id=123456 就知道这是第几条数据,有信息泄露风险。
常见做法是“双 ID”:数据库用自增 id 做关联和索引,业务层另存一个 external_id 字段,填入 bin2hex(random_bytes(16)) 这类值。
- 别试图用
UUID_SHORT()(MySQL)替代 —— 它依赖服务器启动时间和服务器 ID,在容器或云环境容易重复 - PostgreSQL 的
gen_random_uuid()需要pgcrypto扩展,且返回的是标准 UUID 格式(带横线),若需紧凑字符串得额外REPLACE(uuid::text, '-', '') - 如果已有表结构,新增唯一字段后务必加
UNIQUE INDEX,否则无法阻止插入重复值
别忽略时钟回拨和容器重启对 time()-系 ID 的影响
任何基于时间戳拼接的方案(比如 time().mt_rand(1000,9999))在 NTP 校正、虚拟机休眠恢复、K8s Pod 重建后都可能生成重复值。这不是概率问题,是确定性风险。
有人用 file_get_contents('/proc/sys/kernel/random/uuid') 想取系统 UUID —— 实际读出来的是内核随机数接口,格式不定,且在 Windows 或某些容器里根本不存在该路径。
- 真要时间相关又去重?用
snowflake类算法,但 PHP 没原生支持,需引入成熟库如symfony/uid -
symfony/uid的Ulid是时间有序、无碰撞、URL 安全的,但要注意它依赖hrtime(),PHP 版本需 ≥ 7.3 - 别自己手写“时间+进程ID+计数器”——进程 ID 可能复用,计数器跨请求不保留,极易翻车
random_bytes()。











