composer require rafalswierczek/uuid4
$uuid4 = Uuid4Factory::create();
$uuid4 = new Uuid4('f3d7fa06-d938-4c22-9505-c585efa381df');
$uuid4 = new Uuid4(Uuid4Factory::createBinary()->toHex());
$uuid4 = new Uuid4(Uuid4Factory::create()->toHex());
$uuid4Binary = Uuid4Factory::createBinary();
$uuid4Binary = new Uuid4Binary(random_bytes(16));
$uuid4Binary = new Uuid4Binary(Uuid4Factory::createBinary()->toBinary());
$uuid4Binary = new Uuid4Binary(Uuid4Factory::create()->toBinary());
// example 1:
$userClass = new class()
{
private Uuid4Interface $uuid4;
public function getUuid(bool $toHex = true): string
{
return $toHex ? $this->uuid4->toHex() : $this->uuid4->toBinary();
}
public function setUuid(Uuid4Interface $uuid4): void
{
$this->uuid4 = $uuid4;
}
};
$userClass->setUuid(Uuid4Factory::createBinary());
$uuid4 = $userClass->getUuid(toHex: true); // hex format
// example 2:
$unknownSource = 'f3d7fa06-d938-4c22-9505-c585efaxxxxx';
Uuid4::validate($unknownSource);
// example 3:
$uuid4 = new Uuid4('f3d7fa06-d938-4c22-9505-c585efa381df'); // this also calls validate method because it is VO
$uuid4Binary = new Uuid4Binary($uuid4->toBinary()); // this also calls validate method because it is VO
$hexEqualsBin = $uuid4->equals($uuid4Binary);
$binEqualsHex = $uuid4Binary->equals($uuid4);
UUID v4 is data of 128 random bits (with small modifications) represented in hexadecimal notation.
Data is divided into 16 octets (from 0 to 15), 8 bits each.
Octets are grouped into sections with following names:
- time_low (octets 0-3)
- time_mid (octets 4-5)
- time_high_and_version (octets 6-7)
- clock_seq_and_reserved (octet 8)
- clock_seq_low (octet 9)
- node (octets 10-15)
Result of UUID4 in hex notation looks like this:
f2e0aa63-22f2-410c-bcfa-9475cf573193
As you can see, for example time_low
has 4 octets, each is as follows f2
, e0
, aa
, 63
in hex notation.
Now once you have 128 random bits, you have to modify octet 8 in the way that two most significant bits (MSB) are set to: 0
and 1
. For example, let's say 8 octet is as follows: 01101101
. Now you have to make sure that two bits on the left are 00
and then you can add desired 10
so the result is: 10101101
. It's done this way:
01101101
& 00111111
= 00101101
00101101
| 10000000
= 10101101
Once clock_seq_and_reserved is updated it's time to modify octet 6 (first 8 bits of time_high_and_version). You have to do the same steps but with 00001111
for AND and 01000000
for OR. For example if octet 6 is 10100101
, the result is 01000101
so first 4 bits are replaced with 0100
which are bits reserved for UUID v4.
After modifying octet 8 and 6 of 128 random bits and converting it to hex notation you have ready to use UUID v4 string :)
RFC: https://datatracker.ietf.org/doc/html/rfc4122#section-4.4