Subversion Repositories uuid_mac_utils

Rev

Rev 81 | Rev 83 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 81 Rev 82
Line 1546... Line 1546...
1546
               substr($hash, 12, 4).'-'.
1546
               substr($hash, 12, 4).'-'.
1547
               substr($hash, 16, 4).'-'.
1547
               substr($hash, 16, 4).'-'.
1548
               substr($hash, 20, 12);
1548
               substr($hash, 20, 12);
1549
}
1549
}
1550
 
1550
 
-
 
1551
/**
-
 
1552
 * The sorting of SQL Server is rather confusing and incompatible with UUIDv6 and UUIDv7.
-
 
1553
 * Therefore this method generates UUID which are sortable by SQL Server.
-
 
1554
 * Version 1: Resolution of 1 milliseconds, random part of 16 bits, local timezone, NOT UUIDv8 conform.
-
 
1555
 * Version 2: Resolution of 1 milliseconds, random part of 18 bits, UTC time, UUIDv8 conform.
-
 
1556
 * C# implementation: https://gist.github.com/danielmarschall/7fafd270a3bc107d38e8449ce7420c25
-
 
1557
 * PHP implementation: https://github.com/danielmarschall/uuid_mac_utils/blob/master/includes/uuid_utils.inc.php
-
 
1558
 *
-
 
1559
 * @param int      $hickelUuidVersion (optional)
-
 
1560
 * @param DateTime $dt                (optional)
-
 
1561
 * @return string The UUID
-
 
1562
 */
-
 
1563
function gen_uuid_v8_sqlserver_sortable(int $hickelUuidVersion = 2, DateTime $dt = null): string {
-
 
1564
        // The sorting in SQL Server is like this:
-
 
1565
 
-
 
1566
        if ($dt == null) $dt = new DateTime();
-
 
1567
 
-
 
1568
        // First Sort block 5, nibbles from left to right (i.e. 000000000001 < 000000000010 < ... < 010000000000 < 100000000000)
-
 
1569
        if ($hickelUuidVersion == 1) {
-
 
1570
                $block5 = "000000000000";
-
 
1571
        } else if ($hickelUuidVersion == 2) {
-
 
1572
                $block5 = "4849434B454C"/*Hex:"HICKEL"*/;
-
 
1573
        } else {
-
 
1574
                throw new Exception("Invalid version");
-
 
1575
        }
-
 
1576
 
-
 
1577
        // Then: Sort block 4, nibbles from left to right
-
 
1578
        if ($hickelUuidVersion == 1) {
-
 
1579
                $year = $dt->format('Y');
-
 
1580
                $block4 = substr($year, 2, 2).substr($year, 0, 2); // Example: 0x2420 = 2024
-
 
1581
        } else {
-
 
1582
                $variant = 0x8; // First nibble needs to be 0b10_ (0x8-0xB) for "RFC 4122bis". We use it to store 2 more random bits.
-
 
1583
                $rnd2bits = rand(0x0, 0x3);
-
 
1584
                $year = $dt->format('Y');
-
 
1585
                $block4 = sprintf('%01x%03x', $variant + ($rnd2bits & 0x3), $year);
-
 
1586
        }
-
 
1587
 
-
 
1588
        // Then: Sort block 3, bytes from right to left (i.e. 0100 < 1000 < 0001 < 0010)
-
 
1589
        if ($hickelUuidVersion == 1) {
-
 
1590
                $block3 = $dt->format('dm');
-
 
1591
        } else {
-
 
1592
                $uuidVersion = 8; // First nibble needs to be "8" for "UUIDv8 = Custom UUID"
-
 
1593
                $dayOfYear = intval($dt->format('z')) + 1; /* 1..366 */
-
 
1594
                $block3 = sprintf('%01x%03x', $uuidVersion, $dayOfYear);
-
 
1595
        }
-
 
1596
 
-
 
1597
        // Then: Sort block 2, bytes from right to left
-
 
1598
        if ($hickelUuidVersion == 1) {
-
 
1599
                $block2 = $dt->format('ih');
-
 
1600
        } else {
-
 
1601
                $minuteOfDay = (intval($dt->format('i')) + intval($dt->format('h')) * 60) + 1; // 1..1440
-
 
1602
                $block2 = sprintf('%04x', $minuteOfDay);
-
 
1603
        }
-
 
1604
 
-
 
1605
        // Then: Sort block 1, bytes from right to left
-
 
1606
        $millisecond8bits = ceil(($dt->format('v') / 999) * 255);
-
 
1607
        if ($hickelUuidVersion == 1) {
-
 
1608
                $rnd16bits = rand(0x0000, 0xFFFF-1);
-
 
1609
                $block1 = sprintf('%04x%02x', $rnd16bits, $millisecond8bits).$dt->format('s');
-
 
1610
        } else {
-
 
1611
                $rnd16bits = rand(0x0000, 0xFFFF);
-
 
1612
                $block1 = sprintf('%04x%02x%02x', $rnd16bits, $millisecond8bits, $dt->format('s'));
-
 
1613
        }
-
 
1614
 
-
 
1615
        // Now build and parse UUID
-
 
1616
        usleep((int)ceil(999 / 255)); // Make sure that "millisecond" is not repeated on this system
-
 
1617
        return "$block1-$block2-$block3-$block4-$block5";
-
 
1618
}
-
 
1619
 
1551
# --------------------------------------
1620
# --------------------------------------
1552
 
1621
 
1553
// http://php.net/manual/de/function.hex2bin.php#113057
1622
// http://php.net/manual/de/function.hex2bin.php#113057
1554
if (!function_exists('hex2bin')) {
1623
if (!function_exists('hex2bin')) {
1555
    function hex2bin($str) {
1624
    function hex2bin($str) {