"DrUUID" is an implementation for PHP of---and associated API for---the data format described in RFC 9562, Universally Unique IDentifiers (UUIDs). It is able to mint new UUIDs, import existing UUIDs, extract information from UUIDs, and compare two UUIDs for bit-exact equality.
The API is designed to be as simple as possible, with an implementation as accurate as practical given the limits of PHP. All other concerns, including PHP compatibility, efficiency and extensibility are secondary.
Questions and comments are very welcome, and should be directed to the author via his Web site.
This manual often makes references to binary and hexdecimal strings for input and output. For the sake of simplicity please assume that such strings are always in network order (big-endian).
For methods accepting a UUID as an argument, the UUID may be:
UUID object
This manual often makes reference to invalid UUIDs. For simplicity this is merely any string more or less than 16 bytes long. DrUUID performs no other validation on UUIDs.
The core DrUUID API consists of four static methods: UUID::mint(), UUID::import(), UUID::compare() as well as UUID::mintStr(). Of these UUID::mint() and UUID::import() return an instance of the UUID class.
UUID UUID::mint( [int version [, ... ]] )
The UUID::mint() method generates ("mints", like coinage) a new UUID. It is capable of producing Version 1 (time-based), Version 3 (MD5 hash-based), Version 4 (random), Version 5 (SHA-1 hash-based), Version 6 (ordered time-based), and Version 7 (Unix time-based) UUIDs. Its argument list is generic: required and optional argument depend upon the specified version to produce. For backwards-compatibility reasons Version 1 UUIDs are produced unless otherwise specified, but using Version 7 is recommended.
UUID UUID::mint( 1 )
Version 1 UUIDs are generated based on the current time and a MAC address (called a node).
If specified, node should be either a 6-byte binary string or a 12-character hexadecimal string (with or without separators) representing a MAC address. DrUUID does not attempt to detect the host's MAC address. Invalid nodes will throw an exception.
The sequence argument specifies a clock sequence and should be a two-byte binary string. This should only be used for debugging. Invalid sequences will throw an exception.
Finally, the time argument may be specified to employ a past or future time (as a Unix timestamp with microseconds like that returned by microtime() for example) instead of the curent time. This should only be used for debugging and never used to generate UUIDs for any purpose but testing. Input which cannot be parsed as a timestamp will throw an exception.
UUID UUID::mint( 3, string name, UUID|string namespace )
Version 3 UUIDs are generated based upon a an MD5 hash of an arbitrary name and its associated name-space. For example the name "www.example.com" is within the DNS namespace, much as "Canada" is within a name-space of the world's countries. A name/namespace pair will predictably generate the same UUID.
The name argument is an arbitrary name and should be in a binary form appropriate for namespace. It is the responsibility of the user to assure the proper conversion to binary form. For many namespaces (like the DNS) the appropriate representation is plain text and therefore no conversion is required.
The namespace argument is itself a UUID; invalid UUIDs will throw an exception.
Note that the continued use of Version 3 UUIDs is discouraged: Version 5 UUIDs should be used instead whenever possible.
UUID UUID::mint( 4 )
Version 4 UUIDs are generated from random numbers. Save for embedded version information they are completely random.
UUID UUID::mint( 5, string name, UUID|string namespace )
Version 5 UUIDs are generated based upon a an SHA-1 hash of an arbitrary name and its associated name-space. For example the name "www.example.com" is within the DNS namespace, much as "Canada" is within a name-space of the world's countries. A name/namespace pair will predictably generate the same UUID.
The name argument is an arbitrary name and should be in a binary form appropriate for namespace. It is the responsibility of the user to assure the proper conversion to binary form. For many namespaces (like the DNS) the appropriate representation is plain text and therefore no conversion is required.
The namespace argument is itself a UUID; invalid UUIDs will throw an exception.
Version 5 UUIDs are preferred over Version 3 UUIDs.
UUID UUID::mint( 6 )
Version 6 UUIDs are generated based on the current time and a MAC address (called a node), the same as Version 1 UUIDs. Version 6 UUIDs differ only in that they will sort chronologically.
See the description of Version 1 UUIDs above for usage details.
UUID UUID::mint( void )
UUID UUID::mint( 7 )
Version 7 UUIDs (the default type) are generated based on the current time using a simpler algorithm than Version 1 or Version 6 UUIDs. Version 7 is the recommended form to use for new software.
The time argument may be specified to employ a past or future time (as a Unix timestamp with microseconds like that returned by microtime() for example) instead of the curent time. This should only be used for debugging and never used to generate UUIDs for any purpose but testing. Input which cannot be parsed as a timestamp will throw an exception.
Support for Version 8 UUIDs has been stubbed in, but as their contents have no agreed-upon interpretation attempting to create one will throw an exception.
A subclass may implement Version 8 UUIDs by overriding the mintCustom() and __get() methods to implement necessary logic.
UUID UUID::import( string uuid )
The UUID::import() method imports a UUID string as a UUID object. Invalid UUIDs will throw an exception.
bool|null UUID::compare( UUID|string uuid1, UUID|string uuid2 )
The UUID::compare() method compares two UUIDs for equivalency. If both UUIDs, as binary numbers, are equal, the method returns true. The method will return null if either arguments is not a valid UUID.
This method is useful for determining if two different UUID representations (eg. canonical string, lowercase hex string, uppercase hex string, binary, URN) are in fact the same UUID.
string UUID::mintStr( [int version [, ... ] )
The UUID::mintStr() method performs the same functions as the UUID::mint() method, but returns the UUID directly as a string in canonical form.
UUID objects cannot be instantiated manually; they must be created via UUID::mint() or UUID::import(). When cast to a string a UUID object will be rendered in the canonical string form (eg. 550e8400-e29b-41d4-a716-446655440000). They have no public methods, but do have a number of public properties:
DrUUID only includes a basic implementation of in-memory storage for Version 1 and Version 6 UUIDs which is consistent with Section 6.3 of RFC 9562. This implementation, however, is not sufficient for optimal uniqueness for Version 1 or Version 6 UUIDs. If using these types (Version 7 or Version 4 are preferred for new applications), a custom storage implementation can be provided to DrUUID for holding state.
void UUID::registerStorage( UUIDStorage store )
The class_name argument must be the name of a defined class which imprements the UUIDStorage interface, described below. Any further arguments will be passed to UUID::initStorage().
If no supplementary arguments are passed, UUID::initStorage() must be called before the custom storage may be used.
interface UUIDStorage {
public function getNode(): ?string;
public function getSequence(string $timestamp, string $node): ?string;
public function setSequence(string $sequence): void;
public function setTimestamp(string $timestamp): void;
const maxSequence = 16383; // 00111111 11111111
}
The UUIDStorage interface defines a set of methods which DrUUID ill call during the generation of Version 1 and Version 6 UUIDs in a predictable order to query storage and write data. The order of the method calls is as follows:
getNode()
getSequence(), passing the timestamp and node ID
setSequence()
setTimestamp() to update the stored timestamp, signalling the end of communication
The following subsections serve as implementation notes for the interface's methods.
As DrUUID is unable to retrieve the system's MAC address, it calls the getNode() method, which might implement a means of doing so or retrieve one from storage. If it does return a value, it should be formatted as six bytes, in big-endian order (the reverse of conventional hexdecimal pair representation).
The getSequence() method is the heart of the interface, taking as input the target timestamp (as a number of 100ns ticks since the Unix epoch) and the node ID (as a six-byte string). Output should be a two-byte string, with the two most significant bits set to zero.
Per Section 5.1 of RFC 9562, the clock sequence should be randomized if the node ID changes, and should be incremented if the target timestamp is lower than that in storage. Due to the limits of 32-bit systems and the difficulties inherent in comparing floating-point numbers, the input timestamp is always a string with integer precision.
This method simply alerts the storage of a new clock sequence, if either the user has supplied a sequence or the storage failed to return a result. Input is a two-byte string; no return value is required.
The method serves as a marker that communication with the storage is complete and any buffered data may be written to stable storage if appropriate. Input is a string representation of the number of 100ns ticks since the Unix epoch.
For convenience DrUUID includes a few class constants representing the registry of UUID namespaces defined in Section 6.6 of RFC 9562 for use in Version 3 or 5 UUIDs.
These constants are briefly documented in this appendix.
| Constant | Namespace description | UUID |
|---|---|---|
UUID::nsDNS
| DNS hostnames (e.g. "www.example.com") | 6ba7b810-9dad-11d1-80b4-00c04fd430c8 |
UUID::nsURL
| Any valid URL (e.g. "http://www.example.com/example.html") | 6ba7b811-9dad-11d1-80b4-00c04fd430c8 |
UUID::nsOID
| An ISO Object Identifier | 6ba7b812-9dad-11d1-80b4-00c04fd430c8 |
UUID::nsX500
| An X.500 Distinguished Name | 6ba7b814-9dad-11d1-80b4-00c04fd430c8 |
DrUUID and its manual (i.e. this document) were written by J. King. They are both governed by the following license:
Copyright (c) 2009, 2025 J. King Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This manual's stylesheet was written by Dustin Wilson. It is licensed under the Creative Commons Attribution license (v2.5).
This software is dedicated to Seung Park. HLN forever!
UUID::initRandom(), UUID::initBignum(), UUID::initStorage(), and UUID::initAccurate() methods have all been removed as they are no longer needed
UUID::seq() and UUID::randomBytes() have been made protected
UUIDStorageStable class has been removed; with the advent of Version 7 UUIDs stable storage is not as important as it once might have been, and the functionality was poorly tested and only useful in narrow circumstances. The UUID::registerStorage() method is still available for using custom implementations of stable storage
UUIDException and UUIDStorageException classes have been removed. All misuse not caught by PHP itself will now result in InvalidArgumentException being thrown instead
UUID class have been removed or made protected, depending on whether they have been made obsolete or were always meant to be internal. Only the namespace constants remain
lib.uuid.php backwards-compatibility file has been removed as namespaces are now a longstanding PHP feature
UUID::import() method is now stricter in interpreting its input. Non-hexdecimal characters other than dashes or enclosing curly braces will now throw an exception
UUID::compare() method now returns null if either input is invalid
UUID::registerStorage() method has been changed. It now expects an instance of a class implementing the UUIDStorage interface
UUID::mint() method are now used only for creating Version 3 and Version 5 UUIDs
UUID::mint() method is now 7 to coincide with the recommendation in RFC 9562
UUID::mint() have been renamed to $name and $namespace, respectively
UUID::mint() method should be understood to include the UUID::mintStr() method as well.
/dev/urandom, as all available functions use it internally anyway
DateTimeInterface as input to UUID::mint(1)
UUID::initBignum() method to trigger bignum support
UUID::initBignum() may be passed a constant to explicitly choose a strategy
UUID::seq() is no longer required. It remains a public method, but is now undocumented
UUID::initRandom() are now no-ops
UUID::initRandom() may now be passed a constant to explicitly choose a randomness source; it now returns an integer constant representing a source rather than a string
UUID::mintStr() method to return canonical strings rather than objects
UUID::initAccurate() method as a shortcut to optimal accuracy.
UUID::mintTime() [Dave Gardner]
UUID::seq() [David Ward]
UUID->time now returns a string with a fixed precision
UUID::import() is now a no-op
UUID::mint(1), as well as the addition of UUID::seq().
UUID::import as reported by Sander van Lambalgen.
UUID::compare() method. Also allowed input UUIDs to be RFC 4122 URNs.
UUID::initRandom() method. See Section 4 for details. As a consequence generating random numbers is now much faster. Acknowledgement to Rubén Marrero for the impulse to implement this.
/dev/urandom from being used. Reported by Rubén Marrero.