Subversion Repositories oidinfo_api

Rev

Rev 36 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 36 Rev 43
Line 1... Line 1...
1
<?php
1
<?php
2
 
2
 
3
/*
3
/*
4
 * UUID utils for PHP
4
 * UUID utils for PHP
5
 * Copyright 2011 - 2023 Daniel Marschall, ViaThinkSoft
5
 * Copyright 2011 - 2024 Daniel Marschall, ViaThinkSoft
6
 * Version 2023-11-11
6
 * Version 2024-03-09
7
 *
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
10
 * You may obtain a copy of the License at
11
 *
11
 *
Line 831... Line 831...
831
                case 3:
831
                case 3:
832
                        echo sprintf("%-32s %s\n", "Variant:", "[0b111] Reserved for future use");
832
                        echo sprintf("%-32s %s\n", "Variant:", "[0b111] Reserved for future use");
833
                        break;
833
                        break;
834
        }
834
        }
835
 
835
 
-
 
836
        // START: HickelSOFT UUID
-
 
837
 
-
 
838
        // Block 5
-
 
839
        $signature = substr($uuid,20,12);
-
 
840
        if (strtolower($signature) == '5ce32bd83b96') {
-
 
841
                // HickelSOFT "SQL Server sortable UUID in C#"
-
 
842
                // Version 2: Resolution of 1 milliseconds, random part of 18 bits, UTC time, UUIDv8 conform.
-
 
843
                // Example: 2088dc33-000d-8045-87e8-5ce32bd83b96
-
 
844
                // Block 4
-
 
845
                $unused2bits = hexdec(substr($uuid,16,1)) & 0x3;
-
 
846
                $year = hexdec(substr($uuid,17,3));
-
 
847
                // Block 3
-
 
848
                $dayOfYear = hexdec(substr($uuid,13,3)); // 1..366
-
 
849
                $day = (($dayOfYear < 1) || ($dayOfYear > 366)) ? "XX" : intval(getDateFromDay($year, $dayOfYear)->format('d'));
-
 
850
                $month = (($dayOfYear < 1) || ($dayOfYear > 366)) ? "XX" : intval(getDateFromDay($year, $dayOfYear)->format('m'));
-
 
851
                // Block 2
-
 
852
                $minuteOfDay = hexdec(substr($uuid,8,4)); // 1..1440
-
 
853
                $minutes = (($minuteOfDay < 1) || ($minuteOfDay > 1440)) ? "XX" : ($minuteOfDay-1) % 60;
-
 
854
                $hours = (($minuteOfDay < 1) || ($minuteOfDay > 1440)) ? "XX" : (int)floor(($minuteOfDay-1) / 60);
-
 
855
                // Block 1
-
 
856
                $rnd16bits = substr($uuid,0,4);
-
 
857
                $millisecond8bits = hexdec(substr($uuid,4,2));
-
 
858
                $milliseconds = round($millisecond8bits / 255 * 999);
-
 
859
                $seconds = hexdec(substr($uuid,6,2));
-
 
860
                // Verbose info
-
 
861
                $utc_time =
-
 
862
                        str_pad("$year",4,'0',STR_PAD_LEFT).'-'.
-
 
863
                        str_pad("$month",2,'0',STR_PAD_LEFT).'-'.
-
 
864
                        str_pad("$day",2,'0',STR_PAD_LEFT).' '.
-
 
865
                        str_pad("$hours",2,'0',STR_PAD_LEFT).':'.
-
 
866
                        str_pad("$minutes",2,'0',STR_PAD_LEFT).':'.
-
 
867
                        str_pad("$seconds",2,'0',STR_PAD_LEFT)."'".
-
 
868
                        str_pad("$milliseconds",2,'0',STR_PAD_LEFT);
-
 
869
                if (strpos($utc_time,'X') === false) {
-
 
870
                        $deviation = "(deviation -2ms..2ms)";
-
 
871
                        echo "\n<u>Interpretation of <a href=\"https://gist.github.com/danielmarschall/7fafd270a3bc107d38e8449ce7420c25\">HickelSOFT \"SQL Server Sortable Custom UUID\", Version 2</a></u>\n\n";
-
 
872
                        echo sprintf("%-32s %s\n", "Random 16 bits:", "[0x$rnd16bits] 0b".str_pad("".base_convert($rnd16bits, 16, 2), 16, '0', STR_PAD_LEFT));
-
 
873
                        echo sprintf("%-32s %s\n", "Milliseconds:", "[0x".substr($uuid,4,2)."] $milliseconds $deviation");
-
 
874
                        echo sprintf("%-32s %s\n", "Seconds:", "[0x".substr($uuid,6,2)."] $seconds");
-
 
875
                        echo sprintf("%-32s %s\n", "Minute of day:", "[0x".substr($uuid,8,4)."] $minuteOfDay (".str_pad("$hours",2,'0',STR_PAD_LEFT).":".str_pad("$minutes",2,'0',STR_PAD_LEFT).")");
-
 
876
                        echo sprintf("%-32s %s\n", "Day of year:", "[0x".substr($uuid,13,3)."] $dayOfYear (Day=$day, Month=$month)");
-
 
877
                        echo sprintf("%-32s %s\n", "Unused 2 bits:", "[$unused2bits] 0b".str_pad("".base_convert("$unused2bits", 16, 2), 2, '0', STR_PAD_LEFT));
-
 
878
                        echo sprintf("%-32s %s\n", "Year:", "[0x".substr($uuid,17,3)."] $year");
-
 
879
                        echo sprintf("%-32s %s\n", "Signature:", "[0x".substr($uuid,20,12)."] HickelSOFT \"SQL Server Sortable Custom UUID\", Version 2 (very likely)");
-
 
880
                        echo sprintf("%-32s %s\n", "UTC Date Time:", "$utc_time $deviation");
-
 
881
                }
-
 
882
        } else if (strtolower($signature) == '000000000000') {
-
 
883
                // HickelSOFT "SQL Server sortable UUID in C#"
-
 
884
                // Version 1: Resolution of 1 milliseconds, random part of 16 bits, local timezone, NOT UUIDv8 conform.
-
 
885
                // Example: ff38da51-1301-0903-2420-000000000000
-
 
886
                // Block 4
-
 
887
                $year = substr($uuid,18,2) . substr($uuid,16,2);
-
 
888
                $year = (!is_numeric($year) || ($year < 2000) || ($year > 2999)) ? "XXXX" : $year = intval($year);
-
 
889
                // Block 3
-
 
890
                $day = substr($uuid,12,2);
-
 
891
                $day = (!is_numeric($day) || ($day < 0) || ($day >= 60)) ? "XX" : intval($day);
-
 
892
                $month = substr($uuid,14,2);
-
 
893
                $month = (!is_numeric($month) || ($month < 0) || ($month >= 60)) ? "XX" : intval($month);
-
 
894
                // Block 2
-
 
895
                $minutes = substr($uuid,8,2);
-
 
896
                $minutes = (!is_numeric($minutes) || ($minutes < 0) || ($minutes >= 60)) ? "XX" : intval($minutes);
-
 
897
                $hours = substr($uuid,10,2);
-
 
898
                $hours = (!is_numeric($hours) || ($hours < 0) || ($hours >= 60)) ? "XX" : intval($hours);
-
 
899
                // Block 1
-
 
900
                $rnd16bits = substr($uuid,0,4);
-
 
901
                $millisecond8bits = hexdec(substr($uuid,4,2));
-
 
902
                $milliseconds = round($millisecond8bits / 255 * 999);
-
 
903
                $seconds = substr($uuid,6,2);
-
 
904
                $seconds = (!is_numeric($seconds) || ($seconds < 0) || ($seconds >= 60)) ? "XX" : intval($seconds);
-
 
905
                // Verbose info
-
 
906
                $local_time =
-
 
907
                        str_pad("$year",4,'0',STR_PAD_LEFT).'-'.
-
 
908
                        str_pad("$month",2,'0',STR_PAD_LEFT).'-'.
-
 
909
                        str_pad("$day",2,'0',STR_PAD_LEFT).' '.
-
 
910
                        str_pad("$hours",2,'0',STR_PAD_LEFT).':'.
-
 
911
                        str_pad("$minutes",2,'0',STR_PAD_LEFT).':'.
-
 
912
                        str_pad("$seconds",2,'0',STR_PAD_LEFT)."'".
-
 
913
                        str_pad("$milliseconds",2,'0',STR_PAD_LEFT);
-
 
914
                if (strpos($local_time,'X') === false) {
-
 
915
                        $deviation = "(deviation -4ms..0ms)";
-
 
916
                        echo "\n<u>Interpretation of <a href=\"https://gist.github.com/danielmarschall/7fafd270a3bc107d38e8449ce7420c25\">HickelSOFT \"SQL Server Sortable Custom UUID\", Version 1</a></u>\n\n";
-
 
917
                        echo sprintf("%-32s %s\n", "Random 16 bits:", "[0x$rnd16bits] 0b".str_pad(base_convert($rnd16bits, 16, 2), 16, '0', STR_PAD_LEFT));
-
 
918
                        echo sprintf("%-32s %s\n", "Milliseconds:", "[0x".substr($uuid,4,2)."] $milliseconds $deviation");
-
 
919
                        echo sprintf("%-32s %s\n", "Seconds:", "[0x".substr($uuid,6,2)."] $seconds");
-
 
920
                        echo sprintf("%-32s %s\n", "Minutes:", "[0x".substr($uuid,8,2)."] $minutes");
-
 
921
                        echo sprintf("%-32s %s\n", "Hours:", "[0x".substr($uuid,10,2)."] $hours");
-
 
922
                        echo sprintf("%-32s %s\n", "Day:", "[0x".substr($uuid,12,2)."] $day");
-
 
923
                        echo sprintf("%-32s %s\n", "Month:", "[0x".substr($uuid,14,2)."] $month");
-
 
924
                        echo sprintf("%-32s %s\n", "Year:", "[0x".substr($uuid,16,4)."] $year");
-
 
925
                        echo sprintf("%-32s %s\n", "Signature:", "[0x".substr($uuid,20,12)."] HickelSOFT \"SQL Server Sortable Custom UUID\", Version 1 (maybe)");
-
 
926
                        echo sprintf("%-32s %s\n", "Generator's Local Date Time:", "$local_time $deviation");
-
 
927
                }
-
 
928
        }
-
 
929
 
-
 
930
        // END: HickelSOFT UUID
-
 
931
 
836
        if (!$echo) {
932
        if (!$echo) {
837
                $out = ob_get_contents();
933
                $out = ob_get_contents();
838
                ob_end_clean();
934
                ob_end_clean();
839
                return $out;
935
                return $out;
840
        } else {
936
        } else {
Line 845... Line 941...
845
function uuid_canonize($uuid) {
941
function uuid_canonize($uuid) {
846
        if (!uuid_valid($uuid)) return false;
942
        if (!uuid_valid($uuid)) return false;
847
        return oid_to_uuid(uuid_to_oid($uuid));
943
        return oid_to_uuid(uuid_to_oid($uuid));
848
}
944
}
849
 
945
 
-
 
946
/*
-
 
947
assert(oid_to_uuid('2.25.111325678376819997685911819737516232943')=='53c08bb6-b2eb-5038-bf28-ad41a08c50ef');
-
 
948
assert(oid_to_uuid('1.2.840.113556.1.8000.2554.21440.35766.45803.20536.48936.11354528.9195759')=='53c08bb6-b2eb-5038-bf28-ad41a08c50ef');
-
 
949
assert(oid_to_uuid('1.3.6.1.4.1.54392.1.6034977117478539320.13774449957690691823')=='53c08bb6-b2eb-5038-bf28-ad41a08c50ef');
-
 
950
assert(oid_to_uuid('1.3.6.1.4.1.54392.2.1405127606.3001765944.3207114049.2693550319')=='53c08bb6-b2eb-5038-bf28-ad41a08c50ef');
-
 
951
assert(oid_to_uuid('1.3.6.1.4.1.54392.3.21440.35766.45803.20536.48936.44353.41100.20719')=='53c08bb6-b2eb-5038-bf28-ad41a08c50ef');
-
 
952
*/
850
function oid_to_uuid($oid) {
953
function oid_to_uuid($oid) {
851
        // TODO: Also support Non-2.25 base UUID-to-OID
-
 
852
        if (!is_uuid_oid($oid,true)) return false;
-
 
853
 
-
 
854
        if (substr($oid,0,1) == '.') {
954
        if (substr($oid,0,1) == '.') $oid = substr($oid, 1); // remove leading dot
855
                $oid = substr($oid, 1);
-
 
856
        }
-
 
857
        $ary = explode('.', $oid);
-
 
858
 
955
 
859
        if (!isset($ary[2])) return false;
956
        // Information about Microsoft and Waterjuice UUID-OID: https://waterjuiceweb.wordpress.com/2019/09/24/guids-to-oids/
860
 
957
 
-
 
958
        $ary = explode('.', $oid);
-
 
959
        if ((count($ary) == 3) && (strpos($oid, '2.25.') === 0)) {
-
 
960
                // ISO/ITU-T UUID-to-OID
-
 
961
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 2.25.111325678376819997685911819737516232943
861
        $val = $ary[2];
962
                $val = $ary[2];
862
 
-
 
863
        $x = gmp_init($val, 10);
963
                $dec = gmp_init($val, 10);
864
        $y = gmp_strval($x, 16);
964
                $hex = gmp_strval($dec, 16);
865
        $y = str_pad($y, 32, "0", STR_PAD_LEFT);
965
                $hex = str_pad($hex, 32, "0", STR_PAD_LEFT);
-
 
966
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
-
 
967
        } else if ((count($ary) == 14) && (strpos($oid, '1.2.840.113556.1.8000.2554.') === 0)) {
866
        return substr($y,  0, 8).'-'.
968
                // Microsoft UUID-to-OID
-
 
969
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.2.840.113556.1.8000.2554.21440.35766.45803.20536.48936.11354528.9195759
-
 
970
                $a = intval($ary[7]);
867
               substr($y,  8, 4).'-'.
971
                $b = intval($ary[8]);
-
 
972
                $c = intval($ary[9]);
868
               substr($y, 12, 4).'-'.
973
                $d = intval($ary[10]);
869
               substr($y, 16, 4).'-'.
974
                $e = intval($ary[11]);
870
               substr($y, 20, 12);
975
                $f = intval($ary[12]);
-
 
976
                $g = intval($ary[13]);
-
 
977
                return dechex($a).dechex($b).'-'.dechex($c).'-'.dechex($d).'-'.dechex($e).'-'.dechex($f).dechex($g);
-
 
978
        } else if ((count($ary) == 10) && (strpos($oid, '1.3.6.1.4.1.54392.1.') === 0)) {
-
 
979
                // Waterjuice UUID-to-OID 2x64 Bits
-
 
980
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.3.6.1.4.1.54392.1.6034977117478539320.13774449957690691823
-
 
981
                $a1 = gmp_strval(gmp_init($ary[8],10),16); if (strlen($a1)>16) return false;
-
 
982
                $a2 = gmp_strval(gmp_init($ary[9],10),16); if (strlen($a2)>16) return false;
-
 
983
                $hex =
-
 
984
                        str_pad($a1, 16, "0", STR_PAD_LEFT).
-
 
985
                        str_pad($a2, 16, "0", STR_PAD_LEFT);
-
 
986
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
-
 
987
        } else if ((count($ary) == 12) && (strpos($oid, '1.3.6.1.4.1.54392.2.') === 0)) {
-
 
988
                // Waterjuice UUID-to-OID 4x32 Bits
-
 
989
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.3.6.1.4.1.54392.2.1405127606.3001765944.3207114049.2693550319
-
 
990
                $a1 = gmp_strval(gmp_init($ary[8],10),16); if (strlen($a1)>8) return false;
-
 
991
                $a2 = gmp_strval(gmp_init($ary[9],10),16); if (strlen($a2)>8) return false;
-
 
992
                $a3 = gmp_strval(gmp_init($ary[10],10),16); if (strlen($a3)>8) return false;
-
 
993
                $a4 = gmp_strval(gmp_init($ary[11],10),16); if (strlen($a4)>8) return false;
-
 
994
                $hex =
-
 
995
                        str_pad($a1, 8, "0", STR_PAD_LEFT).
-
 
996
                        str_pad($a2, 8, "0", STR_PAD_LEFT).
-
 
997
                        str_pad($a3, 8, "0", STR_PAD_LEFT).
-
 
998
                        str_pad($a4, 8, "0", STR_PAD_LEFT);
-
 
999
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
-
 
1000
        } else if ((count($ary) == 16) && (strpos($oid, '1.3.6.1.4.1.54392.3.') === 0)) {
-
 
1001
                // Waterjuice UUID-to-OID 8x16 Bits
-
 
1002
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.3.6.1.4.1.54392.3.21440.35766.45803.20536.48936.44353.41100.20719
-
 
1003
                $a1 = gmp_strval(gmp_init($ary[8],10),16); if (strlen($a1)>4) return false;
-
 
1004
                $a2 = gmp_strval(gmp_init($ary[9],10),16); if (strlen($a2)>4) return false;
-
 
1005
                $a3 = gmp_strval(gmp_init($ary[10],10),16); if (strlen($a3)>4) return false;
-
 
1006
                $a4 = gmp_strval(gmp_init($ary[11],10),16); if (strlen($a4)>4) return false;
-
 
1007
                $a5 = gmp_strval(gmp_init($ary[12],10),16); if (strlen($a5)>4) return false;
-
 
1008
                $a6 = gmp_strval(gmp_init($ary[13],10),16); if (strlen($a6)>4) return false;
-
 
1009
                $a7 = gmp_strval(gmp_init($ary[14],10),16); if (strlen($a7)>4) return false;
-
 
1010
                $a8 = gmp_strval(gmp_init($ary[15],10),16); if (strlen($a8)>4) return false;
-
 
1011
                $hex =
-
 
1012
                        str_pad($a1, 4, "0", STR_PAD_LEFT).
-
 
1013
                        str_pad($a2, 4, "0", STR_PAD_LEFT).
-
 
1014
                        str_pad($a3, 4, "0", STR_PAD_LEFT).
-
 
1015
                        str_pad($a4, 4, "0", STR_PAD_LEFT).
-
 
1016
                        str_pad($a5, 4, "0", STR_PAD_LEFT).
-
 
1017
                        str_pad($a6, 4, "0", STR_PAD_LEFT).
-
 
1018
                        str_pad($a7, 4, "0", STR_PAD_LEFT).
-
 
1019
                        str_pad($a8, 4, "0", STR_PAD_LEFT);
-
 
1020
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
-
 
1021
        } else {
-
 
1022
                return false;
-
 
1023
        }
871
}
1024
}
872
 
