Rev 69 | Rev 71 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 69 | Rev 70 | ||
---|---|---|---|
Line 578... | Line 578... | ||
578 | case 7: |
578 | case 7: |
579 | /* |
579 | /* |
580 | Variant 1, Version 7 UUID |
580 | Variant 1, Version 7 UUID |
581 | - 48 bit Unix Time in milliseconds |
581 | - 48 bit Unix Time in milliseconds |
582 | - 4 bit Version (fix 0x7) |
582 | - 4 bit Version (fix 0x7) |
583 | - 12 bit Random |
583 | - 12 bit Data |
584 | - 2 bit Variant (fix 0b10) |
584 | - 2 bit Variant (fix 0b10) |
585 | - 62 bit Random |
585 | - 62 bit Data |
- | 586 | ||
- | 587 | Structure of data (74 bits): |
|
- | 588 | - OPTIONAL : Sub-millisecond timestamp fraction (0-12 bits) |
|
- | 589 | - OPTIONAL : Carefully seeded counter |
|
- | 590 | - Random generated bits for any remaining space |
|
- | 591 | ||
- | 592 | Since we don't know if timestamp fraction or counters are implemented |
|
- | 593 | (and if so, how many bits), we don't decode this information |
|
586 | */ |
594 | */ |
587 | 595 | ||
588 | echo sprintf("%-32s %s\n", "Version:", "[0x7] Unix Epoch Time"); |
596 | echo sprintf("%-32s %s\n", "Version:", "[0x7] Unix Epoch Time"); |
589 | 597 | ||
590 | $timestamp = substr($uuid, 0, 12); |
598 | $timestamp = substr($uuid, 0, 12); |
Line 1219... | Line 1227... | ||
1219 | 1227 | ||
1220 | # -------------------------------------- |
1228 | # -------------------------------------- |
1221 | // Variant 1, Version 7 (Unix Epoch) UUID |
1229 | // Variant 1, Version 7 (Unix Epoch) UUID |
1222 | # -------------------------------------- |
1230 | # -------------------------------------- |
1223 | 1231 | ||
1224 | function gen_uuid_v7() { |
1232 | function gen_uuid_v7(int $num_ms_frac_bits=12) { |
1225 | return gen_uuid_unix_epoch(); |
1233 | return gen_uuid_unix_epoch($num_ms_frac_bits); |
1226 | } |
1234 | } |
1227 | function gen_uuid_unix_epoch() { |
1235 | function gen_uuid_unix_epoch(int $num_ms_frac_bits=12) { |
1228 | // Start with an UUIDv4 |
- | |
1229 | $uuid = gen_uuid_random(); |
1236 | $uuid_nibbles = ''; |
1230 | 1237 | ||
1231 | // Add the timestamp |
1238 | // Add the timestamp (milliseconds Unix) |
1232 | usleep(1000); // Wait 1ms, to make sure that the time part changes if multiple UUIDs are generated |
- | |
1233 | if (function_exists('gmp_init')) { |
1239 | if (function_exists('gmp_init')) { |
1234 | list($ms,$sec) = explode(' ', microtime(false)); |
1240 | list($ms,$sec) = explode(' ', microtime(false)); |
1235 | $sec = gmp_init($sec, 10); |
1241 | $sec = gmp_init($sec, 10); |
1236 | $ms = gmp_init(substr($ms,2,3), 10); |
1242 | $ms = gmp_init(substr($ms,2,3), 10); |
1237 | $unix_ts = gmp_strval(gmp_add(gmp_mul($sec, '1000'), $ms),16); |
1243 | $unix_ts = gmp_strval(gmp_add(gmp_mul($sec, '1000'), $ms),16); |
1238 | } else { |
1244 | } else { |
1239 | $unix_ts = dechex((int)round(microtime(true)*1000)); |
1245 | $unix_ts = dechex((int)ceil(microtime(true)*1000)); |
1240 | } |
1246 | } |
1241 | $unix_ts = str_pad($unix_ts, 12, '0', STR_PAD_LEFT); |
1247 | $unix_ts = str_pad($unix_ts, 12, '0', STR_PAD_LEFT); |
1242 | for ($i=0;$i<8;$i++) $uuid[$i] = substr($unix_ts, $i, 1); |
1248 | $uuid_nibbles = $unix_ts; |
1243 | for ($i=0;$i<4;$i++) $uuid[9+$i] = substr($unix_ts, 8+$i, 1); |
- | |
1244 | 1249 | ||
1245 | // set version |
1250 | // Version = 7 |
1246 | $uuid[14] = '7'; |
1251 | $uuid_nibbles .= '7'; |
1247 | 1252 | ||
- | 1253 | // Optional: millisecond fraction (max 12 bits) |
|
- | 1254 | if (($num_ms_frac_bits < 0) || ($num_ms_frac_bits > 12)) throw new Exception("Invalid msec frac bits (must be 0..12)"); |
|
- | 1255 | if ($num_ms_frac_bits > 0) { |
|
- | 1256 | $seconds_fraction = (float)explode(' ',microtime(false))[0]; |
|
- | 1257 | $nanoseconds_fraction = $seconds_fraction * 1000000; |
|
- | 1258 | $resolution_ns = 1000000 / pow(2,$num_ms_frac_bits); |
|
- | 1259 | $val = (int)ceil($nanoseconds_fraction / $resolution_ns); |
|
- | 1260 | ||
- | 1261 | // Currently, for the output we only allow frac bits 0, 4, 8, 12 (0-3 nibbles), |
|
- | 1262 | // since UUIDs are usually sorted in their hex notation |
|
- | 1263 | $num_nibbles = (int)ceil($num_ms_frac_bits/4); |
|
- | 1264 | $nibble_string = str_pad(dechex($val), $num_nibbles, '0', STR_PAD_LEFT); |
|
- | 1265 | $uuid_nibbles .= $nibble_string; |
|
- | 1266 | } else { |
|
- | 1267 | $resolution_ns = 1000000; |
|
- | 1268 | } |
|
- | 1269 | ||
- | 1270 | // TODO Not implemented: Optional counter (to be defined as parameter to this method) |
|
- | 1271 | // The counter bits need to be spread before and after the variant bits |
|
- | 1272 | ||
- | 1273 | // Fill with random bits (and the variant bits) |
|
- | 1274 | $uuid = gen_uuid_random(); |
|
- | 1275 | $uuid = str_replace('-', '', $uuid); |
|
- | 1276 | for ($i=0; $i<strlen($uuid_nibbles); $i++) $uuid[$i] = $uuid_nibbles[$i]; |
|
- | 1277 | ||
- | 1278 | // Wait to make sure that the time part changes if multiple UUIDs are generated |
|
- | 1279 | // We don't use usleep(), because it often does not sleep long enough! |
|
- | 1280 | // $resolution_us = (int)ceil($resolution_ns/1000); |
|
- | 1281 | // if ($resolution_us > 0) usleep($resolution_us); |
|
- | 1282 | // We use this naive approach instead: |
|
- | 1283 | if ($num_ms_frac_bits > 0) { |
|
- | 1284 | $seconds_fraction = (float)explode(' ',microtime(false))[0]; |
|
- | 1285 | $nanoseconds_fraction = $seconds_fraction * 1000000; |
|
- | 1286 | $resolution_ns = 1000000 / pow(2,$num_ms_frac_bits); |
|
- | 1287 | $val = (int)ceil($nanoseconds_fraction / $resolution_ns); |
|
- | 1288 | do { |
|
- | 1289 | $seconds_fraction = (float)explode(' ',microtime(false))[0]; |
|
- | 1290 | $nanoseconds_fraction = $seconds_fraction * 1000000; |
|
- | 1291 | $resolution_ns = 1000000 / pow(2,$num_ms_frac_bits); |
|
- | 1292 | $val2 = (int)ceil($nanoseconds_fraction / $resolution_ns); |
|
- | 1293 | } while ($val == $val2); |
|
- | 1294 | } else { |
|
- | 1295 | $unix_ts = dechex((int)ceil(microtime(true)*1000)); |
|
- | 1296 | do { |
|
- | 1297 | $unix_ts2 = dechex((int)ceil(microtime(true)*1000)); |
|
- | 1298 | } while ($unix_ts == $unix_ts2); |
|
- | 1299 | } |
|
- | 1300 | ||
- | 1301 | // Output |
|
1248 | return $uuid; |
1302 | return substr($uuid, 0, 8).'-'. |
- | 1303 | substr($uuid, 8, 4).'-'. |
|
- | 1304 | substr($uuid, 12, 4).'-'. |
|
- | 1305 | substr($uuid, 16, 4).'-'. |
|
- | 1306 | substr($uuid, 20, 12); |
|
1249 | } |
1307 | } |
1250 | 1308 | ||
1251 | # -------------------------------------- |
1309 | # -------------------------------------- |
1252 | // Variant 1, Version 8 (Custom) UUID |
1310 | // Variant 1, Version 8 (Custom) UUID |
1253 | # -------------------------------------- |
1311 | # -------------------------------------- |