uuid.inc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. <?php
  2. /**
  3. * @file
  4. * Handling of universally unique identifiers.
  5. */
  6. /**
  7. * Pattern for detecting a valid UUID.
  8. */
  9. define('UUID_PATTERN', '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}');
  10. /**
  11. * Generates an universally unique identifier.
  12. *
  13. * This function first checks for the PECL alternative for generating
  14. * universally unique identifiers. If that doesn't exist, then it falls back on
  15. * PHP for generating that.
  16. *
  17. * @return string
  18. * An UUID, made up of 32 hex digits and 4 hyphens.
  19. */
  20. function uuid_generate() {
  21. $callback = drupal_static(__FUNCTION__);
  22. if (empty($callback)) {
  23. if (function_exists('uuid_create') && !function_exists('uuid_make')) {
  24. $callback = '_uuid_generate_pecl';
  25. }
  26. elseif (function_exists('com_create_guid')) {
  27. $callback = '_uuid_generate_com';
  28. }
  29. else {
  30. $callback = '_uuid_generate_php';
  31. }
  32. }
  33. return $callback();
  34. }
  35. /**
  36. * Generates a version 5 compliant UUID.
  37. *
  38. * @param string $namespace
  39. * Namespace UUID as a hex encoded string.
  40. * @param string $name
  41. * The name for the generating the UUID.
  42. *
  43. * @return string
  44. * UUID as a hex encoded string.
  45. *
  46. * @link http://www.php.net/manual/en/function.uniqid.php#94959 Code lifted from
  47. * PHP manual comment by Andrew Moore. @endlink
  48. */
  49. function uuid_generate_v5($namespace, $name) {
  50. if (!uuid_is_valid($namespace)) {
  51. return FALSE;
  52. }
  53. // Get hexadecimal components of namespace.
  54. $nhex = str_replace(array('-', '{', '}'), '', $namespace);
  55. // Binary Value.
  56. $nstr = '';
  57. // Convert Namespace UUID to bits.
  58. for ($i = 0; $i < strlen($nhex); $i += 2) {
  59. $nstr .= chr(hexdec($nhex[$i] . $nhex[$i + 1]));
  60. }
  61. // Calculate hash value.
  62. $hash = sha1($nstr . $name);
  63. return sprintf('%08s-%04s-%04x-%04x-%12s',
  64. // 32 bits for "time_low".
  65. substr($hash, 0, 8),
  66. // 16 bits for "time_mid".
  67. substr($hash, 8, 4),
  68. // 16 bits for "time_hi_and_version",
  69. // four most significant bits holds version number 5.
  70. (hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x5000,
  71. // 16 bits, 8 bits for "clk_seq_hi_res",
  72. // 8 bits for "clk_seq_low",
  73. // two most significant bits holds zero and one for variant DCE1.1.
  74. (hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
  75. // 48 bits for "node".
  76. substr($hash, 20, 12)
  77. );
  78. }
  79. /**
  80. * Generate all missing UUIDs.
  81. */
  82. function uuid_sync_all() {
  83. module_invoke_all('uuid_sync');
  84. }
  85. /**
  86. * Generates a UUID URI for an entity.
  87. *
  88. * @param object $entity
  89. * The entity to use for generating the UUID URI.
  90. * @param string $entity_type
  91. * The type of entity being used.
  92. *
  93. * @return string
  94. * The generated UUID URI or normal URI if entity doesn't support UUIDs.
  95. */
  96. function uuid_entity_uuid_uri($entity, $entity_type) {
  97. $entity_info = entity_get_info($entity_type);
  98. if (empty($entity_info['uuid'])) {
  99. $uri = $entity_info['uri callback']($entity);
  100. return $uri['path'];
  101. }
  102. if (isset($entity_info['uuid uri callback'])) {
  103. return $entity_info['uuid uri callback']($entity);
  104. }
  105. return "uuid/{$entity_type}/" . $entity->{$entity_info['entity keys']['uuid']};
  106. }
  107. /**
  108. * Converts an ID URI string to an entity data array.
  109. *
  110. * @param string $uri
  111. * The URI to convert.
  112. *
  113. * @return array
  114. * The entity data.
  115. *
  116. * @see uuid_id_uri_array_to_data()
  117. */
  118. function uuid_id_uri_to_data($uri) {
  119. $parts = explode('/', $uri);
  120. return uuid_id_uri_array_to_data($parts);
  121. }
  122. /**
  123. * Converts a URI array to entity data array.
  124. *
  125. * @param array $uri
  126. * The URI parts, often taken from arg().
  127. *
  128. * @return array
  129. * The entity data.
  130. */
  131. function uuid_id_uri_array_to_data($uri) {
  132. $data = array(
  133. 'request' => $uri,
  134. 'entity_type' => $uri[0],
  135. 'id' => $uri[1],
  136. );
  137. drupal_alter('uuid_id_uri_data', $data);
  138. return $data;
  139. }
  140. /**
  141. * Converts a UUID URI string to an entity data array.
  142. *
  143. * @param string $uri
  144. * The URI to convert.
  145. *
  146. * @return array
  147. * The entity data.
  148. *
  149. * @see uuid_uri_array_to_data()
  150. */
  151. function uuid_uri_to_data($uri, $strip_uuid = TRUE) {
  152. return uuid_uri_array_to_data(explode('/', $uri));
  153. }
  154. /**
  155. * Converts a URI array to entity data array.
  156. *
  157. * @param array $uri
  158. * The URI parts, often taken from arg().
  159. *
  160. * @return array
  161. * The entity data.
  162. */
  163. function uuid_uri_array_to_data($uri, $strip_uuid = TRUE) {
  164. if ($strip_uuid) {
  165. array_shift($uri);
  166. }
  167. $data = array(
  168. 'request' => $uri,
  169. 'entity_type' => isset($uri[0]) ? $uri[0] : NULL,
  170. 'uuid' => isset($uri[1]) ? $uri[1] : NULL,
  171. );
  172. drupal_alter('uuid_uri_data', $data);
  173. return $data;
  174. }
  175. /**
  176. * Generates a UUID using the Windows internal GUID generator.
  177. *
  178. * @see http://php.net/com_create_guid
  179. */
  180. function _uuid_generate_com() {
  181. // Remove {} wrapper and make lower case to keep result consistent.
  182. return drupal_strtolower(trim(com_create_guid(), '{}'));
  183. }
  184. /**
  185. * Generates an universally unique identifier using the PECL extension.
  186. */
  187. function _uuid_generate_pecl() {
  188. return uuid_create(UUID_TYPE_DEFAULT);
  189. }
  190. /**
  191. * Generates a UUID v4 (RFC 4122 section 4.4) using PHP code.
  192. *
  193. * @see http://www.rfc-editor.org/rfc/rfc4122.txt
  194. *
  195. * The UUID layout and fields are defined in section 4.1.2.
  196. *
  197. * Note that there are inconsistencies in the RFC with respect to
  198. * bit numbering. Network Order is correct, so the most significant bit
  199. * always appears first (in left-to-right sequence). See errata 3546:
  200. * http://www.rfc-editor.org/errata_search.php?rfc=4122&eid=3546
  201. *
  202. * Based on code from http://php.net/uniqid
  203. */
  204. function _uuid_generate_php() {
  205. // We limit each generated number to 16 bits (maximum value 0xffff)
  206. // because mt_rand() returns a *signed* integer, and hence a 32-bit
  207. // value can only have a 31-bit magnitude. Constructing a 32-bit
  208. // number from two 16-bit random numbers guarantees that all 32 bits
  209. // are random.
  210. return sprintf('%04x%04x-%04x-4%03x-%04x-%04x%04x%04x',
  211. // 32 bits for "time_low".
  212. mt_rand(0, 0xffff), mt_rand(0, 0xffff),
  213. // 16 bits for "time_mid".
  214. mt_rand(0, 0xffff),
  215. // 12 bits after the initial 0100 (version 4) for "time_hi_and_version".
  216. mt_rand(0, 0x0fff),
  217. // 16 bits in total for "clk_seq_hi_res" and "clk_seq_low", with the
  218. // most significant 2 bits of clk_seq_hi_res set to '10'. We do a
  219. // bitwise OR of a random 14-bit value (maximum 0x3fff) with 0x8000
  220. // (a 16-bit integer with only the most significant bit set).
  221. mt_rand(0, 0x3fff) | 0x8000,
  222. // 48 bits for "node".
  223. mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
  224. );
  225. }
  226. // The if block avoids conflicts with PECL's uuid_is_valid().
  227. if (!function_exists('uuid_is_valid')) {
  228. /**
  229. * Check that a string appears to be in the format of a UUID.
  230. *
  231. * @param string $uuid
  232. * The string to test.
  233. *
  234. * @return bool
  235. * TRUE if the string is well formed.
  236. */
  237. function uuid_is_valid($uuid) {
  238. return preg_match('/^' . UUID_PATTERN . '$/', $uuid);
  239. }
  240. }