[php-src] Issue #24462: convert.quoted-printable-encode drops or duplicates a CR at the end of a write

From: Date: Tue, 20 Oct 2026 15:32:33 +0000
Subject: [php-src] Issue #24462: convert.quoted-printable-encode drops or duplicates a CR at the end of a write
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-253049@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/24462 Author: auraseb ### Description With line-length and line-break-chars set, the convert.quoted-printable-encode filter looks ahead for the line break sequence. When a write ends in the middle of that sequence (for example a trailing "\r" with line-break-chars set to "\r\n"), the held back characters are handled wrongly: 1. If nothing else is written, the "\r" is lost when the stream is closed or the filter removed. 2. If the next write starts with "\n", the "\r" can be emitted twice: once encoded as =0D and again as part of the line break. Decoding the result gives "\r\r\n". Which of the two happens depends on how much room was left in the internal output buffer, so the same data can encode differently depending on how it was split across writes. The following code: ```php <?php function encode(array $chunks): string { $fp = fopen('php://temp', 'w+'); $filter = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_WRITE, [ 'line-length' => 76, 'line-break-chars' => "\r\n", ]); foreach ($chunks as $chunk) { fwrite($fp, $chunk); } stream_filter_remove($filter); rewind($fp); return stream_get_contents($fp); } var_dump(bin2hex(quoted_printable_decode(encode(["a\r"])))); var_dump(bin2hex(quoted_printable_decode(encode(["Hello=\r", "\nWorld"])))); ``` Resulted in this output: ``` string(2) "61" string(28) "48656c6c6f3d0d0d0a576f726c64" ``` But I expected this output instead: ``` string(4) "610d" string(26) "48656c6c6f3d0d0a576f726c64" ``` Root cause: in php_conv_qprint_encode_convert() (ext/standard/filters.c) the main loop does not stop when the input is exhausted while a partial line break is pending. It starts emitting the pending characters as encoded bytes, but leaves lb_cnt set, so a following write that completes the sequence emits the whole line break again. When the output buffer is too small at that point, the converter returns PHP_CONV_ERR_TOO_BIG with no input left, the caller stops calling it, and the pending characters stay in the state. On close the converter is called with a NULL input, which returns immediately, so they are never written. ### PHP Version ``` PHP 8.7.0-dev (master at b7256eee), same code in all supported branches ``` ### Operating System Any

« previous php.bugs (#253049) next »