krmgns / uuid
带日期/时间前缀的随机或可排序的UUID。
Requires
- php: >=8.2
- ext-ctype: *
Requires (Dev)
- phpunit/phpunit: >=9.0
README
在保留生成值版本和变体字段的同时,Uuid库以简单快捷的方法提供三种类型的UUID,可用于需要可排序UUID的地方。
generate()
方法:
Uuid\Uuid
类使用16位长度的随机字节(UUID/v4)。Uuid\DateUuid
类使用12位长度的随机字节和4位长度的UTC日期字节作为前缀,生成的值可排序到第8个十六进制字符。Uuid\DateTimeUuid
类使用10位长度的随机字节和6位长度的UTC日期/时间字节作为前缀,生成的值可排序到第12个十六进制字符。
除了这些UUID可排序外,它们还可以用于某些工作,如文件夹探索(例如,在与图像裁剪服务一起工作时)。
因此,让我们通过一个快速示例来了解一下它的实际应用:
// File: ImageController.php use Uuid\{DateUuid, UuidError}; use Throwable; /** * Eg: cdn.foo.com/image/crop/0134b3ce-ce20-4917-a020-f0514e110834.jpg * @route /image/crop/:image */ public function cropAction(string $image) { // Eg: 0134b3ce-ce20-4917-a020-f0514e110834.jpg [$name, $extension] = explode('.', $image); try { // Since we've created an image file name with DateUuid, // here we're expecting the incoming $image to be valid. $uuid = new DateUuid($name); // Eg: 2023/11/12 $path = $uuid->getDate('/'); } catch (UuidError) { // Invalid DateUuid. throw new BadRequestError(); } catch (Throwable) { // Internal error. throw new InternalServerError(); } // Eg: /images/2023/11/12/0134b3ce-ce20-4917-a020-f0514e110834.jpg $image = sprintf('/images/%s/%s.%s', $path, $name, $extension); // No such file. if (!file_exists($image)) { throw new NotFoundError(); } // Else crop image & serve cropped image here... }
安装
composer require krmgns/uuid
注意/提醒
· 除了所有类都可以接受 $value
参数(#1)作为 string
类型外,Uuid\Uuid
类还可以接受 Uuid\Uuid
类型,Uuid\DateUuid
类也可以接受 Uuid\DateUuid
类型,Uuid\DateTimeUuid
类也可以接受 Uuid\DateTimeUuid
类型,但也可以省略以自动生成。
· 除了 Uuid\Uuid
实现了 Stringable
接口外,Uuid\DateUuid
和 Uuid\DateTimeUuid
是 Uuid\Uuid
类的子类。因此,它们继承了一些有用的方法(如 toString()
、toHashString()
等),同时也覆盖了一些方法(如 isValid()
、generate()
、validate()
等)以及构造方法。
· 由于 Uuid\DateTimeUuid
使用秒级别的即时日期/时间戳(格式:YmdHis
),最好的可排序UUID只能通过这个类生成。
Uuid\Uuid
类
与继承类一样,如果没有提供 $value
(UUID值),则 Uuid\Uuid
类将自行生成并分配其值。否则,给定值将在严格模式下检查(修饰符参数是 $strict
,值为 true
)是否为有效的UUID值后分配。
use Uuid\{Uuid, UuidError}; // Auto-generate. $uuid = new Uuid(); assert($uuid->value === $uuid->toString()); assert($uuid->value === (string) $uuid); assert($uuid->value == $uuid); // Stringable assert(true === $uuid->isEqual($uuid)); assert(true === $uuid->isEqual($uuid->value)); $uuid = new Uuid('26708ec6-ad78-4291-a449-9ee08cf50cfc'); assert(true === $uuid->isValid()); $uuid = new Uuid('invalid', strict: false); assert(false === $uuid->isValid()); try { new Uuid(null); } catch (UuidError $e) { assert("Invalid UUID value: null" === $e->getMessage()); } try { new Uuid('invalid'); } catch (UuidError $e) { assert("Invalid UUID value: 'invalid'" === $e->getMessage()); } // Given value. $uuid = new Uuid($value = '26708ec6-ad78-4291-a449-9ee08cf50cfc'); assert(true === $uuid->isEqual($uuid)); assert(true === $uuid->isEqual($uuid->value)); assert(true === $uuid->isEqual($value)); assert('26708ec6-ad78-4291-a449-9ee08cf50cfc' === $uuid->toString()); assert('26708ec6ad784291a4499ee08cf50cfc' === $uuid->toHashString()); // Null values. $uuid1 = new Uuid('00000000-0000-0000-0000-000000000000', strict: false); $uuid2 = new Uuid('00000000000000000000000000000000', strict: false); assert(false === $uuid1->isValid()); assert(false === $uuid2->isValid()); assert(true === $uuid1->isNull()); assert(true === $uuid2->isNullHash()); assert(Uuid::NULL === $uuid1->value); assert(Uuid::NULL_HASH === $uuid2->value);
静态
// Generating. $uuid = Uuid::generate(); // Eg: fec3cfe2-d378-4181-8ba1-99c54bcfa63e // Validating. $valid = Uuid::validate($uuid); assert(true === $valid); assert(false === Uuid::validate('invalid')); assert(false === Uuid::validate('invalid', strict: false)); assert(false === Uuid::validate(Uuid::NULL)); assert(false === Uuid::validate(Uuid::NULL_HASH)); assert(true === Uuid::validate(Uuid::NULL, strict: false)); assert(true === Uuid::validate(Uuid::NULL_HASH, strict: false)); // Equal checking. assert(true === Uuid::equals($uuid, 'fec3cfe2-d378-4181-8ba1-99c54bcfa63e')); assert(false === Uuid::equals($uuid, 'invalid-uuid-input-value')); // DIY tools. $bins = random_bytes(16); // Add version/variant. $bins = Uuid::modify($bins); // Format as UUID format. $uuid = Uuid::format(bin2hex($bins));
有关更多示例,请参阅 test/unit/UuidTest.php。
Uuid\DateUuid
类
这个类使用12位长度的随机字节和4位长度的UTC日期字节作为前缀。因此,其日期可以重新提取(例如:20231212 或 2023-12-12,使用 $separator
选项),可用于任何用例,且适用于需要可排序UUID的地方。
use Uuid\DateUuid; $date = explode('.', gmdate('Y.m.d')); $time = explode('.', gmdate('00:00:00')); // Getting date. $uuid = new DateUuid(); assert($date === $uuid->getDate()); assert(implode('/', $date) === $uuid->getDate(separator: '/')); $uuid = new DateUuid('d41d8cd98f00b204e9800998ecf8427e', strict: false); assert(null === $uuid->getDate()); // Getting date/time. $uuid = new DateUuid(); assert(implode('-', $date) === $uuid->getDateTime()->format('Y-m-d')); assert(implode(':', $time) === $uuid->getDateTime()->format('H:i:s')); $uuid = new DateUuid('d41d8cd98f00b204e9800998ecf8427e', strict: false); assert(null === $uuid->getDateTime());
静态
// Generating. $uuid = DateUuid::generate(); // Eg: 0134b3ce-25fc-49f8-b9f9-61ed2784c7d1 // Parsing. $uuid1 = new DateUuid(); $uuid2 = new DateUuid('d41d8cd98f00b204e9800998ecf8427e', strict: false); assert(null !== DateUuid::parse($uuid1->value)); assert(null === DateUuid::parse($uuid2->value)); // Next year for falsity (eg: 20241212). $threshold = (gmdate('Y') + 1) . '1212'; assert(null === DateUuid::parse($uuid1->value, $threshold));
有关更多示例,请参阅 test/unit/DateUuidTest.php。
Uuid\DateTimeUuid
类
这个类使用10位长度的随机字节和6位长度的UTC日期/时间字节作为前缀。因此,其日期可以重新提取(例如:20231212、101122 或 2023-12-12、10-11-22,使用 $separator
选项),可用于任何用例,且适用于需要可排序UUID的地方。
use Uuid\DateTimeUuid; $date = explode('.', gmdate('Y.m.d')); $time = explode('.', gmdate('H.i.s')); // Getting date. $uuid = new DateTimeUuid(); assert($date === $uuid->getDate()); assert(implode('/', $date) === $uuid->getDate(separator: '/')); $uuid = new DateTimeUuid('d41d8cd98f00b204e9800998ecf8427e', strict: false); assert(null === $uuid->getDate()); // Getting time. $uuid = new DateTimeUuid(); assert($time === $uuid->getTime()); assert(implode(':', $time) === $uuid->getTime(separator: ':')); $uuid = new DateTimeUuid('d41d8cd98f00b204e9800998ecf8427e', strict: false); assert(null === $uuid->getTime()); // Getting date/time. $uuid = new DateTimeUuid(); assert(implode('-', $date) === $uuid->getDateTime()->format('Y-m-d')); assert(implode(':', $time) === $uuid->getDateTime()->format('H:i:s')); $uuid = new DateTimeUuid('d41d8cd98f00b204e9800998ecf8427e', strict: false); assert(null === $uuid->getDateTime());
静态
// Generating. $uuid = DateTimeUuid::generate(); // Eg: 12666c9c-b0c6-4532-b8da-dbc660ff4170 // Parsing. $uuid1 = new DateTimeUuid(); $uuid2 = new DateTimeUuid('d41d8cd98f00b204e9800998ecf8427e', strict: false); assert(null !== DateTimeUuid::parse($uuid1->value)); assert(null === DateTimeUuid::parse($uuid2->value)); // Next year for falsity (eg: 20241212191919). $threshold = (gmdate('Y') + 1) . '1212191919'; assert(null === DateTimeUuid::parse($uuid1->value, $threshold));
有关更多示例,请参阅 test/unit/DateTimeUuidTest.php。