SDK version: 6.3.1 (regressed from 6.2.0, which used substr) PHP: 8.3 · HTTP client: cURL (CurlHttpClient)
Summary DownloadPDF() returns a corrupted PDF (damaged xref/trailer, renders blank) because CurlHttpClient::setIntuitResponse() splits the raw cURL response into headers/body with mb_substr() using a byte offset.
Root cause — src/Core/HttpClients/CurlHttpClient.php (~line 120):
$headerSize = $this->basecURL->getInfo(CURLINFO_HEADER_SIZE); // BYTES
$rawHeaders = mb_substr($response, 0, $headerSize);
$rawBody = mb_substr($response, $headerSize);
CURLINFO_HEADER_SIZE is a byte count, but mb_substr() splits by multibyte characters. For a binary response body (e.g. a PDF), the split lands at the wrong byte and mangles the content. Text responses (XML/JSON) are valid UTF-8, so they happen to survive — which is why only binary downloads (DownloadPDF) are affected, and CRUD/query still work.
Steps to reproduce
- On PHP 8.x with the cURL client, call DataService::DownloadPDF($invoice) for any invoice.
- Open the resulting file. It is a structurally-damaged PDF ("Couldn't read xref table" / "Couldn't find trailer dictionary") and renders blank.
Expected: a valid PDF (as in 6.2.0). Actual: corrupted/blank PDF; any binary response is byte-mangled.
Suggested fix Use byte-based splitting, since $headerSize is bytes:
$rawHeaders = substr($response, 0, $headerSize);
$rawBody = substr($response, $headerSize);
(or, if mb_substr is intentional, force byte mode: mb_substr($response, 0, $headerSize, '8bit')).
SDK version: 6.3.1 (regressed from 6.2.0, which used substr) PHP: 8.3 · HTTP client: cURL (CurlHttpClient)
Summary DownloadPDF() returns a corrupted PDF (damaged xref/trailer, renders blank) because CurlHttpClient::setIntuitResponse() splits the raw cURL response into headers/body with mb_substr() using a byte offset.
Root cause — src/Core/HttpClients/CurlHttpClient.php (~line 120):
$headerSize = $this->basecURL->getInfo(CURLINFO_HEADER_SIZE); // BYTES
$rawHeaders = mb_substr($response, 0, $headerSize);
$rawBody = mb_substr($response, $headerSize);
CURLINFO_HEADER_SIZE is a byte count, but mb_substr() splits by multibyte characters. For a binary response body (e.g. a PDF), the split lands at the wrong byte and mangles the content. Text responses (XML/JSON) are valid UTF-8, so they happen to survive — which is why only binary downloads (DownloadPDF) are affected, and CRUD/query still work.
Steps to reproduce
Expected: a valid PDF (as in 6.2.0). Actual: corrupted/blank PDF; any binary response is byte-mangled.
Suggested fix Use byte-based splitting, since $headerSize is bytes:
$rawHeaders = substr($response, 0, $headerSize);
$rawBody = substr($response, $headerSize);
(or, if mb_substr is intentional, force byte mode: mb_substr($response, 0, $headerSize, '8bit')).