Subversion Repositories uuid_mac_utils

Compare Revisions

Regard whitespace Rev 69 → Rev 70

/trunk/includes/uuid_utils.inc.php
580,9 → 580,17
Variant 1, Version 7 UUID
- 48 bit Unix Time in milliseconds
- 4 bit Version (fix 0x7)
- 12 bit Random
- 12 bit Data
- 2 bit Variant (fix 0b10)
- 62 bit Random
- 62 bit Data
 
Structure of data (74 bits):
- OPTIONAL : Sub-millisecond timestamp fraction (0-12 bits)
- OPTIONAL : Carefully seeded counter
- Random generated bits for any remaining space
 
Since we don't know if timestamp fraction or counters are implemented
(and if so, how many bits), we don't decode this information
*/
 
echo sprintf("%-32s %s\n", "Version:", "[0x7] Unix Epoch Time");
1221,15 → 1229,13
// Variant 1, Version 7 (Unix Epoch) UUID
# --------------------------------------
 
function gen_uuid_v7() {
return gen_uuid_unix_epoch();
function gen_uuid_v7(int $num_ms_frac_bits=12) {
return gen_uuid_unix_epoch($num_ms_frac_bits);
}
function gen_uuid_unix_epoch() {
// Start with an UUIDv4
$uuid = gen_uuid_random();
function gen_uuid_unix_epoch(int $num_ms_frac_bits=12) {
$uuid_nibbles = '';
 
// Add the timestamp
usleep(1000); // Wait 1ms, to make sure that the time part changes if multiple UUIDs are generated
// Add the timestamp (milliseconds Unix)
if (function_exists('gmp_init')) {
list($ms,$sec) = explode(' ', microtime(false));
$sec = gmp_init($sec, 10);
1236,18 → 1242,70
$ms = gmp_init(substr($ms,2,3), 10);
$unix_ts = gmp_strval(gmp_add(gmp_mul($sec, '1000'), $ms),16);
} else {
$unix_ts = dechex((int)round(microtime(true)*1000));
$unix_ts = dechex((int)ceil(microtime(true)*1000));
}
$unix_ts = str_pad($unix_ts, 12, '0', STR_PAD_LEFT);
for ($i=0;$i<8;$i++) $uuid[$i] = substr($unix_ts, $i, 1);
for ($i=0;$i<4;$i++) $uuid[9+$i] = substr($unix_ts, 8+$i, 1);
$uuid_nibbles = $unix_ts;
 
// set version
$uuid[14] = '7';
// Version = 7
$uuid_nibbles .= '7';
 
return $uuid;
// Optional: millisecond fraction (max 12 bits)
if (($num_ms_frac_bits < 0) || ($num_ms_frac_bits > 12)) throw new Exception("Invalid msec frac bits (must be 0..12)");
if ($num_ms_frac_bits > 0) {
$seconds_fraction = (float)explode(' ',microtime(false))[0];
$nanoseconds_fraction = $seconds_fraction * 1000000;
$resolution_ns = 1000000 / pow(2,$num_ms_frac_bits);
$val = (int)ceil($nanoseconds_fraction / $resolution_ns);
 
// Currently, for the output we only allow frac bits 0, 4, 8, 12 (0-3 nibbles),
// since UUIDs are usually sorted in their hex notation
$num_nibbles = (int)ceil($num_ms_frac_bits/4);
$nibble_string = str_pad(dechex($val), $num_nibbles, '0', STR_PAD_LEFT);
$uuid_nibbles .= $nibble_string;
} else {
$resolution_ns = 1000000;
}
 
// TODO Not implemented: Optional counter (to be defined as parameter to this method)
// The counter bits need to be spread before and after the variant bits
 
// Fill with random bits (and the variant bits)
$uuid = gen_uuid_random();
$uuid = str_replace('-', '', $uuid);
for ($i=0; $i<strlen($uuid_nibbles); $i++) $uuid[$i] = $uuid_nibbles[$i];
 
// Wait to make sure that the time part changes if multiple UUIDs are generated
// We don't use usleep(), because it often does not sleep long enough!
// $resolution_us = (int)ceil($resolution_ns/1000);
// if ($resolution_us > 0) usleep($resolution_us);
// We use this naive approach instead:
if ($num_ms_frac_bits > 0) {
$seconds_fraction = (float)explode(' ',microtime(false))[0];
$nanoseconds_fraction = $seconds_fraction * 1000000;
$resolution_ns = 1000000 / pow(2,$num_ms_frac_bits);
$val = (int)ceil($nanoseconds_fraction / $resolution_ns);
do {
$seconds_fraction = (float)explode(' ',microtime(false))[0];
$nanoseconds_fraction = $seconds_fraction * 1000000;
$resolution_ns = 1000000 / pow(2,$num_ms_frac_bits);
$val2 = (int)ceil($nanoseconds_fraction / $resolution_ns);
} while ($val == $val2);
} else {
$unix_ts = dechex((int)ceil(microtime(true)*1000));
do {
$unix_ts2 = dechex((int)ceil(microtime(true)*1000));
} while ($unix_ts == $unix_ts2);
}
 
// Output
return substr($uuid, 0, 8).'-'.
substr($uuid, 8, 4).'-'.
substr($uuid, 12, 4).'-'.
substr($uuid, 16, 4).'-'.
substr($uuid, 20, 12);
}
 
# --------------------------------------
// Variant 1, Version 8 (Custom) UUID
# --------------------------------------