Subversion Repositories oidplus

Rev

Rev 1438 | Rev 1470 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1438 Rev 1469
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-18
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
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
18
 * limitations under the License.
19
 */
19
 */
20
 
20
 
21
# This library requires either the GMP extension (or BCMath if gmp_supplement.inc.php is present)
21
# This library requires either the GMP extension (or BCMath if gmp_supplement.inc.php is present)
22
// TODO: If we are on 64 bit PHP (PHP_INT_SIZE > 4), then replace GMP with normal PHP operations
22
// TODO: If we are on 64 bit PHP (PHP_INT_SIZE > 4), then replace GMP with normal PHP operations
23
 
23
 
24
if (file_exists($f = __DIR__ . '/mac_utils.inc.php')) include_once $f;
24
if (file_exists($f = __DIR__ . '/mac_utils.inc.php')) include_once $f;
25
else if (file_exists($f = __DIR__ . '/mac_utils.inc.phps')) include_once $f;
25
else if (file_exists($f = __DIR__ . '/mac_utils.inc.phps')) include_once $f;
26
 
26
 
27
if (file_exists($f = __DIR__ . '/gmp_supplement.inc.php')) include_once $f;
27
if (file_exists($f = __DIR__ . '/gmp_supplement.inc.php')) include_once $f;
28
else if (file_exists($f = __DIR__ . '/gmp_supplement.inc.phps')) include_once $f;
28
else if (file_exists($f = __DIR__ . '/gmp_supplement.inc.phps')) include_once $f;
29
 
29
 
30
if (file_exists($f = __DIR__ . '/OidDerConverter.class.php')) include_once $f;
30
if (file_exists($f = __DIR__ . '/OidDerConverter.class.php')) include_once $f;
31
else if (file_exists($f = __DIR__ . '/OidDerConverter.class.phps')) include_once $f;
31
else if (file_exists($f = __DIR__ . '/OidDerConverter.class.phps')) include_once $f;
32
 
32
 
33
// Note: The RFC allows various notations as payload, not a strict notation constraint
33
// Note: The RFC allows various notations as payload, not a strict notation constraint
34
const UUID_NAMEBASED_NS_DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
34
const UUID_NAMEBASED_NS_DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
35
const UUID_NAMEBASED_NS_URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
35
const UUID_NAMEBASED_NS_URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
36
const UUID_NAMEBASED_NS_OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8';
36
const UUID_NAMEBASED_NS_OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8';
37
const UUID_NAMEBASED_NS_X500_DN = '6ba7b814-9dad-11d1-80b4-00c04fd430c8';
37
const UUID_NAMEBASED_NS_X500_DN = '6ba7b814-9dad-11d1-80b4-00c04fd430c8';
38
 
38
 
39
if (!function_exists('_random_int')) {
39
if (!function_exists('_random_int')) {
40
        function _random_int($min, $max) {
40
        function _random_int($min, $max) {
41
                // This function tries a CSRNG and falls back to a RNG if no CSRNG is available
41
                // This function tries a CSRNG and falls back to a RNG if no CSRNG is available
42
                try {
42
                try {
43
                        return random_int($min, $max);
43
                        return random_int($min, $max);
44
                } catch (Exception $e) {
44
                } catch (Exception $e) {
45
                        return mt_rand($min, $max);
45
                        return mt_rand($min, $max);
46
                }
46
                }
47
        }
47
        }
48
}
48
}
49
 
49
 
50
function uuid_valid($uuid) {
50
function uuid_valid($uuid) {
51
        $uuid = str_replace(array('-', '{', '}'), '', $uuid);
51
        $uuid = str_replace(array('-', '{', '}'), '', $uuid);
52
        $uuid = strtoupper($uuid);
52
        $uuid = strtoupper($uuid);
53
        #$uuid = trim($uuid);
53
        #$uuid = trim($uuid);
54
 
54
 
55
        if (strlen($uuid) != 32) return false;
55
        if (strlen($uuid) != 32) return false;
56
 
56
 
57
        $uuid = preg_replace('@[0-9A-F]@i', '', $uuid);
57
        $uuid = preg_replace('@[0-9A-F]@i', '', $uuid);
58
 
58
 
59
        return ($uuid == '');
59
        return ($uuid == '');
60
}
60
}
61
 
61
 
62
function uuid_equal($uuid1, $uuid2) {
62
function uuid_equal($uuid1, $uuid2) {
63
        $uuid1 = uuid_canonize($uuid1);
63
        $uuid1 = uuid_canonize($uuid1);
64
        if (!$uuid1) return false;
64
        if (!$uuid1) return false;
65
        $uuid2 = uuid_canonize($uuid2);
65
        $uuid2 = uuid_canonize($uuid2);
66
        if (!$uuid2) return false;
66
        if (!$uuid2) return false;
67
        return $uuid1 === $uuid2;
67
        return $uuid1 === $uuid2;
68
}
68
}
69
 
69
 
70
function uuid_version($uuid) {
70
function uuid_version($uuid) {
71
        $uuid = uuid_canonize($uuid);
71
        $uuid = uuid_canonize($uuid);
72
        if (!$uuid) return false;
72
        if (!$uuid) return false;
73
        return substr($uuid, 19, 1);
73
        return substr($uuid, 19, 1);
74
}
74
}
75
 
75
 
