From e27d23063e29ca8cf33c2958f58353730fd1ab32 Mon Sep 17 00:00:00 2001 From: Toby Evans Date: Fri, 5 Dec 2025 15:43:10 +1300 Subject: [PATCH 1/2] add parseSessionCookie helper method This helper parses the `_GA_{ga_id}` session cookie (both GS1 & GS2 formats) into an associative array of data. --- src/Helper/ConvertHelper.php | 66 +++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/src/Helper/ConvertHelper.php b/src/Helper/ConvertHelper.php index 4e78426..e00d329 100644 --- a/src/Helper/ConvertHelper.php +++ b/src/Helper/ConvertHelper.php @@ -2,8 +2,8 @@ namespace AlexWestergaard\PhpGa4\Helper; -use AlexWestergaard\PhpGa4\Facade\Type\EventType; use AlexWestergaard\PhpGa4\Exception\Ga4Exception; +use AlexWestergaard\PhpGa4\Facade\Type\EventType; class ConvertHelper { @@ -77,4 +77,68 @@ public static function parseEvents(array $list): array } return $events; } + + /** + * Parse the session cookie (GA_{measurement_id}) into named parts. + * + * @param string $session The cookie value + * @return array + */ + public static function parseSessionCookie(string $session): array + { + $parts = explode('.', $session); + + $version = $parts[0] ?? null; + $k = $parts[1] ?? null; + $data = $parts[2] ?? null; + + // If the data part is empty, return an empty array + if (!$data) { + return []; + } + + if ($version === 'GS1') { + $data = explode('.', $session); + + return [ + 'version' => $data[0] ?? null, + 'domain_level' => $data[1] ?? null, + 'session_id' => $data[2] ?? null, + 'session_number' => $data[3] ?? null, + 'session_engagement' => $data[4] ?? null, + 'timestampt' => $data[5] ?? null + ]; + } + + $cookieParts = explode('$', $data); + + if (empty(array_filter($cookieParts))) { + return []; + } + + $data = array_map( + fn ($part) => match ($part[0]) { + 's' => ['session_id' => $part], + 't' => ['timestamp' => $part], + 'o' => ['session_number' => $part], + 'g' => ['session_engaged' => $part], + 'j' => ['join_timer' => $part], + 'l' => ['logged_in_state' => $part], + 'h' => ['user_id' => $part], + 'd' => ['join_id' => $part], + default => [$part[0] => $part] + }, + $cookieParts + ); + + $result = []; + + foreach ($data as $mapValue) { + foreach ($mapValue as $key => $value) { + $result[$key] = $value; + } + } + + return $result; + } } From cb7276b14c09fd83be5019b3862926066b9dfdc5 Mon Sep 17 00:00:00 2001 From: Toby Evans Date: Fri, 5 Dec 2025 16:31:45 +1300 Subject: [PATCH 2/2] add tests for praseing session cookies --- test/Unit/HelperTest.php | 52 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/test/Unit/HelperTest.php b/test/Unit/HelperTest.php index 7096cd2..90384d2 100644 --- a/test/Unit/HelperTest.php +++ b/test/Unit/HelperTest.php @@ -2,9 +2,9 @@ namespace AlexWestergaard\PhpGa4Test\Unit; -use AlexWestergaard\PhpGa4\Helper; -use AlexWestergaard\PhpGa4\Facade; use AlexWestergaard\PhpGa4\Event; +use AlexWestergaard\PhpGa4\Facade; +use AlexWestergaard\PhpGa4\Helper; use AlexWestergaard\PhpGa4Test\MeasurementTestCase; final class HelperTest extends MeasurementTestCase @@ -82,4 +82,52 @@ public function test_timeasmicro_throws_too_large() $this->analytics->setTimestampMicros($time); } + + public function test_parse_session_cookie_gs1() + { + $sessionData = Helper\ConvertHelper::parseSessionCookie('GS1.1.1689053763.1.1.1689054101.0.0.0'); + $this->assertEquals([ + 'version' => 'GS1', + 'domain_level' => '1', + 'session_id' => '1689053763', + 'session_number' => '1', + 'session_engagement' => '1', + 'timestampt' => '1689054101', + ], $sessionData); + } + + public function test_parse_session_cookie_gs2() + { + $sessionData = Helper\ConvertHelper::parseSessionCookie('GS2.1.s1764888982$o50$g1$t1764890260$j59$l0$h681028196'); + $this->assertEquals([ + 'session_id' => 's1764888982', + 'session_number' => 'o50', + 'session_engaged' => 'g1', + 'timestamp' => 't1764890260', + 'join_timer' => 'j59', + 'logged_in_state' => 'l0', + 'user_id' => 'h681028196', + ], $sessionData); + + // same data, different order + $sessionData = Helper\ConvertHelper::parseSessionCookie('GS2.1.t1764890260$o50$g1$s1764888982$j59$l0$h681028196'); + $this->assertEquals([ + 'session_id' => 's1764888982', + 'session_number' => 'o50', + 'session_engaged' => 'g1', + 'timestamp' => 't1764890260', + 'join_timer' => 'j59', + 'logged_in_state' => 'l0', + 'user_id' => 'h681028196', + ], $sessionData); + } + + public function test_parse_session_cookie_invalid() + { + $sessionData = Helper\ConvertHelper::parseSessionCookie('invalid'); + $this->assertEquals([], $sessionData); + + $sessionData = Helper\ConvertHelper::parseSessionCookie(''); + $this->assertEquals([], $sessionData); + } }