gpslab / base64uid
生成类似YouTube的UID
Requires
- php: >=5.3.0
- paragonie/random_compat: >=2
Requires (Dev)
- php-coveralls/php-coveralls: ^1.0
- phpunit/phpunit: ^4.8.36
- scrutinizer/ocular: ^1.0
README
Base64 UID
生成类似YouTube的UID。
简介
此库生成由64个字符组成、长度为10个字符的唯一标识符(您可以更改标识符的长度)。这为我们提供了6410 = 260 = 1 152 921 504 606 846 976种组合。
要表示这个数字,想象一下,为了获得长度为10个字符的所有可能标识符值,并且每微秒生成一个ID,需要36 559年。
UUID 采用相同的原理,但其主要缺点是太长。它不方便作为公共标识符使用,例如在URL中。为了获得与UUID相同数量的组合,我们需要2128 = 6421行长度为21个字符的行,即比UUID短近2倍(37个字符)。如果我们取与UUID相同长度的标识符,则我们得到6437 = 2222,而UUID为2128。
这种方法最重要的优点是,您可以自己通过更改字符串长度和字符集来控制组合数量。这将优化标识符的长度以满足您的业务需求。
碰撞
可以通过以下公式计算标识符的碰撞概率
p(n) ≈ 1 - exp(N * (ln(N - 1) - ln(N - n)) + n * (ln(N - n) - ln(N) - 1) - (ln(N - 1) - ln(N) - 1))
其中
- N - 可能选项的数量;
- n - 生成的密钥数量。
考虑一个长度为11个字符的标识符,如YouTube,它将给我们 N = 6411 = 266,我们得到
- p(225) ≈ 7.62 * 10-6
- p(230) ≈ 0.0077
- p(236) ≈ 0.9999
这意味着生成236 = 68 719 476 736个标识符时,您几乎可以保证发生碰撞。
对于大数的计算,我推荐使用这个在线计算器。
安装
使用 Composer 非常简单,运行
composer require gpslab/base64uid
使用方法
use GpsLab\Component\Base64UID\Base64UID; $uid = Base64UID::generate(); // iKtwBpOH2E
长度为6个字符(646 = 68 719 476 736种组合)。
$uid = Base64UID::generate(6); // nWzfgA
可变长度的标识符将提供更多的唯一标识符(648 + 649 + 6410 = 1 171 217 378 093 039 616种组合)。
$uid = Base64UID::generate(random_int(8, 10));
您可以自定义字符集。
$charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'; $uid = Base64UID::generate(11, $charset); $charset = '0123456789abcdef'; $uid = Base64UID::generate(11, $charset);
其他生成UID的算法
随机字符
从字符集中生成有限UID的随机字符。
$generator = new RandomCharGenerator(); $uid = $generator->generate(); // iKtwBpOH2E
限制UID的长度和字符集。
$charset = '0123456789abcdef'; $generator = new RandomCharGenerator(6, $charset); $uid = $generator->generate(); // fa6c7d
随机字节
生成随机字节并将其编码为Base64。
$generator = new RandomBytesGenerator(); $uid = $generator->generate(); // YCfGKBxd9k4
$generator = new RandomBytesGenerator(5); $uid = $generator->generate(); // Mm7dpkM
编码随机位
生成随机位图并将其编码为Base64。位图长度为64位,需要64位处理器架构模式。
$binary_generator = new RandomBinaryGenerator(32); $encoder = new HexToBase64BitmapEncoder(); $generator = new EncodeBitmapGenerator($binary_generator, $encoder); $uid = $generator->generate(); // 7MWx2BuWJUw
时间位图的编码
生成包含当前微秒时间的位图并将其编码为Base64。位图长度为64位,需要64位处理器架构模式。
$binary_generator = new TimeBinaryGenerator(); $encoder = new HexToBase64BitmapEncoder(); $generator = new EncodeBitmapGenerator($binary_generator, $encoder); $uid = $generator->generate(); // koLfRhzAoI0 $uid = $generator->generate(); // zALfRhzAovg $uid = $generator->generate(); // 18LfRhzAoQw
生成的位图具有以下结构
{first bit}{random prefix}{current time}{random suffix}
- 第一位 - 位图限制器,用于固定位图大小;
- 前缀 - 用于位图前缀的随机位。生成的位的长度可以从
$prefix_length
配置; - 时间 - 当前时间的微秒位。
- 后缀 - 用于位图后缀的随机位。长度由
64 - 1 - $prefix_length - $time_length
计算得出。
负责选择用于存储当前时间的位数。 $time_length
定义了存储日期的限制
为了减小保存时间的尺寸,可以使用一个 $time_offset
,这允许你移动时间的起始点
浮点时间的编码位图
与之前的生成器 TimeBinaryGenerator
类似,但当前时间的位位置是浮动的。也就是说,前缀和后缀的长度每次都是随机生成的。同时生成的标识符相似度较低,但碰撞的可能性增加。
$binary_generator = new FloatingTimeGenerator(); $encoder = new HexToBase64BitmapEncoder(); $generator = new EncodeBitmapGenerator($binary_generator, $encoder); $uid = $generator->generate(); // 5mqhb6MPH7g $uid = $generator->generate(); // kFvow8joJys $uid = $generator->generate(); // 8QRC30YeP3E
雪花ID
雪花ID使用微秒时间戳和生成器ID。这允许您根据您的环境自定义生成器并减少碰撞的可能性,但标识符彼此非常相似,且标识符揭示了您内部基础设施的方案。Twitter、Instagram等使用的雪花ID。
$generator_id = 0; // value 0-1023 $binary_generator = new SnowflakeGenerator($generator_id); $encoder = new HexToBase64BitmapEncoder(); $generator = new EncodeBitmapGenerator($binary_generator, $encoder); $uid = $generator->generate(); // gBFKQeuAAAA $uid = $generator->generate(); // gBFKQeuAAAE $uid = $generator->generate(); // gBFKQevAAAA
领域驱动设计(DDD)
如何在您的 领域 中使用。
例如创建一个 ArticleId
值对象
class ArticleId { private $id; public function __construct(string $id) { $this->id = $id; } public function id() { return $this->id; } }
文章的存储库接口
interface ArticleRepository { public function nextId(); // more methods ... }
文章的具体存储库
use GpsLab\Component\Base64UID\Base64UID; class ConcreteArticleRepository implements ArticleRepository { public function nextId() { return new ArticleId(Base64UID::generate()); } // more methods ... }
现在我们可以使用 ArticleId
创建一个新实体
$article = new Article( $repository->nextId(), // more article parameters ... );
许可证
此软件包受 MIT许可证 的约束。请参阅文件 LICENSE 中的完整许可证。