76
function uuid_info($uuid, $echo=true) {
76
function uuid_info($uuid, $echo=true) {
77
        if (!uuid_valid($uuid)) return false;
77
        if (!uuid_valid($uuid)) return false;
78
 
78
 
79
        $oid = uuid_to_oid($uuid);
79
        $oid = uuid_to_oid($uuid);
80
 
80
 
81
        echo sprintf("%-32s %s\n", "Your input:", $uuid);
81
        echo sprintf("%-32s %s\n", "Your input:", $uuid);
82
        echo "\n";
82
        echo "\n";
83
        echo "<u>Various notations:</u>\n";
83
        echo "<u>Various notations:</u>\n";
84
        echo "\n";
84
        echo "\n";
85
        echo sprintf("%-32s %s\n", "URN:", 'urn:uuid:' . strtolower(oid_to_uuid(uuid_to_oid($uuid))));
85
        echo sprintf("%-32s %s\n", "URN:", 'urn:uuid:' . strtolower(oid_to_uuid(uuid_to_oid($uuid))));
86
        echo sprintf("%-32s %s\n", "URI:", 'uuid:' . strtolower(oid_to_uuid(uuid_to_oid($uuid))));
86
        echo sprintf("%-32s %s\n", "URI:", 'uuid:' . strtolower(oid_to_uuid(uuid_to_oid($uuid))));
87
        echo sprintf("%-32s %s\n", "Microsoft GUID syntax:", '{' . strtoupper(oid_to_uuid(uuid_to_oid($uuid))) . '}');
87
        echo sprintf("%-32s %s\n", "Microsoft GUID syntax:", '{' . strtoupper(oid_to_uuid(uuid_to_oid($uuid))) . '}');
88
        echo sprintf("%-32s %s\n", "C++ struct syntax:", uuid_c_syntax($uuid));
88
        echo sprintf("%-32s %s\n", "C++ struct syntax:", uuid_c_syntax($uuid));
89
        echo "\n";
89
        echo "\n";
90
 
90
 
91
        echo sprintf("%-32s %s\n", "As OID (ISO/ITU-T 128 bits):", $oid=uuid_to_oid($uuid, '2.25'));
91
        echo sprintf("%-32s %s\n", "As OID (ISO/ITU-T 128 bits):", $oid=uuid_to_oid($uuid, '2.25'));
92
        # Removed because it is too much information (we would also need to add this to the other OIDs too)
92
        # Removed because it is too much information (we would also need to add this to the other OIDs too)
93
        #if (class_exists('OidDerConverter')) {
93
        #if (class_exists('OidDerConverter')) {
94
        #       echo sprintf("%-32s %s\n", "DER encoding of OID:", OidDerConverter::hexarrayToStr(OidDerConverter::oidToDER($oid)));
94
        #       echo sprintf("%-32s %s\n", "DER encoding of OID:", OidDerConverter::hexarrayToStr(OidDerConverter::oidToDER($oid)));
95
        #}
95
        #}
96
        echo sprintf("%-32s %s\n", "As OID (Microsoft):", $oid=uuid_to_oid($uuid, '1.2.840.113556.1.8000.2554'));
96
        echo sprintf("%-32s %s\n", "As OID (Microsoft):", $oid=uuid_to_oid($uuid, '1.2.840.113556.1.8000.2554'));
97
        echo sprintf("%-32s %s\n", "As OID (Waterjuice 2x64 bits):", $oid=uuid_to_oid($uuid, '1.3.6.1.4.1.54392.1'));
97
        echo sprintf("%-32s %s\n", "As OID (Waterjuice 2x64 bits):", $oid=uuid_to_oid($uuid, '1.3.6.1.4.1.54392.1'));
98
        echo sprintf("%-32s %s\n", "As OID (Waterjuice 4x32 bits):", $oid=uuid_to_oid($uuid, '1.3.6.1.4.1.54392.2'));
98
        echo sprintf("%-32s %s\n", "As OID (Waterjuice 4x32 bits):", $oid=uuid_to_oid($uuid, '1.3.6.1.4.1.54392.2'));
99
        echo sprintf("%-32s %s\n", "As OID (Waterjuice 8x16 bits):", $oid=uuid_to_oid($uuid, '1.3.6.1.4.1.54392.3'));
99
        echo sprintf("%-32s %s\n", "As OID (Waterjuice 8x16 bits):", $oid=uuid_to_oid($uuid, '1.3.6.1.4.1.54392.3'));
100
 
100
 
101
        echo "\n";
101
        echo "\n";
102
 
102
 
103
        echo "<u>Interpretation of the UUID:</u>\n\n";
103
        echo "<u>Interpretation of the UUID:</u>\n\n";
104
 
104
 
105
        if (!$echo) ob_start();
105
        if (!$echo) ob_start();
106
 
106
 
107
        #$uuid = trim($uuid);
107
        #$uuid = trim($uuid);
108
        # $uuid = str_replace(array('-', '{', '}'), '', $uuid);
108
        # $uuid = str_replace(array('-', '{', '}'), '', $uuid);
109
        $uuid = strtolower($uuid);
109
        $uuid = strtolower($uuid);
110
        $uuid = preg_replace('@[^0-9A-F]@i', '', $uuid);
110
        $uuid = preg_replace('@[^0-9A-F]@i', '', $uuid);
111
 
111
 
112
        $x = hexdec(substr($uuid, 16, 1));
112
        $x = hexdec(substr($uuid, 16, 1));
113
             if ($x >= 14 /* 0b1110 */) $variant = 3;
113
             if ($x >= 14 /* 0b1110 */) $variant = 3;
114
        else if ($x >= 12 /* 0b110_ */) $variant = 2;
114
        else if ($x >= 12 /* 0b110_ */) $variant = 2;
115
        else if ($x >=  8 /* 0b10__ */) $variant = 1;
115
        else if ($x >=  8 /* 0b10__ */) $variant = 1;
116
        else if ($x >=  0 /* 0b0___ */) $variant = 0;
116
        else if ($x >=  0 /* 0b0___ */) $variant = 0;
117
        else $variant = -1; // should not happen
117
        else $variant = -1; // should not happen
118
 
118
 
119
        if ($uuid == '00000000000000000000000000000000') {
119
        if ($uuid == '00000000000000000000000000000000') {
120
                echo sprintf("%-32s %s\n", "Special Use:", "Nil UUID");
120
                echo sprintf("%-32s %s\n", "Special Use:", "Nil UUID");
121
                echo "\n";
121
                echo "\n";
122
        }
122
        }
123
        else if ($uuid == 'ffffffffffffffffffffffffffffffff') {
123
        else if ($uuid == 'ffffffffffffffffffffffffffffffff') {
124
                echo sprintf("%-32s %s\n", "Special Use:", "Max UUID");
124
                echo sprintf("%-32s %s\n", "Special Use:", "Max UUID");
125
                echo "\n";
125
                echo "\n";
126
        }
126
        }
127
 
127
 
128
        switch ($variant) {
128
        switch ($variant) {
129
                case 0:
129
                case 0:
130
                        echo sprintf("%-32s %s\n", "Variant:", "[0b0__] Network Computing System (NCS)");
130
                        echo sprintf("%-32s %s\n", "Variant:", "[0b0__] Network Computing System (NCS)");
131
 
131
 
132
                        /*
132
                        /*
133
                         * Internal structure of variant #0 UUIDs
133
                         * Internal structure of variant #0 UUIDs
134
                         *
134
                         *
135
                         * The first 6 octets are the number of 4 usec units of time that have
135
                         * The first 6 octets are the number of 4 usec units of time that have
136
                         * passed since 1/1/80 0000 GMT.  The next 2 octets are reserved for
136
                         * passed since 1/1/80 0000 GMT.  The next 2 octets are reserved for
137
                         * future use.  The next octet is an address family.  The next 7 octets
137
                         * future use.  The next octet is an address family.  The next 7 octets
138
                         * are a host ID in the form allowed by the specified address family.
138
                         * are a host ID in the form allowed by the specified address family.
139
                         *
139
                         *
140
                         * Note that while the family field (octet 8) was originally conceived
140
                         * Note that while the family field (octet 8) was originally conceived
141
                         * of as being able to hold values in the range [0..255], only [0..13]
141
                         * of as being able to hold values in the range [0..255], only [0..13]
142
                         * were ever used.  Thus, the 2 MSB of this field are always 0 and are
142
                         * were ever used.  Thus, the 2 MSB of this field are always 0 and are
143
                         * used to distinguish old and current UUID forms.
143
                         * used to distinguish old and current UUID forms.
144
                         */
144
                         */
145
 
145
 
146
                        /*
146
                        /*
147
                        Variant 0 UUID
147
                        Variant 0 UUID
148
                        - 32 bit High Time
148
                        - 32 bit High Time
149
                        - 16 bit Low Time
149
                        - 16 bit Low Time
150
                        - 16 bit Reserved
150
                        - 16 bit Reserved
151
                        -  1 bit Variant (fix 0b0)
151
                        -  1 bit Variant (fix 0b0)
152
                        -  7 bit Family
152
                        -  7 bit Family
153
                        - 56 bit Node
153
                        - 56 bit Node
154
                        */
154
                        */
155
 
155
 
156
                        // Example of an UUID: 333a2276-0000-0000-0d00-00809c000000
156
                        // Example of an UUID: 333a2276-0000-0000-0d00-00809c000000
157
 
157
 
158
                        // TODO: also show legacy format, e.g. 458487b55160.02.c0.64.02.03.00.00.00
158
                        // TODO: also show legacy format, e.g. 458487b55160.02.c0.64.02.03.00.00.00
159
 
159
 
160
                        # see also some notes at See https://github.com/cjsv/uuid/blob/master/Doc
160
                        # see also some notes at See https://github.com/cjsv/uuid/blob/master/Doc
161
 
161
 
162
                        /*
162
                        /*
163
                        NOTE: A generator is not possible, because there are no timestamps left!
163
                        NOTE: A generator is not possible, because there are no timestamps left!
164
                        The last possible timestamp was:
164
                        The last possible timestamp was:
165
                            [0xFFFFFFFFFFFF] 2015-09-05 05:58:26'210655 GMT
165
                            [0xFFFFFFFFFFFF] 2015-09-05 05:58:26'210655 GMT
166
                        That is in the following UUID:
166
                        That is in the following UUID:
167
                            ffffffff-ffff-0000-027f-000001000000
167
                            ffffffff-ffff-0000-027f-000001000000
168
                        Current timestamp generator:
168
                        Current timestamp generator:
169
                            echo dechex(round((microtime(true)+315532800)*250000));
169
                            echo dechex(round((microtime(true)+315532800)*250000));
170
                        */
170
                        */
171
 
171
 
172
                        # Timestamp: Count of 4us intervals since 01 Jan 1980 00:00:00 GMT
172
                        # Timestamp: Count of 4us intervals since 01 Jan 1980 00:00:00 GMT
173
                        # 1/0,000004 = 250000
173
                        # 1/0,000004 = 250000
174
                        # Seconds between 1970 and 1980 : 315532800
174
                        # Seconds between 1970 and 1980 : 315532800
175
                        # 250000*315532800=78883200000000
175
                        # 250000*315532800=78883200000000
176
                        $timestamp = substr($uuid, 0, 12);
176
                        $timestamp = substr($uuid, 0, 12);
177
                        $ts = gmp_init($timestamp, 16);
177
                        $ts = gmp_init($timestamp, 16);
178
                        $ts = gmp_add($ts, gmp_init("78883200000000", 10));
178
                        $ts = gmp_add($ts, gmp_init("78883200000000", 10));
179
                        $ms = gmp_mod($ts, gmp_init("250000", 10));
179
                        $ms = gmp_mod($ts, gmp_init("250000", 10));
180
                        $ts = gmp_div($ts, gmp_init("250000", 10));
180
                        $ts = gmp_div($ts, gmp_init("250000", 10));
181
                        $ts = gmp_strval($ts, 10);
181
                        $ts = gmp_strval($ts, 10);
182
                        $ms = gmp_strval($ms, 10);
182
                        $ms = gmp_strval($ms, 10);
183
                        $ts = gmdate('Y-m-d H:i:s', intval($ts))."'".str_pad($ms, 6/*us*/, '0', STR_PAD_LEFT).' GMT';
183
                        $ts = gmdate('Y-m-d H:i:s', intval($ts))."'".str_pad($ms, 6/*us*/, '0', STR_PAD_LEFT).' GMT';
184
                        echo sprintf("%-32s %s\n", "Timestamp:", "[0x$timestamp] $ts");
184
                        echo sprintf("%-32s %s\n", "Timestamp:", "[0x$timestamp] $ts");
185
 
185
 
186
                        $reserved = substr($uuid, 12, 4);
186
                        $reserved = substr($uuid, 12, 4);
187
                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$reserved]");
187
                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$reserved]");
188
 
188
 
189
                        $family_hex = substr($uuid, 16, 2);
189
                        $family_hex = substr($uuid, 16, 2);
190
                        $family_dec = hexdec($family_hex);
190
                        $family_dec = hexdec($family_hex);
191
                        $nodeid_hex = substr($uuid, 18, 14);
191
                        $nodeid_hex = substr($uuid, 18, 14);
192
                        $nodeid_dec = hexdec($nodeid_hex);
192
                        $nodeid_dec = hexdec($nodeid_hex);
193
 
193
 
194
                        // Sources:
194
                        // Sources:
195
                        // - https://bitsavers.org/pdf/ibm/rs6000/aix_3.0/SC23-2206-0_AIX_Version_3_for_RS6000_Communications_Programming_Concepts_199003.pdf
195
                        // - https://bitsavers.org/pdf/ibm/rs6000/aix_3.0/SC23-2206-0_AIX_Version_3_for_RS6000_Communications_Programming_Concepts_199003.pdf
196
                        // - (For comparison) https://github.com/uuid6/uuid6-ietf-draft/issues/26#issuecomment-1062164457
196
                        // - (For comparison) https://github.com/uuid6/uuid6-ietf-draft/issues/26#issuecomment-1062164457
197
                        // - (For comparison) https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.addressfamily?view=net-7.0 [numbers 0..13 are mostly identical]
197
                        // - (For comparison) https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.addressfamily?view=net-7.0 [numbers 0..13 are mostly identical]
198
 
198
 
199
                        if ($family_dec == 0) {
199
                        if ($family_dec == 0) {
200
                                # Microsoft's AdressFamily: Unspecified 0       Unspecified address family.
200
                                # Microsoft's AdressFamily: Unspecified 0       Unspecified address family.
201
                                # AIX 3.0 Manual:  0   unspec = Unspecified
201
                                # AIX 3.0 Manual:  0   unspec = Unspecified
202
                                $family_name = 'socket_$unspec (Unspecified)';
202
                                $family_name = 'socket_$unspec (Unspecified)';
203
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
203
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
204
                        }
204
                        }
205
                        else if ($family_dec == 1) {
205
                        else if ($family_dec == 1) {
206
                                # Microsoft's AdressFamily: Unix        1       Unix local to host address.
206
                                # Microsoft's AdressFamily: Unix        1       Unix local to host address.
207
                                # AIX 3.0 Manual:  1   unix = Local to host (pipes, portals)
207
                                # AIX 3.0 Manual:  1   unix = Local to host (pipes, portals)
208
                                $family_name = 'socket_$unix (Local to host, e.g. pipes, portals)';
208
                                $family_name = 'socket_$unix (Local to host, e.g. pipes, portals)';
209
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
209
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
210
                        }
210
                        }
211
                        else if ($family_dec == 2) {
211
                        else if ($family_dec == 2) {
212
                                # Microsoft's AdressFamily: InterNetwork        2       Address for IP version 4.
212
                                # Microsoft's AdressFamily: InterNetwork        2       Address for IP version 4.
213
                                # AIX 3.0 Manual:  2   ip = Internet Protocols
213
                                # AIX 3.0 Manual:  2   ip = Internet Protocols
214
                                $family_name = 'socket_$internet (Internet Protocols, e.g. IPv4)';
214
                                $family_name = 'socket_$internet (Internet Protocols, e.g. IPv4)';
215
                                // https://www.ibm.com/docs/en/aix/7.1?topic=u-uuid-gen-command-ncs (AIX 7.1) shows the following example output for /etc/ncs/uuid_gen -P
215
                                // https://www.ibm.com/docs/en/aix/7.1?topic=u-uuid-gen-command-ncs (AIX 7.1) shows the following example output for /etc/ncs/uuid_gen -P
216
                                // := [
216
                                // := [
217
                                //    time_high := 16#458487df,
217
                                //    time_high := 16#458487df,
218
                                //    time_low := 16#9fb2,
218
                                //    time_low := 16#9fb2,
219
                                //    reserved := 16#000,
219
                                //    reserved := 16#000,
220
                                //    family := chr(16#02),
220
                                //    family := chr(16#02),
221
                                //    host := [chr(16#c0), chr(16#64), chr(16#02), chr(16#03),
221
                                //    host := [chr(16#c0), chr(16#64), chr(16#02), chr(16#03),
222
                                //             chr(16#00), chr(16#00), chr(16#00)]
222
                                //             chr(16#00), chr(16#00), chr(16#00)]
223
                                //    ]
223
                                //    ]
224
                                // This means that the IP address is 32 bits hex, and 32 bits are unused
224
                                // This means that the IP address is 32 bits hex, and 32 bits are unused
225
                                $nodeid_desc = hexdec(substr($nodeid_hex,0,2)).'.'.
225
                                $nodeid_desc = hexdec(substr($nodeid_hex,0,2)).'.'.
226
                                               hexdec(substr($nodeid_hex,2,2)).'.'.
226
                                               hexdec(substr($nodeid_hex,2,2)).'.'.
227
                                               hexdec(substr($nodeid_hex,4,2)).'.'.
227
                                               hexdec(substr($nodeid_hex,4,2)).'.'.
228
                                               hexdec(substr($nodeid_hex,6,2));
228
                                               hexdec(substr($nodeid_hex,6,2));
229
                                $rest = substr($nodeid_hex,8,6);
229
                                $rest = substr($nodeid_hex,8,6);
230
                                if ($rest != '000000') $nodeid_desc .= " + unexpected rest 0x$rest";
230
                                if ($rest != '000000') $nodeid_desc .= " + unexpected rest 0x$rest";
231
                        }
231
                        }
232
                        else if ($family_dec == 3) {
232
                        else if ($family_dec == 3) {
233
                                # Microsoft's AdressFamily: ImpLink     3       ARPANET IMP address.
233
                                # Microsoft's AdressFamily: ImpLink     3       ARPANET IMP address.
234
                                # AIX 3.0 Manual:  3   implink = ARPANET imp addresses
234
                                # AIX 3.0 Manual:  3   implink = ARPANET imp addresses
235
                                $family_name = 'socket_$implink (ARPANET imp addresses)';
235
                                $family_name = 'socket_$implink (ARPANET imp addresses)';
236
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
236
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
237
                        }
237
                        }
238
                        else if ($family_dec == 4) {
238
                        else if ($family_dec == 4) {
239
                                # Microsoft's AdressFamily: Pup 4       Address for PUP protocols.
239
                                # Microsoft's AdressFamily: Pup 4       Address for PUP protocols.
240
                                # AIX 3.0 Manual:  4   pup = Pup protocols (for example, BSP)
240
                                # AIX 3.0 Manual:  4   pup = Pup protocols (for example, BSP)
241
                                $family_name = 'socket_$pup (Pup protocols, e.g. BSP)';
241
                                $family_name = 'socket_$pup (Pup protocols, e.g. BSP)';
242
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
242
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
243
                        }
243
                        }
244
                        else if ($family_dec == 5) {
244
                        else if ($family_dec == 5) {
245
                                # Microsoft's AdressFamily: Chaos       5       Address for MIT CHAOS protocols.
245
                                # Microsoft's AdressFamily: Chaos       5       Address for MIT CHAOS protocols.
246
                                # AIX 3.0 Manual:  5   chaos = MIT CHAOS protocols
246
                                # AIX 3.0 Manual:  5   chaos = MIT CHAOS protocols
247
                                $family_name = 'socket_$chaos (MIT CHAOS protocols)';
247
                                $family_name = 'socket_$chaos (MIT CHAOS protocols)';
248
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
248
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
249
                        }
249
                        }
250
                        else if ($family_dec == 6) {
250
                        else if ($family_dec == 6) {
251
                                # Microsoft's AdressFamily: NS  6       Address for Xerox NS protocols.
251
                                # Microsoft's AdressFamily: NS  6       Address for Xerox NS protocols.
252
                                # Microsoft's AdressFamily: Ipx 6       IPX or SPX address.
252
                                # Microsoft's AdressFamily: Ipx 6       IPX or SPX address.
253
                                # AIX 3.0 Manual:  6   ns = XEROX NS protocols
253
                                # AIX 3.0 Manual:  6   ns = XEROX NS protocols
254
                                $family_name = 'socket_$ns (XEROX NS protocols)';
254
                                $family_name = 'socket_$ns (XEROX NS protocols)';
255
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
255
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
256
                        }
256
                        }
257
                        else if ($family_dec == 7) {
257
                        else if ($family_dec == 7) {
258
                                # Microsoft's AdressFamily: Osi 7       Address for OSI protocols.
258
                                # Microsoft's AdressFamily: Osi 7       Address for OSI protocols.
259
                                # Microsoft's AdressFamily: Iso 7       Address for ISO protocols.
259
                                # Microsoft's AdressFamily: Iso 7       Address for ISO protocols.
260
                                # AIX 3.0 Manual:  7   nbs = NBS protocols
260
                                # AIX 3.0 Manual:  7   nbs = NBS protocols
261
                                $family_name = 'socket_$nbs (NBS protocols)';
261
                                $family_name = 'socket_$nbs (NBS protocols)';
262
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
262
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
263
                        }
263
                        }
264
                        else if ($family_dec == 8) {
264
                        else if ($family_dec == 8) {
265
                                # Microsoft's AdressFamily: Ecma        8       European Computer Manufacturers Association (ECMA) address.
265
                                # Microsoft's AdressFamily: Ecma        8       European Computer Manufacturers Association (ECMA) address.
266
                                # AIX 3.0 Manual:  8   ecma = European computer manufacturers
266
                                # AIX 3.0 Manual:  8   ecma = European computer manufacturers
267
                                $family_name = 'socket_$ecma (European computer manufacturers protocols)';
267
                                $family_name = 'socket_$ecma (European computer manufacturers protocols)';
268
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
268
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
269
                        }
269
                        }
270
                        else if ($family_dec == 9) {
270
                        else if ($family_dec == 9) {
271
                                # Microsoft's AdressFamily: DataKit     9       Address for Datakit protocols.
271
                                # Microsoft's AdressFamily: DataKit     9       Address for Datakit protocols.
272
                                # AIX 3.0 Manual:  9   datakit = Datakit protocols
272
                                # AIX 3.0 Manual:  9   datakit = Datakit protocols
273
                                $family_name = 'socket_$datakit (Datakit protocols)';
273
                                $family_name = 'socket_$datakit (Datakit protocols)';
274
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
274
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
275
                        }
275
                        }
276
                        else if ($family_dec == 10) {
276
                        else if ($family_dec == 10) {
277
                                # Microsoft's AdressFamily: Ccitt       10      Addresses for CCITT protocols, such as X.25.
277
                                # Microsoft's AdressFamily: Ccitt       10      Addresses for CCITT protocols, such as X.25.
278
                                # AIX 3.0 Manual:  A   ccitt = CCITT protocols (for example, X.25)
278
                                # AIX 3.0 Manual:  A   ccitt = CCITT protocols (for example, X.25)
279
                                $family_name = 'socket_$ccitt (CCITT protocols, e.g. X.25)';
279
                                $family_name = 'socket_$ccitt (CCITT protocols, e.g. X.25)';
280
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
280
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
281
                        }
281
                        }
282
                        else if ($family_dec == 11) {
282
                        else if ($family_dec == 11) {
283
                                # Microsoft's AdressFamily: Sna 11      IBM SNA address.
283
                                # Microsoft's AdressFamily: Sna 11      IBM SNA address.
284
                                # AIX 3.0 Manual:  B   sna = IBM SNA
284
                                # AIX 3.0 Manual:  B   sna = IBM SNA
285
                                $family_name = 'socket_$sna (IBM SNA)';
285
                                $family_name = 'socket_$sna (IBM SNA)';
286
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
286
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
287
                        }
287
                        }
288
                        else if ($family_dec == 12) {
288
                        else if ($family_dec == 12) {
289
                                # Microsoft's AdressFamily: DecNet      12      DECnet address.
289
                                # Microsoft's AdressFamily: DecNet      12      DECnet address.
290
                                # AIX 3.0 Manual:  C   unspec2 = Unspecified
290
                                # AIX 3.0 Manual:  C   unspec2 = Unspecified
291
                                $family_name = 'socket_$unspec2 (Unspecified)';
291
                                $family_name = 'socket_$unspec2 (Unspecified)';
292
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
292
                                $nodeid_desc = ''; // TODO: how to interprete the Node-ID of that family?
293
                        }
293
                        }
294
                        else if ($family_dec == 13) {
294
                        else if ($family_dec == 13) {
295
                                # Microsoft's AdressFamily: DataLink    13      Direct data-link interface address.
295
                                # Microsoft's AdressFamily: DataLink    13      Direct data-link interface address.
296
                                # AIX 3.0 Manual:  D   dds = Domain DDS protocol
296
                                # AIX 3.0 Manual:  D   dds = Domain DDS protocol
297
                                # Some also call this "Data Link" ... Is that correct?
297
                                # Some also call this "Data Link" ... Is that correct?
298
                                $family_name = 'socket_$dds (Domain DDS protocol)';
298
                                $family_name = 'socket_$dds (Domain DDS protocol)';
299
                                // https://www.ibm.com/docs/en/aix/7.1?topic=u-uuid-gen-command-ncs (AIX 7.1) shows the following example output for /etc/ncs/uuid_gen -C
299
                                // https://www.ibm.com/docs/en/aix/7.1?topic=u-uuid-gen-command-ncs (AIX 7.1) shows the following example output for /etc/ncs/uuid_gen -C
300
                                // = { 0x34dc23af,
300
                                // = { 0x34dc23af,
301
                                //    0xf000,
301
                                //    0xf000,
302
                                //    0x0000,
302
                                //    0x0000,
303
                                //    0x0d,
303
                                //    0x0d,
304
                                //    {0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00} };
304
                                //    {0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00} };
305
                                // https://github.com/cjsv/uuid/blob/master/Doc writes:
305
                                // https://github.com/cjsv/uuid/blob/master/Doc writes:
306
                                //    "Family 13 (dds) looks like node is 00 | nnnnnn 000000."
306
                                //    "Family 13 (dds) looks like node is 00 | nnnnnn 000000."
307
 
307
 
308
                                $nodeid_desc = '';
308
                                $nodeid_desc = '';
309
 
309
 
310
                                $start = substr($nodeid_hex,0,2);
310
                                $start = substr($nodeid_hex,0,2);
311
                                if ($start != '00') $nodeid_desc .= "unexpected start 0x$start + ";
311
                                if ($start != '00') $nodeid_desc .= "unexpected start 0x$start + ";
312
 
312
 
313
                                $nodeid_desc .= ($nodeid_dec >> 24) & 0xFFFFFF;
313
                                $nodeid_desc .= ($nodeid_dec >> 24) & 0xFFFFFF;
314
 
314
 
315
                                $rest = substr($nodeid_hex,8,6);
315
                                $rest = substr($nodeid_hex,8,6);
316
                                if ($rest != '000000') $nodeid_desc .= " + unexpected rest 0x$rest";
316
                                if ($rest != '000000') $nodeid_desc .= " + unexpected rest 0x$rest";
317
                        } else {
317
                        } else {
318
                                $family_name = "Unknown (Family $family_dec)"; # There are probably no more families
318
                                $family_name = "Unknown (Family $family_dec)"; # There are probably no more families
319
                                $nodeid_desc = "Unknown";
319
                                $nodeid_desc = "Unknown";
320
                        }
320
                        }
321
                        echo sprintf("%-32s %s\n", "Family:", "[0x$family_hex] $family_name");
321
                        echo sprintf("%-32s %s\n", "Family:", "[0x$family_hex] $family_name");
322
 
322
 
323
                        echo sprintf("%-32s %s\n", "Node ID:", "[0x$nodeid_hex] $nodeid_desc");
323
                        echo sprintf("%-32s %s\n", "Node ID:", "[0x$nodeid_hex] $nodeid_desc");
324
 
324
 
325
                        break;
325
                        break;
326
                case 1:
326
                case 1:
327
                        // TODO: Show byte order: 00112233-4455-6677-8899-aabbccddeeff => 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
327
                        // TODO: Show byte order: 00112233-4455-6677-8899-aabbccddeeff => 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
328
 
328
 
329
                        $version = hexdec(substr($uuid, 12, 1));
329
                        $version = hexdec(substr($uuid, 12, 1));
330
 
330
 
331
                        if ($version <= 2) {
331
                        if ($version <= 2) {
332
                                echo sprintf("%-32s %s\n", "Variant:", "[0b10_] RFC 4122 (Leach-Mealling-Salz) / DCE 1.1");
332
                                echo sprintf("%-32s %s\n", "Variant:", "[0b10_] RFC 4122 (Leach-Mealling-Salz) / DCE 1.1");
333
                        } else if (($version >= 3) && ($version <= 5)) {
333
                        } else if (($version >= 3) && ($version <= 5)) {
334
                                echo sprintf("%-32s %s\n", "Variant:", "[0b10_] RFC 4122 (Leach-Mealling-Salz)");
334
                                echo sprintf("%-32s %s\n", "Variant:", "[0b10_] RFC 4122 (Leach-Mealling-Salz)");
335
                        } else if (($version >= 6) && ($version <= 8)) {
335
                        } else if (($version >= 6) && ($version <= 8)) {
336
                                echo sprintf("%-32s %s\n", "Variant:", "[0b10_] RFC draft-ietf-uuidrev-rfc4122bis (Davis-Peabody-Leach)"); // TODO: When new RFC is published, replace the RFC number
336
                                echo sprintf("%-32s %s\n", "Variant:", "[0b10_] RFC draft-ietf-uuidrev-rfc4122bis (Davis-Peabody-Leach)"); // TODO: When new RFC is published, replace the RFC number
337
                        } else {
337
                        } else {
338
                                echo sprintf("%-32s %s\n", "Variant:", "[0b10_] Unknown RFC");
338
                                echo sprintf("%-32s %s\n", "Variant:", "[0b10_] Unknown RFC");
339
                        }
339
                        }
340
 
340
 
341
                        switch ($version) {
341
                        switch ($version) {
342
                                case 6:
342
                                case 6:
343
                                        /*
343
                                        /*
344
                                        Variant 1, Version 6 UUID
344
                                        Variant 1, Version 6 UUID
345
                                        - 48 bit High Time
345
                                        - 48 bit High Time
346
                                        -  4 bit Version (fix 0x6)
346
                                        -  4 bit Version (fix 0x6)
347
                                        - 12 bit Low Time
347
                                        - 12 bit Low Time
348
                                        -  2 bit Variant (fix 0b10)
348
                                        -  2 bit Variant (fix 0b10)
349
                                        -  6 bit Clock Sequence High
349
                                        -  6 bit Clock Sequence High
350
                                        -  8 bit Clock Sequence Low
350
                                        -  8 bit Clock Sequence Low
351
                                        - 48 bit MAC Address
351
                                        - 48 bit MAC Address
352
                                        */
352
                                        */
353
                                        echo sprintf("%-32s %s\n", "Version:", "[0x6] Reordered Time-Based");
353
                                        echo sprintf("%-32s %s\n", "Version:", "[0x6] Reordered Time-Based");
354
                                        $uuid = substr($uuid,  0, 8).'-'.
354
                                        $uuid = substr($uuid,  0, 8).'-'.
355
                                                substr($uuid,  8, 4).'-'.
355
                                                substr($uuid,  8, 4).'-'.
356
                                                substr($uuid, 12, 4).'-'.
356
                                                substr($uuid, 12, 4).'-'.
357
                                                substr($uuid, 16, 4).'-'.
357
                                                substr($uuid, 16, 4).'-'.
358
                                                substr($uuid, 20, 12);
358
                                                substr($uuid, 20, 12);
359
                                        $uuid = uuid6_to_uuid1($uuid);
359
                                        $uuid = uuid6_to_uuid1($uuid);
360
                                        $uuid = str_replace('-', '', $uuid);
360
                                        $uuid = str_replace('-', '', $uuid);
361
 
361
 
362
                                /* fallthrough */
362
                                /* fallthrough */
363
                                case 1:
363
                                case 1:
364
                                        /*
364
                                        /*
365
                                        Variant 1, Version 1 UUID
365
                                        Variant 1, Version 1 UUID
366
                                        - 32 bit Low Time
366
                                        - 32 bit Low Time
367
                                        - 16 bit Mid Time
367
                                        - 16 bit Mid Time
368
                                        -  4 bit Version (fix 0x1)
368
                                        -  4 bit Version (fix 0x1)
369
                                        - 12 bit High Time
369
                                        - 12 bit High Time
370
                                        -  2 bit Variant (fix 0b10)
370
                                        -  2 bit Variant (fix 0b10)
371
                                        -  6 bit Clock Sequence High
371
                                        -  6 bit Clock Sequence High
372
                                        -  8 bit Clock Sequence Low
372
                                        -  8 bit Clock Sequence Low
373
                                        - 48 bit MAC Address
373
                                        - 48 bit MAC Address
374
                                        */
374
                                        */
375
 
375
 
376
                                        if ($version == 1) echo sprintf("%-32s %s\n", "Version:", "[0x1] Time-based with unique host identifier");
376
                                        if ($version == 1) echo sprintf("%-32s %s\n", "Version:", "[0x1] Time-based with unique host identifier");
377
 
377
 
378
                                        # Timestamp: Count of 100ns intervals since 15 Oct 1582 00:00:00
378
                                        # Timestamp: Count of 100ns intervals since 15 Oct 1582 00:00:00
379
                                        # 1/0,0000001 = 10000000
379
                                        # 1/0,0000001 = 10000000
380
                                        $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).substr($uuid, 0, 8);
380
                                        $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).substr($uuid, 0, 8);
381
                                        $ts = gmp_init($timestamp, 16);
381
                                        $ts = gmp_init($timestamp, 16);
382
                                        $ts = gmp_sub($ts, gmp_init("122192928000000000", 10));
382
                                        $ts = gmp_sub($ts, gmp_init("122192928000000000", 10));
383
                                        $ms = gmp_mod($ts, gmp_init("10000000", 10));
383
                                        $ms = gmp_mod($ts, gmp_init("10000000", 10));
384
                                        $ts = gmp_div($ts, gmp_init("10000000", 10));
384
                                        $ts = gmp_div($ts, gmp_init("10000000", 10));
385
                                        $ts = gmp_strval($ts, 10);
385
                                        $ts = gmp_strval($ts, 10);
386
                                        $ms = gmp_strval($ms, 10);
386
                                        $ms = gmp_strval($ms, 10);
387
                                        $ts = gmdate('Y-m-d H:i:s', intval($ts))."'".str_pad($ms, 7/*0.1us*/, '0', STR_PAD_LEFT).' GMT';
387
                                        $ts = gmdate('Y-m-d H:i:s', intval($ts))."'".str_pad($ms, 7/*0.1us*/, '0', STR_PAD_LEFT).' GMT';
388
                                        echo sprintf("%-32s %s\n", "Timestamp:", "[0x$timestamp] $ts");
388
                                        echo sprintf("%-32s %s\n", "Timestamp:", "[0x$timestamp] $ts");
389
 
389
 
390
                                        $x = hexdec(substr($uuid, 16, 4));
390
                                        $x = hexdec(substr($uuid, 16, 4));
391
                                        $dec = $x & 0x3FFF; // The highest 2 bits are used by "variant" (10x)
391
                                        $dec = $x & 0x3FFF; // The highest 2 bits are used by "variant" (10x)
392
                                        $hex = substr($uuid, 16, 4);
392
                                        $hex = substr($uuid, 16, 4);
393
                                        $hex = '<abbr title="The highest 2 bits are used by the UUID variant (10xx)">'.$hex[0].'</abbr>'.substr($hex,1);
393
                                        $hex = '<abbr title="The highest 2 bits are used by the UUID variant (10xx)">'.$hex[0].'</abbr>'.substr($hex,1);
394
                                        echo sprintf("%-32s %s\n", "Clock ID:", "[0x$hex] $dec");
394
                                        echo sprintf("%-32s %s\n", "Clock ID:", "[0x$hex] $dec");
395
 
395
 
396
                                        $x = substr($uuid, 20, 12);
396
                                        $x = substr($uuid, 20, 12);
397
                                        $nodeid = '';
397
                                        $nodeid = '';
398
                                        for ($i=0; $i<6; $i++) {
398
                                        for ($i=0; $i<6; $i++) {
399
                                                $nodeid .= substr($x, $i*2, 2);
399
                                                $nodeid .= substr($x, $i*2, 2);
400
                                                if ($i != 5) $nodeid .= '-';
400
                                                if ($i != 5) $nodeid .= '-';
401
                                        }
401
                                        }
402
                                        $nodeid = strtoupper($nodeid);
402
                                        $nodeid = strtoupper($nodeid);
403
                                        echo sprintf("%-32s %s\n", "Node ID:", "[0x$x] $nodeid");
403
                                        echo sprintf("%-32s %s\n", "Node ID:", "[0x$x] $nodeid");
404
 
404
 
405
                                        echo "\n<u>In case that this Node ID is a MAC address, here is the interpretation of that MAC address:</u>\n\n";
405
                                        echo "\n<u>In case that this Node ID is a MAC address, here is the interpretation of that MAC address:</u>\n\n";
406
                                        decode_mac(strtoupper($nodeid));
406
                                        decode_mac(strtoupper($nodeid));
407
 
407
 
408
                                        break;
408
                                        break;
409
                                case 2:
409
                                case 2:
410
                                        /*
410
                                        /*
411
                                        Variant 1, Version 2 UUID
411
                                        Variant 1, Version 2 UUID
412
                                        - 32 bit Local Domain Number
412
                                        - 32 bit Local Domain Number
413
                                        - 16 bit Mid Time
413
                                        - 16 bit Mid Time
414
                                        -  4 bit Version (fix 0x2)
414
                                        -  4 bit Version (fix 0x2)
415
                                        - 12 bit High Time
415
                                        - 12 bit High Time
416
                                        -  2 bit Variant (fix 0b10)
416
                                        -  2 bit Variant (fix 0b10)
417
                                        -  6 bit Clock Sequence
417
                                        -  6 bit Clock Sequence
418
                                        -  8 bit Local Domain
418
                                        -  8 bit Local Domain
419
                                        - 48 bit MAC Address
419
                                        - 48 bit MAC Address
420
                                        */
420
                                        */
421
 
421
 
422
                                        // see also https://unicorn-utterances.com/posts/what-happened-to-uuid-v2
422
                                        // see also https://unicorn-utterances.com/posts/what-happened-to-uuid-v2
423
 
423
 
424
                                        echo sprintf("%-32s %s\n", "Version:", "[0x2] DCE Security version");
424
                                        echo sprintf("%-32s %s\n", "Version:", "[0x2] DCE Security version");
425
 
425
 
426
                                        # The clock_seq_low field (which represents an integer in the range [0, 28-1]) is interpreted as a local domain (as represented by sec_rgy_domain_t; see sec_rgy_domain_t ); that is, an identifier domain meaningful to the local host. (Note that the data type sec_rgy_domain_t can potentially hold values outside the range [0, 28-1]; however, the only values currently registered are in the range [0, 2], so this type mismatch is not significant.) In the particular case of a POSIX host, the value sec_rgy_domain_person is to be interpreted as the "POSIX UID domain", and the value sec_rgy_domain_group is to be interpreted as the "POSIX GID domain".
426
                                        # The clock_seq_low field (which represents an integer in the range [0, 28-1]) is interpreted as a local domain (as represented by sec_rgy_domain_t; see sec_rgy_domain_t ); that is, an identifier domain meaningful to the local host. (Note that the data type sec_rgy_domain_t can potentially hold values outside the range [0, 28-1]; however, the only values currently registered are in the range [0, 2], so this type mismatch is not significant.) In the particular case of a POSIX host, the value sec_rgy_domain_person is to be interpreted as the "POSIX UID domain", and the value sec_rgy_domain_group is to be interpreted as the "POSIX GID domain".
427
                                        $x = substr($uuid, 18, 2);
427
                                        $x = substr($uuid, 18, 2);
428
                                        if ($x == '00') $domain_info = 'Person (e.g. POSIX UID)';
428
                                        if ($x == '00') $domain_info = 'Person (e.g. POSIX UID)';
429
                                        else if ($x == '01') $domain_info = 'Group (e.g. POSIX GID)';
429
                                        else if ($x == '01') $domain_info = 'Group (e.g. POSIX GID)';
430
                                        else if ($x == '02') $domain_info = 'Organization';
430
                                        else if ($x == '02') $domain_info = 'Organization';
431
                                        else $domain_info = 'site-defined (Domain '.hexdec($x).')';
431
                                        else $domain_info = 'site-defined (Domain '.hexdec($x).')';
432
                                        echo sprintf("%-32s %s\n", "Local Domain:", "[0x$x] $domain_info");
432
                                        echo sprintf("%-32s %s\n", "Local Domain:", "[0x$x] $domain_info");
433
 
433
 
434
                                        # The time_low field (which represents an integer in the range [0, 232-1]) is interpreted as a local-ID; that is, an identifier (within the domain specified by clock_seq_low) meaningful to the local host. In the particular case of a POSIX host, when combined with a POSIX UID or POSIX GID domain in the clock_seq_low field (above), the time_low field represents a POSIX UID or POSIX GID, respectively.
434
                                        # The time_low field (which represents an integer in the range [0, 232-1]) is interpreted as a local-ID; that is, an identifier (within the domain specified by clock_seq_low) meaningful to the local host. In the particular case of a POSIX host, when combined with a POSIX UID or POSIX GID domain in the clock_seq_low field (above), the time_low field represents a POSIX UID or POSIX GID, respectively.
435
                                        $x = substr($uuid, 0, 8);
435
                                        $x = substr($uuid, 0, 8);
436
                                        $dec = hexdec($x);
436
                                        $dec = hexdec($x);
437
                                        echo sprintf("%-32s %s\n", "Local Domain Number:", "[0x$x] $dec");
437
                                        echo sprintf("%-32s %s\n", "Local Domain Number:", "[0x$x] $dec");
438
 
438
 
439
                                        # Timestamp: Count of 100ns intervals since 15 Oct 1582 00:00:00
439
                                        # Timestamp: Count of 100ns intervals since 15 Oct 1582 00:00:00
440
                                        # 1/0,0000001 = 10000000
440
                                        # 1/0,0000001 = 10000000
441
                                        $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).'00000000';
441
                                        $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).'00000000';
