oittaa/uuid

一个用于从版本 3 到版本 8 生成 RFC 9562 通用唯一识别码 (UUID) 的 PHP 类。

1.10 2024-07-10 20:19 UTC

This package is auto-updated.

Last update: 2024-09-17 23:31:53 UTC


README

CI codecov

uuid-php

一个用于生成从版本 3 到版本 8 的 RFC 9562 通用唯一识别码 (UUID) 的 PHP 类。

如果您只需要一个唯一的标识符,您应该调用 uuid4()

实现应尽可能使用 UUIDv7 而不是 UUIDv1 和 UUIDv6。

如果您经常每秒生成超过一千个 UUID,您可能想使用 uuid8() 而不是 uuid7()。与 uuid7() 相比,此 uuid8() 实现牺牲了一些熵,但提供了 100 纳秒的粒度,在其他方面兼容。

最小 UUID v4 实现

此最小 RFC 9562 兼容解决方案的功劳归于 Stackoverflow 上的此答案:https://stackoverflow.com/a/15875555

<?php
function uuid4()
{
    $data = random_bytes(16);
    $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
    $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}

echo uuid4();

最小 UUID v7 实现

<?php
function uuid7()
{
    static $last_timestamp = 0;
    $unixts_ms = intval(microtime(true) * 1000);
    if ($last_timestamp >= $unixts_ms) {
        $unixts_ms = $last_timestamp + 1;
    }
    $last_timestamp = $unixts_ms;
    $data = random_bytes(10);
    $data[0] = chr((ord($data[0]) & 0x0f) | 0x70); // set version
    $data[2] = chr((ord($data[2]) & 0x3f) | 0x80); // set variant
    return vsprintf(
        '%s%s-%s-%s-%s-%s%s%s',
        str_split(
            str_pad(dechex($unixts_ms), 12, '0', \STR_PAD_LEFT) .
                bin2hex($data),
            4
        )
    );
}

echo uuid7();

安装

如果您需要比较工具或可排序的标识符,如版本 6、7 和 8 中的,您可能会发现这个小型且快速的包很有用。它不需要任何其他依赖。

composer require oittaa/uuid

使用

如何生成

<?php

require 'vendor/autoload.php';

use UUID\UUID;

// Generate a version 3 (name-based and hashed with MD5) UUID
// Namespaces: NAMESPACE_DNS, NAMESPACE_URL, NAMESPACE_OID, NAMESPACE_X500
$uuid3 = UUID::uuid3(UUID::NAMESPACE_DNS, 'php.net');
echo $uuid3 . "\n"; // 11a38b9a-b3da-360f-9353-a5a725514269

// Generate a version 4 (random) UUID
$uuid4 = UUID::uuid4();
echo $uuid4 . "\n"; // e.g. 2140a926-4a47-465c-b622-4571ad9bb378

// Generate a version 5 (name-based and hashed with SHA1) UUID
$uuid5 = UUID::uuid5(UUID::NAMESPACE_DNS, 'php.net');
echo $uuid5 . "\n"; // c4a760a8-dbcf-5254-a0d9-6a4474bd1b62

// Generate a version 6 (lexicographically sortable) UUID
$uuid6_first = UUID::uuid6();
echo $uuid6_first . "\n"; // e.g. 1ec9414c-232a-6b00-b3c8-9e6bdeced846
$uuid6_second = UUID::uuid6();
var_dump($uuid6_first < $uuid6_second); // bool(true)

// Generate a version 7 (lexicographically sortable) UUID
$uuid7_first = UUID::uuid7();
echo $uuid7_first . "\n"; // e.g. 017f22e2-79b0-7cc3-98c4-dc0c0c07398f
$uuid7_second = UUID::uuid7();
var_dump($uuid7_first < $uuid7_second); // bool(true)

// Generate a version 8 (lexicographically sortable) UUID
$uuid8_first = UUID::uuid8();
echo $uuid8_first . "\n"; // e.g. 017f22e2-79b0-8cc3-98c4-dc0c0c07398f
$uuid8_second = UUID::uuid8();
var_dump($uuid8_first < $uuid8_second); // bool(true)

工具

<?php

require 'vendor/autoload.php';

