123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- .. _nonstandard.guid:
- ===================================
- Globally Unique Identifiers (GUIDs)
- ===================================
- .. tip::
- Using these techniques to work with GUIDs is useful if you're working with
- identifiers that have been stored in GUID byte order. For example, this is
- the case if working with the ``UNIQUEIDENTIFIER`` data type in Microsoft SQL
- Server. This is a GUID, stored as a 16-byte binary string. If working
- directly with the bytes, you may use the GUID functionality in ramsey/uuid
- to properly handle this data type.
- According to the Windows Dev Center article on `GUID structure`_, "GUIDs are the
- Microsoft implementation of the distributed computing environment (DCE)
- universally unique identifier." For all intents and purposes, a GUID string
- representation is identical to that of an `RFC 4122`_ UUID. For historical
- reasons, *the byte order is not*.
- The `.NET Framework documentation`_ explains:
- Note that the order of bytes in the returned byte array is different from
- the string representation of a Guid value. The order of the beginning
- four-byte group and the next two two-byte groups is reversed, whereas the
- order of the last two-byte group and the closing six-byte group is the same.
- This is best explained by example.
- .. code-block:: php
- :caption: Decoding a GUID from byte representation
- :name: nonstandard.guid.decode-bytes-example
- use Ramsey\Uuid\FeatureSet;
- use Ramsey\Uuid\UuidFactory;
- // The bytes of a GUID previously stored in some datastore.
- $guidBytes = hex2bin('0eab93fc9ec9584b975e9c5e68c53624');
- $useGuids = true;
- $featureSet = new FeatureSet($useGuids);
- $factory = new UuidFactory($featureSet);
- $guid = $factory->fromBytes($guidBytes);
- printf(
- "Class: %s\nGUID: %s\nVersion: %d\nBytes: %s\n",
- get_class($guid),
- $guid->toString(),
- $guid->getFields()->getVersion(),
- bin2hex($guid->getBytes())
- );
- This transforms the bytes of a GUID, as represented by ``$guidBytes``, into a
- :php:class:`Ramsey\\Uuid\\Guid\\Guid` instance and prints out some details about
- it. It looks something like this:
- .. code-block:: text
- Class: Ramsey\Uuid\Guid\Guid
- GUID: fc93ab0e-c99e-4b58-975e-9c5e68c53624
- Version: 4
- Bytes: 0eab93fc9ec9584b975e9c5e68c53624
- Note the difference between the string GUID and the bytes. The bytes are
- arranged like this:
- .. code-block:: text
- 0e ab 93 fc 9e c9 58 4b 97 5e 9c 5e 68 c5 36 24
- In an `RFC 4122`_ UUID, the bytes are stored in the same order as you see
- presented in the string representation. This is often called *network byte
- order*, or *big-endian* order. In a GUID, the order of the bytes are reversed
- in each grouping for the first 64 bits and stored in *little-endian* order. The
- remaining 64 bits are stored in network byte order. See `Endianness
- <#nonstandard-guid-endianness>`_ to learn more.
- .. caution::
- The bytes themselves do not indicate their order. If you decode GUID bytes
- as a UUID or UUID bytes as a GUID, you will get the wrong values. However,
- you can always create a GUID or UUID from the same string value; the bytes
- for each will be in a different order, even though the string is the same.
- The key is to know ahead of time in what order the bytes are stored. Then,
- you will be able to decode them using the correct approach.
- Converting GUIDs to UUIDs
- #########################
- Continuing from the example, :ref:`nonstandard.guid.decode-bytes-example`, we
- can take the GUID string representation and convert it into a standard UUID.
- .. code-block:: php
- :caption: Convert a GUID to a UUID
- :name: nonstandard.guid.convert-example
- $uuid = Uuid::fromString($guid->toString());
- printf(
- "Class: %s\nUUID: %s\nVersion: %d\nBytes: %s\n",
- get_class($uuid),
- $uuid->toString(),
- $uuid->getFields()->getVersion(),
- bin2hex($uuid->getBytes())
- );
- Because the GUID was a version 4, random UUID, this creates an instance of
- :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV4` from the GUID string and prints out a
- few details about it. It looks something like this:
- .. code-block:: text
- Class: Ramsey\Uuid\Rfc4122\UuidV4
- UUID: fc93ab0e-c99e-4b58-975e-9c5e68c53624
- Version: 4
- Bytes: fc93ab0ec99e4b58975e9c5e68c53624
- Note how the UUID string is identical to the GUID string. However, the byte
- order is different, since they are in big-endian order. The bytes are now
- arranged like this:
- .. code-block:: text
- fc 93 ab 0e c9 9e 4b 58 97 5e 9c 5e 68 c5 36 24
- .. admonition:: Endianness
- :name: nonstandard.guid.endianness
- Big-endian and little-endian refer to the ordering of bytes in a multi-byte
- number. Big-endian order places the most significant byte first, followed by
- the other bytes in descending order. Little-endian order places the least
- significant byte first, followed by the other bytes in ascending order.
- Take the hexadecimal number ``0x1234``, for example. In big-endian order,
- the bytes are stored as ``12 34``, and in little-endian order, they are
- stored as ``34 12``. In either case, the number is still ``0x1234``.
- Networking protocols usually use big-endian ordering, while computer
- processor architectures often use little-endian ordering.
- The terms originated in Jonathan Swift's *Gulliver's Travels*, where the
- Lilliputians argue over which end of a hard-boiled egg is the best end to
- crack.
- .. _GUID structure: https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid#remarks
- .. _RFC 4122: https://tools.ietf.org/html/rfc4122
- .. _.NET Framework documentation: https://docs.microsoft.com/en-us/dotnet/api/system.guid.tobytearray#remarks
|