Subversion Repositories oidinfo_api

Rev

Rev 9 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

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