442
                                        $ts = gmp_init($timestamp, 16);
442
                                        $ts = gmp_init($timestamp, 16);
443
                                        $ts = gmp_sub($ts, gmp_init("122192928000000000", 10));
443
                                        $ts = gmp_sub($ts, gmp_init("122192928000000000", 10));
444
                                        $ms = gmp_mod($ts, gmp_init("10000000", 10));
444
                                        $ms = gmp_mod($ts, gmp_init("10000000", 10));
445
                                        $ts = gmp_div($ts, gmp_init("10000000", 10));
445
                                        $ts = gmp_div($ts, gmp_init("10000000", 10));
446
                                        $ts = gmp_strval($ts, 10);
446
                                        $ts = gmp_strval($ts, 10);
447
                                        $ms = gmp_strval($ms, 10);
447
                                        $ms = gmp_strval($ms, 10);
448
                                        $ts_min = gmdate('Y-m-d H:i:s', intval($ts))."'".str_pad($ms, 7/*0.1us*/, '0', STR_PAD_LEFT).' GMT';
448
                                        $ts_min = gmdate('Y-m-d H:i:s', intval($ts))."'".str_pad($ms, 7/*0.1us*/, '0', STR_PAD_LEFT).' GMT';
449
 
449
 
450
                                        $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).'FFFFFFFF';
450
                                        $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).'FFFFFFFF';
451
                                        $ts = gmp_init($timestamp, 16);
451
                                        $ts = gmp_init($timestamp, 16);
452
                                        $ts = gmp_sub($ts, gmp_init("122192928000000000", 10));
452
                                        $ts = gmp_sub($ts, gmp_init("122192928000000000", 10));
453
                                        $ms = gmp_mod($ts, gmp_init("10000000", 10));
453
                                        $ms = gmp_mod($ts, gmp_init("10000000", 10));
454
                                        $ts = gmp_div($ts, gmp_init("10000000", 10));
454
                                        $ts = gmp_div($ts, gmp_init("10000000", 10));
455
                                        $ts = gmp_strval($ts, 10);
455
                                        $ts = gmp_strval($ts, 10);
456
                                        $ms = gmp_strval($ms, 10);
456
                                        $ms = gmp_strval($ms, 10);
457
                                        $ts_max = gmdate('Y-m-d H:i:s', intval($ts))."'".str_pad($ms, 7/*0.1us*/, '0', STR_PAD_LEFT).' GMT';
457
                                        $ts_max = gmdate('Y-m-d H:i:s', intval($ts))."'".str_pad($ms, 7/*0.1us*/, '0', STR_PAD_LEFT).' GMT';
458
 
458
 
459
                                        $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4)/*.'xxxxxxxx'*/;
459
                                        $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4)/*.'xxxxxxxx'*/;
460
                                        echo sprintf("%-32s %s\n", "Timestamp:", "[0x$timestamp] $ts_min - $ts_max");
460
                                        echo sprintf("%-32s %s\n", "Timestamp:", "[0x$timestamp] $ts_min - $ts_max");
461
 
461
 
462
                                        $x = hexdec(substr($uuid, 16, 2));
462
                                        $x = hexdec(substr($uuid, 16, 2));
463
                                        $dec = $x & 0x3F; // The highest 2 bits are used by "variant" (10xx)
463
                                        $dec = $x & 0x3F; // The highest 2 bits are used by "variant" (10xx)
464
                                        $hex = substr($uuid, 16, 2);
464
                                        $hex = substr($uuid, 16, 2);
465
                                        $hex = '<abbr title="The highest 2 bits are used by the UUID variant (10xx)">'.$hex[0].'</abbr>'.substr($hex,1);
465
                                        $hex = '<abbr title="The highest 2 bits are used by the UUID variant (10xx)">'.$hex[0].'</abbr>'.substr($hex,1);
466
                                        echo sprintf("%-32s %s\n", "Clock ID:", "[0x$hex] $dec");
466
                                        echo sprintf("%-32s %s\n", "Clock ID:", "[0x$hex] $dec");
467
 
467
 
468
                                        $x = substr($uuid, 20, 12);
468
                                        $x = substr($uuid, 20, 12);
469
                                        $nodeid = '';
469
                                        $nodeid = '';
470
                                        for ($i=0; $i<6; $i++) {
470
                                        for ($i=0; $i<6; $i++) {
471
                                                $nodeid .= substr($x, $i*2, 2);
471
                                                $nodeid .= substr($x, $i*2, 2);
472
                                                if ($i != 5) $nodeid .= '-';
472
                                                if ($i != 5) $nodeid .= '-';
473
                                        }
473
                                        }
474
                                        $nodeid = strtoupper($nodeid);
474
                                        $nodeid = strtoupper($nodeid);
475
                                        echo sprintf("%-32s %s\n", "Node ID:", "[0x$x] $nodeid");
475
                                        echo sprintf("%-32s %s\n", "Node ID:", "[0x$x] $nodeid");
476
 
476
 
477
                                        echo "\n<u>In case that this Node ID is a MAC address, here is the interpretation of that MAC address:</u>\n\n";
477
                                        echo "\n<u>In case that this Node ID is a MAC address, here is the interpretation of that MAC address:</u>\n\n";
478
                                        decode_mac(strtoupper($nodeid));
478
                                        decode_mac(strtoupper($nodeid));
479
 
479
 
480
                                        break;
480
                                        break;
481
                                case 3:
481
                                case 3:
482
                                        /*
482
                                        /*
483
                                        Variant 1, Version 3 UUID
483
                                        Variant 1, Version 3 UUID
484
                                        - 48 bit Hash High
484
                                        - 48 bit Hash High
485
                                        -  4 bit Version (fix 0x3)
485
                                        -  4 bit Version (fix 0x3)
486
                                        - 12 bit Hash Mid
486
                                        - 12 bit Hash Mid
487
                                        -  2 bit Variant (fix 0b10)
487
                                        -  2 bit Variant (fix 0b10)
488
                                        - 62 bit Hash Low
488
                                        - 62 bit Hash Low
489
                                        */
489
                                        */
490
 
490
 
491
                                        echo sprintf("%-32s %s\n", "Version:", "[0x3] Name-based (MD5 hash)");
491
                                        echo sprintf("%-32s %s\n", "Version:", "[0x3] Name-based (MD5 hash)");
492
 
492
 
493
                                        $hash = str_replace('-', '', strtolower($uuid));
493
                                        $hash = str_replace('-', '', strtolower($uuid));
494
 
494
 
495
                                        $hash[12] = '?'; // was overwritten by version
495
                                        $hash[12] = '?'; // was overwritten by version
496
 
496
 
497
                                        $var16a = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b0000));
497
                                        $var16a = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b0000));
498
                                        $var16b = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b0100));
498
                                        $var16b = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b0100));
499
                                        $var16c = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b1000));
499
                                        $var16c = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b1000));
500
                                        $var16d = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b1100));
500
                                        $var16d = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b1100));
501
                                        $hash[16] = '?'; // was partially overwritten by variant
501
                                        $hash[16] = '?'; // was partially overwritten by variant
502
 
502
 
503
                                        $p = 16;
503
                                        $p = 16;
504
                                        $hash = substr($hash,0,$p)."<abbr title=\"$var16a, $var16b, $var16c, or $var16d\">".substr($hash,$p,1).'</abbr>'.substr($hash,$p+1);
504
                                        $hash = substr($hash,0,$p)."<abbr title=\"$var16a, $var16b, $var16c, or $var16d\">".substr($hash,$p,1).'</abbr>'.substr($hash,$p+1);
505
                                        echo sprintf("%-32s %s\n", "MD5(Namespace+Subject):", "[0x$hash]");
505
                                        echo sprintf("%-32s %s\n", "MD5(Namespace+Subject):", "[0x$hash]");
506
 
506
 
507
                                        break;
507
                                        break;
508
                                case 4:
508
                                case 4:
509
                                        /*
509
                                        /*
510
                                        Variant 1, Version 4 UUID
510
                                        Variant 1, Version 4 UUID
511
                                        - 48 bit Random High
511
                                        - 48 bit Random High
512
                                        -  4 bit Version (fix 0x4)
512
                                        -  4 bit Version (fix 0x4)
513
                                        - 12 bit Random Mid
513
                                        - 12 bit Random Mid
514
                                        -  2 bit Variant (fix 0b10)
514
                                        -  2 bit Variant (fix 0b10)
515
                                        - 62 bit Random Low
515
                                        - 62 bit Random Low
516
                                        */
516
                                        */
517
 
517
 
518
                                        echo sprintf("%-32s %s\n", "Version:", "[0x4] Random");
518
                                        echo sprintf("%-32s %s\n", "Version:", "[0x4] Random");
519
 
519
 
520
                                        $rand_line1 = '';
520
                                        $rand_line1 = '';
521
                                        $rand_line2 = '';
521
                                        $rand_line2 = '';
522
                                        for ($i=0; $i<16; $i++) {
522
                                        for ($i=0; $i<16; $i++) {
523
                                                $bin = base_convert(substr($uuid, $i*2, 2), 16, 2);
523
                                                $bin = base_convert(substr($uuid, $i*2, 2), 16, 2);
524
                                                $bin = str_pad($bin, 8, "0", STR_PAD_LEFT);
524
                                                $bin = str_pad($bin, 8, "0", STR_PAD_LEFT);
525
 
525
 
526
                                                if ($i == 6) {
526
                                                if ($i == 6) {
527
                                                        // was overwritten by version
527
                                                        // was overwritten by version
528
                                                        $bin[0] = '?';
528
                                                        $bin[0] = '?';
529
                                                        $bin[1] = '?';
529
                                                        $bin[1] = '?';
530
                                                        $bin[2] = '?';
530
                                                        $bin[2] = '?';
531
                                                        $bin[3] = '?';
531
                                                        $bin[3] = '?';
532
                                                } else if ($i == 8) {
532
                                                } else if ($i == 8) {
533
                                                        // was partially overwritten by variant
533
                                                        // was partially overwritten by variant
534
                                                        $bin[0] = '?';
534
                                                        $bin[0] = '?';
535
                                                        $bin[1] = '?';
535
                                                        $bin[1] = '?';
536
                                                }
536
                                                }
537
 
537
 
538
                                                if ($i<8) $rand_line1 .= "$bin ";
538
                                                if ($i<8) $rand_line1 .= "$bin ";
539
                                                if ($i>=8) $rand_line2 .= "$bin ";
539
                                                if ($i>=8) $rand_line2 .= "$bin ";
540
                                        }
540
                                        }
541
                                        echo sprintf("%-32s %s\n", "Random bits:", trim($rand_line1));
541
                                        echo sprintf("%-32s %s\n", "Random bits:", trim($rand_line1));
542
                                        echo sprintf("%-32s %s\n", "",             trim($rand_line2));
542
                                        echo sprintf("%-32s %s\n", "",             trim($rand_line2));
543
 
543
 
544
                                        $rand_bytes = str_replace('-', '', strtolower($uuid));
544
                                        $rand_bytes = str_replace('-', '', strtolower($uuid));
545
                                        $rand_bytes[12] = '?'; // was overwritten by version
545
                                        $rand_bytes[12] = '?'; // was overwritten by version
546
                                        $var16a = strtoupper(dechex(hexdec($rand_bytes[16]) & 0b0011 | 0b0000));
546
                                        $var16a = strtoupper(dechex(hexdec($rand_bytes[16]) & 0b0011 | 0b0000));
547
                                        $var16b = strtoupper(dechex(hexdec($rand_bytes[16]) & 0b0011 | 0b0100));
547
                                        $var16b = strtoupper(dechex(hexdec($rand_bytes[16]) & 0b0011 | 0b0100));
548
                                        $var16c = strtoupper(dechex(hexdec($rand_bytes[16]) & 0b0011 | 0b1000));
548
                                        $var16c = strtoupper(dechex(hexdec($rand_bytes[16]) & 0b0011 | 0b1000));
549
                                        $var16d = strtoupper(dechex(hexdec($rand_bytes[16]) & 0b0011 | 0b1100));
549
                                        $var16d = strtoupper(dechex(hexdec($rand_bytes[16]) & 0b0011 | 0b1100));
550
                                        $rand_bytes[16] = '?'; // was partially overwritten by variant
550
                                        $rand_bytes[16] = '?'; // was partially overwritten by variant
551
 
551
 
552
                                        $p = 16;
552
                                        $p = 16;
553
                                        $rand_bytes = substr($rand_bytes,0,$p)."<abbr title=\"$var16a, $var16b, $var16c, or $var16d\">".substr($rand_bytes,$p,1).'</abbr>'.substr($rand_bytes,$p+1);
553
                                        $rand_bytes = substr($rand_bytes,0,$p)."<abbr title=\"$var16a, $var16b, $var16c, or $var16d\">".substr($rand_bytes,$p,1).'</abbr>'.substr($rand_bytes,$p+1);
554
                                        echo sprintf("%-32s %s\n", "Random bytes:", "[0x$rand_bytes]");
554
                                        echo sprintf("%-32s %s\n", "Random bytes:", "[0x$rand_bytes]");
555
 
555
 
556
                                        break;
556
                                        break;
557
                                case 5:
557
                                case 5:
558
                                        /*
558
                                        /*
559
                                        Variant 1, Version 5 UUID
559
                                        Variant 1, Version 5 UUID
560
                                        - 48 bit Hash High
560
                                        - 48 bit Hash High
561
                                        -  4 bit Version (fix 0x5)
561
                                        -  4 bit Version (fix 0x5)
562
                                        - 12 bit Hash Mid
562
                                        - 12 bit Hash Mid
563
                                        -  2 bit Variant (fix 0b10)
563
                                        -  2 bit Variant (fix 0b10)
564
                                        - 62 bit Hash Low
564
                                        - 62 bit Hash Low
565
                                        */
565
                                        */
566
 
566
 
567
                                        echo sprintf("%-32s %s\n", "Version:", "[0x5] Name-based (SHA-1 hash)");
567
                                        echo sprintf("%-32s %s\n", "Version:", "[0x5] Name-based (SHA-1 hash)");
568
 
568
 
569
                                        $hash = str_replace('-', '', strtolower($uuid));
569
                                        $hash = str_replace('-', '', strtolower($uuid));
570
 
570
 
571
                                        $hash[12] = '?'; // was overwritten by version
571
                                        $hash[12] = '?'; // was overwritten by version
572
 
572
 
573
                                        $var16a = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b0000));
573
                                        $var16a = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b0000));
574
                                        $var16b = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b0100));
574
                                        $var16b = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b0100));
575
                                        $var16c = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b1000));
575
                                        $var16c = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b1000));
576
                                        $var16d = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b1100));
576
                                        $var16d = strtoupper(dechex(hexdec($hash[16]) & 0b0011 | 0b1100));
577
                                        $hash[16] = '?'; // was partially overwritten by variant
577
                                        $hash[16] = '?'; // was partially overwritten by variant
578
 
578
 
579
                                        $hash .= '????????'; // was cut off
579
                                        $hash .= '????????'; // was cut off
580
 
580
 
581
                                        $p = 16;
581
                                        $p = 16;
582
                                        $hash = substr($hash,0,$p)."<abbr title=\"$var16a, $var16b, $var16c, or $var16d\">".substr($hash,$p,1).'</abbr>'.substr($hash,$p+1);
582
                                        $hash = substr($hash,0,$p)."<abbr title=\"$var16a, $var16b, $var16c, or $var16d\">".substr($hash,$p,1).'</abbr>'.substr($hash,$p+1);
