Instead of breaking it down into individual fields, it’s easier to generate a random block of data and change the individual byte positions. You should also use a better random number generator than mt_rand().
According to RFC 4122 – Section 4.4, you need to change these fields:
time_hi_and_version
(bits 4-7 of 7th octet),clock_seq_hi_and_reserved
(bit 6 & 7 of 9th octet)
All of the other 122 bits should be sufficiently random.
The following approach generates 128 bits of random data using openssl_random_pseudo_bytes()
, makes the permutations on the octets and then uses bin2hex()
and vsprintf()
to do the final formatting.
function guidv4($data)
{
assert(strlen($data) == 16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
echo guidv4(openssl_random_pseudo_bytes(16));
With PHP 7, generating random byte sequences is even simpler using random_bytes()
:
function guidv4($data = null)
{
$data = $data ?? random_bytes(16);
// ...
}