Subversion Repositories oidplus

Rev

Blame | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /*
  4.  * UUID utils for PHP
  5.  * Copyright 2011-2020 Daniel Marschall, ViaThinkSoft
  6.  * Version 2020-02-28
  7.  *
  8.  * Licensed under the Apache License, Version 2.0 (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
  11.  *
  12.  *     http://www.apache.org/licenses/LICENSE-2.0
  13.  *
  14.  * Unless required by applicable law or agreed to in writing, software
  15.  * distributed under the License is distributed on an "AS IS" BASIS,
  16.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17.  * See the License for the specific language governing permissions and
  18.  * limitations under the License.
  19.  */
  20.  
  21. # This library requires either the GMP extension (or BCMath if gmp_supplement.inc.php is present)
  22.  
  23. if (file_exists(__DIR__ . '/mac_utils.inc.phps')) include_once __DIR__ . '/mac_utils.inc.phps';
  24. if (file_exists(__DIR__ . '/gmp_supplement.inc.php')) include_once __DIR__ . '/gmp_supplement.inc.php';
  25.  
  26. define('UUID_NAMEBASED_NS_DNS',     '6ba7b810-9dad-11d1-80b4-00c04fd430c8');
  27. define('UUID_NAMEBASED_NS_URL',     '6ba7b811-9dad-11d1-80b4-00c04fd430c8');
  28. define('UUID_NAMEBASED_NS_OID',     '6ba7b812-9dad-11d1-80b4-00c04fd430c8');
  29. define('UUID_NAMEBASED_NS_X500_DN', '6ba7b814-9dad-11d1-80b4-00c04fd430c8');
  30.  
  31. function uuid_valid($uuid) {
  32.         $uuid = str_replace(array('-', '{', '}'), '', $uuid);
  33.         $uuid = strtoupper($uuid);
  34.  
  35.         if (strlen($uuid) != 32) return false;
  36.  
  37.         $uuid = preg_replace('@[0-9A-F]@', '', $uuid);
  38.  
  39.         return ($uuid == '');
  40. }
  41.  
  42. # TODO: Don't echo
  43. function uuid_info($uuid) {
  44.         if (!uuid_valid($uuid)) return false;
  45.  
  46.         # $uuid = str_replace(array('-', '{', '}'), '', $uuid);
  47.         $uuid = strtoupper($uuid);
  48.         $uuid = preg_replace('@[^0-9A-F]@', '', $uuid);
  49.  
  50.         $x = hexdec(substr($uuid, 16, 1));
  51.              if ($x >= 14 /* 1110 */) $variant = 3;
  52.         else if ($x >= 12 /* 1100 */) $variant = 2;
  53.         else if ($x >=  8 /* 1000 */) $variant = 1;
  54.         else if ($x >=  0 /* 0000 */) $variant = 0;
  55.  
  56.  
  57.         switch ($variant) {
  58.                 case 0:
  59.                         echo sprintf("%-24s %s\n", "Variant:", "[0xx] NCS (reserved for backward compatibility)");
  60.  
  61.                         /*
  62.                          * Internal structure of variant #0 UUIDs
  63.                          *
  64.                          * The first 6 octets are the number of 4 usec units of time that have
  65.                          * passed since 1/1/80 0000 GMT.  The next 2 octets are reserved for
  66.                          * future use.  The next octet is an address family.  The next 7 octets
  67.                          * are a host ID in the form allowed by the specified address family.
  68.                          *
  69.                          * Note that while the family field (octet 8) was originally conceived
  70.                          * of as being able to hold values in the range [0..255], only [0..13]
  71.                          * were ever used.  Thus, the 2 MSB of this field are always 0 and are
  72.                          * used to distinguish old and current UUID forms.
  73.                          *
  74.                          * +--------------------------------------------------------------+
  75.                          * |                    high 32 bits of time                      |  0-3  .time_high
  76.                          * +-------------------------------+-------------------------------
  77.                          * |     low 16 bits of time       |  4-5               .time_low
  78.                          * +-------+-----------------------+
  79.                          * |         reserved              |  6-7               .reserved
  80.                          * +---------------+---------------+
  81.                          * |    family     |   8                                .family
  82.                          * +---------------+----------...-----+
  83.                          * |            node ID               |  9-16           .node
  84.                          * +--------------------------...-----+
  85.                          *
  86.                          */
  87.  
  88.                         // Example of an UUID: 333a2276-0000-0000-0d00-00809c000000
  89.  
  90.                         # TODO: See https://github.com/cjsv/uuid/blob/master/Doc
  91.  
  92.                         # Timestamp: Count of 4us intervals since 01 Jan 1980 00:00:00 GMT
  93.                         # 1/0,000004 = 250000
  94.                         # Seconds between 1970 and 1980 : 315532800
  95.                         # 250000*315532800=78883200000000
  96.                         $timestamp = substr($uuid, 0, 12);
  97.                         $ts = gmp_init($timestamp, 16);
  98.                         $ts = gmp_add($ts, gmp_init("78883200000000"));
  99.                         $ms = gmp_mod($ts, gmp_init("250000"));
  100.                         $ts = gmp_div($ts, gmp_init("250000"));
  101.                         $ts = gmp_strval($ts);
  102.                         $ms = gmp_strval($ms);
  103.                         $ts = gmdate('Y-m-d H:i:s', $ts)."'".str_pad($ms, 7, '0', STR_PAD_LEFT).' GMT';
  104.                         echo sprintf("%-24s %s\n", "Timestamp:", "[0x$timestamp] $ts");
  105.  
  106.                         $reserved = substr($uuid, 12, 4);
  107.                         echo sprintf("%-24s %s\n", "Reserved:", "0x$reserved");
  108.  
  109.                         # Family 13 (dds) looks like node is 00 | nnnnnn 000000.
  110.                         # Family 2 is presumably (ip).
  111.                         # Not sure if anything else was used.
  112.                         $family_hex = substr($uuid, 16, 2);
  113.                         $family_dec = hexdec($family_hex);
  114.                         if ($family_dec == 2) {
  115.                                 $family_ = 'IP';
  116.                         } else if ($family_dec == 13) {
  117.                                 $family_ = 'DDS (Data Link)';
  118.                         } else {
  119.                                 $family_ = "Unknown ($family_dec)"; # There are probably no more families
  120.                         }
  121.                         echo sprintf("%-24s %s\n", "Family:", "[0x$family_hex = $family_dec] $family_");
  122.  
  123.                         $nodeid = substr($uuid, 18, 14);
  124.                         echo sprintf("%-24s %s\n", "Node ID:", "0x$nodeid");
  125.                         # TODO: interprete node id (the family specifies it)
  126.  
  127.                         break;
  128.                 case 1:
  129.                         echo sprintf("%-24s %s\n", "Variant:", "[10x] RFC 4122 (Leach-Mealling-Salz)");
  130.  
  131.                         $version = hexdec(substr($uuid, 12, 1));
  132.                         switch ($version) {
  133.                                 case 1:
  134.                                         echo sprintf("%-24s %s\n", "Version:", "[1] Time-based with unique random host identifier");
  135.  
  136.                                         # Timestamp: Count of 100ns intervals since 15 Oct 1582 00:00:00
  137.                                         # 1/0,0000001 = 10000000
  138.                                         $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).substr($uuid, 0, 8);
  139.                                         $ts = gmp_init($timestamp, 16);
  140.                                         $ts = gmp_sub($ts, gmp_init("122192928000000000"));
  141.                                         $ms = gmp_mod($ts, gmp_init("10000000"));
  142.                                         $ts = gmp_div($ts, gmp_init("10000000"));
  143.                                         $ts = gmp_strval($ts);
  144.                                         $ms = gmp_strval($ms);
  145.                                         $ts = gmdate('Y-m-d H:i:s', $ts)."'".str_pad($ms, 7, '0', STR_PAD_LEFT).' GMT';
  146.                                         echo sprintf("%-24s %s\n", "Timestamp:", "[0x$timestamp] $ts");
  147.  
  148.                                         $x = hexdec(substr($uuid, 16, 4));
  149.                                         $dec = $x & 0x3FFF; // The highest 2 bits are used by "variant" (10x)
  150.                                         $hex = substr($uuid, 16, 4);
  151.                                         echo sprintf("%-24s %s\n", "Clock ID:", "[0x$hex] $dec");
  152.  
  153.                                         $x = substr($uuid, 20, 12);
  154.                                         $nodeid = '';
  155.                                         for ($i=0; $i<6; $i++) {
  156.                                                 $nodeid .= substr($x, $i*2, 2);
  157.                                                 if ($i != 5) $nodeid .= ':';
  158.                                         }
  159.                                         echo sprintf("%-24s %s\n", "Node ID:", "$nodeid");
  160.  
  161.                                         if (function_exists('decode_mac')) {
  162.                                                 echo "\nIn case that this Node ID is a MAC address, here is the interpretation of that MAC address:\n";
  163.                                                 echo decode_mac($nodeid);
  164.                                         }
  165.  
  166.                                         break;
  167.                                 case 2:
  168.                                         echo sprintf("%-24s %s\n", "Version:", "[2] DCE Security version");
  169.  
  170.                                         # 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.
  171.                                         $x = substr($uuid, 0, 8);
  172.                                         echo sprintf("%-24s %s\n", "Local ID:", "0x$x");
  173.  
  174.                                         # 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".
  175.                                         $x = substr($uuid, 18, 2);
  176.                                         if ($x == '00') $domain_info = 'POSIX: User-ID / Non-POSIX: site-defined';
  177.                                         else if ($x == '01') $domain_info = 'POSIX: Group-ID / Non-POSIX: site-defined';
  178.                                         else $domain_info = 'site-defined';
  179.                                         echo sprintf("%-24s %s\n", "Local Domain:", "0x$x ($domain_info)");
  180.  
  181.                                         # Timestamp: Count of 100ns intervals since 15 Oct 1582 00:00:00
  182.                                         # 1/0,0000001 = 10000000
  183.                                         $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).'00000000';
  184.                                         $ts = gmp_init($timestamp, 16);
  185.                                         $ts = gmp_sub($ts, gmp_init("122192928000000000"));
  186.                                         $ms = gmp_mod($ts, gmp_init("10000000"));
  187.                                         $ts = gmp_div($ts, gmp_init("10000000"));
  188.                                         $ts = gmp_strval($ts);
  189.                                         $ms = gmp_strval($ms);
  190.                                         $ts_min = gmdate('Y-m-d H:i:s', $ts)."'".str_pad($ms, 7, '0', STR_PAD_LEFT).' GMT';
  191.  
  192.                                         $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).'FFFFFFFF';
  193.                                         $ts = gmp_init($timestamp, 16);
  194.                                         $ts = gmp_sub($ts, gmp_init("122192928000000000"));
  195.                                         $ms = gmp_mod($ts, gmp_init("10000000"));
  196.                                         $ts = gmp_div($ts, gmp_init("10000000"));
  197.                                         $ts = gmp_strval($ts);
  198.                                         $ms = gmp_strval($ms);
  199.                                         $ts_max = gmdate('Y-m-d H:i:s', $ts)."'".str_pad($ms, 7, '0', STR_PAD_LEFT).' GMT';
  200.  
  201.                                         $timestamp = substr($uuid, 13, 3).substr($uuid, 8, 4).'xxxxxxxx';
  202.                                         echo sprintf("%-24s %s\n", "Timestamp:", "[0x$timestamp] $ts_min - $ts_max");
  203.  
  204.                                         $x = hexdec(substr($uuid, 16, 2).'00');
  205.                                         $dec_min = $x & 0x3FFF; // The highest 2 bits are used by "variant" (10x)
  206.                                         $x = hexdec(substr($uuid, 16, 2).'FF');
  207.                                         $dec_max = $x & 0x3FFF; // The highest 2 bits are used by "variant" (10x)
  208.                                         $hex = substr($uuid, 16, 2).'xx';
  209.                                         echo sprintf("%-24s %s\n", "Clock ID:", "[0x$hex] $dec_min - $dec_max");
  210.  
  211.                                         $x = substr($uuid, 20, 12);
  212.                                         $nodeid = '';
  213.                                         for ($i=0; $i<6; $i++) {
  214.                                                 $nodeid .= substr($x, $i*2, 2);
  215.                                                 if ($i != 5) $nodeid .= ':';
  216.                                         }
  217.                                         echo sprintf("%-24s %s\n", "Node ID:", "$nodeid");
  218.  
  219.                                         if (function_exists('decode_mac')) {
  220.                                                 echo "\nIn case that this Node ID is a MAC address, here is the interpretation of that MAC address:\n";
  221.                                                 echo decode_mac($nodeid);
  222.                                         }
  223.  
  224.                                         break;
  225.                                 case 3:
  226.                                         echo sprintf("%-24s %s\n", "Version:", "[3] Name-based (MD5 hash)");
  227.  
  228.                                         $hash = str_replace('-', '', strtolower($uuid));
  229.                                         $hash[12] = '?'; // was overwritten by version
  230.                                         $hash[16] = '?'; // was partially overwritten by variant
  231.  
  232.                                         echo sprintf("%-24s %s\n", "MD5(Namespace+Subject):", "$hash");
  233.  
  234.                                         break;
  235.                                 case 4:
  236.                                         echo sprintf("%-24s %s\n", "Version:", "[4] Random");
  237.  
  238.                                         $rand = '';
  239.                                         for ($i=0; $i<16; $i++) {
  240.                                                 $bin = base_convert(substr($uuid, $i*2, 2), 16, 2);
  241.                                                 $bin = str_pad($bin, 8, "0", STR_PAD_LEFT);
  242.  
  243.                                                 if ($i == 6) {
  244.                                                         $bin[0] = 'x';
  245.                                                         $bin[1] = 'x';
  246.                                                 } else if ($i == 8) {
  247.                                                         $bin[0] = 'x';
  248.                                                         $bin[1] = 'x';
  249.                                                         $bin[2] = 'x';
  250.                                                         $bin[3] = 'x';
  251.                                                 }
  252.  
  253.                                                 $rand .= "$bin ";
  254.                                         }
  255.  
  256.                                         echo sprintf("%-24s %s\n", "Random bits:", trim($rand));
  257.  
  258.                                         break;
  259.                                 case 5:
  260.                                         echo sprintf("%-24s %s\n", "Version:", "[5] Name-based (SHA-1 hash)");
  261.  
  262.                                         $hash = str_replace('-', '', strtolower($uuid));
  263.                                         $hash[12] = '?'; // was overwritten by version
  264.                                         $hash[16] = '?'; // was partially overwritten by variant
  265.                                         $hash .= '????????'; // was cut off
  266.  
  267.                                         echo sprintf("%-24s %s\n", "SHA1(Namespace+Subject):", "$hash");
  268.  
  269.  
  270.                                         break;
  271.                                 default:
  272.                                         echo sprintf("%-24s %s\n", "Version:", "[$version] Unknown");
  273.                                         break;
  274.                         }
  275.  
  276.                         break;
  277.                 case 2:
  278.                         echo sprintf("%-24s %s\n", "Variant:", "[110] Reserved for Microsoft Corporation");
  279.                         break;
  280.                 case 3:
  281.                         echo sprintf("%-24s %s\n", "Variant:", "[111] Reserved for future use");
  282.                         break;
  283.         }
  284. }
  285.  
  286. function uuid_canonize($uuid) {
  287.         if (!uuid_valid($uuid)) return false;
  288.         return oid_to_uuid(uuid_to_oid($uuid));
  289. }
  290.  
  291. function oid_to_uuid($oid) {
  292.         if (!is_uuid_oid($oid)) return false;
  293.  
  294.         if ($oid[0] == '.') {
  295.                 $oid = substr($oid, 1);
  296.         }
  297.         $ary = explode('.', $oid);
  298.         $val = $ary[2];
  299.  
  300.         $x = gmp_init($val, 10);
  301.         $y = gmp_strval($x, 16);
  302.         $y = str_pad($y, 32, "0", STR_PAD_LEFT);
  303.         return substr($y,  0, 8).'-'.
  304.                substr($y,  8, 4).'-'.
  305.                substr($y, 12, 4).'-'.
  306.                substr($y, 16, 4).'-'.
  307.                substr($y, 20, 12);
  308. }
  309.  
  310. function is_uuid_oid($oid, $only_allow_root=false) {
  311.         if ($oid[0] == '.') $oid = substr($oid, 1); // remove leading dot
  312.  
  313.         $ary = explode('.', $oid);
  314.  
  315.         if ($only_allow_root) {
  316.                 if (count($ary) != 3) return false;
  317.         }
  318.  
  319.         if ($ary[0] != '2') return false;
  320.         if ($ary[1] != '25') return false;
  321.         for ($i=2; $i<count($ary); $i++) {
  322.                 $v = $ary[$i];
  323.                 if (!is_numeric($v)) return false;
  324.                 if ($i == 2) {
  325.                         // Must be in the range of 128 bit UUID
  326.                         $test = gmp_init($v, 10);
  327.                         if (strlen(gmp_strval($test, 16)) > 32) return false;
  328.                 }
  329.                 if ($v < 0) return false;
  330.         }
  331.  
  332.         return true;
  333. }
  334.  
  335. function uuid_to_oid($uuid) {
  336.         if (!uuid_valid($uuid)) return false;
  337.  
  338.         $uuid = str_replace(array('-', '{', '}'), '', $uuid);
  339.         $x = gmp_init($uuid, 16);
  340.         return '2.25.'.gmp_strval($x, 10); # TODO: parameter with or without leading dot
  341. }
  342.  
  343. function gen_uuid($prefer_timebased = true) {
  344.         if ($prefer_timebased) $uuid = gen_uuid_timebased();
  345.         if ($uuid === false) $uuid = gen_uuid_random();
  346.         return $uuid;
  347. }
  348.  
  349. // Version 1 (Time based) UUID
  350. function gen_uuid_timebased() {
  351.         # On Debian: aptitude install php-uuid
  352.         # extension_loaded('uuid')
  353.         if (function_exists('uuid_create')) {
  354.                 # OSSP uuid extension like seen in php5-uuid at Debian 8
  355.                 /*
  356.                 $x = uuid_create($context);
  357.                 uuid_make($context, UUID_MAKE_V1);
  358.                 uuid_export($context, UUID_FMT_STR, $uuid);
  359.                 return trim($uuid);
  360.                 */
  361.  
  362.                 # PECL uuid extension like seen in php-uuid at Debian 9
  363.                 return trim(uuid_create(UUID_TYPE_TIME));
  364.         }
  365.  
  366.         # On Debian: aptitude install uuid-runtime
  367.         $out = array();
  368.         exec('uuidgen -t', $out, $ec);
  369.         if ($ec == 0) return $out[0];
  370.  
  371.         # TODO: Implement the time based generation routine ourselves!
  372.         # At the moment we cannot determine the time based UUID
  373.         return false;
  374. }
  375.  
  376. // Version 2 (DCE Security) UUID
  377. function gen_uuid_dce($domain, $id) {
  378.         # Start with a version 1 UUID
  379.         $uuid = gen_uuid_timebased();
  380.  
  381.         # Add ID
  382.         $uuid = str_pad(dechex($id), 8, '0', STR_PAD_LEFT) . substr($uuid, 8);
  383.  
  384.         # Add domain
  385.         $uuid = substr($uuid,0,21) . str_pad(dechex($domain), 2, '0', STR_PAD_LEFT) . substr($uuid, 23);
  386.  
  387.         # Change version to 2
  388.         $uuid[14] = '2';
  389.  
  390.         return $uuid;
  391. }
  392.  
  393. // Version 3 (MD5 name based) UUID
  394. function gen_uuid_md5_namebased($namespace_uuid, $name) {
  395.         if (!uuid_valid($namespace_uuid)) return false;
  396.         $namespace_uuid = uuid_canonize($namespace_uuid);
  397.         $namespace_uuid = str_replace('-', '', $namespace_uuid);
  398.         $namespace_uuid = hex2bin($namespace_uuid);
  399.  
  400.         $hash = md5($namespace_uuid.$name);
  401.         $hash[12] = '3'; // Set version: 3 = MD5
  402.         $hash[16] = dechex(hexdec($hash[16]) & 0x3 | 0x8); // Set variant to "10xx" (RFC4122)
  403.  
  404.         return substr($hash,  0, 8).'-'.
  405.                substr($hash,  8, 4).'-'.
  406.                substr($hash, 12, 4).'-'.
  407.                substr($hash, 16, 4).'-'.
  408.                substr($hash, 20, 12);
  409. }
  410.  
  411. // Version 4 (Random) UUID
  412. function gen_uuid_random() {
  413.         # On Debian: aptitude install php-uuid
  414.         # extension_loaded('uuid')
  415.         if (function_exists('uuid_create')) {
  416.                 # OSSP uuid extension like seen in php5-uuid at Debian 8
  417.                 /*
  418.                 $x = uuid_create($context);
  419.                 uuid_make($context, UUID_MAKE_V4);
  420.                 uuid_export($context, UUID_FMT_STR, $uuid);
  421.                 return trim($uuid);
  422.                 */
  423.  
  424.                 # PECL uuid extension like seen in php-uuid at Debian 9
  425.                 return trim(uuid_create(UUID_TYPE_RANDOM));
  426.         }
  427.  
  428.         # On Debian: aptitude install uuid-runtime
  429.         $out = array();
  430.         exec('uuidgen -r', $out, $ec);
  431.         if ($ec == 0) return $out[0];
  432.  
  433.         # On Debian Jessie: UUID V4 (Random)
  434.         if (file_exists('/proc/sys/kernel/random/uuid')) {
  435.                 return file_get_contents('/proc/sys/kernel/random/uuid');
  436.         }
  437.  
  438.         # Make the UUID by ourselves
  439.         # Source: http://rogerstringer.com/2013/11/15/generate-uuids-php
  440.         return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
  441.                 mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
  442.                 mt_rand( 0, 0xffff ),
  443.                 mt_rand( 0, 0x0fff ) | 0x4000,
  444.                 mt_rand( 0, 0x3fff ) | 0x8000,
  445.                 mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
  446.         );
  447. }
  448.  
  449. // Version 5 (SHA1 name based) UUID
  450. function gen_uuid_sha1_namebased($namespace_uuid, $name) {
  451.         $namespace_uuid = str_replace('-', '', $namespace_uuid);
  452.         $namespace_uuid = hex2bin($namespace_uuid);
  453.  
  454.         $hash = sha1($namespace_uuid.$name);
  455.         $hash[12] = '5'; // Set version: 5 = SHA1
  456.         $hash[16] = dechex(hexdec($hash[16]) & 0x3 | 0x8); // Set variant to "10xx" (RFC4122)
  457.  
  458.         return substr($hash,  0, 8).'-'.
  459.                substr($hash,  8, 4).'-'.
  460.                substr($hash, 12, 4).'-'.
  461.                substr($hash, 16, 4).'-'.
  462.                substr($hash, 20, 12);
  463. }
  464.  
  465. function uuid_numeric_value($uuid) {
  466.         $oid = uuid_to_oid($uuid);
  467.         if (!$oid) return false;
  468.         return substr($oid, strlen('2.25.'));
  469. }
  470.  
  471. function uuid_c_syntax($uuid) {
  472.         $uuid = str_replace('{', '', $uuid);
  473.         return '{ 0x' . substr($uuid, 0, 8) .
  474.                 ', 0x' . substr($uuid, 9, 4) .
  475.                 ', 0x' . substr($uuid, 14, 4) .
  476.                 ', { 0x' . substr($uuid, 19, 2).
  477.                 ', 0x' . substr($uuid, 21, 2) .
  478.                 ', 0x' . substr($uuid, 24, 2) .
  479.                 ', 0x' . substr($uuid, 26, 2) .
  480.                 ', 0x' . substr($uuid, 28, 2) .
  481.                 ', 0x' . substr($uuid, 30, 2) .
  482.                 ', 0x' . substr($uuid, 32, 2) .
  483.                 ', 0x' . substr($uuid, 34, 2) . ' } }';
  484. }
  485.  
  486. # ---
  487.  
  488. // http://php.net/manual/de/function.hex2bin.php#113057
  489. if ( !function_exists( 'hex2bin' ) ) {
  490.     function hex2bin( $str ) {
  491.         $sbin = "";
  492.         $len = strlen( $str );
  493.         for ( $i = 0; $i < $len; $i += 2 ) {
  494.             $sbin .= pack( "H*", substr( $str, $i, 2 ) );
  495.         }
  496.  
  497.         return $sbin;
  498.     }
  499. }
  500.