1025
 
873
function is_uuid_oid($oid, $only_allow_root=false) {
1026
function is_uuid_oid($oid, $only_allow_root=false) {
874
        // TODO: Also support Non-2.25 base UUID-to-OID
-
 
875
        if (substr($oid,0,1) == '.') $oid = substr($oid, 1); // remove leading dot
1027
        if (substr($oid,0,1) == '.') $oid = substr($oid, 1); // remove leading dot
876
 
1028
 
877
        $ary = explode('.', $oid);
-
 
878
 
-
 
879
        if ($only_allow_root) {
1029
        if ($only_allow_root) {
880
                if (count($ary) != 3) return false;
1030
                return oid_to_uuid($oid) !== false;
881
        } else {
1031
        } else {
882
                if (count($ary) < 3) return false;
1032
                // TODO: Check range of the components (e.g. max 128 bits for 2.25)
883
        }
-
 
884
 
-
 
885
        if ($ary[0] != '2') return false;
1033
                if (strpos($oid,'2.25.') === 0) return true;
886
        if ($ary[1] != '25') return false;
1034
                if (strpos($oid,'1.2.840.113556.1.8000.2554.') === 0) return true;
887
        for ($i=2; $i<count($ary); $i++) {
-
 
888
                $v = $ary[$i];
-
 
889
                if (!is_numeric($v)) return false;
1035
                if (strpos($oid,'1.3.6.1.4.1.54392.1.') === 0) return true;
890
                if ($i == 2) {
-
 
891
                        // Must be in the range of 128 bit UUID
1036
                if (strpos($oid,'1.3.6.1.4.1.54392.2.') === 0) return true;
892
                        $test = gmp_init($v, 10);
-
 
893
                        if (strlen(gmp_strval($test, 16)) > 32) return false;
1037
                if (strpos($oid,'1.3.6.1.4.1.54392.3.') === 0) return true;
894
                }
-
 
895
                if ($v < 0) return false;
1038
                return false;
896
        }
1039
        }
897
 
-
 
898
        return true;
-
 
899
}
1040
}
900
 