583
                                        echo sprintf("%-32s %s\n", "SHA1(Namespace+Subject):", "[0x$hash]");
583
                                        echo sprintf("%-32s %s\n", "SHA1(Namespace+Subject):", "[0x$hash]");
584
 
584
 
585
                                        break;
585
                                        break;
586
                                case 7:
586
                                case 7:
587
                                        /*
587
                                        /*
588
                                        Variant 1, Version 7 UUID
588
                                        Variant 1, Version 7 UUID
589
                                        - 48 bit Unix Time in milliseconds
589
                                        - 48 bit Unix Time in milliseconds
590
                                        -  4 bit Version (fix 0x7)
590
                                        -  4 bit Version (fix 0x7)
591
                                        - 12 bit Data
591
                                        - 12 bit Data
592
                                        -  2 bit Variant (fix 0b10)
592
                                        -  2 bit Variant (fix 0b10)
593
                                        - 62 bit Data
593
                                        - 62 bit Data
594
 
594
 
595
                                        Structure of data (74 bits):
595
                                        Structure of data (74 bits):
596
                                        - OPTIONAL : Sub-millisecond timestamp fraction (0-12 bits)
596
                                        - OPTIONAL : Sub-millisecond timestamp fraction (0-12 bits)
597
                                        - OPTIONAL : Carefully seeded counter
597
                                        - OPTIONAL : Carefully seeded counter
598
                                        - Random generated bits for any remaining space
598
                                        - Random generated bits for any remaining space
599
 
599
 
600
                                        Since we don't know if timestamp fraction or counters are implemented
600
                                        Since we don't know if timestamp fraction or counters are implemented
601
                                        (and if so, how many bits), we don't decode this information
601
                                        (and if so, how many bits), we don't decode this information
602
                                        */
602
                                        */
603
 
603
 
604
                                        echo sprintf("%-32s %s\n", "Version:", "[0x7] Unix Epoch Time");
604
                                        echo sprintf("%-32s %s\n", "Version:", "[0x7] Unix Epoch Time");
605
 
605
 
606
                                        $timestamp = substr($uuid, 0, 12);
606
                                        $timestamp = substr($uuid, 0, 12);
607
 
607
 
608
                                        // Timestamp: Split into seconds and milliseconds
608
                                        // Timestamp: Split into seconds and milliseconds
609
                                        $ts = gmp_init($timestamp, 16);
609
                                        $ts = gmp_init($timestamp, 16);
610
                                        $ms = gmp_mod($ts, gmp_init("1000", 10));
610
                                        $ms = gmp_mod($ts, gmp_init("1000", 10));
611
                                        $ts = gmp_div($ts, gmp_init("1000", 10));
611
                                        $ts = gmp_div($ts, gmp_init("1000", 10));
612
                                        $ts = gmp_strval($ts, 10);
612
                                        $ts = gmp_strval($ts, 10);
613
                                        $ms = gmp_strval($ms, 10);
613
                                        $ms = gmp_strval($ms, 10);
614
                                        $ts = gmdate('Y-m-d H:i:s', intval($ts))."'".str_pad($ms, 3/*ms*/, '0', STR_PAD_LEFT).' GMT';
614
                                        $ts = gmdate('Y-m-d H:i:s', intval($ts))."'".str_pad($ms, 3/*ms*/, '0', STR_PAD_LEFT).' GMT';
615
                                        echo sprintf("%-32s %s\n", "Timestamp:", "[0x$timestamp] $ts");
615
                                        echo sprintf("%-32s %s\n", "Timestamp:", "[0x$timestamp] $ts");
616
 
616
 
617
                                        $rand = '';
617
                                        $rand = '';
618
                                        for ($i=6; $i<16; $i++) {
618
                                        for ($i=6; $i<16; $i++) {
619
                                                $bin = base_convert(substr($uuid, $i*2, 2), 16, 2);
619
                                                $bin = base_convert(substr($uuid, $i*2, 2), 16, 2);
620
                                                $bin = str_pad($bin, 8, "0", STR_PAD_LEFT);
620
                                                $bin = str_pad($bin, 8, "0", STR_PAD_LEFT);
621
 
621
 
622
                                                if ($i == 6) {
622
                                                if ($i == 6) {
623
                                                        // was overwritten by version
623
                                                        // was overwritten by version
624
                                                        $bin[0] = '?';
624
                                                        $bin[0] = '?';
625
                                                        $bin[1] = '?';
625
                                                        $bin[1] = '?';
626
                                                        $bin[2] = '?';
626
                                                        $bin[2] = '?';
627
                                                        $bin[3] = '?';
627
                                                        $bin[3] = '?';
628
                                                } else if ($i == 8) {
628
                                                } else if ($i == 8) {
629
                                                        // was partially overwritten by variant
629
                                                        // was partially overwritten by variant
630
                                                        $bin[0] = '?';
630
                                                        $bin[0] = '?';
631
                                                        $bin[1] = '?';
631
                                                        $bin[1] = '?';
632
                                                }
632
                                                }
633
 
633
 
634
                                                $rand .= "$bin ";
634
                                                $rand .= "$bin ";
635
                                        }
635
                                        }
636
                                        echo sprintf("%-32s %s\n", "Random bits:", trim($rand));
636
                                        echo sprintf("%-32s %s\n", "Random bits:", trim($rand));
637
 
637
 
638
                                        $rand_bytes = substr(str_replace('-', '', strtolower($uuid)),13);
638
                                        $rand_bytes = substr(str_replace('-', '', strtolower($uuid)),13);
639
                                        $var16a = strtoupper(dechex(hexdec($rand_bytes[3]) & 0b0011 | 0b0000));
639
                                        $var16a = strtoupper(dechex(hexdec($rand_bytes[3]) & 0b0011 | 0b0000));
640
                                        $var16b = strtoupper(dechex(hexdec($rand_bytes[3]) & 0b0011 | 0b0100));
640
                                        $var16b = strtoupper(dechex(hexdec($rand_bytes[3]) & 0b0011 | 0b0100));
641
                                        $var16c = strtoupper(dechex(hexdec($rand_bytes[3]) & 0b0011 | 0b1000));
641
                                        $var16c = strtoupper(dechex(hexdec($rand_bytes[3]) & 0b0011 | 0b1000));
642
                                        $var16d = strtoupper(dechex(hexdec($rand_bytes[3]) & 0b0011 | 0b1100));
642
                                        $var16d = strtoupper(dechex(hexdec($rand_bytes[3]) & 0b0011 | 0b1100));
643
                                        $rand_bytes[3] = '?'; // was partially overwritten by variant
643
                                        $rand_bytes[3] = '?'; // was partially overwritten by variant
644
 
644
 
645
                                        $p = 3;
645
                                        $p = 3;
646
                                        $rand_bytes = substr($rand_bytes,0,$p)."<abbr title=\"$var16a, $var16b, $var16c, or $var16d\">".substr($rand_bytes,$p,1).'</abbr>'.substr($rand_bytes,$p+1);
646
                                        $rand_bytes = substr($rand_bytes,0,$p)."<abbr title=\"$var16a, $var16b, $var16c, or $var16d\">".substr($rand_bytes,$p,1).'</abbr>'.substr($rand_bytes,$p+1);
647
                                        echo sprintf("%-32s %s\n", "Random bytes:", "[0x$rand_bytes]");
647
                                        echo sprintf("%-32s %s\n", "Random bytes:", "[0x$rand_bytes]");
648
 
648
 
649
                                        // TODO: convert to and from Base32 CROCKFORD ULID (make 2 methods in uuid_utils.inc.php)
649
                                        // TODO: convert to and from Base32 CROCKFORD ULID (make 2 methods in uuid_utils.inc.php)
650
                                        // e.g. ULID: 01GCZ05N3JFRKBRWKNGCQZGP44
650
                                        // e.g. ULID: 01GCZ05N3JFRKBRWKNGCQZGP44
651
                                        // "Be aware that all version 7 UUIDs may be converted to ULIDs but not all ULIDs may be converted to UUIDs."
651
                                        // "Be aware that all version 7 UUIDs may be converted to ULIDs but not all ULIDs may be converted to UUIDs."
652
 
652
 
653
                                        break;
653
                                        break;
654
                                case 8:
654
                                case 8:
655
                                        /*
655
                                        /*
656
                                        Variant 1, Version 8 UUID
656
                                        Variant 1, Version 8 UUID
657
                                        - 48 bit Custom data [Block 1+2]
657
                                        - 48 bit Custom data [Block 1+2]
658
                                        -  4 bit Version (fix 0x8)
658
                                        -  4 bit Version (fix 0x8)
659
                                        - 12 bit Custom data [Block 3]
659
                                        - 12 bit Custom data [Block 3]
660
                                        -  2 bit Variant (fix 0b10)
660
                                        -  2 bit Variant (fix 0b10)
661
                                        - 62 bit Custom data [Block 4+5]
661
                                        - 62 bit Custom data [Block 4+5]
662
                                        */
662
                                        */
663
 
663
 
664
                                        echo sprintf("%-32s %s\n", "Version:", "[0x8] Custom implementation");
664
                                        echo sprintf("%-32s %s\n", "Version:", "[0x8] Custom implementation");
665
 
665
 
666
                                        $custom_data = substr($uuid,0,12).substr($uuid,13); // exclude version nibble
666
                                        $custom_data = substr($uuid,0,12).substr($uuid,13); // exclude version nibble
667
                                        $custom_data[15] = dechex(hexdec($custom_data[15]) & 0b0011); // nibble was partially overwritten by variant
667
                                        $custom_data[15] = dechex(hexdec($custom_data[15]) & 0b0011); // nibble was partially overwritten by variant
668
                                        $custom_data = strtolower($custom_data);
668
                                        $custom_data = strtolower($custom_data);
669
 
669
 
670
                                        $custom_block1 = substr($uuid,  0, 8);
670
                                        $custom_block1 = substr($uuid,  0, 8);
671
                                        $custom_block2 = substr($uuid,  8, 4);
671
                                        $custom_block2 = substr($uuid,  8, 4);
672
                                        $custom_block3 = substr($uuid, 12, 4);
672
                                        $custom_block3 = substr($uuid, 12, 4);
673
                                        $custom_block4 = substr($uuid, 16, 4);
673
                                        $custom_block4 = substr($uuid, 16, 4);
674
                                        $custom_block5 = substr($uuid, 20);
674
                                        $custom_block5 = substr($uuid, 20);
675
 
675
 
676
                                        $custom_block3 = substr($custom_block3, 1); // remove version
676
                                        $custom_block3 = substr($custom_block3, 1); // remove version
677
                                        $custom_block4[0] = dechex(hexdec($custom_block4[0]) & 0b0011); // remove variant
677
                                        $custom_block4[0] = dechex(hexdec($custom_block4[0]) & 0b0011); // remove variant
678
 
678
 
679
                                        echo sprintf("%-32s %s\n", "Custom data:", "[0x$custom_data]");
679
                                        echo sprintf("%-32s %s\n", "Custom data:", "[0x$custom_data]");
680
                                        echo sprintf("%-32s %s\n", "Custom data block1 (32 bit):", "[0x$custom_block1]");
680
                                        echo sprintf("%-32s %s\n", "Custom data block1 (32 bit):", "[0x$custom_block1]");
681
                                        echo sprintf("%-32s %s\n", "Custom data block2 (16 bit):", "[0x$custom_block2]");
681
                                        echo sprintf("%-32s %s\n", "Custom data block2 (16 bit):", "[0x$custom_block2]");
682
                                        echo sprintf("%-32s %s\n", "Custom data block3 (12 bit):", "[0x$custom_block3]");
682
                                        echo sprintf("%-32s %s\n", "Custom data block3 (12 bit):", "[0x$custom_block3]");
683
                                        echo sprintf("%-32s %s\n", "Custom data block4 (14 bit):", "[0x$custom_block4]");
683
                                        echo sprintf("%-32s %s\n", "Custom data block4 (14 bit):", "[0x$custom_block4]");
684
                                        echo sprintf("%-32s %s\n", "Custom data block5 (48 bit):", "[0x$custom_block5]");
684
                                        echo sprintf("%-32s %s\n", "Custom data block5 (48 bit):", "[0x$custom_block5]");
685
 
685
 
686
                                        // START: Check if Custom UUIDv8 is likely an OIDplus 2.0 Custom UUID
686
                                        // START: Check if Custom UUIDv8 is likely an OIDplus 2.0 Custom UUID
687
 
687
 
688
                                        $oidplus_systemid_hex = $custom_block1;
688
                                        $oidplus_systemid_hex = $custom_block1;
689
                                        $oidplus_systemid_int = hexdec($oidplus_systemid_hex); // 31 bit hash of public key
689
                                        $oidplus_systemid_int = hexdec($oidplus_systemid_hex); // 31 bit hash of public key
690
                                        $oidplus_systemid_valid = hexdec($custom_block1) < 0x80000000;
690
                                        $oidplus_systemid_valid = hexdec($custom_block1) < 0x80000000;
691
 
691
 
692
                                        $oidplus_creation_hex = $custom_block2;
692
                                        $oidplus_creation_hex = $custom_block2;
693
                                        $oidplus_creation_int = hexdec($oidplus_creation_hex); // days since 1 January 1970, or 0 if unknown
693
                                        $oidplus_creation_int = hexdec($oidplus_creation_hex); // days since 1 January 1970, or 0 if unknown
694
                                        //$oidplus_creation_valid = ($oidplus_creation_int >= 14610/*1 Jan 2010*/) && ($oidplus_creation_int <= floor(time()/24/60/60)/*Today*/);
694
                                        //$oidplus_creation_valid = ($oidplus_creation_int >= 14610/*1 Jan 2010*/) && ($oidplus_creation_int <= floor(time()/24/60/60)/*Today*/);
695
                                        $oidplus_creation_unknown = $oidplus_creation_int == 0;
695
                                        $oidplus_creation_unknown = $oidplus_creation_int == 0;
696
 
696
 
697
                                        $oidplus_reserved_hex = $custom_block3;
697
                                        $oidplus_reserved_hex = $custom_block3;
698
                                        $oidplus_reserved_int = hexdec($oidplus_reserved_hex);
698
                                        $oidplus_reserved_int = hexdec($oidplus_reserved_hex);
699
 
699
 
700
                                        $oidplus_namespace_hex = $custom_block4;
700
                                        $oidplus_namespace_hex = $custom_block4;
701
                                        $oidplus_namespace_int = hexdec($oidplus_namespace_hex);
701
                                        $oidplus_namespace_int = hexdec($oidplus_namespace_hex);
702
 
702
 
703
                                        $oidplus_data_hex = $custom_block5;
703
                                        $oidplus_data_hex = $custom_block5;
704
                                        $oidplus_data_int = (PHP_INT_SIZE == 4) ? gmp_strval(gmp_init($oidplus_data_hex,16),10) : hexdec($custom_block5);
704
                                        $oidplus_data_int = (PHP_INT_SIZE == 4) ? gmp_strval(gmp_init($oidplus_data_hex,16),10) : hexdec($custom_block5);
705
 
705
 
706
                                        if ($oidplus_systemid_valid && ($oidplus_reserved_int == 0)) {
706
                                        if ($oidplus_systemid_valid && ($oidplus_reserved_int == 0)) {
707
                                                if (($oidplus_namespace_int == 0) && $oidplus_creation_unknown && (strtolower($oidplus_data_hex) == '1890afd80709')) {
707
                                                if (($oidplus_namespace_int == 0) && $oidplus_creation_unknown && (strtolower($oidplus_data_hex) == '1890afd80709')) {
708
                                                        // System GUID, e.g. 6e932dd7-0000-8000-8000-1890afd80709
708
                                                        // System GUID, e.g. 6e932dd7-0000-8000-8000-1890afd80709
709
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
709
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
710
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
710
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
711
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60))); /**@phpstan-ignore-line*/
711
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60))); /**@phpstan-ignore-line*/
712
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
712
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
713
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=System");
713
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=System");
714
                                                        echo sprintf("%-32s %s\n", "Data (empty string hash):", "[0x$oidplus_data_hex] SHA1('') = ????????????????????????????$oidplus_data_hex");
714
                                                        echo sprintf("%-32s %s\n", "Data (empty string hash):", "[0x$oidplus_data_hex] SHA1('') = ????????????????????????????$oidplus_data_hex");
715
                                                }
715
                                                }
716
                                                else if (($oidplus_namespace_int == 1) && $oidplus_creation_unknown) {
716
                                                else if (($oidplus_namespace_int == 1) && $oidplus_creation_unknown) {
717
                                                        // User GUID, e.g. 6e932dd7-0000-8000-8001-2938f50e857e (User), 6e932dd7-0000-8000-8001-000000000000 (Admin)
717
                                                        // User GUID, e.g. 6e932dd7-0000-8000-8001-2938f50e857e (User), 6e932dd7-0000-8000-8001-000000000000 (Admin)
718
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
718
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
719
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
719
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
720
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));  /**@phpstan-ignore-line*/
720
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));  /**@phpstan-ignore-line*/
721
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
721
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
722
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=User");
722
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=User");
723
                                                        if ($oidplus_data_int == 0) {
723
                                                        if ($oidplus_data_int == 0) {
724
                                                                echo sprintf("%-32s %s\n", "Data (Username):", "[0x$oidplus_data_hex] 0=Admin");
724
                                                                echo sprintf("%-32s %s\n", "Data (Username):", "[0x$oidplus_data_hex] 0=Admin");
725
                                                        } else {
725
                                                        } else {
726
                                                                echo sprintf("%-32s %s\n", "Data (Username):", "[0x$oidplus_data_hex] SHA1(UserName) = ????????????????????????????$oidplus_data_hex");
726
                                                                echo sprintf("%-32s %s\n", "Data (Username):", "[0x$oidplus_data_hex] SHA1(UserName) = ????????????????????????????$oidplus_data_hex");
727
                                                        }
727
                                                        }
728
                                                }
728
                                                }
729
                                                else if (($oidplus_namespace_int == 2)/* && $oidplus_creation_valid*/) {
729
                                                else if (($oidplus_namespace_int == 2)/* && $oidplus_creation_valid*/) {
730
                                                        // Log entry GUID, e.g. 6e932dd7-458c-8000-8002-0000000004d2
730
                                                        // Log entry GUID, e.g. 6e932dd7-458c-8000-8002-0000000004d2
731
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
731
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
732
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
732
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
733
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));
733
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));
734
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
734
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
735
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=Log Entry");
735
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=Log Entry");
736
                                                        echo sprintf("%-32s %s\n", "Data (Sequence number):", "[0x$oidplus_data_hex] $oidplus_data_int");
736
                                                        echo sprintf("%-32s %s\n", "Data (Sequence number):", "[0x$oidplus_data_hex] $oidplus_data_int");
737
                                                }
737
                                                }
738
                                                else if (($oidplus_namespace_int == 3) && $oidplus_creation_unknown) {
738
                                                else if (($oidplus_namespace_int == 3) && $oidplus_creation_unknown) {
739
                                                        // Configuration entry GUID, e.g. 6e932dd7-0000-8000-8003-f14dda42862a
739
                                                        // Configuration entry GUID, e.g. 6e932dd7-0000-8000-8003-f14dda42862a
740
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
740
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
741
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
741
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
742
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60))); /**@phpstan-ignore-line*/
742
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60))); /**@phpstan-ignore-line*/
743
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
743
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
744
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=Configuration Entry");
744
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=Configuration Entry");
745
                                                        echo sprintf("%-32s %s\n", "Data (Setting name hash):", "[0x$oidplus_data_hex] SHA1(SettingName) = ????????????????????????????$oidplus_data_hex");
745
                                                        echo sprintf("%-32s %s\n", "Data (Setting name hash):", "[0x$oidplus_data_hex] SHA1(SettingName) = ????????????????????????????$oidplus_data_hex");
746
                                                }
746
                                                }
747
                                                else if ($oidplus_namespace_int == 4) {
747
                                                else if ($oidplus_namespace_int == 4) {
748
                                                        // ASN.1 Alpahnumeric identifier GUID, e.g. 6e932dd7-0000-8000-8004-208ded8a3f8f
748
                                                        // ASN.1 Alpahnumeric identifier GUID, e.g. 6e932dd7-0000-8000-8004-208ded8a3f8f
749
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
749
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
750
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
750
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
751
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));
751
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));
752
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
752
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
753
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=ASN.1 Alphanumeric ID");
753
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=ASN.1 Alphanumeric ID");
754
                                                        $oidplus_data_24hi_hex = substr($oidplus_data_hex, 0, 6);
754
                                                        $oidplus_data_24hi_hex = substr($oidplus_data_hex, 0, 6);
755
                                                        $oidplus_data_24lo_hex = substr($oidplus_data_hex, 6, 6);
755
                                                        $oidplus_data_24lo_hex = substr($oidplus_data_hex, 6, 6);
756
                                                        echo sprintf("%-32s %s\n", "Data (OID hash):", "[0x$oidplus_data_24hi_hex] SHA1(OID) = ????????????????????????????$oidplus_data_24hi_hex");
756
                                                        echo sprintf("%-32s %s\n", "Data (OID hash):", "[0x$oidplus_data_24hi_hex] SHA1(OID) = ????????????????????????????$oidplus_data_24hi_hex");
