PageRenderTime 74ms CodeModel.GetById 37ms RepoModel.GetById 0ms app.codeStats 0ms

/Module/UuidGenerator/UUID.php

https://github.com/DerDu/AIO-System
PHP | 324 lines | 209 code | 42 blank | 73 comment | 14 complexity | e29a4b69844215b7b0be3559e7004557 MD5 | raw file
Possible License(s): GPL-2.0, MIT, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /*-
  3. * Copyright (c) 2008 Fredrik Lindberg - http://www.shapeshifter.se
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. *
  26. */
  27. /*
  28. * UUID (RFC4122) Generator
  29. * http://tools.ietf.org/html/rfc4122
  30. *
  31. * Implements version 1, 3, 4 and 5
  32. */
  33. class UUID {
  34. /* UUID versions */
  35. const UUID_TIME = 1; /* Time based UUID */
  36. const UUID_NAME_MD5 = 3; /* Name based (MD5) UUID */
  37. const UUID_RANDOM = 4; /* Random UUID */
  38. const UUID_NAME_SHA1 = 5; /* Name based (SHA1) UUID */
  39. /* UUID formats */
  40. const FMT_FIELD = 100;
  41. const FMT_STRING = 101;
  42. const FMT_BINARY = 102;
  43. const FMT_QWORD = 1; /* Quad-word, 128-bit (not impl.) */
  44. const FMT_DWORD = 2; /* Double-word, 64-bit (not impl.) */
  45. const FMT_WORD = 4; /* Word, 32-bit (not impl.) */
  46. const FMT_SHORT = 8; /* Short (not impl.) */
  47. const FMT_BYTE = 16; /* Byte */
  48. const FMT_DEFAULT = 16;
  49. /* Field UUID representation */
  50. static private $m_uuid_field = array(
  51. 'time_low' => 0, /* 32-bit */
  52. 'time_mid' => 0, /* 16-bit */
  53. 'time_hi' => 0, /* 16-bit */
  54. 'clock_seq_hi' => 0, /* 8-bit */
  55. 'clock_seq_low' => 0, /* 8-bit */
  56. 'node' => array() /* 48-bit */
  57. );
  58. static private $m_generate = array(
  59. self::UUID_TIME => "generateTime",
  60. self::UUID_RANDOM => "generateRandom",
  61. self::UUID_NAME_MD5 => "generateNameMD5",
  62. self::UUID_NAME_SHA1 => "generateNameSHA1"
  63. );
  64. static private $m_convert = array(
  65. self::FMT_FIELD => array(
  66. self::FMT_BYTE => "conv_field2byte",
  67. self::FMT_STRING => "conv_field2string",
  68. self::FMT_BINARY => "conv_field2binary"
  69. ),
  70. self::FMT_BYTE => array(
  71. self::FMT_FIELD => "conv_byte2field",
  72. self::FMT_STRING => "conv_byte2string",
  73. self::FMT_BINARY => "conv_byte2binary"
  74. ),
  75. self::FMT_STRING => array(
  76. self::FMT_BYTE => "conv_string2byte",
  77. self::FMT_FIELD => "conv_string2field",
  78. self::FMT_BINARY => "conv_string2binary"
  79. ),
  80. );
  81. /* Swap byte order of a 32-bit number */
  82. static private function swap32($x) {
  83. return (($x & 0x000000ff) << 24) | (($x & 0x0000ff00) << 8) |
  84. (($x & 0x00ff0000) >> 8) | (($x & 0xff000000) >> 24);
  85. }
  86. /* Swap byte order of a 16-bit number */
  87. static private function swap16($x) {
  88. return (($x & 0x00ff) << 8) | (($x & 0xff00) >> 8);
  89. }
  90. /* Auto-detect UUID format */
  91. static private function detectFormat($src) {
  92. if (is_string($src))
  93. return self::FMT_STRING;
  94. else if (is_array($src)) {
  95. $len = count($src);
  96. if ($len == 1 || ($len % 2) == 0)
  97. return $len;
  98. else
  99. return (-1);
  100. }
  101. else
  102. return self::FMT_BINARY;
  103. }
  104. /*
  105. * Public API, generate a UUID of 'type' in format 'fmt' for
  106. * the given namespace 'ns' and node 'node'
  107. */
  108. static public function generate($type, $fmt = self::FMT_BYTE,
  109. $node = "", $ns = "") {
  110. $func = self::$m_generate[$type];
  111. if (!isset($func))
  112. return null;
  113. $conv = self::$m_convert[self::FMT_FIELD][$fmt];
  114. $uuid = self::$func($ns, $node);
  115. return self::$conv($uuid);
  116. }
  117. /*
  118. * Public API, convert a UUID from one format to another
  119. */
  120. static public function convert($uuid, $from, $to) {
  121. $conv = self::$m_convert[$from][$to];
  122. if (!isset($conv))
  123. return ($uuid);
  124. return (self::$conv($uuid));
  125. }
  126. /*
  127. * Generate an UUID version 4 (pseudo random)
  128. */
  129. static private function generateRandom($ns, $node) {
  130. $uuid = self::$m_uuid_field;
  131. $uuid['time_hi'] = (4 << 12) | (mt_rand(0, 0x1000));
  132. $uuid['clock_seq_hi'] = (1 << 7) | mt_rand(0, 128);
  133. $uuid['time_low'] = mt_rand(0, 0xffff) + (mt_rand(0, 0xffff) << 16);
  134. $uuid['time_mid'] = mt_rand(0, 0xffff);
  135. $uuid['clock_seq_low'] = mt_rand(0, 255);
  136. for ($i = 0; $i < 6; $i++)
  137. $uuid['node'][$i] = mt_rand(0, 255);
  138. return ($uuid);
  139. }
  140. /*
  141. * Generate UUID version 3 and 5 (name based)
  142. */
  143. static private function generateName($ns, $node, $hash, $version) {
  144. $ns_fmt = self::detectFormat($ns);
  145. $field = self::convert($ns, $ns_fmt, self::FMT_FIELD);
  146. /* Swap byte order to keep it in big endian on all platforms */
  147. $field['time_low'] = self::swap32($field['time_low']);
  148. $field['time_mid'] = self::swap16($field['time_mid']);
  149. $field['time_hi'] = self::swap16($field['time_hi']);
  150. /* Convert the namespace to binary and concatenate node */
  151. $raw = self::convert($field, self::FMT_FIELD, self::FMT_BINARY);
  152. $raw .= $node;
  153. /* Hash the namespace and node and convert to a byte array */
  154. $val = $hash($raw, true);
  155. $tmp = unpack('C16', $val);
  156. foreach (array_keys($tmp) as $key)
  157. $byte[$key - 1] = $tmp[$key];
  158. /* Convert byte array to a field array */
  159. $field = self::conv_byte2field($byte);
  160. $field['time_low'] = self::swap32($field['time_low']);
  161. $field['time_mid'] = self::swap16($field['time_mid']);
  162. $field['time_hi'] = self::swap16($field['time_hi']);
  163. /* Apply version and constants */
  164. $field['clock_seq_hi'] &= 0x3f;
  165. $field['clock_seq_hi'] |= (1 << 7);
  166. $field['time_hi'] &= 0x0fff;
  167. $field['time_hi'] |= ($version << 12);
  168. return ($field);
  169. }
  170. static private function generateNameMD5($ns, $node) {
  171. return self::generateName($ns, $node, "md5",
  172. self::UUID_NAME_MD5);
  173. }
  174. static private function generateNameSHA1($ns, $node) {
  175. return self::generateName($ns, $node, "sha1",
  176. self::UUID_NAME_SHA1);
  177. }
  178. /*
  179. * Generate UUID version 1 (time based)
  180. */
  181. static private function generateTime($ns, $node) {
  182. $uuid = self::$m_uuid_field;
  183. /*
  184. * Get current time in 100 ns intervals. The magic value
  185. * is the offset between UNIX epoch and the UUID UTC
  186. * time base October 15, 1582.
  187. */
  188. $tp = gettimeofday();
  189. $time = ($tp['sec'] * 10000000) + ($tp['usec'] * 10) +
  190. 0x01B21DD213814000;
  191. $uuid['time_low'] = $time & 0xffffffff;
  192. /* Work around PHP 32-bit bit-operation limits */
  193. $high = intval($time / 0xffffffff);
  194. $uuid['time_mid'] = $high & 0xffff;
  195. $uuid['time_hi'] = (($high >> 16) & 0xfff) | (self::UUID_TIME << 12);
  196. /*
  197. * We don't support saved state information and generate
  198. * a random clock sequence each time.
  199. */
  200. $uuid['clock_seq_hi'] = 0x80 | mt_rand(0, 64);
  201. $uuid['clock_seq_low'] = mt_rand(0, 255);
  202. /*
  203. * Node should be set to the 48-bit IEEE node identifier, but
  204. * we leave it for the user to supply the node.
  205. */
  206. for ($i = 0; $i < 6; $i++)
  207. $uuid['node'][$i] = ord(substr($node, $i, 1));
  208. return ($uuid);
  209. }
  210. /* Assumes correct byte order */
  211. static private function conv_field2byte($src) {
  212. $uuid[0] = ($src['time_low'] & 0xff000000) >> 24;
  213. $uuid[1] = ($src['time_low'] & 0x00ff0000) >> 16;
  214. $uuid[2] = ($src['time_low'] & 0x0000ff00) >> 8;
  215. $uuid[3] = ($src['time_low'] & 0x000000ff);
  216. $uuid[4] = ($src['time_mid'] & 0xff00) >> 8;
  217. $uuid[5] = ($src['time_mid'] & 0x00ff);
  218. $uuid[6] = ($src['time_hi'] & 0xff00) >> 8;
  219. $uuid[7] = ($src['time_hi'] & 0x00ff);
  220. $uuid[8] = $src['clock_seq_hi'];
  221. $uuid[9] = $src['clock_seq_low'];
  222. for ($i = 0; $i < 6; $i++)
  223. $uuid[10+$i] = $src['node'][$i];
  224. return ($uuid);
  225. }
  226. static private function conv_field2string($src) {
  227. $str = sprintf(
  228. '%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x',
  229. ($src['time_low']), ($src['time_mid']), ($src['time_hi']),
  230. $src['clock_seq_hi'], $src['clock_seq_low'],
  231. $src['node'][0], $src['node'][1], $src['node'][2],
  232. $src['node'][3], $src['node'][4], $src['node'][5]);
  233. return ($str);
  234. }
  235. static private function conv_field2binary($src) {
  236. $byte = self::conv_field2byte($src);
  237. return self::conv_byte2binary($byte);
  238. }
  239. static private function conv_byte2field($uuid) {
  240. $field = self::$m_uuid_field;
  241. $field['time_low'] = ($uuid[0] << 24) | ($uuid[1] << 16) |
  242. ($uuid[2] << 8) | $uuid[3];
  243. $field['time_mid'] = ($uuid[4] << 8) | $uuid[5];
  244. $field['time_hi'] = ($uuid[6] << 8) | $uuid[7];
  245. $field['clock_seq_hi'] = $uuid[8];
  246. $field['clock_seq_low'] = $uuid[9];
  247. for ($i = 0; $i < 6; $i++)
  248. $field['node'][$i] = $uuid[10+$i];
  249. return ($field);
  250. }
  251. static public function conv_byte2string($src) {
  252. $field = self::conv_byte2field($src);
  253. return self::conv_field2string($field);
  254. }
  255. static private function conv_byte2binary($src) {
  256. $raw = pack('C16', $src[0], $src[1], $src[2], $src[3],
  257. $src[4], $src[5], $src[6], $src[7], $src[8], $src[9],
  258. $src[10], $src[11], $src[12], $src[13], $src[14], $src[15]);
  259. return ($raw);
  260. }
  261. static private function conv_string2field($src) {
  262. $parts = sscanf($src, '%x-%x-%x-%x-%02x%02x%02x%02x%02x%02x');
  263. $field = self::$m_uuid_field;
  264. $field['time_low'] = ($parts[0]);
  265. $field['time_mid'] = ($parts[1]);
  266. $field['time_hi'] = ($parts[2]);
  267. $field['clock_seq_hi'] = ($parts[3] & 0xff00) >> 8;
  268. $field['clock_seq_low'] = $parts[3] & 0x00ff;
  269. for ($i = 0; $i < 6; $i++)
  270. $field['node'][$i] = $parts[4+$i];
  271. return ($field);
  272. }
  273. static private function conv_string2byte($src) {
  274. $field = self::conv_string2field($src);
  275. return self::conv_field2byte($field);
  276. }
  277. static private function conv_string2binary($src) {
  278. $byte = self::conv_string2byte($src);
  279. return self::conv_byte2binary($byte);
  280. }
  281. }
  282. ?>