Skip to content

Commit 55d8833

Browse files
committed
feat: support version 8, custom UUIDs
1 parent 0ba1ffb commit 55d8833

22 files changed

+332
-30
lines changed

docs/reference.rst

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Reference
1919
reference/rfc4122-uuidv5
2020
reference/rfc4122-uuidv6
2121
reference/rfc4122-uuidv7
22+
reference/rfc4122-uuidv8
2223
reference/guid-fields
2324
reference/guid-guid
2425
reference/nonstandard-fields

docs/reference/rfc4122-uuidv8.rst

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.. _reference.rfc4122.uuidv8:
2+
3+
===============
4+
Rfc4122\\UuidV8
5+
===============
6+
7+
.. php:namespace:: Ramsey\Uuid\Rfc4122
8+
9+
.. php:class:: UuidV8
10+
11+
Implements :php:interface:`Ramsey\\Uuid\\Rfc4122\\UuidInterface`.
12+
13+
UuidV8 represents a :ref:`version 8, custom UUID <rfc4122.version8>`.

docs/rfc4122.rst

+6-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ RFC 4122 UUIDs
1515
rfc4122/version5
1616
rfc4122/version6
1717
rfc4122/version7
18+
rfc4122/version8
1819

1920
`RFC 4122`_ defines five versions of UUID, while a `new Internet-Draft under
2021
review`_ defines three new versions. Each version has different generation
@@ -57,6 +58,10 @@ Version 7: Unix Epoch Time
5758
sortable UUID without the privacy and entropy concerns associated with
5859
version 1 and version 6 UUIDs. For more details, see :ref:`rfc4122.version7`.
5960

61+
Version 8: Custom
62+
This version of UUID allows applications to generate custom identifiers in
63+
an RFC-compatible format. For more details, see :doc:`rfc4122/version8`.
64+
6065

6166
.. _RFC 4122: https://tools.ietf.org/html/rfc4122
62-
.. _new Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04
67+
.. _new Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00

docs/rfc4122/version6.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,6 @@ need the benefit of a monotonically increasing unique identifier, see
208208
:ref:`rfc4122.version7`.
209209

210210

211-
.. _Internet-Draft under review: https://datatracker.ietf.org/doc/draft-peabody-dispatch-new-uuid-format/
211+
.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6
212212
.. _two problems that have long existed: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
213213
.. _RFC 4122: https://tools.ietf.org/html/rfc4122

docs/rfc4122/version7.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ This will print something like this:
167167
ULID, unless it was converted from a version 7 UUID.
168168

169169
.. _ULIDs: https://github.com/ulid/spec
170-
.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.2
170+
.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7
171171
.. _two problems that have long existed: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
172172
.. _Crockford's Base 32 algorithm: https://www.crockford.com/base32.html
173173
.. _tuupola/base32: https://packagist.org/packages/tuupola/base32

docs/rfc4122/version8.rst

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
.. _rfc4122.version8:
2+
3+
=================
4+
Version 8: Custom
5+
=================
6+
7+
.. note::
8+
9+
Version 8, custom UUIDs are a new format of UUID, proposed in an
10+
`Internet-Draft under review`_ at the IETF. While the draft is still going
11+
through the IETF process, the version 7 format is not expected to change
12+
in any way that breaks compatibility.
13+
14+
Version 8 UUIDs allow applications to create custom UUIDs in an RFC-compatible
15+
way. The only requirement is the version and variant bits must be set according
16+
to the UUID specification. The bytes provided may contain any value according to
17+
your application's needs. Be aware, however, that other applications may not
18+
understand the semantics of the value.
19+
20+
.. warning::
21+
22+
The bytes should be a 16-byte octet string, an open blob of data that you
23+
may fill with 128 bits of information. However, bits 48 through 51 will be
24+
replaced with the UUID version field, and bits 64 and 65 will be replaced
25+
with the UUID variant. You must not rely on these bits for your application
26+
needs.
27+
28+
.. code-block:: php
29+
:caption: Generate a version 8, custom UUID
30+
:name: rfc4122.version8.example
31+
32+
use Ramsey\Uuid\Uuid;
33+
34+
$uuid = Uuid::uuid8("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff");
35+
36+
printf(
37+
"UUID: %s\nVersion: %d\n",
38+
$uuid->toString(),
39+
$uuid->getFields()->getVersion()
40+
);
41+
42+
This will generate a version 8 UUID and print out its string representation.
43+
It will look something like this:
44+
45+
.. code-block:: text
46+
47+
UUID: 00112233-4455-8677-8899-aabbccddeeff
48+
Version: 8
49+
50+
51+
.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8

psalm-baseline.xml