757
                                                        echo sprintf("%-32s %s\n", "Data (Name hash):", "[0x$oidplus_data_24lo_hex] SHA1(AlphaNumId) = ????????????????????????????$oidplus_data_24lo_hex");
757
                                                        echo sprintf("%-32s %s\n", "Data (Name hash):", "[0x$oidplus_data_24lo_hex] SHA1(AlphaNumId) = ????????????????????????????$oidplus_data_24lo_hex");
758
                                                }
758
                                                }
759
                                                else if ($oidplus_namespace_int == 5) {
759
                                                else if ($oidplus_namespace_int == 5) {
760
                                                        // Unicode Label entry GUID, e.g. 6e932dd7-0000-8000-8005-208dedaf9a96
760
                                                        // Unicode Label entry GUID, e.g. 6e932dd7-0000-8000-8005-208dedaf9a96
761
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
761
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
762
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
762
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
763
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));
763
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));
764
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
764
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
765
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=Unicode Label");
765
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=Unicode Label");
766
                                                        $oidplus_data_24hi_hex = substr($oidplus_data_hex, 0, 6);
766
                                                        $oidplus_data_24hi_hex = substr($oidplus_data_hex, 0, 6);
767
                                                        $oidplus_data_24lo_hex = substr($oidplus_data_hex, 6, 6);
767
                                                        $oidplus_data_24lo_hex = substr($oidplus_data_hex, 6, 6);
768
                                                        echo sprintf("%-32s %s\n", "Data (OID hash):", "[0x$oidplus_data_24hi_hex] SHA1(OID) = ????????????????????????????$oidplus_data_24hi_hex");
768
                                                        echo sprintf("%-32s %s\n", "Data (OID hash):", "[0x$oidplus_data_24hi_hex] SHA1(OID) = ????????????????????????????$oidplus_data_24hi_hex");
769
                                                        echo sprintf("%-32s %s\n", "Data (Name hash):", "[0x$oidplus_data_24lo_hex] SHA1(UnicodeLabel) = ????????????????????????????$oidplus_data_24lo_hex");
769
                                                        echo sprintf("%-32s %s\n", "Data (Name hash):", "[0x$oidplus_data_24lo_hex] SHA1(UnicodeLabel) = ????????????????????????????$oidplus_data_24lo_hex");
770
                                                }
770
                                                }
771
                                                else if (($oidplus_namespace_int >= 6) && ($oidplus_namespace_int <= 0xF)) {
771
                                                else if (($oidplus_namespace_int >= 6) && ($oidplus_namespace_int <= 0xF)) {
772
                                                        // System reserved
772
                                                        // System reserved
773
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
773
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
774
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
774
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
775
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));
775
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));
776
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
776
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
777
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=Unknown (System Reserved)");
777
                                                        echo sprintf("%-32s %s\n", "Namespace:", "[0x$oidplus_namespace_hex] $oidplus_namespace_int=Unknown (System Reserved)");
778
                                                        echo sprintf("%-32s %s\n", "Data (Setting name hash):", "[0x$oidplus_data_hex] Unknown");
778
                                                        echo sprintf("%-32s %s\n", "Data (Setting name hash):", "[0x$oidplus_data_hex] Unknown");
779
                                                }
779
                                                }
780
                                                else if ($oidplus_namespace_int > 0xF) {
780
                                                else if ($oidplus_namespace_int > 0xF) {
781
                                                        // Information Object GUID, e.g. 6e932dd7-458c-8000-b9e9-c1e3894d1105
781
                                                        // Information Object GUID, e.g. 6e932dd7-458c-8000-b9e9-c1e3894d1105
782
                                                        $known_objecttype_plugins = array(
782
                                                        $known_objecttype_plugins = array(
783
                                                                // Latest list here: https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md
783
                                                                // Latest list here: https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md
784
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.1' => 'doi (ViaThinkSoft plugin)',
784
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.1' => 'doi (ViaThinkSoft plugin)',
785
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.2' => 'gs1 (ViaThinkSoft plugin)',
785
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.2' => 'gs1 (ViaThinkSoft plugin)',
786
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.3' => 'guid (ViaThinkSoft plugin)',
786
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.3' => 'guid (ViaThinkSoft plugin)',
787
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.4' => 'ipv4 (ViaThinkSoft plugin)',
787
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.4' => 'ipv4 (ViaThinkSoft plugin)',
788
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.5' => 'ipv6 (ViaThinkSoft plugin)',
788
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.5' => 'ipv6 (ViaThinkSoft plugin)',
789
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.6' => 'java (ViaThinkSoft plugin)',
789
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.6' => 'java (ViaThinkSoft plugin)',
790
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.7' => 'oid (ViaThinkSoft plugin)',
790
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.7' => 'oid (ViaThinkSoft plugin)',
791
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.8' => 'other (ViaThinkSoft plugin)',
791
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.8' => 'other (ViaThinkSoft plugin)',
792
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.9' => 'domain (ViaThinkSoft plugin)',
792
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.9' => 'domain (ViaThinkSoft plugin)',
793
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.10' => 'fourcc (ViaThinkSoft plugin)',
793
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.10' => 'fourcc (ViaThinkSoft plugin)',
794
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.11' => 'aid (ViaThinkSoft plugin)',
794
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.11' => 'aid (ViaThinkSoft plugin)',
795
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.12' => 'php (ViaThinkSoft plugin)',
795
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.12' => 'php (ViaThinkSoft plugin)',
796
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.13' => 'mac (ViaThinkSoft plugin)',
796
                                                                '1.3.6.1.4.1.37476.2.5.2.4.8.13' => 'mac (ViaThinkSoft plugin)',
797
                                                                '1.3.6.1.4.1.37553.8.1.8.8.53354196964.27255728261' => 'circuit (Frdlweb plugin)',
797
                                                                '1.3.6.1.4.1.37553.8.1.8.8.53354196964.27255728261' => 'circuit (Frdlweb plugin)',
798
                                                                '1.3.6.1.4.1.37476.9000.108.19361.856' => 'ns (Frdlweb plugin)',
798
                                                                '1.3.6.1.4.1.37476.9000.108.19361.856' => 'ns (Frdlweb plugin)',
799
                                                                '1.3.6.1.4.1.37553.8.1.8.8.53354196964.32927' => 'pen (Frdlweb plugin)',
799
                                                                '1.3.6.1.4.1.37553.8.1.8.8.53354196964.32927' => 'pen (Frdlweb plugin)',
800
                                                                '1.3.6.1.4.1.37553.8.1.8.8.53354196964.39870' => 'uri (Frdlweb plugin)',
800
                                                                '1.3.6.1.4.1.37553.8.1.8.8.53354196964.39870' => 'uri (Frdlweb plugin)',
801
                                                                '1.3.6.1.4.1.37553.8.1.8.8.53354196964.1958965295' => 'web+fan (Frdlweb plugin)'
801
                                                                '1.3.6.1.4.1.37553.8.1.8.8.53354196964.1958965295' => 'web+fan (Frdlweb plugin)'
802
                                                        );
802
                                                        );
803
                                                        $namespace_desc = 'Unknown object type';
803
                                                        $namespace_desc = 'Unknown object type';
804
                                                        foreach ($known_objecttype_plugins as $oid => $name) {
804
                                                        foreach ($known_objecttype_plugins as $oid => $name) {
805
                                                                if ((hexdec(substr(sha1($oid), -4)) & 0x3fff) == $oidplus_namespace_int) $namespace_desc = "$oid = $name";
805
                                                                if ((hexdec(substr(sha1($oid), -4)) & 0x3fff) == $oidplus_namespace_int) $namespace_desc = "$oid = $name";
806
                                                        }
806
                                                        }
807
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
807
                                                        echo "\n<u>Interpretation of <a href=\"https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md\">OIDplus 2.0 Custom UUID</a></u>\n\n";
808
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
808
                                                        echo sprintf("%-32s %s\n", "System ID:", "[0x$oidplus_systemid_hex] ".$oidplus_systemid_int);
809
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));
809
                                                        echo sprintf("%-32s %s\n", "Creation time:", "[0x$oidplus_creation_hex] ".($oidplus_creation_unknown ? 'Unknown' : date('Y-m-d', $oidplus_creation_int*24*60*60)));
810
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
810
                                                        echo sprintf("%-32s %s\n", "Reserved:", "[0x$oidplus_reserved_hex]");
811
                                                        echo sprintf("%-32s %s\n", "Namespace (Obj.type OID hash):", "[0x$oidplus_namespace_hex] $namespace_desc");
811
                                                        echo sprintf("%-32s %s\n", "Namespace (Obj.type OID hash):", "[0x$oidplus_namespace_hex] $namespace_desc");
812
                                                        echo sprintf("%-32s %s\n", "Data (Object name hash):", "[0x$oidplus_data_hex] SHA1(ObjectName) = ????????????????????????????$oidplus_data_hex");
812
                                                        echo sprintf("%-32s %s\n", "Data (Object name hash):", "[0x$oidplus_data_hex] SHA1(ObjectName) = ????????????????????????????$oidplus_data_hex");
813
                                                }
813
                                                }
814
                                        }
814
                                        }
815
 
815
 
816
                                        // END: OIDplus 2.0 Custom UUID Interpretation
816
                                        // END: OIDplus 2.0 Custom UUID Interpretation
817
 
817
 
818
                                        break;
818
                                        break;
819
                                default:
819
                                default:
820
                                        echo sprintf("%-32s %s\n", "Version:", "[0x".dechex($version)."] Unknown");
820
                                        echo sprintf("%-32s %s\n", "Version:", "[0x".dechex($version)."] Unknown");
821
                                        break;
821
                                        break;
822
                        }
822
                        }
823
 
823
 
824
                        break;
824
                        break;
825
                case 2:
825
                case 2:
826
                        // TODO: Show byte order: 00112233-4455-6677-8899-aabbccddeeff => 33 22 11 00 55 44 77 66 88 99 aa bb cc dd ee ff
826
                        // TODO: Show byte order: 00112233-4455-6677-8899-aabbccddeeff => 33 22 11 00 55 44 77 66 88 99 aa bb cc dd ee ff
827
 
827
 
828
                        // TODO: Is there any scheme in that legacy Microsoft GUIDs?
828
                        // TODO: Is there any scheme in that legacy Microsoft GUIDs?
829
                        echo sprintf("%-32s %s\n", "Variant:", "[0b110] Reserved for Microsoft Corporation");
829
                        echo sprintf("%-32s %s\n", "Variant:", "[0b110] Reserved for Microsoft Corporation");
830
                        break;
830
                        break;
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 {
841
                return true;
937
                return true;
842
        }
938
        }
843
}
939
}
844
 
940
 
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
 
850
/*
946
/*
851
assert(oid_to_uuid('2.25.111325678376819997685911819737516232943')=='53c08bb6-b2eb-5038-bf28-ad41a08c50ef');
947
assert(oid_to_uuid('2.25.111325678376819997685911819737516232943')=='53c08bb6-b2eb-5038-bf28-ad41a08c50ef');
852
assert(oid_to_uuid('1.2.840.113556.1.8000.2554.21440.35766.45803.20536.48936.11354528.9195759')=='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');
853
assert(oid_to_uuid('1.3.6.1.4.1.54392.1.6034977117478539320.13774449957690691823')=='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');
854
assert(oid_to_uuid('1.3.6.1.4.1.54392.2.1405127606.3001765944.3207114049.2693550319')=='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');
855
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');
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');
856
*/
952
*/
857
function oid_to_uuid($oid) {
953
function oid_to_uuid($oid) {
858
        if (substr($oid,0,1) == '.') $oid = substr($oid, 1); // remove leading dot
954
        if (substr($oid,0,1) == '.') $oid = substr($oid, 1); // remove leading dot
859
 
955
 
860
        // Information about Microsoft and Waterjuice UUID-OID: https://waterjuiceweb.wordpress.com/2019/09/24/guids-to-oids/
956
        // Information about Microsoft and Waterjuice UUID-OID: https://waterjuiceweb.wordpress.com/2019/09/24/guids-to-oids/
861
 
957
 
862
        $ary = explode('.', $oid);
958
        $ary = explode('.', $oid);
863
        if ((count($ary) == 3) && (strpos($oid, '2.25.') === 0)) {
959
        if ((count($ary) == 3) && (strpos($oid, '2.25.') === 0)) {
864
                // ISO/ITU-T UUID-to-OID
960
                // ISO/ITU-T UUID-to-OID
865
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 2.25.111325678376819997685911819737516232943
961
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 2.25.111325678376819997685911819737516232943
866
                $val = $ary[2];
962
                $val = $ary[2];
867
                $dec = gmp_init($val, 10);
963
                $dec = gmp_init($val, 10);
868
                $hex = gmp_strval($dec, 16);
964
                $hex = gmp_strval($dec, 16);
869
                $hex = str_pad($hex, 32, "0", STR_PAD_LEFT);
965
                $hex = str_pad($hex, 32, "0", STR_PAD_LEFT);
870
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
966
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
871
        } else if ((count($ary) == 14) && (strpos($oid, '1.2.840.113556.1.8000.2554.') === 0)) {
967
        } else if ((count($ary) == 14) && (strpos($oid, '1.2.840.113556.1.8000.2554.') === 0)) {
872
                // Microsoft UUID-to-OID
968
                // Microsoft UUID-to-OID
873
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.2.840.113556.1.8000.2554.21440.35766.45803.20536.48936.11354528.9195759
969
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.2.840.113556.1.8000.2554.21440.35766.45803.20536.48936.11354528.9195759
874
                $a = $ary[7];
970
                $a = intval($ary[7]);
875
                $b = $ary[8];
971
                $b = intval($ary[8]);
876
                $c = $ary[9];
972
                $c = intval($ary[9]);
877
                $d = $ary[10];
973
                $d = intval($ary[10]);
878
                $e = $ary[11];
974
                $e = intval($ary[11]);
879
                $f = $ary[12];
975
                $f = intval($ary[12]);
880
                $g = $ary[13];
976
                $g = intval($ary[13]);
881
                return dechex($a).dechex($b).'-'.dechex($c).'-'.dechex($d).'-'.dechex($e).'-'.dechex($f).dechex($g);
977
                return dechex($a).dechex($b).'-'.dechex($c).'-'.dechex($d).'-'.dechex($e).'-'.dechex($f).dechex($g);
882
        } else if ((count($ary) == 10) && (strpos($oid, '1.3.6.1.4.1.54392.1.') === 0)) {
978
        } else if ((count($ary) == 10) && (strpos($oid, '1.3.6.1.4.1.54392.1.') === 0)) {
883
                // Waterjuice UUID-to-OID 2x64 Bits
979
                // Waterjuice UUID-to-OID 2x64 Bits
884
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.3.6.1.4.1.54392.1.6034977117478539320.13774449957690691823
980
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.3.6.1.4.1.54392.1.6034977117478539320.13774449957690691823
885
                $a1 = gmp_strval(gmp_init($ary[8],10),16); if (strlen($a1)>16) return false;
981
                $a1 = gmp_strval(gmp_init($ary[8],10),16); if (strlen($a1)>16) return false;
886
                $a2 = gmp_strval(gmp_init($ary[9],10),16); if (strlen($a2)>16) return false;
982
                $a2 = gmp_strval(gmp_init($ary[9],10),16); if (strlen($a2)>16) return false;
887
                $hex =
983
                $hex =
888
                        str_pad($a1, 16, "0", STR_PAD_LEFT).
984
                        str_pad($a1, 16, "0", STR_PAD_LEFT).
889
                        str_pad($a2, 16, "0", STR_PAD_LEFT);
985
                        str_pad($a2, 16, "0", STR_PAD_LEFT);
890
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
986
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
891
        } else if ((count($ary) == 12) && (strpos($oid, '1.3.6.1.4.1.54392.2.') === 0)) {
987
        } else if ((count($ary) == 12) && (strpos($oid, '1.3.6.1.4.1.54392.2.') === 0)) {
892
                // Waterjuice UUID-to-OID 4x32 Bits
988
                // Waterjuice UUID-to-OID 4x32 Bits
893
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.3.6.1.4.1.54392.2.1405127606.3001765944.3207114049.2693550319
989
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.3.6.1.4.1.54392.2.1405127606.3001765944.3207114049.2693550319
894
                $a1 = gmp_strval(gmp_init($ary[8],10),16); if (strlen($a1)>8) return false;
990
                $a1 = gmp_strval(gmp_init($ary[8],10),16); if (strlen($a1)>8) return false;
895
                $a2 = gmp_strval(gmp_init($ary[9],10),16); if (strlen($a2)>8) return false;
991
                $a2 = gmp_strval(gmp_init($ary[9],10),16); if (strlen($a2)>8) return false;
896
                $a3 = gmp_strval(gmp_init($ary[10],10),16); if (strlen($a3)>8) return false;
992
                $a3 = gmp_strval(gmp_init($ary[10],10),16); if (strlen($a3)>8) return false;
897
                $a4 = gmp_strval(gmp_init($ary[11],10),16); if (strlen($a4)>8) return false;
993
                $a4 = gmp_strval(gmp_init($ary[11],10),16); if (strlen($a4)>8) return false;
898
                $hex =
994
                $hex =
899
                        str_pad($a1, 8, "0", STR_PAD_LEFT).
995
                        str_pad($a1, 8, "0", STR_PAD_LEFT).
900
                        str_pad($a2, 8, "0", STR_PAD_LEFT).
996
                        str_pad($a2, 8, "0", STR_PAD_LEFT).
901
                        str_pad($a3, 8, "0", STR_PAD_LEFT).
997
                        str_pad($a3, 8, "0", STR_PAD_LEFT).
902
                        str_pad($a4, 8, "0", STR_PAD_LEFT);
998
                        str_pad($a4, 8, "0", STR_PAD_LEFT);
903
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
999
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
904
        } else if ((count($ary) == 16) && (strpos($oid, '1.3.6.1.4.1.54392.3.') === 0)) {
1000
        } else if ((count($ary) == 16) && (strpos($oid, '1.3.6.1.4.1.54392.3.') === 0)) {
905
                // Waterjuice UUID-to-OID 8x16 Bits
1001
                // Waterjuice UUID-to-OID 8x16 Bits
906
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.3.6.1.4.1.54392.3.21440.35766.45803.20536.48936.44353.41100.20719
1002
                // Example: {53c08bb6-b2eb-5038-bf28-ad41a08c50ef} = 1.3.6.1.4.1.54392.3.21440.35766.45803.20536.48936.44353.41100.20719
907
                $a1 = gmp_strval(gmp_init($ary[8],10),16); if (strlen($a1)>4) return false;
1003
                $a1 = gmp_strval(gmp_init($ary[8],10),16); if (strlen($a1)>4) return false;
908
                $a2 = gmp_strval(gmp_init($ary[9],10),16); if (strlen($a2)>4) return false;
1004
                $a2 = gmp_strval(gmp_init($ary[9],10),16); if (strlen($a2)>4) return false;
909
                $a3 = gmp_strval(gmp_init($ary[10],10),16); if (strlen($a3)>4) return false;
1005
                $a3 = gmp_strval(gmp_init($ary[10],10),16); if (strlen($a3)>4) return false;
910
                $a4 = gmp_strval(gmp_init($ary[11],10),16); if (strlen($a4)>4) return false;
1006
                $a4 = gmp_strval(gmp_init($ary[11],10),16); if (strlen($a4)>4) return false;
911
                $a5 = gmp_strval(gmp_init($ary[12],10),16); if (strlen($a5)>4) return false;
1007
                $a5 = gmp_strval(gmp_init($ary[12],10),16); if (strlen($a5)>4) return false;
912
                $a6 = gmp_strval(gmp_init($ary[13],10),16); if (strlen($a6)>4) return false;
1008
                $a6 = gmp_strval(gmp_init($ary[13],10),16); if (strlen($a6)>4) return false;
913
                $a7 = gmp_strval(gmp_init($ary[14],10),16); if (strlen($a7)>4) return false;
1009
                $a7 = gmp_strval(gmp_init($ary[14],10),16); if (strlen($a7)>4) return false;
914
                $a8 = gmp_strval(gmp_init($ary[15],10),16); if (strlen($a8)>4) return false;
1010
                $a8 = gmp_strval(gmp_init($ary[15],10),16); if (strlen($a8)>4) return false;
915
                $hex =
1011
                $hex =
916
                        str_pad($a1, 4, "0", STR_PAD_LEFT).
1012
                        str_pad($a1, 4, "0", STR_PAD_LEFT).
917
                        str_pad($a2, 4, "0", STR_PAD_LEFT).
1013
                        str_pad($a2, 4, "0", STR_PAD_LEFT).
918
                        str_pad($a3, 4, "0", STR_PAD_LEFT).
1014
                        str_pad($a3, 4, "0", STR_PAD_LEFT).
919
                        str_pad($a4, 4, "0", STR_PAD_LEFT).
1015
                        str_pad($a4, 4, "0", STR_PAD_LEFT).
920
                        str_pad($a5, 4, "0", STR_PAD_LEFT).
1016
                        str_pad($a5, 4, "0", STR_PAD_LEFT).
921
                        str_pad($a6, 4, "0", STR_PAD_LEFT).
1017
                        str_pad($a6, 4, "0", STR_PAD_LEFT).
922
                        str_pad($a7, 4, "0", STR_PAD_LEFT).
1018
                        str_pad($a7, 4, "0", STR_PAD_LEFT).
923
                        str_pad($a8, 4, "0", STR_PAD_LEFT);
1019
                        str_pad($a8, 4, "0", STR_PAD_LEFT);
924
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
1020
                return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4).'-'.substr($hex,16,4).'-'.substr($hex,20,12);
925
        } else {
1021
        } else {
926
                return false;
1022
                return false;
927
        }
1023
        }
928
}
1024
}
929
 