1041
 
901
function uuid_to_oid($uuid, $base='2.25') {
1042
function uuid_to_oid($uuid, $base='2.25') {
902
        if (!uuid_valid($uuid)) return false;
1043
        if (!uuid_valid($uuid)) return false;
903
        #$base = oid_sanitize($base);
1044
        #$base = oid_sanitize($base);
Line 1407... Line 1548...
1407
               substr($hash, 12, 4).'-'.
1548
               substr($hash, 12, 4).'-'.
1408
               substr($hash, 16, 4).'-'.
1549
               substr($hash, 16, 4).'-'.
1409
               substr($hash, 20, 12);
1550
               substr($hash, 20, 12);
1410
}
1551
}
1411
 
1552
 
-
 
1553
/**
-
 
1554
 * The sorting of SQL Server is rather confusing and incompatible with UUIDv6 and UUIDv7.
-
 
1555
 * Therefore this method generates UUID which are sortable by SQL Server.
-
 
1556
 * Version 1: Resolution of 1 milliseconds, random part of 16 bits, local timezone, 48 zero bits "signature", NOT UUIDv8 conform.
-
 
1557
 * Version 2: Resolution of 1 milliseconds, random part of 16 bits, UTC time, 48 bit random "signature", UUIDv8 conform.
-
 
1558
 * C# implementation: https://gist.github.com/danielmarschall/7fafd270a3bc107d38e8449ce7420c25
-
 
1559
 * PHP implementation: https://github.com/danielmarschall/uuid_mac_utils/blob/master/includes/uuid_utils.inc.php
-
 
1560
 *
-
 
1561
 * @param int      $hickelUuidVersion (optional)
-
 
1562
 * @param DateTime $dt                (optional)
-
 
1563
 * @return string The UUID
-
 
1564
 */
