Guest User

Untitled

a guest
Mar 2nd, 2018
273
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.85 KB | None | 0 0
  1. <?php
  2.  
  3. /**
  4. * Guid - class generating/verifying project-wide unique identifiers to be used as IDs in the database
  5. *
  6. * @package tools
  7. * @author Dave Broome <daveb@finda.co.nz>
  8. * @author Jakub Nesetril <jakub@finda.co.nz>
  9. * @todo Store guids as integers internally and only display them in URLs as base31
  10. * @copyright APN Finda, Ltd., 15 December, 2006
  11. **/
  12. class Guid {
  13.  
  14. /**
  15. * @var Array List of vowels to be stripped from a GUID
  16. **/
  17. protected static $vowels = array('a','e','i','o','u');
  18.  
  19. /**
  20. * @var Array List of consonants replacing vowels
  21. **/
  22. protected static $consonants = array('v','w','x','y','z');
  23.  
  24. /**
  25. * @var int Configuration to set up the block of guids fetched at once from DB into memcache
  26. **/
  27. protected static $guid_block = 10000;
  28.  
  29. /**
  30. * @var int The wait interval for concurrent synchronisation
  31. **/
  32. protected static $wait_interval = 200000;
  33.  
  34.  
  35. /**
  36. * @return string Base-31 number to be converted to decimal
  37. * @author Dave Broome <daveb@finda.co.nz>
  38. * @author Jakub Nesetril <jakub@finda.co.nz>
  39. * @param int $decimal
  40. **/
  41. protected static function decimal_to_modified_base_31($decimal) {
  42. return str_replace(self::$vowels, self::$consonants, base_convert($decimal, 10, 31));
  43. }
  44.  
  45.  
  46. /**
  47. * @return int
  48. * @author Dave Broome <daveb@finda.co.nz>
  49. * @author Jakub Nesetril <jakub@finda.co.nz>
  50. * @param string $base_31 Base-31 number to be converted to decimal
  51. **/
  52. protected static function modified_base_31_to_decimal($base_31) {
  53. return base_convert(str_replace(self::$consonants, self::$vowels, $base_31), 31, 10);
  54. }
  55.  
  56.  
  57. /**
  58. * Reserves a block of guids from database and sets up cache records
  59. *
  60. * @return int Returns the current valid Guid
  61. * @author Jakub Nesetril <jakub@finda.co.nz>
  62. * @todo implement a mutex on the DB fetching, so that two processes don't allocate two blocks
  63. * @global adodb_distributor $db
  64. **/
  65. protected static function seedCache()
  66. {
  67. global $db;
  68.  
  69. $db->execute("START TRANSACTION");
  70. $guid_decimal = $db->getOne("SELECT value FROM constant WHERE name = 'next-guid-decimal' FOR UPDATE");
  71. $db->execute("UPDATE constant SET value = value + ".self::$guid_block." WHERE name = 'next-guid-decimal'");
  72. $db->execute("COMMIT");
  73.  
  74. Cache::set('Guid_maximum', $guid_decimal+self::$guid_block-1, 'Guid');
  75. Cache::set('Guid_current', $guid_decimal, 'Guid');
  76.  
  77. return $guid_decimal;
  78. }
  79.  
  80.  
  81. /**
  82. * Verify if a provided value is a valid GUID
  83. *
  84. * Checks if candidate contains only allowed alfanumeric characters (no vowels), if it's smaller
  85. * then the current maximum GUID and if it's bigger then the starting guid (1708)
  86. *
  87. * @return bool
  88. * @author Dave Broome <daveb@finda.co.nz>
  89. * @author Jakub Nesetril <jakub@finda.co.nz>
  90. * @param string $spec
  91. **/
  92. public static function isGuid($spec) {
  93. $start = '31';
  94.  
  95. // invalid chars
  96. if (!preg_match('/[0-9b-df-hj-np-tv-z]+/', $spec)) {
  97. return false;
  98. }
  99.  
  100. $next_guid_decimal = (Cache::exists('Guid_current')) ? Cache::get('Guid_current') : self::seedCache();
  101.  
  102. // if proposed guid is more than highest guid or less then lowest guid
  103. if (self::modified_base_31_to_decimal($spec) > $next_guid_decimal || self::modified_base_31_to_decimal($spec) < $start)
  104. {
  105. return false;
  106. }
  107. else return true;
  108. }
  109.  
  110.  
  111. /**
  112. * Return a freshly generated unique ID
  113. *
  114. * @return string
  115. * @author Dave Broome <daveb@finda.co.nz>
  116. * @author Jakub Nesetril <jakub@finda.co.nz>
  117. **/
  118. public static function getGuid() {
  119. // find out what the current guid is
  120. $current = (Cache::exists('Guid_current')) ? Cache::increment('Guid_current') : self::seedCache();
  121. $maximum = Cache::get('Guid_maximum');
  122.  
  123.  
  124. // if current allocation block of guids has been exhausted, delete the cache
  125. if ($current >= $maximum) Cache::delete('Guid_current');
  126.  
  127. if ($current > $maximum) // if due to some bizzare concurency issue, we have exceeded our maximum and cannot return an overlapping guid
  128. {
  129. usleep(self::$wait_interval); // sleep for 0.2 second
  130. return self::getGuid();
  131. }
  132.  
  133. return self::decimal_to_modified_base_31($current);
  134. }
  135.  
  136. /**
  137. * Return a unique ID in decimal format
  138. *
  139. * @return int
  140. * @author Jakub Nesetril <jakub@finda.co.nz>
  141. **/
  142. public static function getGuidDecimal()
  143. {
  144. return self::modified_base_31_to_decimal(self::getGuid());
  145. }
  146.  
  147. }
  148.  
  149. ?>
Add Comment
Please, Sign In to add comment