1025
 
930
function is_uuid_oid($oid, $only_allow_root=false) {
1026
function is_uuid_oid($oid, $only_allow_root=false) {
931
        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
932
 
1028
 
933
        if ($only_allow_root) {
1029
        if ($only_allow_root) {
934
                return oid_to_uuid($oid) !== false;
1030
                return oid_to_uuid($oid) !== false;
935
        } else {
1031
        } else {
936
                // TODO: Check range of the components (e.g. max 128 bits for 2.25)
1032
                // TODO: Check range of the components (e.g. max 128 bits for 2.25)
937
                if (strpos($oid,'2.25.') === 0) return true;
1033
                if (strpos($oid,'2.25.') === 0) return true;
938
                if (strpos($oid,'1.2.840.113556.1.8000.2554.') === 0) return true;
1034
                if (strpos($oid,'1.2.840.113556.1.8000.2554.') === 0) return true;
939
                if (strpos($oid,'1.3.6.1.4.1.54392.1.') === 0) return true;
1035
                if (strpos($oid,'1.3.6.1.4.1.54392.1.') === 0) return true;
940
                if (strpos($oid,'1.3.6.1.4.1.54392.2.') === 0) return true;
1036
                if (strpos($oid,'1.3.6.1.4.1.54392.2.') === 0) return true;
941
                if (strpos($oid,'1.3.6.1.4.1.54392.3.') === 0) return true;
1037
                if (strpos($oid,'1.3.6.1.4.1.54392.3.') === 0) return true;
942
                return false;
1038
                return false;
943
        }
1039
        }
944
}
1040
}
945
 
1041
 
946
function uuid_to_oid($uuid, $base='2.25') {
1042
function uuid_to_oid($uuid, $base='2.25') {
947
        if (!uuid_valid($uuid)) return false;
1043
        if (!uuid_valid($uuid)) return false;
948
        #$base = oid_sanitize($base);
1044
        #$base = oid_sanitize($base);
949
 
1045
 
950
        $uuid = str_replace(array('-', '{', '}'), '', $uuid);
1046
        $uuid = str_replace(array('-', '{', '}'), '', $uuid);
951
 
1047
 
952
        // Information about Microsoft and Waterjuice UUID-OID: https://waterjuiceweb.wordpress.com/2019/09/24/guids-to-oids/
1048
        // Information about Microsoft and Waterjuice UUID-OID: https://waterjuiceweb.wordpress.com/2019/09/24/guids-to-oids/
953
 
1049
 
954
        if ($base == '2.25') {
1050
        if ($base == '2.25') {
955
                $x = gmp_init($uuid, 16);
1051
                $x = gmp_init($uuid, 16);
956
                return $base.'.'.gmp_strval($x, 10);
1052
                return $base.'.'.gmp_strval($x, 10);
957
        } else if ($base == '1.2.840.113556.1.8000.2554') {
1053
        } else if ($base == '1.2.840.113556.1.8000.2554') {
958
                return $base.'.'.
1054
                return $base.'.'.
959
                        gmp_strval(gmp_init(substr($uuid,0,4),16),10).'.'.
1055
                        gmp_strval(gmp_init(substr($uuid,0,4),16),10).'.'.
960
                        gmp_strval(gmp_init(substr($uuid,4,4),16),10).'.'.
1056
                        gmp_strval(gmp_init(substr($uuid,4,4),16),10).'.'.
961
                        gmp_strval(gmp_init(substr($uuid,8,4),16),10).'.'.
1057
                        gmp_strval(gmp_init(substr($uuid,8,4),16),10).'.'.
962
                        gmp_strval(gmp_init(substr($uuid,12,4),16),10).'.'.
1058
                        gmp_strval(gmp_init(substr($uuid,12,4),16),10).'.'.
963
                        gmp_strval(gmp_init(substr($uuid,16,4),16),10).'.'.
1059
                        gmp_strval(gmp_init(substr($uuid,16,4),16),10).'.'.
964
                        gmp_strval(gmp_init(substr($uuid,20,6),16),10).'.'.
1060
                        gmp_strval(gmp_init(substr($uuid,20,6),16),10).'.'.
965
                        gmp_strval(gmp_init(substr($uuid,26,6),16),10);
1061
                        gmp_strval(gmp_init(substr($uuid,26,6),16),10);
966
        } else if ($base == '1.3.6.1.4.1.54392.1') {
1062
        } else if ($base == '1.3.6.1.4.1.54392.1') {
967
                return $base.'.'.
1063
                return $base.'.'.
968
                        gmp_strval(gmp_init(substr($uuid,0,16),16),10).'.'.
1064
                        gmp_strval(gmp_init(substr($uuid,0,16),16),10).'.'.
969
                        gmp_strval(gmp_init(substr($uuid,16,16),16),10);
1065
                        gmp_strval(gmp_init(substr($uuid,16,16),16),10);
970
        } else if ($base == '1.3.6.1.4.1.54392.2') {
1066
        } else if ($base == '1.3.6.1.4.1.54392.2') {
971
                return $base.'.'.
1067
                return $base.'.'.
972
                        gmp_strval(gmp_init(substr($uuid,0,8),16),10).'.'.
1068
                        gmp_strval(gmp_init(substr($uuid,0,8),16),10).'.'.
973
                        gmp_strval(gmp_init(substr($uuid,8,8),16),10).'.'.
1069
                        gmp_strval(gmp_init(substr($uuid,8,8),16),10).'.'.
974
                        gmp_strval(gmp_init(substr($uuid,16,8),16),10).'.'.
1070
                        gmp_strval(gmp_init(substr($uuid,16,8),16),10).'.'.
975
                        gmp_strval(gmp_init(substr($uuid,24,8),16),10);
1071
                        gmp_strval(gmp_init(substr($uuid,24,8),16),10);
976
        } else if ($base == '1.3.6.1.4.1.54392.3') {
1072
        } else if ($base == '1.3.6.1.4.1.54392.3') {
977
                return $base.'.'.
1073
                return $base.'.'.
978
                        gmp_strval(gmp_init(substr($uuid,0,4),16),10).'.'.
1074
                        gmp_strval(gmp_init(substr($uuid,0,4),16),10).'.'.
979
                        gmp_strval(gmp_init(substr($uuid,4,4),16),10).'.'.
1075
                        gmp_strval(gmp_init(substr($uuid,4,4),16),10).'.'.
980
                        gmp_strval(gmp_init(substr($uuid,8,4),16),10).'.'.
1076
                        gmp_strval(gmp_init(substr($uuid,8,4),16),10).'.'.
981
                        gmp_strval(gmp_init(substr($uuid,12,4),16),10).'.'.
1077
                        gmp_strval(gmp_init(substr($uuid,12,4),16),10).'.'.
982
                        gmp_strval(gmp_init(substr($uuid,16,4),16),10).'.'.
1078
                        gmp_strval(gmp_init(substr($uuid,16,4),16),10).'.'.
983
                        gmp_strval(gmp_init(substr($uuid,20,4),16),10).'.'.
1079
                        gmp_strval(gmp_init(substr($uuid,20,4),16),10).'.'.
984
                        gmp_strval(gmp_init(substr($uuid,24,4),16),10).'.'.
1080
                        gmp_strval(gmp_init(substr($uuid,24,4),16),10).'.'.
985
                        gmp_strval(gmp_init(substr($uuid,28,4),16),10);
1081
                        gmp_strval(gmp_init(substr($uuid,28,4),16),10);
986
        } else {
1082
        } else {
987
                throw new Exception("Unsupported UUID-to-OID base");
1083
                throw new Exception("Unsupported UUID-to-OID base");
988
        }
1084
        }
989
}
1085
}
990
 
1086
 
991
function uuid_numeric_value($uuid) {
1087
function uuid_numeric_value($uuid) {
992
        $oid = uuid_to_oid($uuid);
1088
        $oid = uuid_to_oid($uuid);
993
        if (!$oid) return false;
1089
        if (!$oid) return false;
994
        return substr($oid, strlen('2.25.'));
1090
        return substr($oid, strlen('2.25.'));
995
}
1091
}
996
 
1092
 
997
function uuid_c_syntax($uuid) {
1093
function uuid_c_syntax($uuid) {
998
        $uuid = str_replace('{', '', $uuid);
1094
        $uuid = str_replace('{', '', $uuid);
999
        return '{ 0x' . substr($uuid, 0, 8) .
1095
        return '{ 0x' . substr($uuid, 0, 8) .
1000
                ', 0x' . substr($uuid, 9, 4) .
1096
                ', 0x' . substr($uuid, 9, 4) .
1001
                ', 0x' . substr($uuid, 14, 4) .
1097
                ', 0x' . substr($uuid, 14, 4) .
1002
                ', { 0x' . substr($uuid, 19, 2).
1098
                ', { 0x' . substr($uuid, 19, 2).
1003
                ', 0x' . substr($uuid, 21, 2) .
1099
                ', 0x' . substr($uuid, 21, 2) .
1004
                ', 0x' . substr($uuid, 24, 2) .
1100
                ', 0x' . substr($uuid, 24, 2) .
1005
                ', 0x' . substr($uuid, 26, 2) .
1101
                ', 0x' . substr($uuid, 26, 2) .
1006
                ', 0x' . substr($uuid, 28, 2) .
1102
                ', 0x' . substr($uuid, 28, 2) .
1007
                ', 0x' . substr($uuid, 30, 2) .
1103
                ', 0x' . substr($uuid, 30, 2) .
1008
                ', 0x' . substr($uuid, 32, 2) .
1104
                ', 0x' . substr($uuid, 32, 2) .
1009
                ', 0x' . substr($uuid, 34, 2) . ' } }';
1105
                ', 0x' . substr($uuid, 34, 2) . ' } }';
1010
}
1106
}
1011
 
1107
 
1012
function gen_uuid($prefer_mac_address_based = true) {
1108
function gen_uuid($prefer_mac_address_based = true) {
1013
        $uuid = $prefer_mac_address_based ? gen_uuid_reordered()/*UUIDv6*/ : false;
1109
        $uuid = $prefer_mac_address_based ? gen_uuid_reordered()/*UUIDv6*/ : false;
1014
        if ($uuid === false) $uuid = gen_uuid_unix_epoch()/*UUIDv7*/;
1110
        if ($uuid === false) $uuid = gen_uuid_unix_epoch()/*UUIDv7*/;
1015
        return $uuid;
1111
        return $uuid;
1016
}
1112
}
1017
 
1113
 
1018
# --------------------------------------
1114
# --------------------------------------
1019
// Variant 1, Version 1 (Time based) UUID
1115
// Variant 1, Version 1 (Time based) UUID
1020
# --------------------------------------
1116
# --------------------------------------
1021
 
1117
 
1022
function gen_uuid_v1() {
1118
function gen_uuid_v1() {
1023
        return gen_uuid_timebased();
1119
        return gen_uuid_timebased();
1024
}
1120
}
1025
function gen_uuid_timebased($force_php_implementation=false) {
1121
function gen_uuid_timebased($force_php_implementation=false) {
1026
        # On Debian: apt-get install php-uuid
1122
        # On Debian: apt-get install php-uuid
1027
        # extension_loaded('uuid')
1123
        # extension_loaded('uuid')
1028
        if (!$force_php_implementation && function_exists('uuid_create')) {
1124
        if (!$force_php_implementation && function_exists('uuid_create')) {
1029
                # OSSP uuid extension like seen in php5-uuid at Debian 8
1125
                # OSSP uuid extension like seen in php5-uuid at Debian 8
1030
                /*
1126
                /*
1031
                $x = uuid_create($context);
1127
                $x = uuid_create($context);
1032
                uuid_make($context, UUID_MAKE_V1);
1128
                uuid_make($context, UUID_MAKE_V1);
1033
                uuid_export($context, UUID_FMT_STR, $uuid);
1129
                uuid_export($context, UUID_FMT_STR, $uuid);
1034
                return trim($uuid);
1130
                return trim($uuid);
1035
                */
1131
                */
1036
 
1132
 
1037
                # PECL uuid extension like seen in php-uuid at Debian 9
1133
                # PECL uuid extension like seen in php-uuid at Debian 9
1038
                return trim(uuid_create(UUID_TYPE_TIME));
1134
                return trim(uuid_create(UUID_TYPE_TIME));
1039
        }
1135
        }
1040
 
1136
 
1041
        # On Debian: apt-get install uuid-runtime
1137
        # On Debian: apt-get install uuid-runtime
1042
        if (!$force_php_implementation && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
1138
        if (!$force_php_implementation && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
1043
                $out = array();
1139
                $out = array();
1044
                $ec = -1;
1140
                $ec = -1;
1045
                exec('uuidgen -t 2>/dev/null', $out, $ec);
1141
                exec('uuidgen -t 2>/dev/null', $out, $ec);
1046
                if ($ec == 0) return trim($out[0]);
1142
                if ($ec == 0) return trim($out[0]);
1047
        }
1143
        }
1048
 
1144
 
1049
        # If we hadn't any success yet, then implement the time based generation routine ourselves!
1145
        # If we hadn't any success yet, then implement the time based generation routine ourselves!
1050
        # Based on https://github.com/fredriklindberg/class.uuid.php/blob/master/class.uuid.php
1146
        # Based on https://github.com/fredriklindberg/class.uuid.php/blob/master/class.uuid.php
1051
 
1147
 
1052
        $uuid = array(
1148
        $uuid = array(
1053
                'time_low' => 0,                /* 32-bit */
1149
                'time_low' => 0,                /* 32-bit */
1054
                'time_mid' => 0,                /* 16-bit */
1150
                'time_mid' => 0,                /* 16-bit */
1055
                'time_hi' => 0,                 /* 16-bit */
1151
                'time_hi' => 0,                 /* 16-bit */
1056
                'clock_seq_hi' => 0,            /*  8-bit */
1152
                'clock_seq_hi' => 0,            /*  8-bit */
1057
                'clock_seq_low' => 0,           /*  8-bit */
1153
                'clock_seq_low' => 0,           /*  8-bit */
1058
                'node' => array()               /* 48-bit */
1154
                'node' => array()               /* 48-bit */
1059
        );
1155
        );
1060
 
1156
 
1061
        /*
1157
        /*
1062
         * Get current time in 100 ns intervals. The magic value
1158
         * Get current time in 100 ns intervals. The magic value
1063
         * is the offset between UNIX epoch and the UUID UTC
1159
         * is the offset between UNIX epoch and the UUID UTC
1064
         * time base October 15, 1582.
1160
         * time base October 15, 1582.
1065
         */
1161
         */
1066
        if (time_nanosleep(0,100) !== true) usleep(1); // Wait 100ns, to make sure that the time part changes if multiple UUIDs are generated
1162
        if (time_nanosleep(0,100) !== true) usleep(1); // Wait 100ns, to make sure that the time part changes if multiple UUIDs are generated
1067
        $tp = gettimeofday();
1163
        $tp = gettimeofday();
1068
        if (PHP_INT_SIZE == 4) {
1164
        if (PHP_INT_SIZE == 4) {
1069
                $tp['sec'] = gmp_init($tp['sec'],10);
1165
                $tp['sec'] = gmp_init($tp['sec'],10);
1070
                $tp['usec'] = gmp_init($tp['usec'],10);
1166
                $tp['usec'] = gmp_init($tp['usec'],10);
1071
                $time = gmp_add(gmp_add(gmp_mul($tp['sec'], gmp_init('10000000',10)),gmp_mul($tp['usec'], gmp_init('10',10))),gmp_init('01B21DD213814000',16));
1167
                $time = gmp_add(gmp_add(gmp_mul($tp['sec'], gmp_init('10000000',10)),gmp_mul($tp['usec'], gmp_init('10',10))),gmp_init('01B21DD213814000',16));
1072
                $uuid['time_low'] = gmp_and($time, gmp_init('ffffffff',16));
1168
                $uuid['time_low'] = gmp_and($time, gmp_init('ffffffff',16));
1073
                $high = gmp_shiftr($time,32);
1169
                $high = gmp_shiftr($time,32);
1074
                $uuid['time_mid'] = gmp_and($high, gmp_init('ffff',16));
1170
                $uuid['time_mid'] = gmp_and($high, gmp_init('ffff',16));
1075
                $uuid['time_hi'] = gmp_intval(gmp_and(gmp_shiftr($high,16),gmp_init('fff',16))) | (1/*TimeBased*/ << 12);
1171
                $uuid['time_hi'] = gmp_intval(gmp_and(gmp_shiftr($high,16),gmp_init('fff',16))) | (1/*TimeBased*/ << 12);
1076
        } else {
1172
        } else {
1077
                $time = ($tp['sec'] * 10000000) + ($tp['usec'] * 10) + 0x01B21DD213814000;
1173
                $time = ($tp['sec'] * 10000000) + ($tp['usec'] * 10) + 0x01B21DD213814000;
1078
                $uuid['time_low'] = $time & 0xffffffff;
1174
                $uuid['time_low'] = $time & 0xffffffff;
1079
                /* Work around PHP 32-bit bit-operation limits */
1175
                /* Work around PHP 32-bit bit-operation limits */
1080
                $high = intval($time / 0xffffffff);
1176
                $high = intval($time / 0xffffffff);
1081
                $uuid['time_mid'] = $high & 0xffff;
1177
                $uuid['time_mid'] = $high & 0xffff;
1082
                $uuid['time_hi'] = (($high >> 16) & 0xfff) | (1/*TimeBased*/ << 12);
1178
                $uuid['time_hi'] = (($high >> 16) & 0xfff) | (1/*TimeBased*/ << 12);
1083
        }
1179
        }
1084
 
1180
 
1085
        /*
1181
        /*
1086
         * We don't support saved state information and generate
1182
         * We don't support saved state information and generate
1087
         * a random clock sequence each time.
1183
         * a random clock sequence each time.
1088
         */
1184
         */
1089
        $uuid['clock_seq_hi'] = _random_int(0, 255) & 0b00111111 | 0b10000000; // set variant to 0b10__ (RFC 4122)
1185
        $uuid['clock_seq_hi'] = _random_int(0, 255) & 0b00111111 | 0b10000000; // set variant to 0b10__ (RFC 4122)
1090
        $uuid['clock_seq_low'] = _random_int(0, 255);
1186
        $uuid['clock_seq_low'] = _random_int(0, 255);
1091
 
1187
 
1092
        /*
1188
        /*
1093
         * Node should be set to the 48-bit IEEE node identifier
1189
         * Node should be set to the 48-bit IEEE node identifier
1094
         */
1190
         */
1095
        $mac = get_mac_address();
1191
        $mac = get_mac_address();
1096
        if ($mac) {
1192
        if ($mac) {
1097
                $node = str_replace('-','',str_replace(':','',$mac));
1193
                $node = str_replace('-','',str_replace(':','',$mac));
1098
                for ($i = 0; $i < 6; $i++) {
1194
                for ($i = 0; $i < 6; $i++) {
1099
                        $uuid['node'][$i] = hexdec(substr($node, $i*2, 2));
1195
                        $uuid['node'][$i] = hexdec(substr($node, $i*2, 2));
1100
                }
1196
                }
1101
        } else {
1197
        } else {
1102
                // If we cannot get a MAC address, then generate a random AAI
1198
                // If we cannot get a MAC address, then generate a random AAI
1103
                // RFC 4122 requires the multicast bit to be set, to make sure
1199
                // RFC 4122 requires the multicast bit to be set, to make sure
1104
                // that a UUID from a system with network card never conflicts
1200
                // that a UUID from a system with network card never conflicts
1105
                // with a UUID from a system without network ard.
1201
                // with a UUID from a system without network ard.
1106
                // We are additionally defining the other 3 bits as AAI,
1202
                // We are additionally defining the other 3 bits as AAI,
1107
                // to avoid that we are misusing the CID or OUI from other vendors
1203
                // to avoid that we are misusing the CID or OUI from other vendors
1108
                // if we would create multicast ELI (based on CID) or EUI (based on OUI).
1204
                // if we would create multicast ELI (based on CID) or EUI (based on OUI).
1109
                $uuid['node'] = explode('-', gen_aai(48, true/*Multicast*/));
1205
                $uuid['node'] = explode('-', gen_aai(48, true/*Multicast*/));
1110
                $uuid['node'] = array_map('hexdec', $uuid['node']);
1206
                $uuid['node'] = array_map('hexdec', $uuid['node']);
1111
        }
1207
        }
1112
 
1208
 
1113
        /*
1209
        /*
1114
         * Now output the UUID
1210
         * Now output the UUID
1115
         */
1211
         */
1116
        return sprintf(
1212
        return sprintf(
1117
                '%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x',
1213
                '%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x',
1118
                ($uuid['time_low']), ($uuid['time_mid']), ($uuid['time_hi']),
1214
                ($uuid['time_low']), ($uuid['time_mid']), ($uuid['time_hi']),
1119
                $uuid['clock_seq_hi'], $uuid['clock_seq_low'],
1215
                $uuid['clock_seq_hi'], $uuid['clock_seq_low'],
1120
                $uuid['node'][0], $uuid['node'][1], $uuid['node'][2],
1216
                $uuid['node'][0], $uuid['node'][1], $uuid['node'][2],
1121
                $uuid['node'][3], $uuid['node'][4], $uuid['node'][5]);
1217
                $uuid['node'][3], $uuid['node'][4], $uuid['node'][5]);
1122
}
1218
}
1123
 