-
 
1565
function gen_uuid_v8_sqlserver_sortable(int $hickelUuidVersion = 2, DateTime $dt = null): string {
-
 
1566
        // The sorting in SQL Server is like this:
-
 
1567
 
-
 
1568
        if ($dt == null) $dt = new DateTime();
-
 
1569
 
-
 
1570
        // First Sort block 5, nibbles from left to right (i.e. 000000000001 < 000000000010 < ... < 010000000000 < 100000000000)
-
 
1571
        if ($hickelUuidVersion == 1) {
-
 
1572
                $block5 = "000000000000";
-
 
1573
        } else if ($hickelUuidVersion == 2) {
-
 
1574
                $block5 = "5ce32bd83b96";
-
 
1575
        } else {
-
 
1576
                throw new Exception("Invalid version");
-
 
1577
        }
-
 
1578
 
-
 
1579
        // Then: Sort block 4, nibbles from left to right
-
 
1580
        if ($hickelUuidVersion == 1) {
-
 
1581
                $year = $dt->format('Y');
-
 
1582
                $block4 = substr($year, 2, 2).substr($year, 0, 2); // Example: 0x2420 = 2024
-
 
1583
        } else {
-
 
1584
                $variant = 0x8; // First nibble needs to be 0b10_ (0x8-0xB) for "RFC 4122bis". We use it to store 2 more random bits.
-
 
1585
                $unused2bits = 0; // Cannot be used for random, because it would affect the sorting
-
 
1586
                $year = $dt->format('Y');
-
 
1587
                $block4 = sprintf('%01x%03x', $variant + ($unused2bits & 0x3), $year);
-
 
1588
        }
-
 
1589
 
-
 
1590
        // Then: Sort block 3, bytes from right to left (i.e. 0100 < 1000 < 0001 < 0010)
-
 
1591
        if ($hickelUuidVersion == 1) {
-
 
1592
                $block3 = $dt->format('dm');
-
 
1593
        } else {
-
 
1594
                $uuidVersion = 8; // First nibble needs to be "8" for "UUIDv8 = Custom UUID"
-
 
1595
                $dayOfYear = intval($dt->format('z')) + 1; /* 1..366 */
-
 
1596
                $block3 = sprintf('%01x%03x', $uuidVersion, $dayOfYear);
-
 
1597
        }
-
 
1598
 
-
 
1599
        // Then: Sort block 2, bytes from right to left
-
 
1600
        if ($hickelUuidVersion == 1) {
-
 
1601
                $block2 = $dt->format('ih');
-
 
1602
        } else {
-
 
1603
                $minuteOfDay = (intval($dt->format('i')) + intval($dt->format('h')) * 60) + 1; // 1..1440
-
 
1604
                $block2 = sprintf('%04x', $minuteOfDay);
-
 
1605
        }
-
 
1606
 
-
 
1607
        // Then: Sort block 1, bytes from right to left
-
 
1608
        if ($hickelUuidVersion == 1) {
-
 
1609
                $millisecond8bits = ceil(($dt->format('v') / 999) * 255); // deviation -4ms..0ms
-
 
1610
                $rnd16bits = _random_int(0x0000, 0xFFFF-1);
-
 
1611
                $block1 = sprintf('%04x%02x', $rnd16bits, $millisecond8bits).$dt->format('s');
-
 
1612
        } else {
-
 
1613
                $millisecond8bits = round(($dt->format('v') / 999) * 255); // deviation -2ms..2ms
-
 
1614
                $rnd16bits = _random_int(0x0000, 0xFFFF);
-
 
1615
                $block1 = sprintf('%04x%02x%02x', $rnd16bits, $millisecond8bits, $dt->format('s'));
-
 
1616
        }
-
 
1617
 
-
 
1618
        $sleep_ms = (int)ceil(999 / 255); // Make sure that "millisecond" is not repeated on this system
-
 
1619
        if (time_nanosleep(0,$sleep_ms*1000*1000) !== true) usleep($sleep_ms*1000);
-
 
1620
 
-
 
1621
        return strtolower("$block1-$block2-$block3-$block4-$block5");
-
 
1622
}
-
 