+3-16
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,6 @@
4747
<code>$timeGenerator</code>
4848
</PropertyNotSetInConstructor>
4949
</file>
50-
<file src="src/Fields/SerializableFieldsTrait.php">
51-
<UnusedMethodCall occurrences="1">
52-
<code>unserialize</code>
53-
</UnusedMethodCall>
54-
</file>
5550
<file src="src/Generator/PeclUuidNameGenerator.php">
5651
<ImpureFunctionCall occurrences="3">
5752
<code>uuid_generate_md5</code>
@@ -66,11 +61,6 @@
6661
<code>$this</code>
6762
</ImpureVariable>
6863
</file>
69-
<file src="src/Lazy/LazyUuidFromString.php">
70-
<UnusedMethodCall occurrences="1">
71-
<code>unserialize</code>
72-
</UnusedMethodCall>
73-
</file>
7464
<file src="src/Nonstandard/UuidBuilder.php">
7565
<ImpureVariable occurrences="3">
7666
<code>$this</code>
@@ -96,7 +86,9 @@
9686
</MixedArrayAssignment>
9787
</file>
9888
<file src="src/Rfc4122/UuidBuilder.php">
99-
<ImpureVariable occurrences="19">
89+
<ImpureVariable occurrences="21">
90+
<code>$this</code>
91+
<code>$this</code>
10092
<code>$this</code>
10193
<code>$this</code>
10294
<code>$this</code>
@@ -123,11 +115,6 @@
123115
<code>NonstandardUuidV6</code>
124116
</DeprecatedClass>
125117
</file>
126-
<file src="src/Type/Decimal.php">
127-
<UnusedMethodCall occurrences="1">
128-
<code>unserialize</code>
129-
</UnusedMethodCall>
130-
</file>
131118
<file src="src/Type/Hexadecimal.php">
132119
<UnusedMethodCall occurrences="1">
133120
<code>unserialize</code>

src/Rfc4122/MaxTrait.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* The max UUID is special form of UUID that is specified to have all 128 bits
2121
* set to one. It is the inverse of the nil UUID.
2222
*
23-
* @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4 Max UUID
23+
* @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.10 Max UUID
2424
*
2525
* @psalm-immutable
2626
*/

src/Rfc4122/UuidBuilder.php

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ public function build(CodecInterface $codec, string $bytes): UuidInterface
9595
return new UuidV6($fields, $this->numberConverter, $codec, $this->timeConverter);
9696
case Uuid::UUID_TYPE_UNIX_TIME:
9797
return new UuidV7($fields, $this->numberConverter, $codec, $this->unixTimeConverter);
98+
case Uuid::UUID_TYPE_CUSTOM:
99+
return new UuidV8($fields, $this->numberConverter, $codec, $this->timeConverter);
98100
}
99101