1219
 
1124
# --------------------------------------
1220
# --------------------------------------
1125
// Variant 1, Version 2 (DCE Security) UUID
1221
// Variant 1, Version 2 (DCE Security) UUID
1126
# --------------------------------------
1222
# --------------------------------------
1127
 
1223
 
1128
define('DCE_DOMAIN_PERSON', 0);
1224
define('DCE_DOMAIN_PERSON', 0);
1129
define('DCE_DOMAIN_GROUP', 1);
1225
define('DCE_DOMAIN_GROUP', 1);
1130
define('DCE_DOMAIN_ORG', 2);
1226
define('DCE_DOMAIN_ORG', 2);
1131
function gen_uuid_v2($domain, $id) {
1227
function gen_uuid_v2($domain, $id) {
1132
        return gen_uuid_dce($domain, $id);
1228
        return gen_uuid_dce($domain, $id);
1133
}
1229
}
1134
function gen_uuid_dce($domain, $id) {
1230
function gen_uuid_dce($domain, $id) {
1135
        if (($domain ?? '') === '') throw new Exception("Domain ID missing");
1231
        if (($domain ?? '') === '') throw new Exception("Domain ID missing");
1136
        if (!is_numeric($domain)) throw new Exception("Invalid Domain ID");
1232
        if (!is_numeric($domain)) throw new Exception("Invalid Domain ID");
1137
        if (($domain < 0) || ($domain > 0xFF)) throw new Exception("Domain ID must be in range 0..255");
1233
        if (($domain < 0) || ($domain > 0xFF)) throw new Exception("Domain ID must be in range 0..255");
1138
 
1234
 
1139
        if (($id ?? '') === '') throw new Exception("ID value missing");
1235
        if (($id ?? '') === '') throw new Exception("ID value missing");
1140
        if (!is_numeric($id)) throw new Exception("Invalid ID value");
1236
        if (!is_numeric($id)) throw new Exception("Invalid ID value");
1141
        if (($id < 0) || ($id > 0xFFFFFFFF)) throw new Exception("ID value must be in range 0..4294967295");
1237
        if (($id < 0) || ($id > 0xFFFFFFFF)) throw new Exception("ID value must be in range 0..4294967295");
1142
 
1238
 
1143
        # Start with a version 1 UUID
1239
        # Start with a version 1 UUID
1144
        $uuid = gen_uuid_timebased();
1240
        $uuid = gen_uuid_timebased();
1145
 
1241
 
1146
        # Add Domain Number
1242
        # Add Domain Number
1147
        $uuid = str_pad(dechex($id), 8, '0', STR_PAD_LEFT) . substr($uuid, 8);
1243
        $uuid = str_pad(dechex($id), 8, '0', STR_PAD_LEFT) . substr($uuid, 8);
1148
 
1244
 
1149
        # Add Domain (this overwrites part of the clock sequence)
1245
        # Add Domain (this overwrites part of the clock sequence)
1150
        $uuid = substr($uuid,0,21) . str_pad(dechex($domain), 2, '0', STR_PAD_LEFT) . substr($uuid, 23);
1246
        $uuid = substr($uuid,0,21) . str_pad(dechex($domain), 2, '0', STR_PAD_LEFT) . substr($uuid, 23);
1151
 
1247
 
1152
        # Change version to 2
1248
        # Change version to 2
1153
        $uuid[14] = '2';
1249
        $uuid[14] = '2';
1154
 
1250
 
1155
        return $uuid;
1251
        return $uuid;
1156
}
1252
}
1157
 
1253
 
1158
# --------------------------------------
1254
# --------------------------------------
1159
// Variant 1, Version 3 (MD5 name based) UUID
1255
// Variant 1, Version 3 (MD5 name based) UUID
1160
# --------------------------------------
1256
# --------------------------------------
1161
 
1257
 
1162
function gen_uuid_v3($namespace_uuid, $name) {
1258
function gen_uuid_v3($namespace_uuid, $name) {
1163
        return gen_uuid_md5_namebased($namespace_uuid, $name);
1259
        return gen_uuid_md5_namebased($namespace_uuid, $name);
1164
}
1260
}
1165
function gen_uuid_md5_namebased($namespace_uuid, $name) {
1261
function gen_uuid_md5_namebased($namespace_uuid, $name) {
1166
        if (($namespace_uuid ?? '') === '') throw new Exception("Namespace UUID missing");
1262
        if (($namespace_uuid ?? '') === '') throw new Exception("Namespace UUID missing");
1167
        if (!uuid_valid($namespace_uuid)) throw new Exception("Invalid namespace UUID '$namespace_uuid'");
1263
        if (!uuid_valid($namespace_uuid)) throw new Exception("Invalid namespace UUID '$namespace_uuid'");
1168
 
1264
 
1169
        $namespace_uuid = uuid_canonize($namespace_uuid);
1265
        $namespace_uuid = uuid_canonize($namespace_uuid);
1170
        $namespace_uuid = str_replace('-', '', $namespace_uuid);
1266
        $namespace_uuid = str_replace('-', '', $namespace_uuid);
1171
        $namespace_uuid = hex2bin($namespace_uuid);
1267
        $namespace_uuid = hex2bin($namespace_uuid);
1172
 
1268
 
1173
        $hash = md5($namespace_uuid.$name);
1269
        $hash = md5($namespace_uuid.$name);
1174
        $hash[12] = '3'; // Set version: 3 = MD5
1270
        $hash[12] = '3'; // Set version: 3 = MD5
1175
        $hash[16] = dechex(hexdec($hash[16]) & 0b0011 | 0b1000); // Set variant to "10xx" (RFC4122)
1271
        $hash[16] = dechex(hexdec($hash[16]) & 0b0011 | 0b1000); // Set variant to "10xx" (RFC4122)
1176
 
1272
 
1177
        return substr($hash,  0, 8).'-'.
1273
        return substr($hash,  0, 8).'-'.
1178
               substr($hash,  8, 4).'-'.
1274
               substr($hash,  8, 4).'-'.
1179
               substr($hash, 12, 4).'-'.
1275
               substr($hash, 12, 4).'-'.
1180
               substr($hash, 16, 4).'-'.
1276
               substr($hash, 16, 4).'-'.
1181
               substr($hash, 20, 12);
1277
               substr($hash, 20, 12);
1182
}
1278
}
1183
 
1279
 
1184
# --------------------------------------
1280
# --------------------------------------
1185
// Variant 1, Version 4 (Random) UUID
1281
// Variant 1, Version 4 (Random) UUID
1186
# --------------------------------------
1282
# --------------------------------------
1187
 
1283
 
1188
function gen_uuid_v4() {
1284
function gen_uuid_v4() {
1189
        return gen_uuid_random();
1285
        return gen_uuid_random();
1190
}
1286
}
1191
function gen_uuid_random() {
1287
function gen_uuid_random() {
1192
        # On Windows: Requires
1288
        # On Windows: Requires
1193
        #    extension_dir = "C:\php-8.0.3-nts-Win32-vs16-x64\ext"
1289
        #    extension_dir = "C:\php-8.0.3-nts-Win32-vs16-x64\ext"
1194
        #    extension=com_dotnet
1290
        #    extension=com_dotnet
1195
        if (function_exists('com_create_guid')) {
1291
        if (function_exists('com_create_guid')) {
1196
                $uuid = trim(com_create_guid(), '{}');
1292
                $uuid = trim(com_create_guid(), '{}');
1197
                if (uuid_version($uuid) === '4') { // <-- just to make 100% sure that Windows's CoCreateGuid() did output UUIDv4
1293
                if (uuid_version($uuid) === '4') { // <-- just to make 100% sure that Windows's CoCreateGuid() did output UUIDv4
1198
                        return strtolower($uuid);
1294
                        return strtolower($uuid);
1199
                }
1295
                }
1200
        }
1296
        }
1201
 
1297
 
1202
        # On Debian: apt-get install php-uuid
1298
        # On Debian: apt-get install php-uuid
1203
        # extension_loaded('uuid')
1299
        # extension_loaded('uuid')
1204
        if (function_exists('uuid_create')) {
1300
        if (function_exists('uuid_create')) {
1205
                # OSSP uuid extension like seen in php5-uuid at Debian 8
1301
                # OSSP uuid extension like seen in php5-uuid at Debian 8
1206
                /*
1302
                /*
1207
                $x = uuid_create($context);
1303
                $x = uuid_create($context);
1208
                uuid_make($context, UUID_MAKE_V4);
1304
                uuid_make($context, UUID_MAKE_V4);
1209
                uuid_export($context, UUID_FMT_STR, $uuid);
1305
                uuid_export($context, UUID_FMT_STR, $uuid);
1210
                return trim($uuid);
1306
                return trim($uuid);
1211
                */
1307
                */
1212
 
1308
 
1213
                # PECL uuid extension like seen in php-uuid at Debian 9
1309
                # PECL uuid extension like seen in php-uuid at Debian 9
1214
                return trim(uuid_create(UUID_TYPE_RANDOM));
1310
                return trim(uuid_create(UUID_TYPE_RANDOM));
1215
        }
1311
        }
1216
 
1312
 
1217
        if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
1313
        if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
1218
                # On Debian Jessie: UUID V4 (Random)
1314
                # On Debian Jessie: UUID V4 (Random)
1219
                if (file_exists($uuidv4_file = '/proc/sys/kernel/random/uuid')) {
1315
                if (file_exists($uuidv4_file = '/proc/sys/kernel/random/uuid')) {
1220
                        $uuid = file_get_contents($uuidv4_file);
1316
                        $uuid = file_get_contents($uuidv4_file);
1221
                        if (uuid_version($uuid) === '4') { // <-- just to make 100% sure that it did output UUIDv4
1317
                        if (uuid_version($uuid) === '4') { // <-- just to make 100% sure that it did output UUIDv4
1222
                                return $uuid;
1318
                                return $uuid;
1223
                        }
1319
                        }
1224
                }
1320
                }
1225
 
1321
 
1226
                # On Debian: apt-get install uuid-runtime
1322
                # On Debian: apt-get install uuid-runtime
1227
                $out = array();
1323
                $out = array();
1228
                $ec = -1;
1324
                $ec = -1;
1229
                exec('uuidgen -r 2>/dev/null', $out, $ec);
1325
                exec('uuidgen -r 2>/dev/null', $out, $ec);
1230
                if ($ec == 0) return trim($out[0]);
1326
                if ($ec == 0) return trim($out[0]);
1231
        }
1327
        }
1232
 
1328
 
1233
        # Make the UUID by ourselves
1329
        # Make the UUID by ourselves
1234
 
1330
 
1235
        if (function_exists('openssl_random_pseudo_bytes')) {
1331
        if (function_exists('openssl_random_pseudo_bytes')) {
1236
                // Source: https://www.php.net/manual/en/function.com-create-guid.php#119168
1332
                // Source: https://www.php.net/manual/en/function.com-create-guid.php#119168
1237
                $data = openssl_random_pseudo_bytes(16);
1333
                $data = openssl_random_pseudo_bytes(16);
1238
                $data[6] = chr(ord($data[6]) & 0x0f | 0x40);    // set version to 0100
1334
                $data[6] = chr(ord($data[6]) & 0x0f | 0x40);    // set version to 0100
1239
                $data[8] = chr(ord($data[8]) & 0x3f | 0x80);    // set bits 6-7 to 10
1335
                $data[8] = chr(ord($data[8]) & 0x3f | 0x80);    // set bits 6-7 to 10
1240
                return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
1336
                return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
1241
        } else {
1337
        } else {
1242
                // Source: http://rogerstringer.com/2013/11/15/generate-uuids-php
1338
                // Source: http://rogerstringer.com/2013/11/15/generate-uuids-php
1243
                return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
1339
                return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
1244
                        _random_int( 0, 0xffff ), _random_int( 0, 0xffff ),
1340
                        _random_int( 0, 0xffff ), _random_int( 0, 0xffff ),
1245
                        _random_int( 0, 0xffff ),
1341
                        _random_int( 0, 0xffff ),
1246
                        _random_int( 0, 0x0fff ) | 0x4000,
1342
                        _random_int( 0, 0x0fff ) | 0x4000,
1247
                        _random_int( 0, 0x3fff ) | 0x8000,
1343
                        _random_int( 0, 0x3fff ) | 0x8000,
1248
                        _random_int( 0, 0xffff ), _random_int( 0, 0xffff ), _random_int( 0, 0xffff )
1344
                        _random_int( 0, 0xffff ), _random_int( 0, 0xffff ), _random_int( 0, 0xffff )
1249
                );
1345
                );
1250
        }
1346
        }
1251
}
1347
}
1252
 
1348
 
1253
# --------------------------------------
1349
# --------------------------------------
1254
// Variant 1, Version 5 (SHA1 name based) UUID
1350
// Variant 1, Version 5 (SHA1 name based) UUID
1255
# --------------------------------------
1351
# --------------------------------------
1256
 
1352
 
1257
function gen_uuid_v5($namespace_uuid, $name) {
1353
function gen_uuid_v5($namespace_uuid, $name) {
1258
        return gen_uuid_sha1_namebased($namespace_uuid, $name);
1354
        return gen_uuid_sha1_namebased($namespace_uuid, $name);
1259
}
1355
}
1260
function gen_uuid_sha1_namebased($namespace_uuid, $name) {
1356
function gen_uuid_sha1_namebased($namespace_uuid, $name) {
1261
        if (($namespace_uuid ?? '') === '') throw new Exception("Namespace UUID missing");
1357
        if (($namespace_uuid ?? '') === '') throw new Exception("Namespace UUID missing");
1262
        if (!uuid_valid($namespace_uuid)) throw new Exception("Invalid namespace UUID '$namespace_uuid'");
1358
        if (!uuid_valid($namespace_uuid)) throw new Exception("Invalid namespace UUID '$namespace_uuid'");
1263
 
1359
 
1264
        $namespace_uuid = str_replace('-', '', $namespace_uuid);
1360
        $namespace_uuid = str_replace('-', '', $namespace_uuid);
1265
        $namespace_uuid = hex2bin($namespace_uuid);
1361
        $namespace_uuid = hex2bin($namespace_uuid);
1266
 
1362
 
1267
        $hash = sha1($namespace_uuid.$name);
1363
        $hash = sha1($namespace_uuid.$name);
1268
        $hash[12] = '5'; // Set version: 5 = SHA1
1364
        $hash[12] = '5'; // Set version: 5 = SHA1
1269
        $hash[16] = dechex(hexdec($hash[16]) & 0b0011 | 0b1000); // Set variant to "0b10__" (RFC4122/DCE1.1)
1365
        $hash[16] = dechex(hexdec($hash[16]) & 0b0011 | 0b1000); // Set variant to "0b10__" (RFC4122/DCE1.1)
1270
 
1366
 
1271
        return substr($hash,  0, 8).'-'.
1367
        return substr($hash,  0, 8).'-'.
1272
               substr($hash,  8, 4).'-'.
1368
               substr($hash,  8, 4).'-'.
1273
               substr($hash, 12, 4).'-'.
1369
               substr($hash, 12, 4).'-'.
1274
               substr($hash, 16, 4).'-'.
1370
               substr($hash, 16, 4).'-'.
1275
               substr($hash, 20, 12);
1371
               substr($hash, 20, 12);
1276
}
1372
}
1277
 
1373
 
1278
# --------------------------------------
1374
# --------------------------------------
1279
// Variant 1, Version 6 (Reordered) UUID
1375
// Variant 1, Version 6 (Reordered) UUID
1280
# --------------------------------------
1376
# --------------------------------------
1281
 
1377
 
1282
function gen_uuid_v6() {
1378
function gen_uuid_v6() {
1283
        return gen_uuid_reordered();
1379
        return gen_uuid_reordered();
1284
}
1380
}
1285
function gen_uuid_reordered() {
1381
function gen_uuid_reordered() {
1286
        // Start with a UUIDv1
1382
        // Start with a UUIDv1
1287
        $uuid = gen_uuid_timebased();
1383
        $uuid = gen_uuid_timebased();
1288
 
1384
 
1289
        // Convert to UUIDv6
1385
        // Convert to UUIDv6
1290
        return uuid1_to_uuid6($uuid);
1386
        return uuid1_to_uuid6($uuid);
1291
}
1387
}
1292
function uuid6_to_uuid1($hex) {
1388
function uuid6_to_uuid1($hex) {
1293
        $hex = uuid_canonize($hex);
1389
        $hex = uuid_canonize($hex);
1294
        if ($hex === false) return false;
1390
        if ($hex === false) return false;
1295
        $hex = preg_replace('@[^0-9A-F]@i', '', $hex);
1391
        $hex = preg_replace('@[^0-9A-F]@i', '', $hex);
1296
        $hex = substr($hex, 7, 5).
1392
        $hex = substr($hex, 7, 5).
1297
               substr($hex, 13, 3).
1393
               substr($hex, 13, 3).
1298
               substr($hex, 3, 4).
1394
               substr($hex, 3, 4).
1299
               '1' . substr($hex, 0, 3).
1395
               '1' . substr($hex, 0, 3).
1300
               substr($hex, 16);
1396
               substr($hex, 16);
1301
        return substr($hex,  0, 8).'-'.
1397
        return substr($hex,  0, 8).'-'.
1302
               substr($hex,  8, 4).'-'.
1398
               substr($hex,  8, 4).'-'.
1303
               substr($hex, 12, 4).'-'.
1399
               substr($hex, 12, 4).'-'.
1304
               substr($hex, 16, 4).'-'.
1400
               substr($hex, 16, 4).'-'.
1305
               substr($hex, 20, 12);
1401
               substr($hex, 20, 12);
1306
}
1402
}
1307
function uuid1_to_uuid6($hex) {
1403
function uuid1_to_uuid6($hex) {
1308
        $hex = uuid_canonize($hex);
1404
        $hex = uuid_canonize($hex);
1309
        if ($hex === false) return false;
1405
        if ($hex === false) return false;
1310
        $hex = preg_replace('@[^0-9A-F]@i', '', $hex);
1406
        $hex = preg_replace('@[^0-9A-F]@i', '', $hex);
1311
        $hex = substr($hex, 13, 3).
1407
        $hex = substr($hex, 13, 3).
1312
               substr($hex, 8, 4).
1408
               substr($hex, 8, 4).
1313
               substr($hex, 0, 5).
1409
               substr($hex, 0, 5).
1314
               '6' . substr($hex, 5, 3).
1410
               '6' . substr($hex, 5, 3).
1315
               substr($hex, 16);
1411
               substr($hex, 16);
1316
        return substr($hex,  0, 8).'-'.
1412
        return substr($hex,  0, 8).'-'.
1317
               substr($hex,  8, 4).'-'.
1413
               substr($hex,  8, 4).'-'.
1318
               substr($hex, 12, 4).'-'.
1414
               substr($hex, 12, 4).'-'.
1319
               substr($hex, 16, 4).'-'.
1415
               substr($hex, 16, 4).'-'.
1320
               substr($hex, 20, 12);
1416
               substr($hex, 20, 12);
1321
}
1417
}
1322
 
1418
 
1323
# --------------------------------------
1419
# --------------------------------------
1324
// Variant 1, Version 7 (Unix Epoch) UUID
1420
// Variant 1, Version 7 (Unix Epoch) UUID
1325
# --------------------------------------
1421
# --------------------------------------
1326
 
1422
 