1623
 
1412
# --------------------------------------
1624
# --------------------------------------
1413
 
1625
 
1414
// http://php.net/manual/de/function.hex2bin.php#113057
1626
// http://php.net/manual/de/function.hex2bin.php#113057
1415
if (!function_exists('hex2bin')) {
1627
if (!function_exists('hex2bin')) {
1416
    function hex2bin($str) {
1628
    function hex2bin($str) {
Line 1449... Line 1661...
1449
        $sponge = SHA3::init(SHA3::SHAKE256);
1661
        $sponge = SHA3::init(SHA3::SHAKE256);
1450
        $sponge->absorb($msg);
1662
        $sponge->absorb($msg);
1451
        $bin = $sponge->squeeze($outputLength);
1663
        $bin = $sponge->squeeze($outputLength);
1452
        return $binary ? $bin : bin2hex($bin);
1664
        return $binary ? $bin : bin2hex($bin);
1453
}
1665
}
-
 
1666
 
-
 
1667
/**
-
 
1668
 * Converts the day of year of a year into a DateTime object
-
 
1669
 * @param int $year The year
-
 
1670
 * @param int $dayOfYear The day of year (value 1 till 365 or 1 till 366 for leap years)
-
 
1671
 * @return \DateTime The resulting date
-
 
1672
 */
-
 
1673
function getDateFromDay(int $year, int $dayOfYear): \DateTime {
-
 
1674
        // Note: "Y z" and "z Y" make a difference for leap years (last tested with PHP 8.0.3)
-
 
1675
        $date = \DateTime::createFromFormat('Y z', strval($year) . ' ' . strval($dayOfYear-1));
-
 
1676
        return $date;
-
 
1677
}
-
 
1678