100102
throw new UnsupportedOperationException(

src/Rfc4122/UuidV6.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* Reordered time, or version 6, UUIDs include timestamp, clock sequence, and
2121
* node values that are combined into a 128-bit unsigned integer
2222
*
23-
* @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1 UUID Version 6
23+
* @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6 UUID Version 6
2424
*
2525
* @psalm-immutable
2626
*/

src/Rfc4122/UuidV7.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
use Ramsey\Uuid\Uuid;
2323

2424
/**
25-
* Gregorian time, or version 1, UUIDs include timestamp, clock sequence, and node
26-
* values that are combined into a 128-bit unsigned integer
25+
* Unix Epoch time, or version 7, UUIDs include a timestamp in milliseconds
26+
* since the Unix Epoch, along with random bytes
27+
*
28+
* @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7 UUID Version 7
2729
*
2830
* @psalm-immutable
2931
*/

src/Rfc4122/UuidV8.php

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the ramsey/uuid library
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*
9+
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
10+
* @license http://opensource.org/licenses/MIT MIT
11+
*/
12+
13+
declare(strict_types=1);
14+
15+
namespace Ramsey\Uuid\Rfc4122;
16+
17+
use Ramsey\Uuid\Codec\CodecInterface;
18+
use Ramsey\Uuid\Converter\NumberConverterInterface;
19+
use Ramsey\Uuid\Converter\TimeConverterInterface;
20+
use Ramsey\Uuid\Exception\InvalidArgumentException;
21+
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
22+
use Ramsey\Uuid\Uuid;
23+
24+
/**
25+
* Version 8, Custom UUIDs provide an RFC 4122 compatible format for
26+
* experimental or vendor-specific uses
27+
*
28+
* The only requirement for version 8 UUIDs is that the version and variant bits
29+
* must be set. Otherwise, implementations are free to set the other bits
30+
* according to their needs. As a result, the uniqueness of version 8 UUIDs is
31+
* implementation-specific and should not be assumed.
32+
*
33+
* @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8 UUID Version 8
34+
*
35+
* @psalm-immutable
36+
*/
37+
final class UuidV8 extends Uuid implements UuidInterface
38+
{
39+
/**
40+
* Creates a version 8 (custom) UUID
41+
*
42+
* @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
43+
* @param NumberConverterInterface $numberConverter The number converter to use
44+
* for converting hex values to/from integers
45+
* @param CodecInterface $codec The codec to use when encoding or decoding
46+
* UUID strings
47+
* @param TimeConverterInterface $timeConverter The time converter to use
48+
* for converting timestamps extracted from a UUID to unix timestamps
49+
*/
50+
public function __construct(
51+
Rfc4122FieldsInterface $fields,
52+
NumberConverterInterface $numberConverter,
53+
CodecInterface $codec,
54+
TimeConverterInterface $timeConverter
55+
) {
56+
if ($fields->getVersion() !== Uuid::UUID_TYPE_CUSTOM) {
57+
throw new InvalidArgumentException(
58+
'Fields used to create a UuidV8 must represent a '
59+
. 'version 8 (custom) UUID'
60+
);
61+
}
62+
63+
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
64+
}
65+
}

src/Rfc4122/Validator.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
final class Validator implements ValidatorInterface
2929
{
3030
private const VALID_PATTERN = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-'
31-
. '[1-7][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z';
31+
. '[1-8][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z';
3232

3333
/**
3434
* @psalm-return non-empty-string

src/Rfc4122/VersionTrait.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ private function isCorrectVersion(): bool
5353
Uuid::UUID_TYPE_TIME, Uuid::UUID_TYPE_DCE_SECURITY,
5454
Uuid::UUID_TYPE_HASH_MD5, Uuid::UUID_TYPE_RANDOM,
5555
Uuid::UUID_TYPE_HASH_SHA1, Uuid::UUID_TYPE_REORDERED_TIME,
56-
Uuid::UUID_TYPE_UNIX_TIME => true,
56+
Uuid::UUID_TYPE_UNIX_TIME, Uuid::UUID_TYPE_CUSTOM => true,
5757
default => false,
5858
};
5959
}

src/Uuid.php

+38-3
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class Uuid implements UuidInterface
8888
* The max UUID is a special form of UUID that is specified to have all 128
8989
* bits set to one
9090
*
91-
* @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4 Max UUID
91+
* @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.10 Max UUID
9292
*/
9393
public const MAX = 'ffffffff-ffff-ffff-ffff-ffffffffffff';
9494

@@ -173,17 +173,22 @@ class Uuid implements UuidInterface
173173
/**
174174
* Version 6 (reordered time) UUID
175175
*
176-
* @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1 UUID Version 6
176+
* @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6 UUID Version 6
177177
*/
178178
public const UUID_TYPE_REORDERED_TIME = 6;
179179

180180
/**
181181
* Version 7 (Unix Epoch time) UUID
182182
*
183-
* @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.2 UUID Version 7
183+
* @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7 UUID Version 7
184184
*/
185185
public const UUID_TYPE_UNIX_TIME = 7;
186186

187+
/**
188+
* @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8 UUID Version 8
189+
*/
190+
public const UUID_TYPE_CUSTOM = 8;
191+
187192
/**
188193
* DCE Security principal domain
189194
*
@@ -690,4 +695,34 @@ public static function uuid7(?DateTimeInterface $dateTime = null): UuidInterface
690695
'The provided factory does not support the uuid7() method',
691696
);
692697
}
698+
699+
/**
700+
* Returns a version 8 (custom) UUID
701+
*
702+
* The bytes provided may contain any value according to your application's
703+
* needs. Be aware, however, that other applications may not understand the
704+
* semantics of the value.
705+
*
706+
* @param string $bytes A 16-byte octet string. This is an open blob
707+
* of data that you may fill with 128 bits of information. Be aware,
708+
* however, bits 48 through 51 will be replaced with the UUID version
709+
* field, and bits 64 and 65 will be replaced with the UUID variant. You
710+
* MUST NOT rely on these bits for your application needs.
711+
*
712+
* @return UuidInterface A UuidInterface instance that represents a
713+
* version 8 UUID
714+
*/
715+
public static function uuid8(string $bytes): UuidInterface
716+
{
717+
$factory = self::getFactory();
718+
719+
if (method_exists($factory, 'uuid8')) {
720+
/** @var UuidInterface */
721+
return $factory->uuid8($bytes);
722+
}
723+
724+
throw new UnsupportedOperationException(
725+
'The provided factory does not support the uuid8() method',
726+
);
727+
}
693728
}

src/UuidFactory.php

+21
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,27 @@ public function uuid7(?DateTimeInterface $dateTime = null): UuidInterface
400400
return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_UNIX_TIME);
401401
}
402402

403+
/**
404+
* Returns a version 8 (Custom) UUID
405+
*
406+
* The bytes provided may contain any value according to your application's
407+
* needs. Be aware, however, that other applications may not understand the
408+
* semantics of the value.
409+
*
410+
* @param string $bytes A 16-byte octet string. This is an open blob
411+
* of data that you may fill with 128 bits of information. Be aware,
412+
* however, bits 48 through 51 will be replaced with the UUID version
413+
* field, and bits 64 and 65 will be replaced with the UUID variant. You
414+
* MUST NOT rely on these bits for your application needs.
415+
*
416+
* @return UuidInterface A UuidInterface instance that represents a
417+
* version 8 UUID
418+
*/
419+
public function uuid8(string $bytes): UuidInterface
420+
{
421+
return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_CUSTOM);
422+
}
423+
403424
/**
404425
* Returns a Uuid created from the provided byte string
405426
*

0 commit comments

Comments
 (0)