PageRenderTime 66ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/src/mako/utility/UUID.php

https://github.com/mako-framework/framework
PHP | 202 lines | 97 code | 31 blank | 74 comment | 3 complexity | c16c4854930bc84254b250f0fd2645e1 MD5 | raw file
  1. <?php
  2. /**
  3. * @copyright Frederic G. Østby
  4. * @license http://www.makoframework.com/license
  5. */
  6. namespace mako\utility;
  7. use mako\utility\exceptions\UUIDException;
  8. use function bin2hex;
  9. use function chr;
  10. use function dechex;
  11. use function explode;
  12. use function hex2bin;
  13. use function hexdec;
  14. use function md5;
  15. use function microtime;
  16. use function ord;
  17. use function preg_match;
  18. use function random_bytes;
  19. use function sha1;
  20. use function sprintf;
  21. use function str_replace;
  22. use function str_split;
  23. use function strlen;
  24. use function substr;
  25. use function vsprintf;
  26. /**
  27. * Class that generates and validates UUIDs.
  28. */
  29. class UUID
  30. {
  31. /**
  32. * DNS namespace.
  33. *
  34. * @var string
  35. */
  36. public const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
  37. /**
  38. * URL namespace.
  39. *
  40. * @var string
  41. */
  42. public const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
  43. /**
  44. * ISO OID namespace.
  45. *
  46. * @var string
  47. */
  48. public const OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8';
  49. /**
  50. * X.500 DN namespace.
  51. *
  52. * @var string
  53. */
  54. public const X500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8';
  55. /**
  56. * The "nil" UUID.
  57. *
  58. * @var string
  59. */
  60. public const NIL = '00000000-0000-0000-0000-000000000000';
  61. /**
  62. * Checks if a UUID is valid.
  63. *
  64. * @param string $uuid The UUID to validate
  65. * @return bool
  66. */
  67. public static function validate(string $uuid): bool
  68. {
  69. $uuid = str_replace(['urn:uuid:', '{', '}'], '', $uuid);
  70. return (bool) preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i', $uuid);
  71. }
  72. /**
  73. * Converts a UUID from its hexadecimal representation to a binary string.
  74. *
  75. * @param string $uuid UUID
  76. * @return string
  77. */
  78. public static function toBinary(string $uuid): string
  79. {
  80. if(!static::validate($uuid))
  81. {
  82. throw new UUIDException('The provided string is not a valid UUID.');
  83. }
  84. $hex = str_replace(['urn:uuid:', '{', '}', '-'], '', $uuid);
  85. $binary = '';
  86. for($i = 0; $i < 32; $i += 2)
  87. {
  88. $binary .= chr(hexdec("{$hex[$i]}{$hex[$i + 1]}"));
  89. }
  90. return $binary;
  91. }
  92. /**
  93. * Converts a binary UUID to its hexadecimal representation.
  94. *
  95. * @param string $bytes Binary representation of a UUID
  96. * @return string
  97. */
  98. public static function toHexadecimal(string $bytes): string
  99. {
  100. if(strlen($bytes) !== 16)
  101. {
  102. throw new UUIDException('The input must be exactly 16 bytes.');
  103. }
  104. return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($bytes), 4));
  105. }
  106. /**
  107. * Returns a V3 UUID.
  108. *
  109. * @param string $namespace Namespace
  110. * @param string $name Name
  111. * @return string
  112. */
  113. public static function v3(string $namespace, string $name): string
  114. {
  115. $hash = md5(static::toBinary($namespace) . $name);
  116. return sprintf
  117. (
  118. '%s-%s-%x-%x-%s',
  119. substr($hash, 0, 8),
  120. substr($hash, 8, 4),
  121. (hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x3000,
  122. (hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
  123. substr($hash, 20, 12)
  124. );
  125. }
  126. /**
  127. * Returns a V4 UUID.
  128. *
  129. * @return string
  130. */
  131. public static function v4(): string
  132. {
  133. $random = random_bytes(16);
  134. $random[6] = chr(ord($random[6]) & 0x0f | 0x40);
  135. $random[8] = chr(ord($random[8]) & 0x3f | 0x80);
  136. return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($random), 4));
  137. }
  138. /**
  139. * Returns a V5 UUID.
  140. *
  141. * @param string $namespace Namespace
  142. * @param string $name Name
  143. * @return string
  144. */
  145. public static function v5(string $namespace, string $name): string
  146. {
  147. $hash = sha1(static::toBinary($namespace) . $name);
  148. return sprintf
  149. (
  150. '%s-%s-%x-%x-%s',
  151. substr($hash, 0, 8),
  152. substr($hash, 8, 4),
  153. (hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x5000,
  154. (hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
  155. substr($hash, 20, 12)
  156. );
  157. }
  158. /**
  159. * Returns a sequential (COMB) v4 UUID.
  160. *
  161. * @return string
  162. */
  163. public static function sequential(): string
  164. {
  165. [$usec, $sec] = explode(' ', microtime());
  166. $random = hex2bin(dechex($sec . substr($usec, 2, 5)) . bin2hex(random_bytes(10)));
  167. $random[6] = chr(ord($random[6]) & 0x0f | 0x40);
  168. $random[8] = chr(ord($random[8]) & 0x3f | 0x80);
  169. return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($random), 4));
  170. }
  171. }