<?php
class ClickId
{
private $wmId;
private $campaignId;
private $dc;
private $timestamp;
private $rand;
public function __construct(
int $wmId,
int $campaignId,
int $dc,
int $timestamp,
int $rand
)
{
$this->timestamp = $timestamp;
$this->dc = $dc;
$this->campaignId = $campaignId;
$this->wmId = $wmId;
}
function getWmID(): int
{
return $this->wmId;
}
function getCampaignID(): int
{
return $this->campaignId;
}
function getDC(): int
{
return $this->dc;
}
function getTimestamp(): int
{
return $this->timestamp;
}
function getRand(): int
{
}
}
interface ClickIdCoder
{
function encode(ClickId $id): string;
function decode(string $data): ClickId;
}
abstract class BinaryClickIdCodec implements ClickIdCoder
{
//2025-01-01 00:00:00 UTC
const BASE_TIMESTAMP = 1735689600;
function encode(ClickId $id): string
{
$nts = $id->getTimestamp() - self::BASE_TIMESTAMP;
$part0 = pack("V", $nts); $part1 = pack("V", $id->getWmID()); $part2 = pack("V", $id->getCampaignID()); $part3 = pack("C", $id->getDC()); $part4 = pack("v", $id->getRand()); return $part0 . $part1 . $part2 . $part3 . $part4;
}
function decode(string $data): ClickId
{
return new ClickId(
$wmId,
$campaignId,
$dc,
$nts + self::BASE_TIMESTAMP,
$rand
);
}
}
// 16-байтовый формат уникального ид "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
// Составные части:
//wm_id = 4 byte (compressed)
//campaign_id = 4 byte
//ts = 4 byte (after 2025-01-01 UTC)
//dc = 1 byte
//rand = 2 byte
class ClickIdUUIDCodec extends BinaryClickIdCodec
{
function encode(ClickId $id): string
{
$encoded = parent::encode($id);
$padding = base_convert($id->getRand() % ($id->getDC() & 0xFF), 10, 16); return "$parts[0]$parts[1]-$parts[2]-$parts[3]-$parts[4]-$parts[5]$parts[6]$parts[7]";
}
function decode(string $data): ClickId
{
return parent::decode(hex2bin($data));
}
// сжатый формат байтового хранения числа, первые биты показывают количество не нулевых байт
// имеет оверхед для значений которые достигли максимального значения, тк будет на 2 бита больше места занимать
// private function compressPackInt(int $n): string
// {
//
// }
}
class ClickIdBase64Codec extends BinaryClickIdCodec
{
function encode(ClickId $id): string
{
}
function decode(string $data): ClickId
{
}
}
$i = 13463;
$ar = unpack("V", "\x97\x34\x00\x00");
$part0 = pack("V", 75234); $part2 = pack("V", 5123); $part4 = pack("v", 7734); $padding = (strlen($padding) > 1) ?
$padding : '0'.$padding;
$hex = bin2hex($part0) . "-" . $pp[0] . "-" . $pp[1] . "-" . $pp[2] . "-" . $pp[3] . bin2hex($part3) . bin2hex($part4) . $padding; echo "\n";
$b64 = base64_encode($part0 . $part1 . $part2 . $part3 . $part4); echo "\n";
$codec = new ClickIdBase64Codec();
$click = $codec->encode(new ClickId(12, 5123, 41, 1735689800, 7734));
$clickId = $codec->decode($click);
$hex = hex2bin($hex);
echo bin2hex( $parts[2] . $parts[3]) . " = $wmId";
PD9waHAKCmNsYXNzIENsaWNrSWQKewogICAgcHJpdmF0ZSAkd21JZDsKICAgIHByaXZhdGUgJGNhbXBhaWduSWQ7CiAgICBwcml2YXRlICRkYzsKICAgIHByaXZhdGUgJHRpbWVzdGFtcDsKICAgIHByaXZhdGUgJHJhbmQ7CgogICAgcHVibGljIGZ1bmN0aW9uIF9fY29uc3RydWN0KAogICAgICAgIGludCAkd21JZCwKICAgICAgICBpbnQgJGNhbXBhaWduSWQsCiAgICAgICAgaW50ICRkYywKICAgICAgICBpbnQgJHRpbWVzdGFtcCwKICAgICAgICBpbnQgJHJhbmQKICAgICkKICAgIHsKICAgICAgICAkdGhpcy0+cmFuZCA9ICRyYW5kOwogICAgICAgICR0aGlzLT50aW1lc3RhbXAgPSAkdGltZXN0YW1wOwogICAgICAgICR0aGlzLT5kYyA9ICRkYzsKICAgICAgICAkdGhpcy0+Y2FtcGFpZ25JZCA9ICRjYW1wYWlnbklkOwogICAgICAgICR0aGlzLT53bUlkID0gJHdtSWQ7CgogICAgfQoKICAgIGZ1bmN0aW9uIGdldFdtSUQoKTogaW50CiAgICB7CiAgICAgICAgcmV0dXJuICR0aGlzLT53bUlkOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldENhbXBhaWduSUQoKTogaW50CiAgICB7CiAgICAgICAgcmV0dXJuICR0aGlzLT5jYW1wYWlnbklkOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldERDKCk6IGludAogICAgewogICAgICAgIHJldHVybiAkdGhpcy0+ZGM7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0VGltZXN0YW1wKCk6IGludAogICAgewogICAgICAgIHJldHVybiAkdGhpcy0+dGltZXN0YW1wOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldFJhbmQoKTogaW50CiAgICB7CiAgICAgICAgcmV0dXJuICR0aGlzLT5yYW5kOwogICAgfQp9CgppbnRlcmZhY2UgQ2xpY2tJZENvZGVyCnsKICAgIGZ1bmN0aW9uIGVuY29kZShDbGlja0lkICRpZCk6IHN0cmluZzsKCiAgICBmdW5jdGlvbiBkZWNvZGUoc3RyaW5nICRkYXRhKTogQ2xpY2tJZDsKfQoKYWJzdHJhY3QgY2xhc3MgQmluYXJ5Q2xpY2tJZENvZGVjIGltcGxlbWVudHMgQ2xpY2tJZENvZGVyCnsKICAgIC8vMjAyNS0wMS0wMSAwMDowMDowMCBVVEMKICAgIGNvbnN0IEJBU0VfVElNRVNUQU1QID0gMTczNTY4OTYwMDsKCiAgICBmdW5jdGlvbiBlbmNvZGUoQ2xpY2tJZCAkaWQpOiBzdHJpbmcKICAgIHsKICAgICAgICAkbnRzID0gJGlkLT5nZXRUaW1lc3RhbXAoKSAtIHNlbGY6OkJBU0VfVElNRVNUQU1QOwogICAgICAgICRwYXJ0MCA9IHBhY2soIlYiLCAkbnRzKTsKICAgICAgICAkcGFydDEgPSBwYWNrKCJWIiwgJGlkLT5nZXRXbUlEKCkpOwogICAgICAgICRwYXJ0MiA9IHBhY2soIlYiLCAkaWQtPmdldENhbXBhaWduSUQoKSk7CiAgICAgICAgJHBhcnQzID0gcGFjaygiQyIsICRpZC0+Z2V0REMoKSk7CiAgICAgICAgJHBhcnQ0ID0gcGFjaygidiIsICRpZC0+Z2V0UmFuZCgpKTsKICAgICAgICByZXR1cm4gJHBhcnQwIC4gJHBhcnQxIC4gJHBhcnQyIC4gJHBhcnQzIC4gJHBhcnQ0OwogICAgfQoKICAgIGZ1bmN0aW9uIGRlY29kZShzdHJpbmcgJGRhdGEpOiBDbGlja0lkCiAgICB7CiAgICAgICAgJHBhcnRzID0gc3RyX3NwbGl0KCRkYXRhLCAyKTsKICAgICAgICAkbnRzID0gY3VycmVudCh1bnBhY2soIlYiLCAkcGFydHNbMF0gLiAkcGFydHNbMV0pKTsKICAgICAgICAkd21JZCA9IGN1cnJlbnQodW5wYWNrKCJWIiwgJHBhcnRzWzJdIC4gJHBhcnRzWzNdKSk7CiAgICAgICAgJGNhbXBhaWduSWQgPSBjdXJyZW50KHVucGFjaygiViIsICRwYXJ0c1s0XSAuICRwYXJ0c1s1XSkpOwogICAgICAgICRkYyA9IGN1cnJlbnQodW5wYWNrKCJDIiwgJHBhcnRzWzZdWzBdKSk7CiAgICAgICAgJHJhbmQgPSBjdXJyZW50KHVucGFjaygidiIsICRwYXJ0c1s2XVsxXSAuICRwYXJ0c1s3XVswXSkpOwogICAgICAgIHJldHVybiBuZXcgQ2xpY2tJZCgKICAgICAgICAgICAgJHdtSWQsCiAgICAgICAgICAgICRjYW1wYWlnbklkLAogICAgICAgICAgICAkZGMsCiAgICAgICAgICAgICRudHMgKyBzZWxmOjpCQVNFX1RJTUVTVEFNUCwKICAgICAgICAgICAgJHJhbmQKICAgICAgICApOwogICAgfQp9CgovLyAxNi3QsdCw0LnRgtC+0LLRi9C5INGE0L7RgNC80LDRgiDRg9C90LjQutCw0LvRjNC90L7Qs9C+INC40LQgInh4eHh4eHh4LXh4eHgteHh4eC14eHh4LXh4eHh4eHh4eHh4eCIKLy8g0KHQvtGB0YLQsNCy0L3Ri9C1INGH0LDRgdGC0Lg6Ci8vd21faWQgPSA0IGJ5dGUgKGNvbXByZXNzZWQpCi8vY2FtcGFpZ25faWQgPSA0IGJ5dGUKLy90cyA9IDQgYnl0ZSAoYWZ0ZXIgMjAyNS0wMS0wMSBVVEMpCi8vZGMgPSAxIGJ5dGUKLy9yYW5kID0gMiBieXRlCmNsYXNzIENsaWNrSWRVVUlEQ29kZWMgZXh0ZW5kcyBCaW5hcnlDbGlja0lkQ29kZWMKewogICAgZnVuY3Rpb24gZW5jb2RlKENsaWNrSWQgJGlkKTogc3RyaW5nCiAgICB7CiAgICAgICAgJGVuY29kZWQgPSBwYXJlbnQ6OmVuY29kZSgkaWQpOwogICAgICAgICRwYWRkaW5nID0gYmFzZV9jb252ZXJ0KCRpZC0+Z2V0UmFuZCgpICUgKCRpZC0+Z2V0REMoKSAmIDB4RkYpLCAxMCwgMTYpOwogICAgICAgICRwYXJ0cyA9IHN0cl9zcGxpdChiaW4yaGV4KCRlbmNvZGVkKSAuICRwYWRkaW5nLCA0KTsKICAgICAgICByZXR1cm4gIiRwYXJ0c1swXSRwYXJ0c1sxXS0kcGFydHNbMl0tJHBhcnRzWzNdLSRwYXJ0c1s0XS0kcGFydHNbNV0kcGFydHNbNl0kcGFydHNbN10iOwogICAgfQoKICAgIGZ1bmN0aW9uIGRlY29kZShzdHJpbmcgJGRhdGEpOiBDbGlja0lkCiAgICB7CiAgICAgICAgJGRhdGEgPSBzdHJfcmVwbGFjZSgnLScsICcnLCAkZGF0YSk7CiAgICAgICAgcmV0dXJuIHBhcmVudDo6ZGVjb2RlKGhleDJiaW4oJGRhdGEpKTsKICAgIH0KCiAgICAvLyDRgdC20LDRgtGL0Lkg0YTQvtGA0LzQsNGCINCx0LDQudGC0L7QstC+0LPQviDRhdGA0LDQvdC10L3QuNGPINGH0LjRgdC70LAsINC/0LXRgNCy0YvQtSDQsdC40YLRiyDQv9C+0LrQsNC30YvQstCw0Y7RgiDQutC+0LvQuNGH0LXRgdGC0LLQviDQvdC1INC90YPQu9C10LLRi9GFINCx0LDQudGCCiAgICAvLyDQuNC80LXQtdGCINC+0LLQtdGA0YXQtdC0INC00LvRjyDQt9C90LDRh9C10L3QuNC5INC60L7RgtC+0YDRi9C1INC00L7RgdGC0LjQs9C70Lgg0LzQsNC60YHQuNC80LDQu9GM0L3QvtCz0L4g0LfQvdCw0YfQtdC90LjRjywg0YLQuiDQsdGD0LTQtdGCINC90LAgMiDQsdC40YLQsCDQsdC+0LvRjNGI0LUg0LzQtdGB0YLQsCDQt9Cw0L3QuNC80LDRgtGMCi8vICAgIHByaXZhdGUgZnVuY3Rpb24gY29tcHJlc3NQYWNrSW50KGludCAkbik6IHN0cmluZwovLyAgICB7Ci8vCi8vICAgIH0KfQoKY2xhc3MgQ2xpY2tJZEJhc2U2NENvZGVjIGV4dGVuZHMgQmluYXJ5Q2xpY2tJZENvZGVjCnsKICAgIGZ1bmN0aW9uIGVuY29kZShDbGlja0lkICRpZCk6IHN0cmluZwogICAgewogICAgICAgIHJldHVybiBiYXNlNjRfZW5jb2RlKHBhcmVudDo6ZW5jb2RlKCRpZCkpOwogICAgfQoKICAgIGZ1bmN0aW9uIGRlY29kZShzdHJpbmcgJGRhdGEpOiBDbGlja0lkCiAgICB7CiAgICAgICAgcmV0dXJuIHBhcmVudDo6ZGVjb2RlKGJhc2U2NF9kZWNvZGUoJGRhdGEpKTsKICAgIH0KfQoKJGkgPSAxMzQ2MzsKJGFyID0gdW5wYWNrKCJDKiIsIHBhY2soIkwiLCAkaSkpOwpwcmludF9yKCRhcik7CiRhciA9IHVucGFjaygiQyoiLCBwYWNrKCJOIiwgJGkpKTsKcHJpbnRfcigkYXIpOwokYXIgPSB1bnBhY2soIkMqIiwgcGFjaygiViIsICRpKSk7CnByaW50X3IoJGFyKTsKCiRhciA9IHBhY2soIlYiLCAkaSk7CnByaW50X3Iob3JkKCRhclswXSkpOwoKCiRhciA9IHVucGFjaygiViIsICJceDk3XHgzNFx4MDBceDAwIik7CnByaW50X3IoJGFyKTsKCgokcGFydDAgPSBwYWNrKCJWIiwgNzUyMzQpOwokcGFydDEgPSBwYWNrKCJWIiwgMTIpOwokcGFydDIgPSBwYWNrKCJWIiwgNTEyMyk7CiRwYXJ0MyA9IHBhY2soIkMiLCA0MSk7CiRwYXJ0NCA9IHBhY2soInYiLCA3NzM0KTsKICAgICAgICAkcGFkZGluZyA9IGRlY2hleCg0MSAmIDB4RkYpOwogICAgICAgICRwYWRkaW5nID0gKHN0cmxlbigkcGFkZGluZykgPiAxKSA/ICRwYWRkaW5nIDogJzAnLiRwYWRkaW5nOwoKICAgICAgICAkcHAgPSBzdHJfc3BsaXQoYmluMmhleCgkcGFydDEgLiAkcGFydDIpLCA0KTsKICAgICAgICAkaGV4ID0gYmluMmhleCgkcGFydDApIC4gIi0iIC4gJHBwWzBdIC4gIi0iIC4gJHBwWzFdIC4gIi0iIC4gJHBwWzJdIC4gIi0iIC4gJHBwWzNdIC4gYmluMmhleCgkcGFydDMpIC4gYmluMmhleCgkcGFydDQpIC4gJHBhZGRpbmc7CnByaW50X3IoJGhleCk7CmVjaG8gIlxuIjsKJGI2NCA9IGJhc2U2NF9lbmNvZGUoJHBhcnQwIC4gJHBhcnQxIC4gJHBhcnQyIC4gJHBhcnQzIC4gJHBhcnQ0KTsKcHJpbnRfcigkYjY0KTsKZWNobyAiXG4iOwokY29kZWMgPSBuZXcgQ2xpY2tJZEJhc2U2NENvZGVjKCk7CiRjbGljayA9ICRjb2RlYy0+ZW5jb2RlKG5ldyBDbGlja0lkKDEyLCA1MTIzLCA0MSwgMTczNTY4OTgwMCwgNzczNCkpOwokY2xpY2tJZCA9ICRjb2RlYy0+ZGVjb2RlKCRjbGljayk7CnZhcl9kdW1wKCRjbGljayk7CnZhcl9kdW1wKCRjbGlja0lkKTsKCgogICAgICAgICRoZXggPSBzdHJfcmVwbGFjZSgnLScsICcnLCAkaGV4KTsKICAgICAgICAkaGV4ID0gaGV4MmJpbigkaGV4KTsKICAgICAgICAkcGFydHMgPSBzdHJfc3BsaXQoJGhleCwgMik7CiAgICAgICAgJG50cyA9IGN1cnJlbnQodW5wYWNrKCJWIiwgJHBhcnRzWzBdIC4gJHBhcnRzWzFdKSk7CiAgICAgICAgJHdtSWQgPSBjdXJyZW50KHVucGFjaygiViIsICRwYXJ0c1syXSAuICRwYXJ0c1szXSkpOwogICAgICAgICRjYW1wYWlnbklkID0gY3VycmVudCh1bnBhY2soIlYiLCAkcGFydHNbNF0gLiAkcGFydHNbNV0pKTsKICAgICAgICAkcmFuZCA9IGN1cnJlbnQodW5wYWNrKCJ2IiwgJHBhcnRzWzZdKSk7CiAgICAgICAgJGRjID0gY3VycmVudCh1bnBhY2soIkMiLCAkcGFydHNbN10pKTsKICAgICAgICAKICAgICAgICBlY2hvIGJpbjJoZXgoICRwYXJ0c1syXSAuICRwYXJ0c1szXSkgLiAiID0gJHdtSWQiOw==