1327
function gen_uuid_v7(int $num_ms_frac_bits=12) {
1423
function gen_uuid_v7(int $num_ms_frac_bits=12) {
1328
        return gen_uuid_unix_epoch($num_ms_frac_bits);
1424
        return gen_uuid_unix_epoch($num_ms_frac_bits);
1329
}
1425
}
1330
function gen_uuid_unix_epoch(int $num_ms_frac_bits=12) {
1426
function gen_uuid_unix_epoch(int $num_ms_frac_bits=12) {
1331
        $uuid_nibbles = '';
1427
        $uuid_nibbles = '';
1332
 
1428
 
1333
        // Add the timestamp (milliseconds Unix)
1429
        // Add the timestamp (milliseconds Unix)
1334
        if (function_exists('gmp_init')) {
1430
        if (function_exists('gmp_init')) {
1335
                list($ms,$sec) = explode(' ', microtime(false));
1431
                list($ms,$sec) = explode(' ', microtime(false));
1336
                $sec = gmp_init($sec, 10);
1432
                $sec = gmp_init($sec, 10);
1337
                $ms = gmp_init(substr($ms,2,3), 10);
1433
                $ms = gmp_init(substr($ms,2,3), 10);
1338
                $unix_ts = gmp_strval(gmp_add(gmp_mul($sec, '1000'), $ms),16);
1434
                $unix_ts = gmp_strval(gmp_add(gmp_mul($sec, '1000'), $ms),16);
1339
        } else {
1435
        } else {
1340
                $unix_ts = dechex((int)ceil(microtime(true)*1000));
1436
                $unix_ts = dechex((int)ceil(microtime(true)*1000));
1341
        }
1437
        }
1342
        $unix_ts = str_pad($unix_ts, 12, '0', STR_PAD_LEFT);
1438
        $unix_ts = str_pad($unix_ts, 12, '0', STR_PAD_LEFT);
1343
        $uuid_nibbles = $unix_ts;
1439
        $uuid_nibbles = $unix_ts;
1344
 
1440
 
1345
        // Version = 7
1441
        // Version = 7
1346
        $uuid_nibbles .= '7';
1442
        $uuid_nibbles .= '7';
1347
 
1443
 
1348
        // Optional: millisecond fraction (max 12 bits)
1444
        // Optional: millisecond fraction (max 12 bits)
1349
        if (($num_ms_frac_bits < 0) || ($num_ms_frac_bits > 12)) throw new Exception("Invalid msec frac bits (must be 0..12)");
1445
        if (($num_ms_frac_bits < 0) || ($num_ms_frac_bits > 12)) throw new Exception("Invalid msec frac bits (must be 0..12)");
1350
        $resolution_ns = 1000000 / pow(2,$num_ms_frac_bits);
1446
        $resolution_ns = 1000000 / pow(2,$num_ms_frac_bits);
1351
        if ($num_ms_frac_bits > 0) {
1447
        if ($num_ms_frac_bits > 0) {
1352
                $seconds_fraction = (float)explode(' ',microtime(false))[0]; // <sec=0>,<msec>
1448
                $seconds_fraction = (float)explode(' ',microtime(false))[0]; // <sec=0>,<msec>
1353
 
1449
 
1354
                $ms_fraction = $seconds_fraction * 1000; // <msec>,<us>
1450
                $ms_fraction = $seconds_fraction * 1000; // <msec>,<us>
1355
                $ms_fraction -= floor($ms_fraction); // <msec=0>,<us>
1451
                $ms_fraction -= floor($ms_fraction); // <msec=0>,<us>
1356
 
1452
 
1357
                $ns_fraction = $ms_fraction * 1000000; // <ns>
1453
                $ns_fraction = $ms_fraction * 1000000; // <ns>
1358
                $val = (int)ceil($ns_fraction / $resolution_ns);
1454
                $val = (int)ceil($ns_fraction / $resolution_ns);
1359
 
1455
 
1360
                // Currently, for the output we only allow frac bits 0, 4, 8, 12 (0-3 nibbles),
1456
                // Currently, for the output we only allow frac bits 0, 4, 8, 12 (0-3 nibbles),
1361
                // since UUIDs are usually sorted in their hex notation, and one of the main
1457
                // since UUIDs are usually sorted in their hex notation, and one of the main
1362
                // reasons for using the sub-millisecond fractions it to increase monotonicity
1458
                // reasons for using the sub-millisecond fractions it to increase monotonicity
1363
                $num_nibbles = (int)ceil($num_ms_frac_bits/4);
1459
                $num_nibbles = (int)ceil($num_ms_frac_bits/4);
1364
                $uuid_nibbles .= str_pad(dechex($val), $num_nibbles, '0', STR_PAD_LEFT);
1460
                $uuid_nibbles .= str_pad(dechex($val), $num_nibbles, '0', STR_PAD_LEFT);
1365
        }
1461
        }
1366
 
1462
 
1367
        // TODO Not implemented: Optional counter (to be defined as parameter to this method)
1463
        // TODO Not implemented: Optional counter (to be defined as parameter to this method)
1368
        // The counter bits need to be spread before and after the variant bits
1464
        // The counter bits need to be spread before and after the variant bits
1369
 
1465
 
1370
        // Fill with random bits (and the variant bits)
1466
        // Fill with random bits (and the variant bits)
1371
        $uuid = gen_uuid_random();
1467
        $uuid = gen_uuid_random();
1372
        $uuid = str_replace('-', '', $uuid);
1468
        $uuid = str_replace('-', '', $uuid);
1373
        for ($i=0; $i<strlen($uuid_nibbles); $i++) $uuid[$i] = $uuid_nibbles[$i];
1469
        for ($i=0; $i<strlen($uuid_nibbles); $i++) $uuid[$i] = $uuid_nibbles[$i];
1374
 
1470
 
1375
        // Wait to make sure that the time part changes if multiple UUIDs are generated
1471
        // Wait to make sure that the time part changes if multiple UUIDs are generated
1376
        if (time_nanosleep(0,(int)ceil($resolution_ns)) !== true) usleep((int)ceil($resolution_ns/1000));
1472
        if (time_nanosleep(0,(int)ceil($resolution_ns)) !== true) usleep((int)ceil($resolution_ns/1000));
1377
 
1473
 
1378
        // Output
1474
        // Output
1379
        return substr($uuid,  0, 8).'-'.
1475
        return substr($uuid,  0, 8).'-'.
1380
               substr($uuid,  8, 4).'-'.
1476
               substr($uuid,  8, 4).'-'.
1381
               substr($uuid, 12, 4).'-'.
1477
               substr($uuid, 12, 4).'-'.
1382
               substr($uuid, 16, 4).'-'.
1478
               substr($uuid, 16, 4).'-'.
1383
               substr($uuid, 20, 12);
1479
               substr($uuid, 20, 12);
1384
}
1480
}
1385
 
1481
 
1386
# --------------------------------------
1482
# --------------------------------------
1387
// Variant 1, Version 8 (Custom) UUID
1483
// Variant 1, Version 8 (Custom) UUID
1388
# --------------------------------------
1484
# --------------------------------------
1389
 
1485
 
1390
function gen_uuid_v8($block1_32bit, $block2_16bit, $block3_12bit, $block4_14bit, $block5_48bit) {
1486
function gen_uuid_v8($block1_32bit, $block2_16bit, $block3_12bit, $block4_14bit, $block5_48bit) {
1391
        return gen_uuid_custom($block1_32bit, $block2_16bit, $block3_12bit, $block4_14bit, $block5_48bit);
1487
        return gen_uuid_custom($block1_32bit, $block2_16bit, $block3_12bit, $block4_14bit, $block5_48bit);
1392
}
1488
}
1393
function gen_uuid_custom($block1_32bit, $block2_16bit, $block3_12bit, $block4_14bit, $block5_48bit) {
1489
function gen_uuid_custom($block1_32bit, $block2_16bit, $block3_12bit, $block4_14bit, $block5_48bit) {
1394
        if (preg_replace('@[0-9A-F]@i', '', $block1_32bit) != '') throw new Exception("Invalid data for block 1. Must be hex input");
1490
        if (preg_replace('@[0-9A-F]@i', '', $block1_32bit) != '') throw new Exception("Invalid data for block 1. Must be hex input");
1395
        if (preg_replace('@[0-9A-F]@i', '', $block2_16bit) != '') throw new Exception("Invalid data for block 2. Must be hex input");
1491
        if (preg_replace('@[0-9A-F]@i', '', $block2_16bit) != '') throw new Exception("Invalid data for block 2. Must be hex input");
1396
        if (preg_replace('@[0-9A-F]@i', '', $block3_12bit) != '') throw new Exception("Invalid data for block 3. Must be hex input");
1492
        if (preg_replace('@[0-9A-F]@i', '', $block3_12bit) != '') throw new Exception("Invalid data for block 3. Must be hex input");
1397
        if (preg_replace('@[0-9A-F]@i', '', $block4_14bit) != '') throw new Exception("Invalid data for block 4. Must be hex input");
1493
        if (preg_replace('@[0-9A-F]@i', '', $block4_14bit) != '') throw new Exception("Invalid data for block 4. Must be hex input");
1398
        if (preg_replace('@[0-9A-F]@i', '', $block5_48bit) != '') throw new Exception("Invalid data for block 5. Must be hex input");
1494
        if (preg_replace('@[0-9A-F]@i', '', $block5_48bit) != '') throw new Exception("Invalid data for block 5. Must be hex input");
1399
 
1495
 
1400
        $block1 = str_pad(substr($block1_32bit, -8),  8, '0', STR_PAD_LEFT);
1496
        $block1 = str_pad(substr($block1_32bit, -8),  8, '0', STR_PAD_LEFT);
1401
        $block2 = str_pad(substr($block2_16bit, -4),  4, '0', STR_PAD_LEFT);
1497
        $block2 = str_pad(substr($block2_16bit, -4),  4, '0', STR_PAD_LEFT);
1402
        $block3 = str_pad(substr($block3_12bit, -4),  4, '0', STR_PAD_LEFT);
1498
        $block3 = str_pad(substr($block3_12bit, -4),  4, '0', STR_PAD_LEFT);
1403
        $block4 = str_pad(substr($block4_14bit, -4),  4, '0', STR_PAD_LEFT);
1499
        $block4 = str_pad(substr($block4_14bit, -4),  4, '0', STR_PAD_LEFT);
1404
        $block5 = str_pad(substr($block5_48bit,-12), 12, '0', STR_PAD_LEFT);
1500
        $block5 = str_pad(substr($block5_48bit,-12), 12, '0', STR_PAD_LEFT);
1405
 
1501
 
1406
        $block3[0] = '8'; // Version 8 = Custom
1502
        $block3[0] = '8'; // Version 8 = Custom
1407
        $block4[0] = dechex(hexdec($block4[0]) & 0b0011 | 0b1000); // Variant 0b10__ = RFC4122
1503
        $block4[0] = dechex(hexdec($block4[0]) & 0b0011 | 0b1000); // Variant 0b10__ = RFC4122
1408
 
1504
 
1409
        return strtolower($block1.'-'.$block2.'-'.$block3.'-'.$block4.'-'.$block5);
1505
        return strtolower($block1.'-'.$block2.'-'.$block3.'-'.$block4.'-'.$block5);
1410
}
1506
}
1411
 
1507
 
1412
function gen_uuid_v8_namebased($hash_algo, $namespace_uuid, $name) {
1508
function gen_uuid_v8_namebased($hash_algo, $namespace_uuid, $name) {
1413
        if (($hash_algo ?? '') === '') throw new Exception("Hash algorithm argument missing");
1509
        if (($hash_algo ?? '') === '') throw new Exception("Hash algorithm argument missing");
1414
 
1510
 
1415
        if (($namespace_uuid ?? '') === '') throw new Exception("Namespace UUID missing");
1511
        if (($namespace_uuid ?? '') === '') throw new Exception("Namespace UUID missing");
1416
        if (!uuid_valid($namespace_uuid)) throw new Exception("Invalid namespace UUID '$namespace_uuid'");
1512
        if (!uuid_valid($namespace_uuid)) throw new Exception("Invalid namespace UUID '$namespace_uuid'");
1417
 
1513
 
1418
        $uuid1 = uuid_valid($hash_algo) ? hex2bin(str_replace('-','',uuid_canonize($hash_algo))) : ''; // old "hash space" concept (dropped in Internet Draft 12)
1514
        $uuid1 = uuid_valid($hash_algo) ? hex2bin(str_replace('-','',uuid_canonize($hash_algo))) : ''; // old "hash space" concept (dropped in Internet Draft 12)
1419
        $uuid2 = hex2bin(str_replace('-','',uuid_canonize($namespace_uuid)));
1515
        $uuid2 = hex2bin(str_replace('-','',uuid_canonize($namespace_uuid)));
1420
        $payload = $uuid1 . $uuid2 . $name;
1516
        $payload = $uuid1 . $uuid2 . $name;
1421
 
1517
 
1422
        if (uuid_valid($hash_algo)) {
1518
        if (uuid_valid($hash_algo)) {
1423
                if (uuid_equal($hash_algo, '59031ca3-fbdb-47fb-9f6c-0f30e2e83145')) $hash_algo = 'sha224';
1519
                if (uuid_equal($hash_algo, '59031ca3-fbdb-47fb-9f6c-0f30e2e83145')) $hash_algo = 'sha224';
1424
                if (uuid_equal($hash_algo, '3fb32780-953c-4464-9cfd-e85dbbe9843d')) $hash_algo = 'sha256';
1520
                if (uuid_equal($hash_algo, '3fb32780-953c-4464-9cfd-e85dbbe9843d')) $hash_algo = 'sha256';
1425
                if (uuid_equal($hash_algo, 'e6800581-f333-484b-8778-601ff2b58da8')) $hash_algo = 'sha384';
1521
                if (uuid_equal($hash_algo, 'e6800581-f333-484b-8778-601ff2b58da8')) $hash_algo = 'sha384';
1426
                if (uuid_equal($hash_algo, '0fde22f2-e7ba-4fd1-9753-9c2ea88fa3f9')) $hash_algo = 'sha512';
1522
                if (uuid_equal($hash_algo, '0fde22f2-e7ba-4fd1-9753-9c2ea88fa3f9')) $hash_algo = 'sha512';
1427
                if (uuid_equal($hash_algo, '003c2038-c4fe-4b95-a672-0c26c1b79542')) $hash_algo = 'sha512/224';
1523
                if (uuid_equal($hash_algo, '003c2038-c4fe-4b95-a672-0c26c1b79542')) $hash_algo = 'sha512/224';
1428
                if (uuid_equal($hash_algo, '9475ad00-3769-4c07-9642-5e7383732306')) $hash_algo = 'sha512/256';
1524
                if (uuid_equal($hash_algo, '9475ad00-3769-4c07-9642-5e7383732306')) $hash_algo = 'sha512/256';
1429
                if (uuid_equal($hash_algo, '9768761f-ac5a-419e-a180-7ca239e8025a')) $hash_algo = 'sha3-224';
1525
                if (uuid_equal($hash_algo, '9768761f-ac5a-419e-a180-7ca239e8025a')) $hash_algo = 'sha3-224';
1430
                if (uuid_equal($hash_algo, '2034d66b-4047-4553-8f80-70e593176877')) $hash_algo = 'sha3-256';
1526
                if (uuid_equal($hash_algo, '2034d66b-4047-4553-8f80-70e593176877')) $hash_algo = 'sha3-256';
1431
                if (uuid_equal($hash_algo, '872fb339-2636-4bdd-bda6-b6dc2a82b1b3')) $hash_algo = 'sha3-384';
1527
                if (uuid_equal($hash_algo, '872fb339-2636-4bdd-bda6-b6dc2a82b1b3')) $hash_algo = 'sha3-384';
1432
                if (uuid_equal($hash_algo, 'a4920a5d-a8a6-426c-8d14-a6cafbe64c7b')) $hash_algo = 'sha3-512';
1528
                if (uuid_equal($hash_algo, 'a4920a5d-a8a6-426c-8d14-a6cafbe64c7b')) $hash_algo = 'sha3-512';
1433
                if (uuid_equal($hash_algo, '7ea218f6-629a-425f-9f88-7439d63296bb')) $hash_algo = 'shake128';
1529
                if (uuid_equal($hash_algo, '7ea218f6-629a-425f-9f88-7439d63296bb')) $hash_algo = 'shake128';
1434
                if (uuid_equal($hash_algo, '2e7fc6a4-2919-4edc-b0ba-7d7062ce4f0a')) $hash_algo = 'shake256';
1530
                if (uuid_equal($hash_algo, '2e7fc6a4-2919-4edc-b0ba-7d7062ce4f0a')) $hash_algo = 'shake256';
1435
        }
1531
        }
1436
 
1532
 
1437
        if ($hash_algo == 'shake128') $hash = shake128($payload, 16/*min. required bytes*/, false);
1533
        if ($hash_algo == 'shake128') $hash = shake128($payload, 16/*min. required bytes*/, false);
1438
        else if ($hash_algo == 'shake256') $hash = shake256($payload, 16/*min. required bytes*/, false);
1534
        else if ($hash_algo == 'shake256') $hash = shake256($payload, 16/*min. required bytes*/, false);
1439
        else $hash = hash($hash_algo, $payload, false);
1535
        else $hash = hash($hash_algo, $payload, false);
1440
 
1536
 
1441
        if ($hash == null) {
1537
        if ($hash == null) {
1442
                throw new Exception("Unknown Hash Algorithm $hash_algo");
1538
                throw new Exception("Unknown Hash Algorithm $hash_algo");
1443
        }
1539
        }
1444
 
1540
 
1445
        $hash = str_pad($hash, 32, '0', STR_PAD_RIGHT); // fill short hashes with zeros to the right
1541
        $hash = str_pad($hash, 32, '0', STR_PAD_RIGHT); // fill short hashes with zeros to the right
1446
 
1542
 
1447
        $hash[12] = '8'; // Set version: 8 = Custom
1543
        $hash[12] = '8'; // Set version: 8 = Custom
1448
        $hash[16] = dechex(hexdec($hash[16]) & 0b0011 | 0b1000); // Set variant to "0b10__" (RFC4122/DCE1.1)
1544
        $hash[16] = dechex(hexdec($hash[16]) & 0b0011 | 0b1000); // Set variant to "0b10__" (RFC4122/DCE1.1)
1449
 
1545
 
1450
        return substr($hash,  0, 8).'-'.
1546
        return substr($hash,  0, 8).'-'.
1451
               substr($hash,  8, 4).'-'.
1547
               substr($hash,  8, 4).'-'.
1452
               substr($hash, 12, 4).'-'.
1548
               substr($hash, 12, 4).'-'.
1453
               substr($hash, 16, 4).'-'.
1549
               substr($hash, 16, 4).'-'.
1454
               substr($hash, 20, 12);
1550
               substr($hash, 20, 12);
1455
}
1551
}
1456
 
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
 
1457
# --------------------------------------
1624
# --------------------------------------
1458
 
1625
 
1459
// http://php.net/manual/de/function.hex2bin.php#113057
1626
// http://php.net/manual/de/function.hex2bin.php#113057
1460
if (!function_exists('hex2bin')) {
1627
if (!function_exists('hex2bin')) {
1461
    function hex2bin($str) {
1628
    function hex2bin($str) {
1462
        $sbin = "";
1629
        $sbin = "";
1463
        $len = strlen($str);
1630
        $len = strlen($str);
1464
        for ( $i = 0; $i < $len; $i += 2 ) {
1631
        for ( $i = 0; $i < $len; $i += 2 ) {
1465
            $sbin .= pack("H*", substr($str, $i, 2));
1632
            $sbin .= pack("H*", substr($str, $i, 2));
1466
        }
1633
        }
1467
        return $sbin;
1634
        return $sbin;
1468
    }
1635
    }
1469
}
1636
}
1470
 
1637
 
1471
// https://stackoverflow.com/questions/72127764/shift-right-left-bitwise-operators-in-php7-gmp-extension
1638
// https://stackoverflow.com/questions/72127764/shift-right-left-bitwise-operators-in-php7-gmp-extension
1472
if (!function_exists('gmp_shiftl')) {
1639
if (!function_exists('gmp_shiftl')) {
1473
    function gmp_shiftl($x,$n) { // shift left
1640
    function gmp_shiftl($x,$n) { // shift left
1474
        return(gmp_mul($x,gmp_pow(2,$n)));
1641
        return(gmp_mul($x,gmp_pow(2,$n)));
1475
    }
1642
    }
1476
}
1643
}
1477
 
1644
 
1478
if (!function_exists('gmp_shiftr')) {
1645
if (!function_exists('gmp_shiftr')) {
1479
    function gmp_shiftr($x,$n) { // shift right
1646
    function gmp_shiftr($x,$n) { // shift right
1480
        return(gmp_div_q($x,gmp_pow(2,$n)));
1647
        return(gmp_div_q($x,gmp_pow(2,$n)));
1481
    }
1648
    }
1482
}
1649
}
1483
 
1650
 
1484
function shake128(string $msg, int $outputLength=512, bool $binary=false): string {
1651
function shake128(string $msg, int $outputLength=512, bool $binary=false): string {
1485
        include_once __DIR__.'/SHA3.php';
1652
        include_once __DIR__.'/SHA3.php';
1486
        $sponge = SHA3::init(SHA3::SHAKE128);
1653
        $sponge = SHA3::init(SHA3::SHAKE128);
1487
        $sponge->absorb($msg);
1654
        $sponge->absorb($msg);
1488
        $bin = $sponge->squeeze($outputLength);
1655
        $bin = $sponge->squeeze($outputLength);
1489
        return $binary ? $bin : bin2hex($bin);
1656
        return $binary ? $bin : bin2hex($bin);
1490
}
1657
}
1491
 
1658
 
1492
function shake256(string $msg, int $outputLength=512, bool $binary=false): string {
1659
function shake256(string $msg, int $outputLength=512, bool $binary=false): string {
1493
        include_once __DIR__.'/SHA3.php';
1660
        include_once __DIR__.'/SHA3.php';
1494
        $sponge = SHA3::init(SHA3::SHAKE256);
1661
        $sponge = SHA3::init(SHA3::SHAKE256);
1495
        $sponge->absorb($msg);
1662
        $sponge->absorb($msg);
1496
        $bin = $sponge->squeeze($outputLength);
1663
        $bin = $sponge->squeeze($outputLength);
1497
        return $binary ? $bin : bin2hex($bin);
1664
        return $binary ? $bin : bin2hex($bin);
1498
}
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
 
1499
 
1679