Created
May 5, 2024 13:13
-
-
Save lroman242/c870cead4d1ee7536f91a4c1055a3e6c to your computer and use it in GitHub Desktop.
GCLID decode / get timestamp from GCLID
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Function decodes GCLID (Google Click ID) and extract timestamp from it. | |
* | |
* @param string $gclid | |
* | |
* @return int|null | |
*/ | |
function getTimestampFromGclid(string $gclid): ?int | |
{ | |
// Decode the base64/web encoded gclid | |
$decodedBytes = base64_decode(str_replace(['-', '_'], ['+', '/'], $gclid)); | |
// Check if the gclid is valid and determine its type | |
$type = ord($decodedBytes[0]); | |
switch ($type) { | |
case 0x08: // Old gclid Type with Microsecond-Timestamp | |
if (strlen($decodedBytes) >= 9) { | |
$bytes = substr($decodedBytes, 1, 8); // Extract the timestamp at offset 1 | |
$microseconds = decodeVLQ($bytes); // Decode timestamp bytes into integer | |
return (int)ceil($microseconds / 1000000); // Convert to seconds | |
} | |
break; | |
case 0x10: // Version with Old gclid Message in a Sub-Sub-Message | |
$oldMessageOffset = strpos($decodedBytes, "\x08", 8); // Find timestamp offset | |
if ($oldMessageOffset !== false && strlen($decodedBytes) >= $oldMessageOffset + 9) { | |
$bytes = substr($decodedBytes, $oldMessageOffset + 1, 8); // Extract the timestamp at offset $oldMessageOffset + 1 | |
$microseconds = decodeVLQ($bytes); // Decode timestamp bytes into integer | |
return (int)ceil($microseconds / 1000000); // Convert to seconds | |
} | |
break; | |
case 0x0A: // gclid version with Seconds-Since-Epoch | |
if (strlen($decodedBytes) >= 9) { | |
$bytes = substr($decodedBytes, 5, 8); // Extract the timestamp at offset 5 | |
return decodeVLQ($bytes); // Decode timestamp bytes into integer (already in seconds) | |
} | |
break; | |
} | |
return null; // Invalid gclid | |
} | |
/** | |
* Decode binary data including variable-length quantities. | |
* | |
* @param $bytes | |
* | |
* @return int | |
*/ | |
function decodeVLQ($bytes): int | |
{ | |
// $val = 0; | |
// foreach (str_split($bytes) as $i => $byte) { | |
// $val = PHP_INT_SIZE < 8 && function_exists('bcadd') ? | |
// bcadd($val, bcmul(ord($byte) & 0x7f, bcpow(2, $i * 7))) : | |
// $val + ((ord($byte) & 0x7f) * pow(2, $i * 7)); | |
// if (!(ord($byte) & 0x80)) break; | |
// } | |
// return $val; | |
// Unpack the bytes using the 'C*' format to treat each byte as an unsigned char | |
$unpacked = unpack('C*', $bytes); | |
$val = 0; | |
$shift = 0; | |
// Iterate over each unpacked byte | |
foreach ($unpacked as $byte) { | |
// Add the lower 7 bits of the byte to the decoded value | |
$val |= ($byte & 0x7F) << $shift; | |
// Shift by 7 bits for the next byte | |
$shift += 7; | |
// If the MSB is 0, stop decoding (end of the VLQ) | |
if (!($byte & 0x80)) { | |
break; | |
} | |
} | |
return $val; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment