diff --git a/docs/index.rst b/docs/index.rst index 632a9cd..65a48e8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,11 +7,13 @@ For `ramsey/uuid `_ |version|. Updated on |today This work is licensed under the `Creative Commons Attribution 4.0 International `_ license. + +Contents +-------- + .. toctree:: :maxdepth: 2 - :numbered: 1 :includehidden: - :caption: Contents introduction quickstart @@ -21,3 +23,10 @@ This work is licensed under the `Creative Commons Attribution 4.0 International FAQs reference copyright + + +Indices and Tables +------------------ + +* :ref:`genindex` +* :ref:`search` diff --git a/docs/introduction.rst b/docs/introduction.rst index 174fde5..90a1c78 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -2,9 +2,9 @@ Introduction ============ -ramsey/uuid is a PHP library for generating and working with [RFC4122]_ version +ramsey/uuid is a PHP library for generating and working with `RFC 4122`_ version 1, 2, 3, 4, and 5 universally unique identifiers (UUID). ramsey/uuid also -supports optional and non-standard features, such as version 6 UUIDs [UUIDV6]_, +supports optional and non-standard features, such as `version 6 UUIDs`_, GUIDs, and other approaches for encoding/decoding UUIDs. What Is a UUID? @@ -12,7 +12,7 @@ What Is a UUID? A universally unique identifier, or UUID, is a 128-bit unsigned integer, usually represented as a hexadecimal string split into five groups with dashes. The most -widely-known and used types of UUIDs are defined by [RFC4122]_. +widely-known and used types of UUIDs are defined by `RFC 4122`_. A UUID, when encoded in hexadecimal string format, looks like: @@ -24,3 +24,7 @@ The probability of duplicating a UUID is close to zero, so they are a great choice for generating unique identifiers in distributed systems. UUIDs can also be stored in binary format, as a string of 16 bytes. + + +.. _RFC 4122: https://tools.ietf.org/html/rfc4122 +.. _version 6 UUIDs: http://gh.peabody.io/uuidv6/ diff --git a/docs/nonstandard.rst b/docs/nonstandard.rst index 3e1be7d..2374a52 100644 --- a/docs/nonstandard.rst +++ b/docs/nonstandard.rst @@ -7,5 +7,4 @@ Nonstandard UUIDs nonstandard/version6 nonstandard/comb - nonstandard/ordered-time nonstandard/guid diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 8b8b719..e53fc1d 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -58,7 +58,7 @@ the static generation methods. $uuid->getFields()->getVersion() ); -This will return an instance of ``Ramsey\Uuid\Rfc4122\UuidV4``. +This will return an instance of :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV4`. .. tip:: .. rubric:: Use the Interfaces @@ -66,10 +66,11 @@ This will return an instance of ``Ramsey\Uuid\Rfc4122\UuidV4``. Feel free to use ``instanceof`` to check the specific instance types of UUIDs. However, when using type hints, it's best to use the interfaces. - The most lenient interface is ``Ramsey\Uuid\UuidInterface``, while - ``Ramsey\Uuid\Rfc4122\UuidInterface`` ensures the UUIDs you're using conform - to the `RFC 4122`_ standard. If you're not sure which one to use, start with - the stricter ``Ramsey\Uuid\Rfc4122\UuidInterface``. + The most lenient interface is :php:interface:`Ramsey\\Uuid\\UuidInterface`, + while :php:interface:`Ramsey\\Uuid\\Rfc4122\\UuidInterface` ensures the + UUIDs you're using conform to the `RFC 4122`_ standard. If you're not sure + which one to use, start with the stricter + :php:interface:`Rfc4122\\UuidInterface `. ramsey/uuid provides a number of helpful static methods that help you work with and generate most types of UUIDs, without any special customization of the @@ -103,6 +104,6 @@ library. * - :php:meth:`Uuid::fromInteger() ` - Creates a UUID instance from a string integer. * - :php:meth:`Uuid::fromDateTime() ` - - Creates a version 1 UUID instance from a PHP ``DateTimeInterface``. + - Creates a version 1 UUID instance from a PHP ``\DateTimeInterface``. .. _RFC 4122: https://tools.ietf.org/html/rfc4122 diff --git a/docs/reference.rst b/docs/reference.rst index 062e727..9f278b1 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -22,4 +22,3 @@ Reference reference/exceptions reference/helper reference/name-based-namespaces - reference/references diff --git a/docs/reference/rfc4122-uuidv2.rst b/docs/reference/rfc4122-uuidv2.rst index 4c69b6f..2745de2 100644 --- a/docs/reference/rfc4122-uuidv2.rst +++ b/docs/reference/rfc4122-uuidv2.rst @@ -21,25 +21,19 @@ Rfc4122\\UuidV2 .. caution:: - It is important to note that a version 2 UUID suffers from some loss of - fidelity of the timestamp, due to replacing the ``time_low`` field with - the local identifier. When constructing the timestamp value for date - purposes, we replace the local identifier bits with zeros. As a result, - the timestamp can be off by a range of 0 to 429.4967295 seconds (or - about 7 minutes, 9 seconds, and 496730 microseconds). - - Astute observers might note this value directly corresponds to - 2\ :sup:`32` -- 1, or ``0xffffffff``. The local identifier is 32-bits, - and we have set each of these bits to 0, so the maximum range of - timestamp drift is ``0x00000000`` to ``0xffffffff`` (counted in - 100-nanosecond intervals). + It is important to note that version 2 UUIDs suffer from some loss + of timestamp precision. See :ref:`rfc4122.version2.timestamp-problems` + to learn more. :returns: A date object representing the timestamp associated with the UUID :returntype: ``\DateTimeInterface`` .. php:method:: getLocalDomain() - :returns: The local domain identifier for this UUID, which is one of :php:const:`Ramsey\\Uuid\\Uuid::DCE_DOMAIN_PERSON`, :php:const:`Ramsey\\Uuid\\Uuid::DCE_DOMAIN_GROUP`, or :php:const:`Ramsey\\Uuid\\Uuid::DCE_DOMAIN_ORG` + :returns: The local domain identifier for this UUID, which is one of + :php:const:`Ramsey\\Uuid\\Uuid::DCE_DOMAIN_PERSON`, + :php:const:`Ramsey\\Uuid\\Uuid::DCE_DOMAIN_GROUP`, or + :php:const:`Ramsey\\Uuid\\Uuid::DCE_DOMAIN_ORG` :returntype: ``int`` .. php:method:: getLocalDomainName() diff --git a/docs/reference/types.rst b/docs/reference/types.rst index 8212eda..2556ffc 100644 --- a/docs/reference/types.rst +++ b/docs/reference/types.rst @@ -68,3 +68,11 @@ Types A value object representing a timestamp, for type-safety purposes, to ensure that timestamps used by ramsey/uuid are truly timestamp integers and not some other kind of string or integer. + + .. php:method:: getSeconds() + + :returntype: :php:class:`Ramsey\\Uuid\\Type\\Integer` + + .. php:method:: getMicroseconds() + + :returntype: :php:class:`Ramsey\\Uuid\\Type\\Integer` diff --git a/docs/rfc4122.rst b/docs/rfc4122.rst index a27a11d..78ed8a4 100644 --- a/docs/rfc4122.rst +++ b/docs/rfc4122.rst @@ -14,7 +14,7 @@ RFC 4122 UUIDs rfc4122/version4 rfc4122/version5 -[RFC4122]_ defines five versions of UUID. Each version has different generation +`RFC 4122`_ defines five versions of UUID. Each version has different generation algorithms and properties. Which one you choose to use depends on your use-case. You can find out more about their applications on the specific page for that version. @@ -43,3 +43,6 @@ Version 5: Named-based (SHA-1) This version of UUID hashes together a namespace and a name to create a deterministic UUID. The hashing algorithm used is SHA-1. For more details, see :doc:`rfc4122/version5`. + + +.. _RFC 4122: https://tools.ietf.org/html/rfc4122 diff --git a/docs/rfc4122/version1.rst b/docs/rfc4122/version1.rst index 8c6da00..e0bf719 100644 --- a/docs/rfc4122/version1.rst +++ b/docs/rfc4122/version1.rst @@ -16,20 +16,19 @@ can determine what nodes in your infrastructure created the UUIDs and at what time. .. tip:: + It is also possible to use a **randomly-generated node**, rather than a hardware address. This is useful for when you don't want to leak machine information, while still using a UUID based on time. Keep reading to find out how. - -Default Mode -############ - By default, ramsey/uuid will attempt to look up a MAC address for the machine it is running on, using this value as the node. If it cannot find a MAC address, it will generate a random node. .. code-block:: php + :caption: Generate a version 1, time-based UUID + :name: rfc4122.version1.example use Ramsey\Uuid\Uuid; @@ -55,42 +54,77 @@ It will look something like this: Date: Sun, 01 Mar 2020 23:32:15 +0000 Node: 0242ac130003 -After creating a ``UuidInterface`` object from a string (or bytes), you can -check to see if it's a version 1 UUID by checking its instance type. +You may provide custom values for version 1 UUIDs, including node and clock +sequence. .. code-block:: php + :caption: Provide custom node and clock sequence to create a version 1, + time-based UUID + :name: rfc4122.version1.custom-example - use Ramsey\Uuid\Rfc4122\UuidV1; + use Ramsey\Uuid\Provider\Node\StaticNodeProvider; + use Ramsey\Uuid\Type\Hexadecimal; use Ramsey\Uuid\Uuid; - $uuid = Uuid::fromString('200e43fa-5c14-11ea-bc55-0242ac130003'); + $nodeProvider = new StaticNodeProvider(new Hexadecimal('121212121212')); + $clockSequence = 16383; - if ($uuid instanceof UuidV1) { - printf( - "UUID: %s\nVersion: %d\nDate: %s\nNode: %s\n", - $uuid->toString(), - $uuid->getFields()->getVersion(), - $uuid->getDateTime()->format('r'), - $uuid->getFields()->getNode()->toString() - ); - } + $uuid = Uuid::uuid1($nodeProvider->getNode(), $clockSequence); .. tip:: - Check out the :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV1` API - documentation to learn more about what you can do with a ``UuidV1`` - instance. + + Version 1 UUIDs generated in ramsey/uuid are instances of UuidV1. Check out + the :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV1` API documentation to learn + more about what you can do with a UuidV1 instance. -Random or Custom Node -##################### +.. _rfc4122.version1.custom: + +Providing a Custom Node +####################### You may override the default behavior by passing your own node value when generating a version 1 UUID. -In the following example, we use ``RandomNodeProvider`` to generate a random -node, which we pass when creating the UUID. +In the :ref:`example above `, we saw how to +pass a custom node and clock sequence. An interesting thing to note about the +example is its use of StaticNodeProvider. Why didn't we pass in a +:php:class:`Hexadecimal ` value, instead? + +According to `RFC 4122, section 4.5`_, node values that do not identify the +host --- in other words, our own custom node value --- should set the +unicast/multicast bit to one (1). This bit will never be set in IEEE 802 +addresses obtained from network cards, so it helps to distinguish it from a +hardware MAC address. + +The StaticNodeProvider sets this bit for you. This is why we used it rather +than providing a :php:class:`Hexadecimal ` +value directly. + +Recall from the example that the node value we set was ``121212121212``, but if +you take a look at this value with ``$uuid->getFields()->getNode()->toString()``, +it becomes: + +.. code-block:: text + + 131212121212 + +That's a result of this bit being set by the StaticNodeProvider. + + +.. _rfc4122.version1.random: + +Generating a Random Node +######################## + +Instead of providing a custom node, you may also generate a random node each +time you generate a version 1 UUID. The RandomNodeProvider may be used to +generate a random node value, and like the StaticNodeProvider, it also sets the +unicast/multicast bit for you. .. code-block:: php + :caption: Provide a random node value to create a version 1, time-based UUID + :name: rfc4122.version1.random-example use Ramsey\Uuid\Provider\Node\RandomNodeProvider; use Ramsey\Uuid\Uuid; @@ -99,58 +133,52 @@ node, which we pass when creating the UUID. $uuid = Uuid::uuid1($nodeProvider->getNode()); -You may also set the node value of your choice. In this example, we use -``StaticNodeProvider`` to do so. -.. code-block:: php +.. _rfc4122.version1.clock: - use Ramsey\Uuid\Provider\Node\StaticNodeProvider; - use Ramsey\Uuid\Type\Hexadecimal; - use Ramsey\Uuid\Uuid; +What's a Clock Sequence? +######################## - $myCustomNode = new Hexadecimal('1234567890ab'); - $nodeProvider = new StaticNodeProvider($myCustomNode); +The clock sequence part of a version 1 UUID helps prevent collisions. Since this +UUID is based on a timestamp and a machine node value, it is possible for +collisions to occur for multiple UUIDs generated within the same microsecond on +the same machine. - $uuid = Uuid::uuid1($nodeProvider->getNode()); +The clock sequence is the solution to this problem. -.. attention:: - According to [RFC4122]_, nodes that do not identify the host should set the - unicast/multicast bit to one (``1``). This bit will never be set in IEEE 802 - addresses obtained from network cards, so it helps to distinguish it from a - hardware MAC address. +The clock sequence is a 14-bit number --- this supports values from 0 to 16,383 +--- which means it should be possible to generate up to 16,384 UUIDs per +microsecond with the same node value, before hitting a collision. - ``RandomNodeProvider`` and ``StaticNodeProvider`` of ramsey/uuid set this - bit for you, so they’re the easiest to use, but if you use a custom node - provider, be sure to set this bit. +.. caution:: - See [RFC4122]_, `section 4.5 `_, - for more details. + ramsey/uuid does not use *stable storage* for clock sequence values. + Instead, all clock sequences are randomly-generated. If you are generating + a lot of version 1 UUIDs every microsecond, it is possible to hit collisions + because of the random values. If this is the case, you should use your own + mechanism for generating clock sequence values, to ensure against + randomly-generated duplicates. + + See `section 4.2 of RFC 4122`_, for more information. -Using the Factory -################# +.. _rfc4122.version1.privacy: -It is possible to override the behavior of ``Uuid::uuid1()`` globally, by -overriding values on the ``FeatureSet`` and ``UuidFactory``. +Privacy Concerns +################ -For example, if you wish to always use a specific node whenever ``Uuid::uuid1()`` -is called, you may do the following: +As discussed earlier in this section, version 1 UUIDs use a MAC address from a +local hardware network interface. This means it is possible to uniquely identify +the machine on which a version 1 UUID was created. -.. code-block:: php +If the value provided by the timestamp of a version 1 UUID is important to you, +but you do not wish to expose the interface address of any of your local +machines, see :ref:`rfc4122.version1.random` or :ref:`rfc4122.version1.custom`. - use Ramsey\Uuid\FeatureSet; - use Ramsey\Uuid\Provider\Node\StaticNodeProvider; - use Ramsey\Uuid\Type\Hexadecimal; - use Ramsey\Uuid\Uuid; - use Ramsey\Uuid\UuidFactory; +If you do not need an identifier with a timestamp value embedded in it, see +:ref:`rfc4122.version4` to learn about random UUIDs. - $nodeProvider = new StaticNodeProvider(new Hexadecimal('1234567890ab')); - $featureSet = new FeatureSet(); - $featureSet->setNodeProvider($nodeProvider); - - $factory = new UuidFactory($featureSet); - - Uuid::setFactory($factory); - - $uuid = Uuid::uuid1(); +.. _RFC 4122: https://tools.ietf.org/html/rfc4122 +.. _RFC 4122, section 4.5: https://tools.ietf.org/html/rfc4122#section-4.5 +.. _section 4.2 of RFC 4122: https://tools.ietf.org/html/rfc4122#section-4.2 diff --git a/docs/rfc4122/version2.rst b/docs/rfc4122/version2.rst index f10d58d..e1a1ca4 100644 --- a/docs/rfc4122/version2.rst +++ b/docs/rfc4122/version2.rst @@ -4,13 +4,23 @@ Version 2: DCE Security ======================= +.. tip:: + + DCE Security UUIDs are so-called because they were defined as part of the + "Authentication and Security Services" for the `Distributed Computing + Environment`_ (DCE) in the early 1990s. + + Version 2 UUIDs are not widely used. See :ref:`rfc4122.version2.problems` + before deciding whether to use them. + Like a :ref:`version 1 UUID `, a version 2 UUID uses the current time, along with the MAC address (or *node*) for a network interface on the local machine. Additionally, a version 2 UUID replaces the low part of the time field with a local identifier such as the user ID or group ID of the local account that created the UUID. This serves three purposes: -1. You can know *when* the identifier was created (see :ref:`rfc4122.version2.caveats`). +1. You can know *when* the identifier was created (see + :ref:`rfc4122.version2.timestamp-problems`). 2. You can know *where* the identifier was created. 3. You can know *who* created the identifier. @@ -19,8 +29,13 @@ only is there no need for a central authority to generate identifiers, but you can determine what nodes in your infrastructure created the UUIDs, at what time they were created, and the account on the machine that created them. -.. code-block:: +By default, ramsey/uuid will attempt to look up a MAC address for the machine it +is running on, using this value as the node. If it cannot find a MAC address, it +will generate a random node. + +.. code-block:: php :caption: Use a domain to generate a version 2, DCE Security UUID + :name: rfc4122.version2.example use Ramsey\Uuid\Uuid; @@ -39,7 +54,7 @@ they were created, and the account on the machine that created them. This will generate a version 2 UUID and print out its string representation, the time the UUID was created, and the node used to create it, as well as the name of the local domain specified and the local domain identifier (in this case, a -POSIX UID, automatically obtained from the local machine). +`POSIX`_ UID, automatically obtained from the local machine). It will look something like this: @@ -52,22 +67,110 @@ It will look something like this: Domain: person ID: 501 -.. todo:: +Just as with version 1 UUIDs, you may provide custom values for version 2 UUIDs, +including local identifier, node, and clock sequence. - Needs discussion on domains (list the domains), ability to specify the node - and clock sequence (though the lower 8 bits of the clock sequence, originally - a 14-bit integer, are replaced with the domain). In theory, 2^8-1 domains - could be defined, but only 3 are registered by the DCE specification. - Discuss ability to pass the local identifier. +.. code-block:: php + :caption: Provide custom identifier, node, and clock sequence to create a + version 2, DCE Security UUID + :name: rfc4122.version2.custom-example - .. epigraph:: + use Ramsey\Uuid\Provider\Node\StaticNodeProvider; + use Ramsey\Uuid\Type\Hexadecimal; + use Ramsey\Uuid\Type\Integer; + use Ramsey\Uuid\Uuid; - Note that the [domain] can potentially hold values outside the range - [0, 2\ :sup:`8` -- 1]; however, the only values currently registered are in - the range [0, 2]… [DCE11SEC]_ + $localId = new Integer(1001); + $nodeProvider = new StaticNodeProvider(new Hexadecimal('121212121212')); + $clockSequence = 63; + + $uuid = Uuid::uuid2( + Uuid::DCE_DOMAIN_ORG, + $localId, + $nodeProvider->getNode(), + $clockSequence + ); + +.. tip:: + + Version 2 UUIDs generated in ramsey/uuid are instances of UuidV2. Check out + the :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV2` API documentation to learn + more about what you can do with a UuidV2 instance. -.. _rfc4122.version2.caveats: +.. _rfc4122.version2.domains: + +Domains +####### + +The *domain* value tells what the local identifier represents. + +If using the *person* or *group* domains, ramsey/uuid will attempt to look up +these values from the local machine. On `POSIX`_ systems, it will use ``id -u`` +and ``id -g``, respectively. On Windows, it will use ``whoami`` and ``wmic``. + +The *org* domain is site-defined. Its intent it to identify the organization +that generated the UUID, but since this can have different meanings for +different companies and projects, you get to define its value. + +.. list-table:: DCE Security Domains + :widths: 30 70 + :align: center + :header-rows: 1 + :name: rfc4122.version2.table-domains + + * - Constant + - Description + * - :php:const:`Uuid::DCE_DOMAIN_PERSON ` + - The local identifier refers to a *person* (e.g., UID). + * - :php:const:`Uuid::DCE_DOMAIN_GROUP ` + - The local identifier refers to a *group* (e.g., GID). + * - :php:const:`Uuid::DCE_DOMAIN_ORG ` + - The local identifier refers to an *organization* (this is site-defined). + +.. note:: + + According to section 5.2.1.1 of `DCE 1.1: Authentication and Security Services + `_, the domain "can potentially hold + values outside the range [0, 2\ :sup:`8` -- 1]; however, the only values + currently registered are in the range [0, 2]." + + As a result, ramsey/uuid supports only the *person*, *group*, and *org* + domains. + + +.. _rfc4122.version2.nodes: + +Custom and Random Nodes +####################### + +In the :ref:`example above `, we provided a +custom node when generating a version 2 UUID. You may also generate random +node values. + +To learn more, see the :ref:`rfc4122.version1.custom` and +:ref:`rfc4122.version1.random` sections under :ref:`rfc4122.version1`. + + +.. _rfc4122.version2.clock: + +Clock Sequence +############## + +In a version 2 UUID, the clock sequence serves the same purpose as in a version +1 UUID. See :ref:`rfc4122.version1.clock` to learn more. + +.. warning:: + + The clock sequence in a version 2 UUID is a 6-bit number. It supports values + from 0 to 63. This is different from the 14-bit number used by version 1 + UUIDs. + + See :ref:`rfc4122.version2.uniqueness-problems` to understand how this + affects version 2 UUIDs. + + +.. _rfc4122.version2.problems: Problems With Version 2 UUIDs ############################# @@ -75,27 +178,95 @@ Problems With Version 2 UUIDs Version 2 UUIDs can be useful for the data they contain. However, there are trade-offs in choosing to use them. + +.. _rfc4122.version2.privacy-problems: + +Privacy +------- + +Unless using a randomly-generated node, version 2 UUIDs use the MAC address for +a local hardware interface as the node value. In addition, they use a local +identifier --- usually an account or group ID. Some may consider the use of +these identifying features a breach of privacy. The use of a timestamp further +complicates the issue, since these UUIDs could be used to identify a user +account on a specific machine at a specific time. + +If you don't need an identifier with a local identifier and timestamp value +embedded in it, see :ref:`rfc4122.version4` to learn about random UUIDs. + + +.. _rfc4122.version2.uniqueness-problems: + +Limited Uniqueness +------------------ + +With the inclusion of the local identifier and domain comes a serious limitation +in the amount of unique UUIDs that may be created. This is because: + +1. The local identifier replaces the lower 32 bits of the timestamp. +2. The domain replaces the lower 8 bits of the clock sequence. + +As a result, the timestamp advances --- the clock *ticks* --- only once every +429.49 seconds (about 7 minutes). This means the clock sequence is important to +ensure uniqueness, but since the clock sequence is only 6 bits, compared to 14 +bits for version 1 UUIDs, **only 64 unique UUIDs per combination of node, +domain, and identifier may be generated per 7-minute tick of the clock**. + +You can overcome this lack of uniqueness by using a +:ref:`random node `, which provides 47 bits of +randomness to the UUID --- after setting the unicast/multicast bit (see +discussion on :ref:`rfc4122.version1.custom`) --- increasing the number of UUIDs +per 7-minute clock tick to 2\ :sup:`53` (or 9,007,199,254,740,992), at the +expense of remaining locally unique. + +.. note:: + + This lack of uniqueness did not present a problem for DCE, since: + + [T]he security architecture of DCE depends upon the uniqueness of + security-version UUIDs *only within the context of a cell*; that is, + only within the context of the local [Registration Service's] + (persistent) datastore, and that degree of uniqueness can be guaranteed + by the RS itself (namely, the RS maintains state in its datastore, in + the sense that it can always check that every UUID it maintains is + different from all other UUIDs it maintains). In other words, while + security-version UUIDs are (like all UUIDs) specified to be "globally + unique in space and time", security is not compromised if they are + merely "locally unique per cell". + + -- `DCE 1.1: Authentication and Security Services, section 5.2.1.1 + `_ + + +.. _rfc4122.version2.timestamp-problems: + Lossy Timestamps ---------------- -Version 2 UUIDs are first generated in the same way as version 1 UUIDs, but then -the low part of the timestamp (the ``time_low`` field) is replaced by a 32-bit -integer that represents a local identifier, which refers to +Version 2 UUIDs are generated in the same way as version 1 UUIDs, but the low +part of the timestamp (the ``time_low`` field) is replaced by a 32-bit integer +that represents a local identifier. Because of this, not only do version 2 UUIDs +have :ref:`limited uniqueness `, but they +also lack time precision. -It is important to note that a version 2 UUID suffers from some loss of -fidelity of the timestamp, due to replacing the time_low field with the -local identifier. When constructing the timestamp value for date -purposes, we replace the local identifier bits with zeros. As a result, -the timestamp can be off by a range of 0 to 429.4967295 seconds (or 7 -minutes, 9 seconds, and 496730 microseconds). +When reconstructing the timestamp to return a ``\DateTimeInterface`` instance +from :php:meth:`UuidV2::getDateTime() `, +we replace the 32 lower bits of the timestamp with zeros, since the local +identifier should not be part of the timestamp. This results in a loss of +precision, causing the timestamp to be off by a range of 0 to 429.4967295 +seconds (or 7 minutes, 9 seconds, and 496,730 microseconds). -Astute observers might note this value directly corresponds to -2\ :sup:`32` -- 1, or ``0xffffffff``. The local identifier is 32-bits, and we -have set each of these bits to 0, so the maximum range of timestamp drift is -``0x00000000`` to ``0xffffffff`` (counted in 100-nanosecond intervals). +When using version 2 UUIDs, treat the timestamp as an approximation. At worst, +it could be off by about 7 minutes. -Limited Unique UUIDs --------------------- +.. hint:: -With the inclusion of the local identifier comes a serious limitation in the -amount of unique UUIDs that may be created. + If the value 429.4967295 looks familiar, it's because it directly + corresponds to 2\ :sup:`32` -- 1, or ``0xffffffff``. The local identifier is + 32-bits, and we have set each of these bits to 0, so the maximum range of + timestamp drift is ``0x00000000`` to ``0xffffffff`` (counted in + 100-nanosecond intervals). + + +.. _Distributed Computing Environment: https://en.wikipedia.org/wiki/Distributed_Computing_Environment +.. _POSIX: https://en.wikipedia.org/wiki/POSIX diff --git a/docs/rfc4122/version3.rst b/docs/rfc4122/version3.rst index ed5d0db..4d6722d 100644 --- a/docs/rfc4122/version3.rst +++ b/docs/rfc4122/version3.rst @@ -6,7 +6,7 @@ Version 3: Name-based (MD5) .. attention:: - [RFC4122]_ states, "If backward compatibility is not an issue, SHA-1 is + `RFC 4122`_ states, "If backward compatibility is not an issue, SHA-1 is preferred." As a result, the use of :ref:`version 5 UUIDs ` is preferred over version 3 UUIDs, unless you have a specific use-case for version 3 UUIDs. @@ -18,7 +18,7 @@ Version 3: Name-based (MD5) `. The only difference is the hashing algorithm used to generate the UUID. - Version 3 UUIDs use MD5 [RFC1321]_ as the hashing algorithm for combining + Version 3 UUIDs use `MD5`_ as the hashing algorithm for combining the namespace and the name. Due to the use of a different hashing algorithm, version 3 UUIDs generated with @@ -58,7 +58,11 @@ With this custom namespace, the version 3 UUID for the name "widget/1234567890" will always be ``53564aa3-4154-3ca5-ac90-dba59dc7d3cb``. .. tip:: - Version 3 UUIDs generated in ramsey/uuid are instances of - ``Ramsey\Uuid\Rfc4122\UuidV3``. Check out the - :php:interface:`Ramsey\\Uuid\\Rfc4122\\UuidInterface` API documentation to - learn more about what you can do with a ``UuidV3`` instance. + + Version 3 UUIDs generated in ramsey/uuid are instances of UuidV3. Check out + the :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV3` API documentation to learn + more about what you can do with a UuidV3 instance. + + +.. _RFC 4122: https://tools.ietf.org/html/rfc4122 +.. _MD5: https://en.wikipedia.org/wiki/MD5 diff --git a/docs/rfc4122/version4.rst b/docs/rfc4122/version4.rst index 948db14..f4606eb 100644 --- a/docs/rfc4122/version4.rst +++ b/docs/rfc4122/version4.rst @@ -9,9 +9,9 @@ randomly-generated and do not contain any information about the time they are created or the machine that generated them. If you don't care about this information, then a version 4 UUID might be perfect for your needs. -To generate a version 4 UUID, you may use the ``Uuid::uuid4()`` static method. - .. code-block:: php + :caption: Generate a version 4, random UUID + :name: rfc4122.version4.example use Ramsey\Uuid\Uuid; @@ -23,21 +23,17 @@ To generate a version 4 UUID, you may use the ``Uuid::uuid4()`` static method. $uuid->getFields()->getVersion() ); -After creating a ``UuidInterface`` object from a string (or bytes), you can -check to see if it's a version 4 UUID by checking its instance type. +This will generate a version 4 UUID and print out its string representation. +It will look something like this: -.. code-block:: php +.. code-block:: text - use Ramsey\Uuid\Rfc4122\UuidV4; - use Ramsey\Uuid\Uuid; + UUID: 1ee9aa1b-6510-4105-92b9-7171bb2f3089 + Version: 4 - $uuid = Uuid::fromString('6b8d3b65-a527-49d5-b6dc-cf195877feef'); - - if ($uuid instanceof UuidV4) { - printf("%s is a version 4 UUID!\n", $uuid->toString()); - } .. tip:: - Check out the :php:interface:`Ramsey\\Uuid\\Rfc4122\\UuidInterface` API - documentation to learn more about what you can do with a ``UuidV4`` - instance. + + Version 4 UUIDs generated in ramsey/uuid are instances of UuidV4. Check out + the :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV4` API documentation to learn + more about what you can do with a UuidV4 instance. diff --git a/docs/rfc4122/version5.rst b/docs/rfc4122/version5.rst index 32445e0..ddf6106 100644 --- a/docs/rfc4122/version5.rst +++ b/docs/rfc4122/version5.rst @@ -4,7 +4,8 @@ Version 5: Name-based (SHA-1) ============================= -.. caution:: +.. danger:: + Since :ref:`version 3 ` and version 5 UUIDs essentially use a *salt* (the namespace) to hash data, it may be tempting to use them to hash passwords. **DO NOT do this under any circumstances!** You should not @@ -36,7 +37,8 @@ to the namespace they're created in. RFC 4122 defines some for URLs. .. note:: - Version 5 UUIDs use [SHA1]_ as the hashing algorithm for combining the + + Version 5 UUIDs use `SHA-1`_ as the hashing algorithm for combining the namespace and the name. .. code-block:: php @@ -53,10 +55,10 @@ will always be ``a8f6ae40-d8a7-58f0-be05-a22f94eca9ec``. See for yourself. Run the code above, and you'll see it always generates the same UUID. .. tip:: - Version 5 UUIDs generated in ramsey/uuid are instances of - ``Ramsey\Uuid\Rfc4122\UuidV5``. Check out the - :php:interface:`Ramsey\\Uuid\\Rfc4122\\UuidInterface` API documentation to - learn more about what you can do with a ``UuidV5`` instance. + + Version 5 UUIDs generated in ramsey/uuid are instances of UuidV5. Check out + the :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV5` API documentation to learn + more about what you can do with a UuidV5 instance. .. _rfc4122.version5.custom-namespaces: @@ -100,3 +102,6 @@ will always be ``a35477ae-bfb1-5f2e-b5a4-4711594d855f``. We can publish this namespace, allowing others to use it to generate identifiers for widgets. When two or more systems try to reference the same widget, they'll end up generating the same identifier for it, which is exactly what we want. + + +.. _SHA-1: https://en.wikipedia.org/wiki/SHA-1 diff --git a/src/Rfc4122/UuidV2.php b/src/Rfc4122/UuidV2.php index 67cf189..74906f0 100644 --- a/src/Rfc4122/UuidV2.php +++ b/src/Rfc4122/UuidV2.php @@ -37,9 +37,11 @@ use const STR_PAD_LEFT; * 128-bit unsigned integer * * @link https://publications.opengroup.org/c311 DCE 1.1: Authentication and Security Services - * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01 DCE 1.1, §5.2.1.1 - * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, §11.5.1.1 - * @link https://github.com/google/uuid Go package for UUIDs based on RFC 4122 and DCE 1.1: Auth and Security Services + * @link https://publications.opengroup.org/c706 DCE 1.1: Remote Procedure Call + * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01 DCE 1.1: Auth & Sec, §5.2.1.1 + * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1: Auth & Sec, §11.5.1.1 + * @link https://pubs.opengroup.org/onlinepubs/9629399/apdxa.htm DCE 1.1: RPC, Appendix A + * @link https://github.com/google/uuid Go package for UUIDs (includes DCE implementation) * * @psalm-immutable */