use UUID\UUID;

// Test if a given string is a valid UUID
$isvalid = UUID::isValid('11a38b9a-b3da-360f-9353-a5a725514269');
var_dump($isvalid); // bool(true)

// The string standard representation of the UUID.
$tostring = UUID::toString('{C4A760A8-DBCF-5254-A0D9-6A4474BD1B62}');
var_dump($tostring); // string(36) "c4a760a8-dbcf-5254-a0d9-6a4474bd1b62"

// Test if two UUIDs are equal
$equals1 = UUID::equals(
    'c4a760a8-dbcf-5254-a0d9-6a4474bd1b62',
    '2140a926-4a47-465c-b622-4571ad9bb378'
);
var_dump($equals1); // bool(false)

$equals2 = UUID::equals(
    'c4a760a8-dbcf-5254-a0d9-6a4474bd1b62',
    'C4A760A8-DBCF-5254-A0D9-6A4474BD1B62'
);
var_dump($equals2); // bool(true)

$equals3 = UUID::equals(
    'urn:uuid:c4a760a8-dbcf-5254-a0d9-6a4474bd1b62',
    '{C4A760A8-DBCF-5254-A0D9-6A4474BD1B62}'
);
var_dump($equals3); // bool(true)

// UUID comparison. Returns < 0 if uuid1 is less than uuid2;
// > 0 if uuid1 is greater than uuid2, and 0 if they are equal.
$cmp1 = UUID::cmp(
    '11a38b9a-b3da-360f-9353-a5a725514269',
    '2140a926-4a47-465c-b622-4571ad9bb378'
);
var_dump($cmp1 < 0); // bool(true)

$cmp2 = UUID::cmp(
    'c4a760a8-dbcf-5254-a0d9-6a4474bd1b62',
    '2140a926-4a47-465c-b622-4571ad9bb378'
);
var_dump($cmp2 > 0); // bool(true)

$cmp3 = UUID::cmp(
    'urn:uuid:c4a760a8-dbcf-5254-a0d9-6a4474bd1b62',
    '{C4A760A8-DBCF-5254-A0D9-6A4474BD1B62}'
);
var_dump($cmp3 === 0); // bool(true)

// Extract Unix time from versions 6, 7, and 8 as a string.
$uuid6_time = UUID::getTime('1ec9414c-232a-6b00-b3c8-9e6bdeced846');
var_dump($uuid6_time); // string(18) "1645557742.0000000"
$uuid7_time = UUID::getTime('017f22e2-79b0-7cc3-98c4-dc0c0c07398f');
var_dump($uuid7_time); // string(18) "1645557742.0000000"
$uuid8_time = UUID::getTime('017f22e2-79b0-8cc3-98c4-dc0c0c07398f');
var_dump($uuid8_time); // string(18) "1645557742.0007977"

// Extract the UUID version.
$uuid_version = UUID::getVersion('2140a926-4a47-465c-b622-4571ad9bb378');
var_dump($uuid_version); // int(4)

UUIDv6 字段和位布局

        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                           time_high                           |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |           time_mid            |      time_low_and_version     |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |clk_seq_hi_res |  clk_seq_low  |         node (0-1)            |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                         node (2-5)                            |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

UUIDv7 字段和位布局


        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                           unix_ts_ms                          |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |          unix_ts_ms           |  ver  |       rand_a          |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |var|                        rand_b                             |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                            rand_b                             |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

UUIDv8 字段和位布局

        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                           unix_ts_ms                          |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |          unix_ts_ms           |  ver  |       subsec          |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |var|sub|                     rand                              |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                             rand                              |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • unix_ts_ms:48 位大端无符号数字,表示具有毫秒级精度的 Unix 纪元时间戳
  • ver:4 位 UUIDv8 版本(1000)
  • subsec:12 位分配给次秒精度值
  • var:2 位 UUID 变体(10)
  • sub:2 位分配给次秒精度值
  • rand:剩余的 60 位用伪随机数据填充

14 位专门用于次秒精度,提供 100 纳秒分辨率。《unix_ts_ms》和《subsec》字段通过单调递增计时器保证同一时间戳生成的 UUID 的顺序。