fork download
  1. <?php
  2.  
  3. class ClickId
  4. {
  5. private $wmId;
  6. private $campaignId;
  7. private $dc;
  8. private $timestamp;
  9. private $rand;
  10.  
  11. public function __construct(
  12. int $wmId,
  13. int $campaignId,
  14. int $dc,
  15. int $timestamp,
  16. int $rand
  17. )
  18. {
  19. $this->rand = $rand;
  20. $this->timestamp = $timestamp;
  21. $this->dc = $dc;
  22. $this->campaignId = $campaignId;
  23. $this->wmId = $wmId;
  24.  
  25. }
  26.  
  27. function getWmID(): int
  28. {
  29. return $this->wmId;
  30. }
  31.  
  32. function getCampaignID(): int
  33. {
  34. return $this->campaignId;
  35. }
  36.  
  37. function getDC(): int
  38. {
  39. return $this->dc;
  40. }
  41.  
  42. function getTimestamp(): int
  43. {
  44. return $this->timestamp;
  45. }
  46.  
  47. function getRand(): int
  48. {
  49. return $this->rand;
  50. }
  51. }
  52.  
  53. interface ClickIdCoder
  54. {
  55. function encode(ClickId $id): string;
  56.  
  57. function decode(string $data): ClickId;
  58. }
  59.  
  60. abstract class BinaryClickIdCodec implements ClickIdCoder
  61. {
  62. //2025-01-01 00:00:00 UTC
  63. const BASE_TIMESTAMP = 1735689600;
  64.  
  65. function encode(ClickId $id): string
  66. {
  67. $nts = $id->getTimestamp() - self::BASE_TIMESTAMP;
  68. $part0 = pack("V", $nts);
  69. $part1 = pack("V", $id->getWmID());
  70. $part2 = pack("V", $id->getCampaignID());
  71. $part3 = pack("C", $id->getDC());
  72. $part4 = pack("v", $id->getRand());
  73. return $part0 . $part1 . $part2 . $part3 . $part4;
  74. }
  75.  
  76. function decode(string $data): ClickId
  77. {
  78. $parts = str_split($data, 2);
  79. $nts = current(unpack("V", $parts[0] . $parts[1]));
  80. $wmId = current(unpack("V", $parts[2] . $parts[3]));
  81. $campaignId = current(unpack("V", $parts[4] . $parts[5]));
  82. $dc = current(unpack("C", $parts[6][0]));
  83. $rand = current(unpack("v", $parts[6][1] . $parts[7][0]));
  84. return new ClickId(
  85. $wmId,
  86. $campaignId,
  87. $dc,
  88. $nts + self::BASE_TIMESTAMP,
  89. $rand
  90. );
  91. }
  92. }
  93.  
  94. // 16-байтовый формат уникального ид "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  95. // Составные части:
  96. //wm_id = 4 byte (compressed)
  97. //campaign_id = 4 byte
  98. //ts = 4 byte (after 2025-01-01 UTC)
  99. //dc = 1 byte
  100. //rand = 2 byte
  101. class ClickIdUUIDCodec extends BinaryClickIdCodec
  102. {
  103. function encode(ClickId $id): string
  104. {
  105. $encoded = parent::encode($id);
  106. $padding = base_convert($id->getRand() % ($id->getDC() & 0xFF), 10, 16);
  107. $parts = str_split(bin2hex($encoded) . $padding, 4);
  108. return "$parts[0]$parts[1]-$parts[2]-$parts[3]-$parts[4]-$parts[5]$parts[6]$parts[7]";
  109. }
  110.  
  111. function decode(string $data): ClickId
  112. {
  113. $data = str_replace('-', '', $data);
  114. return parent::decode(hex2bin($data));
  115. }
  116.  
  117. // сжатый формат байтового хранения числа, первые биты показывают количество не нулевых байт
  118. // имеет оверхед для значений которые достигли максимального значения, тк будет на 2 бита больше места занимать
  119. // private function compressPackInt(int $n): string
  120. // {
  121. //
  122. // }
  123. }
  124.  
  125. class ClickIdBase64Codec extends BinaryClickIdCodec
  126. {
  127. function encode(ClickId $id): string
  128. {
  129. return base64_encode(parent::encode($id));
  130. }
  131.  
  132. function decode(string $data): ClickId
  133. {
  134. return parent::decode(base64_decode($data));
  135. }
  136. }
  137.  
  138. $i = 13463;
  139. $ar = unpack("C*", pack("L", $i));
  140. print_r($ar);
  141. $ar = unpack("C*", pack("N", $i));
  142. print_r($ar);
  143. $ar = unpack("C*", pack("V", $i));
  144. print_r($ar);
  145.  
  146. $ar = pack("V", $i);
  147. print_r(ord($ar[0]));
  148.  
  149.  
  150. $ar = unpack("V", "\x97\x34\x00\x00");
  151. print_r($ar);
  152.  
  153.  
  154. $part0 = pack("V", 75234);
  155. $part1 = pack("V", 12);
  156. $part2 = pack("V", 5123);
  157. $part3 = pack("C", 41);
  158. $part4 = pack("v", 7734);
  159. $padding = dechex(41 & 0xFF);
  160. $padding = (strlen($padding) > 1) ? $padding : '0'.$padding;
  161.  
  162. $pp = str_split(bin2hex($part1 . $part2), 4);
  163. $hex = bin2hex($part0) . "-" . $pp[0] . "-" . $pp[1] . "-" . $pp[2] . "-" . $pp[3] . bin2hex($part3) . bin2hex($part4) . $padding;
  164. print_r($hex);
  165. echo "\n";
  166. $b64 = base64_encode($part0 . $part1 . $part2 . $part3 . $part4);
  167. print_r($b64);
  168. echo "\n";
  169. $codec = new ClickIdBase64Codec();
  170. $click = $codec->encode(new ClickId(12, 5123, 41, 1735689800, 7734));
  171. $clickId = $codec->decode($click);
  172. var_dump($click);
  173. var_dump($clickId);
  174.  
  175.  
  176. $hex = str_replace('-', '', $hex);
  177. $hex = hex2bin($hex);
  178. $parts = str_split($hex, 2);
  179. $nts = current(unpack("V", $parts[0] . $parts[1]));
  180. $wmId = current(unpack("V", $parts[2] . $parts[3]));
  181. $campaignId = current(unpack("V", $parts[4] . $parts[5]));
  182. $rand = current(unpack("v", $parts[6]));
  183. $dc = current(unpack("C", $parts[7]));
  184.  
  185. echo bin2hex( $parts[2] . $parts[3]) . " = $wmId";
Success #stdin #stdout 0.03s 25304KB
stdin
Standard input is empty
stdout
Array
(
    [1] => 151
    [2] => 52
    [3] => 0
    [4] => 0
)
Array
(
    [1] => 0
    [2] => 0
    [3] => 52
    [4] => 151
)
Array
(
    [1] => 151
    [2] => 52
    [3] => 0
    [4] => 0
)
151Array
(
    [1] => 13463
)
e2250100-0c00-0000-0314-000029361e29
4iUBAAwAAAADFAAAKTYe
string(20) "yAAAAAwAAAADFAAAKTYe"
object(ClickId)#2 (5) {
  ["wmId":"ClickId":private]=>
  int(12)
  ["campaignId":"ClickId":private]=>
  int(5123)
  ["dc":"ClickId":private]=>
  int(41)
  ["timestamp":"ClickId":private]=>
  int(1735689800)
  ["rand":"ClickId":private]=>
  int(7734)
}
0c000000 = 12