/AB2/Selector/HashRandomizer.php

https://github.com/RealSelf/ab · PHP · 70 lines · 42 code · 7 blank · 21 comment · 2 complexity · d9dd7e3e0fdf15b9b93bf5e0a3c76d10 MD5 · raw file

  1. <?php
  2. /**
  3. * This randomizer hashes a (subject ID, test key) pair.
  4. *
  5. */
  6. class AB2_Selector_HashRandomizer implements AB2_Selector_Randomizer {
  7. private $_algo = 'sha256';
  8. private $_testKey;
  9. private $_testKeyHash;
  10. /**
  11. * @param string $testKey
  12. * @return void
  13. */
  14. public function __construct($testKey) {
  15. $this->_testKey = $testKey;
  16. }
  17. /**
  18. * Map a subject (user) ID to a value in the half-open interval [0, 1).
  19. *
  20. * @param $subjectID
  21. * @return float
  22. */
  23. public function randomize($subjectID) {
  24. return !is_null($subjectID) ? $this->hash1($subjectID) : 0;
  25. }
  26. private function hash1($subjectID) {
  27. $h = hash($this->_algo, "$this->_testKey-$subjectID");
  28. return $this->mapHex($h);
  29. }
  30. private function hash2($subjectID) {
  31. $h = hash($this->_algo, "$this->_testKey-$subjectID");
  32. $h = hash($this->_algo, $h);
  33. $w = $this->mapHex($h);
  34. return $w;
  35. }
  36. private function hash3($subjectID) {
  37. if (is_null($this->_testKeyHash)) {
  38. $this->_testKeyHash = substr(hash($this->_algo, $this->_testKey), 0, 24);
  39. }
  40. $h = hash($this->_algo, "$this->_testKeyHash-$subjectID");
  41. $h = hash($this->_algo, $h);
  42. $w = $this->mapHex($h);
  43. return $w;
  44. }
  45. /**
  46. * Map a hex value to the half-open interval [0, 1) while
  47. * preserving uniformity of the input distribution.
  48. *
  49. * @param string $hex a hex string
  50. * @return float
  51. */
  52. private function mapHex($hex) {
  53. $len = min(40, strlen($hex));
  54. $vMax = 1 << $len;
  55. $v = 0;
  56. for ($i = 0; $i < $len; $i++) {
  57. $bit = hexdec($hex[$i]) < 8 ? 0 : 1;
  58. $v = ($v << 1) + $bit;
  59. }
  60. $w = $v / $vMax;
  61. return $w;
  62. }
  63. }