From c0d080b973489c586fd0d14bc05e2c6a7b0bb4cd Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Sat, 27 Jun 2026 15:21:13 +0200 Subject: [PATCH 1/3] fix: fall back when payload compression fails --- .changeset/cold-buckets-gzip.md | 5 +++++ lib/Consumer/ForkCurl.php | 15 +++++++++------ lib/Consumer/LibCurl.php | 9 ++++++--- lib/Consumer/Socket.php | 12 ++++++------ lib/HttpClient.php | 3 ++- 5 files changed, 28 insertions(+), 16 deletions(-) create mode 100644 .changeset/cold-buckets-gzip.md diff --git a/.changeset/cold-buckets-gzip.md b/.changeset/cold-buckets-gzip.md new file mode 100644 index 0000000..ed8438b --- /dev/null +++ b/.changeset/cold-buckets-gzip.md @@ -0,0 +1,5 @@ +--- +'posthog-php': patch +--- + +Fall back to uncompressed batch uploads when local gzip compression fails. diff --git a/lib/Consumer/ForkCurl.php b/lib/Consumer/ForkCurl.php index 4e91b91..425afca 100644 --- a/lib/Consumer/ForkCurl.php +++ b/lib/Consumer/ForkCurl.php @@ -62,14 +62,17 @@ public function flushBatch($messages) $cmd2 = "echo " . $payload . " | gzip > " . $tmpfname; exec($cmd2, $output, $exit); - if (0 != $exit) { + if (0 == $exit) { + $cmd .= " -H 'Content-Encoding: gzip'"; + $cmd .= " --data-binary '@" . $tmpfname . "'"; + } else { $this->handleError($exit, $output); - return self::FLUSH_BATCH_NON_RETRYABLE_FAILURE; + if (is_file($tmpfname)) { + unlink($tmpfname); + } + $tmpfname = ""; + $cmd .= " -d " . $payload; } - - $cmd .= " -H 'Content-Encoding: gzip'"; - - $cmd .= " --data-binary '@" . $tmpfname . "'"; } else { $cmd .= " -d " . $payload; } diff --git a/lib/Consumer/LibCurl.php b/lib/Consumer/LibCurl.php index 343fb33..25361e7 100644 --- a/lib/Consumer/LibCurl.php +++ b/lib/Consumer/LibCurl.php @@ -68,11 +68,13 @@ public function flushBatch($messages) return self::FLUSH_BATCH_NON_RETRYABLE_FAILURE; } + $isCompressed = false; if ($this->compress_request) { - $payload = gzencode($payload); + $compressedPayload = gzencode($payload); - if (false === $payload) { - return self::FLUSH_BATCH_NON_RETRYABLE_FAILURE; + if (false !== $compressedPayload) { + $payload = $compressedPayload; + $isCompressed = true; } } @@ -86,6 +88,7 @@ public function flushBatch($messages) ], [ 'shouldVerify' => $shouldVerify, + 'compressRequest' => $isCompressed, ] ); diff --git a/lib/Consumer/Socket.php b/lib/Consumer/Socket.php index b4e18e8..0964d05 100644 --- a/lib/Consumer/Socket.php +++ b/lib/Consumer/Socket.php @@ -196,15 +196,15 @@ private function createBody($host, $content) // Send user agent in the form of {library_name}/{library_version} as per RFC 7231. $req .= "User-Agent: " . $this->userAgent() . "\r\n"; - // Compress content if compress_request is true + // Compress content if compress_request is true. If local compression fails, + // keep sending the original uncompressed payload. if ($this->compress_request) { - $content = gzencode($content); + $compressedContent = gzencode($content); - if (false === $content) { - return false; + if (false !== $compressedContent) { + $content = $compressedContent; + $req .= "Content-Encoding: gzip\r\n"; } - - $req .= "Content-Encoding: gzip\r\n"; } $req .= "Content-length: " . strlen($content) . "\r\n"; diff --git a/lib/HttpClient.php b/lib/HttpClient.php index bbf78fd..ab58905 100644 --- a/lib/HttpClient.php +++ b/lib/HttpClient.php @@ -98,6 +98,7 @@ public function sendRequest(string $path, ?string $payload, array $extraHeaders $shouldRetry = $requestOptions['shouldRetry'] ?? true; $shouldVerify = $requestOptions['shouldVerify'] ?? true; $includeEtag = $requestOptions['includeEtag'] ?? false; + $compressRequest = $requestOptions['compressRequest'] ?? $this->compressRequests; do { // open connection @@ -109,7 +110,7 @@ public function sendRequest(string $path, ?string $payload, array $extraHeaders $headers = []; $headers[] = 'Content-Type: application/json'; - if ($this->compressRequests) { + if ($compressRequest) { $headers[] = 'Content-Encoding: gzip'; } From c39b0c0ceb82c44f23bb7d86b2db3bc768cbf3bc Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Sun, 28 Jun 2026 10:50:17 +0200 Subject: [PATCH 2/3] Address compression fallback review comments --- lib/Consumer/LibCurl.php | 2 ++ lib/Consumer/Socket.php | 2 ++ lib/HttpClient.php | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Consumer/LibCurl.php b/lib/Consumer/LibCurl.php index 25361e7..640654c 100644 --- a/lib/Consumer/LibCurl.php +++ b/lib/Consumer/LibCurl.php @@ -75,6 +75,8 @@ public function flushBatch($messages) if (false !== $compressedPayload) { $payload = $compressedPayload; $isCompressed = true; + } else { + $this->handleError(0, "Failed to gzip batch payload; sending uncompressed."); } } diff --git a/lib/Consumer/Socket.php b/lib/Consumer/Socket.php index 0964d05..143f35d 100644 --- a/lib/Consumer/Socket.php +++ b/lib/Consumer/Socket.php @@ -204,6 +204,8 @@ private function createBody($host, $content) if (false !== $compressedContent) { $content = $compressedContent; $req .= "Content-Encoding: gzip\r\n"; + } else { + $this->handleError(0, "Failed to gzip batch payload; sending uncompressed."); } } diff --git a/lib/HttpClient.php b/lib/HttpClient.php index ab58905..908978e 100644 --- a/lib/HttpClient.php +++ b/lib/HttpClient.php @@ -84,7 +84,8 @@ public function __construct( * shouldRetry?: bool, * shouldVerify?: bool, * includeEtag?: bool, - * timeout?: int + * timeout?: int, + * compressRequest?: bool * } $requestOptions * @return HttpResponse */ From d1432920fef1af4cd988f2408fbd41f0982b1115 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Sun, 28 Jun 2026 11:10:23 +0200 Subject: [PATCH 3/3] Fix compression fallback request options --- lib/Consumer/LibCurl.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/Consumer/LibCurl.php b/lib/Consumer/LibCurl.php index 640654c..ef6b91e 100644 --- a/lib/Consumer/LibCurl.php +++ b/lib/Consumer/LibCurl.php @@ -81,6 +81,13 @@ public function flushBatch($messages) } $shouldVerify = $this->options['verify_batch_events_request'] ?? true; + $requestOptions = [ + 'shouldVerify' => $shouldVerify, + ]; + if ($this->compress_request) { + $requestOptions['compressRequest'] = $isCompressed; + } + $response = $this->httpClient->sendRequest( '/batch/', $payload, @@ -88,10 +95,7 @@ public function flushBatch($messages) // Send user agent in the form of {library_name}/{library_version} as per RFC 7231. "User-Agent: {$this->userAgent()}", ], - [ - 'shouldVerify' => $shouldVerify, - 'compressRequest' => $isCompressed, - ] + $requestOptions ); if (!$shouldVerify) {