PageRenderTime 66ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/inc/functions/class.uuid.php

https://bitbucket.org/drn05r/myexperiment-rdf
PHP | 538 lines | 208 code | 47 blank | 283 comment | 14 complexity | 0e8e08516a7d15e21978900f4c60b227 MD5 | raw file
  1. <?php
  2. /**
  3. * @file inc/functions/class.uuid.php
  4. * @brief Class for generating UUIDs for Pack Relationship URNs.
  5. * @version beta
  6. * @author Fredrik Lindberg
  7. * @details Class for generating UUIDs for Pack Relationship URNs.
  8. */
  9. /*-
  10. * Copyright (c) 2008 Fredrik Lindberg - http://www.shapeshifter.se
  11. * All rights reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or without
  14. * modification, are permitted provided that the following conditions
  15. * are met:
  16. * 1. Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. * 2. Redistributions in binary form must reproduce the above copyright
  19. * notice, this list of conditions and the following disclaimer in the
  20. * documentation and/or other materials provided with the distribution.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  23. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  24. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  25. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  27. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  31. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. *
  33. */
  34. /**
  35. * @class UUID
  36. * @brief UUID (RFC4122) Generator, see http://tools.ietf.org/html/rfc4122. Implements versiona 1, 3, 4 and 5.
  37. */
  38. class UUID {
  39. /* UUID versions */
  40. /** @brief Time based UUID */
  41. const UUID_TIME = 1;
  42. /** @brief Name based (MD5) UUID */
  43. const UUID_NAME_MD5 = 3;
  44. /** @brief Random UUID */
  45. const UUID_RANDOM = 4;
  46. /** @brief Name based (SHA1) UUID */
  47. const UUID_NAME_SHA1 = 5;
  48. /* UUID formats */
  49. /** @brief Field format */
  50. const FMT_FIELD = 100;
  51. /** @brief String format */
  52. const FMT_STRING = 101;
  53. /** @brief Binary format */
  54. const FMT_BINARY = 102;
  55. /** @brief Quad-word format, 128-bit (not impl.) */
  56. const FMT_QWORD = 1;
  57. /** @brief Double-word format, 64-bit (not impl.) */
  58. const FMT_DWORD = 2;
  59. /** @brief Word format, 32-bit (not impl.) */
  60. const FMT_WORD = 4;
  61. /** @brief Short format (not impl.) */
  62. const FMT_SHORT = 8;
  63. /** @brief Byte format */
  64. const FMT_BYTE = 16;
  65. /** @brief Default format (byte) */
  66. const FMT_DEFAULT = 16;
  67. /** @brief Field UUID representation. */
  68. static private $m_uuid_field = array(
  69. 'time_low' => 0, /* 32-bit */
  70. 'time_mid' => 0, /* 16-bit */
  71. 'time_hi' => 0, /* 16-bit */
  72. 'clock_seq_hi' => 0, /* 8-bit */
  73. 'clock_seq_low' => 0, /* 8-bit */
  74. 'node' => array() /* 48-bit */
  75. );
  76. /** @brief Array associating versions of UUID with functions to generate them. */
  77. static private $m_generate = array(
  78. self::UUID_TIME => "generateTime",
  79. self::UUID_RANDOM => "generateRandom",
  80. self::UUID_NAME_MD5 => "generateNameMD5",
  81. self::UUID_NAME_SHA1 => "generateNameSHA1"
  82. );
  83. /** @brief Multi-dimensional array associating format with the formats it can be converted to and the functions required to do it. */
  84. static private $m_convert = array(
  85. self::FMT_FIELD => array(
  86. self::FMT_BYTE => "conv_field2byte",
  87. self::FMT_STRING => "conv_field2string",
  88. self::FMT_BINARY => "conv_field2binary"
  89. ),
  90. self::FMT_BYTE => array(
  91. self::FMT_FIELD => "conv_byte2field",
  92. self::FMT_STRING => "conv_byte2string",
  93. self::FMT_BINARY => "conv_byte2binary"
  94. ),
  95. self::FMT_STRING => array(
  96. self::FMT_BYTE => "conv_string2byte",
  97. self::FMT_FIELD => "conv_string2field",
  98. self::FMT_BINARY => "conv_string2binary"
  99. ),
  100. );
  101. /**
  102. * @brief Swap byte order of a 32-bit number.
  103. *
  104. * @param $x
  105. * 32-bit number to have its byte order swapped.
  106. *
  107. * @return
  108. * The 32-bit number passed as a parameter with its byet order swapped.
  109. *
  110. */
  111. static private function swap32($x) {
  112. return (($x & 0x000000ff) << 24) | (($x & 0x0000ff00) << 8) |
  113. (($x & 0x00ff0000) >> 8) | (($x & 0xff000000) >> 24);
  114. }
  115. /**
  116. * @brief Swap byte order of a 16-bit number.
  117. *
  118. * @param $x
  119. * 16-bit number to have its byte order swapped.
  120. *
  121. * @return
  122. * The 16-bit number passed as a parameter with its byet order swapped.
  123. *
  124. */
  125. static private function swap16($x) {
  126. return (($x & 0x00ff) << 8) | (($x & 0xff00) >> 8);
  127. }
  128. /**
  129. * @brief Auto-detect UUID format
  130. *
  131. * @param $src
  132. * The source (raw) representation of the UUID.
  133. *
  134. * @return
  135. * A constant integer representing the format of UUID to be generated.
  136. */
  137. static private function detectFormat($src) {
  138. if (is_string($src))
  139. return self::FMT_STRING;
  140. else if (is_array($src)) {
  141. $len = count($src);
  142. if ($len == 1 || ($len % 2) == 0)
  143. return $len;
  144. else
  145. return (-1);
  146. }
  147. else
  148. return self::FMT_BINARY;
  149. }
  150. /**
  151. * @brief Public API, generate a UUID of 'type' in format 'fmt' for
  152. * the given namespace 'ns' and node 'node'
  153. *
  154. * @param $type
  155. * An integer representing the type/version of UUID to be generated.
  156. *
  157. * @param $fmt
  158. * An integer representing the format of the UUID to be generated.
  159. *
  160. * @param $node
  161. * The node for which the UUID is being generated.
  162. *
  163. * @param $ns
  164. * The namespace of the node for which the UUID is to be generated.
  165. *
  166. * @return
  167. * The UUID generated based on the parameters provided.
  168. */
  169. static public function generate($type, $fmt = self::FMT_BYTE, $node = "", $ns = "") {
  170. $func = self::$m_generate[$type];
  171. if (!isset($func))
  172. return null;
  173. $conv = self::$m_convert[self::FMT_FIELD][$fmt];
  174. $uuid = self::$func($ns, $node);
  175. return self::$conv($uuid);
  176. }
  177. /**
  178. * @brief Public API, convert a UUID from one format to another.
  179. *
  180. * @param $uuid
  181. * A string representing the UUID
  182. *
  183. * @param $from
  184. * An integer representing the format from which to be converted.
  185. *
  186. * @param $to
  187. * An integer representing the format to which to be converted.
  188. *
  189. * @return
  190. * The converted UUID in the format specified in $to parameter.
  191. */
  192. static public function convert($uuid, $from, $to) {
  193. $conv = self::$m_convert[$from][$to];
  194. if (!isset($conv))
  195. return ($uuid);
  196. return (self::$conv($uuid));
  197. }
  198. /**
  199. * @brief Generate an UUID version 4 (pseudo random).
  200. *
  201. * @param $ns
  202. * The namespace for which the UUID is to be generated. (Not used on version 4).
  203. *
  204. * @param $node
  205. * The node for which the UUID is to be generated. (Not used in version 4).
  206. *
  207. * @return
  208. * The generated UUID.
  209. */
  210. static private function generateRandom($ns, $node) {
  211. $uuid = self::$m_uuid_field;
  212. $uuid['time_hi'] = (4 << 12) | (mt_rand(0, 0x1000));
  213. $uuid['clock_seq_hi'] = (1 << 7) | mt_rand(0, 128);
  214. $uuid['time_low'] = mt_rand(0, 0xffff) + (mt_rand(0, 0xffff) << 16);
  215. $uuid['time_mid'] = mt_rand(0, 0xffff);
  216. $uuid['clock_seq_low'] = mt_rand(0, 255);
  217. for ($i = 0; $i < 6; $i++)
  218. $uuid['node'][$i] = mt_rand(0, 255);
  219. return ($uuid);
  220. }
  221. /**
  222. * @brief Generate UUID version 3 and 5 (name based).
  223. *
  224. * @param $ns
  225. * The namespace from which the UUID is to be generated.
  226. *
  227. * @param $node
  228. * The node from which the UUID is to be generated.
  229. *
  230. * @param $hash
  231. * The type of hash (MD5 or SHA1) to use to generate the UUID.
  232. *
  233. * @param $version
  234. * An integer representing the version (3 or 5) of UUID to be generated.
  235. *
  236. * @return
  237. * The generated UUID.
  238. */
  239. static private function generateName($ns, $node, $hash, $version) {
  240. $ns_fmt = self::detectFormat($ns);
  241. $field = self::convert($ns, $ns_fmt, self::FMT_FIELD);
  242. /* Swap byte order to keep it in big endian on all platforms */
  243. $field['time_low'] = self::swap32($field['time_low']);
  244. $field['time_mid'] = self::swap16($field['time_mid']);
  245. $field['time_hi'] = self::swap16($field['time_hi']);
  246. /* Convert the namespace to binary and concatenate node */
  247. $raw = self::convert($field, self::FMT_FIELD, self::FMT_BINARY);
  248. $raw .= $node;
  249. /* Hash the namespace and node and convert to a byte array */
  250. $val = $hash($raw, true);
  251. $tmp = unpack('C16', $val);
  252. foreach (array_keys($tmp) as $key)
  253. $byte[$key - 1] = $tmp[$key];
  254. /* Convert byte array to a field array */
  255. $field = self::conv_byte2field($byte);
  256. $field['time_low'] = self::swap32($field['time_low']);
  257. $field['time_mid'] = self::swap16($field['time_mid']);
  258. $field['time_hi'] = self::swap16($field['time_hi']);
  259. /* Apply version and constants */
  260. $field['clock_seq_hi'] &= 0x3f;
  261. $field['clock_seq_hi'] |= (1 << 7);
  262. $field['time_hi'] &= 0x0fff;
  263. $field['time_hi'] |= ($version << 12);
  264. return ($field);
  265. }
  266. /**
  267. * @brief Generate a named-based UUID using an MD5 hash
  268. *
  269. * @param $ns
  270. * The namespace from which the UUID is to be generated.
  271. *
  272. * @param $node
  273. * The node from which the UUID is to be generated.
  274. *
  275. * @return
  276. * The generated UUID.
  277. */
  278. static private function generateNameMD5($ns, $node) {
  279. return self::generateName($ns, $node, "md5",
  280. self::UUID_NAME_MD5);
  281. }
  282. /**
  283. * @brief Generate a named-based UUID using an SHA1 hash
  284. *
  285. * @param $ns
  286. * The namespace from which the UUID is to be generated.
  287. *
  288. * @param $node
  289. * The node from which the UUID is to be generated.
  290. *
  291. * @return
  292. * The generated UUID.
  293. */
  294. static private function generateNameSHA1($ns, $node) {
  295. return self::generateName($ns, $node, "sha1",
  296. self::UUID_NAME_SHA1);
  297. }
  298. /**
  299. * @brief Generate UUID version 1 (time based)
  300. *
  301. * @param $ns
  302. * The namespace for which the UUID is to be generated. (Not used for version 1).
  303. *
  304. * @param $node
  305. * The node from which the UUID is to be generated.
  306. *
  307. * @return
  308. * The generated UUID.
  309. */
  310. static private function generateTime($ns, $node) {
  311. $uuid = self::$m_uuid_field;
  312. /*
  313. * Get current time in 100 ns intervals. The magic value
  314. * is the offset between UNIX epoch and the UUID UTC
  315. * time base October 15, 1582.
  316. */
  317. $tp = gettimeofday();
  318. $time = ($tp['sec'] * 10000000) + ($tp['usec'] * 10) +
  319. 0x01B21DD213814000;
  320. $uuid['time_low'] = $time & 0xffffffff;
  321. /* Work around PHP 32-bit bit-operation limits */
  322. $high = intval($time / 0xffffffff);
  323. $uuid['time_mid'] = $high & 0xffff;
  324. $uuid['time_hi'] = (($high >> 16) & 0xfff) | (self::UUID_TIME << 12);
  325. /*
  326. * We don't support saved state information and generate
  327. * a random clock sequence each time.
  328. */
  329. $uuid['clock_seq_hi'] = 0x80 | mt_rand(0, 64);
  330. $uuid['clock_seq_low'] = mt_rand(0, 255);
  331. /*
  332. * Node should be set to the 48-bit IEEE node identifier, but
  333. * we leave it for the user to supply the node.
  334. */
  335. for ($i = 0; $i < 6; $i++)
  336. $uuid['node'][$i] = ord(substr($node, $i, 1));
  337. return ($uuid);
  338. }
  339. /**
  340. * @brief Converts UUID from field to byte format. Assumes correct byte order.
  341. *
  342. * @param $src
  343. * The source (raw) representation of the UUID in field format.
  344. *
  345. * @return
  346. * The UUID in byte format.
  347. */
  348. static private function conv_field2byte($src) {
  349. $uuid[0] = ($src['time_low'] & 0xff000000) >> 24;
  350. $uuid[1] = ($src['time_low'] & 0x00ff0000) >> 16;
  351. $uuid[2] = ($src['time_low'] & 0x0000ff00) >> 8;
  352. $uuid[3] = ($src['time_low'] & 0x000000ff);
  353. $uuid[4] = ($src['time_mid'] & 0xff00) >> 8;
  354. $uuid[5] = ($src['time_mid'] & 0x00ff);
  355. $uuid[6] = ($src['time_hi'] & 0xff00) >> 8;
  356. $uuid[7] = ($src['time_hi'] & 0x00ff);
  357. $uuid[8] = $src['clock_seq_hi'];
  358. $uuid[9] = $src['clock_seq_low'];
  359. for ($i = 0; $i < 6; $i++)
  360. $uuid[10+$i] = $src['node'][$i];
  361. return ($uuid);
  362. }
  363. /**
  364. * @brief Converts UUID from field to string format.
  365. *
  366. * @param $src
  367. * The source (raw) representation of the UUID in field format.
  368. *
  369. * @return
  370. * The UUID in string format.
  371. */
  372. static private function conv_field2string($src) {
  373. $str = sprintf(
  374. '%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x',
  375. ($src['time_low']), ($src['time_mid']), ($src['time_hi']),
  376. $src['clock_seq_hi'], $src['clock_seq_low'],
  377. $src['node'][0], $src['node'][1], $src['node'][2],
  378. $src['node'][3], $src['node'][4], $src['node'][5]);
  379. return ($str);
  380. }
  381. /**
  382. * @brief Converts UUID from field to binary format.
  383. *
  384. * @param $src
  385. * The source (raw) representation of the UUID in field format.
  386. *
  387. * @return
  388. * The UUID in binary format.
  389. */
  390. static private function conv_field2binary($src) {
  391. $byte = self::conv_field2byte($src);
  392. return self::conv_byte2binary($byte);
  393. }
  394. /**
  395. * @brief Converts UUID from byte to field format.
  396. *
  397. * @param $uuid
  398. * The source (raw) representation of the UUID in byte format.
  399. *
  400. * @return
  401. * The UUID in field format.
  402. */
  403. static private function conv_byte2field($uuid) {
  404. $field = self::$m_uuid_field;
  405. $field['time_low'] = ($uuid[0] << 24) | ($uuid[1] << 16) |
  406. ($uuid[2] << 8) | $uuid[3];
  407. $field['time_mid'] = ($uuid[4] << 8) | $uuid[5];
  408. $field['time_hi'] = ($uuid[6] << 8) | $uuid[7];
  409. $field['clock_seq_hi'] = $uuid[8];
  410. $field['clock_seq_low'] = $uuid[9];
  411. for ($i = 0; $i < 6; $i++)
  412. $field['node'][$i] = $uuid[10+$i];
  413. return ($field);
  414. }
  415. /**
  416. * @brief Converts UUID form byte to string format.
  417. *
  418. * @param $src
  419. * The source (raw) representation of the UUID in byte format.
  420. *
  421. * @return
  422. * The UUID in string format.
  423. */
  424. static public function conv_byte2string($src) {
  425. $field = self::conv_byte2field($src);
  426. return self::conv_field2string($field);
  427. }
  428. /**
  429. * @brief Converts UUID from byte to binary format.
  430. *
  431. * @param $src
  432. * The source (raw) representation of the UUID in byte format.
  433. *
  434. * @return
  435. * The UUID in binary format.
  436. */
  437. static private function conv_byte2binary($src) {
  438. $raw = pack('C16', $src[0], $src[1], $src[2], $src[3],
  439. $src[4], $src[5], $src[6], $src[7], $src[8], $src[9],
  440. $src[10], $src[11], $src[12], $src[13], $src[14], $src[15]);
  441. return ($raw);
  442. }
  443. /**
  444. * @brief Converts UUID from string to field format.
  445. *
  446. * @param $src
  447. * The source (raw) representation of the UUID in string format.
  448. *
  449. * @return
  450. * The UUID in field format.
  451. */
  452. static private function conv_string2field($src) {
  453. $parts = sscanf($src, '%x-%x-%x-%x-%02x%02x%02x%02x%02x%02x');
  454. $field = self::$m_uuid_field;
  455. $field['time_low'] = ($parts[0]);
  456. $field['time_mid'] = ($parts[1]);
  457. $field['time_hi'] = ($parts[2]);
  458. $field['clock_seq_hi'] = ($parts[3] & 0xff00) >> 8;
  459. $field['clock_seq_low'] = $parts[3] & 0x00ff;
  460. for ($i = 0; $i < 6; $i++)
  461. $field['node'][$i] = $parts[4+$i];
  462. return ($field);
  463. }
  464. /**
  465. * @brief Converts UUID from string to byte format.
  466. *
  467. * @param $src
  468. * The source (raw) representation of the UUID in string format.
  469. *
  470. * @return
  471. * The UUID in byte format.
  472. */
  473. static private function conv_string2byte($src) {
  474. $field = self::conv_string2field($src);
  475. return self::conv_field2byte($field);
  476. }
  477. /**
  478. * @brief Converts UUID form string to binary format.
  479. *
  480. * @param $src
  481. * The source (raw) representation of the UUID in string format.
  482. *
  483. * @return
  484. * The UUID in binary format.
  485. */
  486. static private function conv_string2binary($src) {
  487. $byte = self::conv_string2byte($src);
  488. return self::conv_byte2binary($byte);
  489. }
  490. }
  491. ?>