gpslab/base64uid

生成类似YouTube的UID

v1.2.0 2020-01-14 15:13 UTC

This package is auto-updated.

Last update: 2024-09-15 02:43:04 UTC


README

Latest Stable Version Total Downloads Build Status Coverage Status Scrutinizer Code Quality SensioLabs Insight StyleCI License

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 中的完整许可证。