Fix #53891: iconv_mime_encode() fails to Q-encode UTF-8 string

The minimum length of an encoded-word is actually the pure encoding
overhead plus the length of the `output-charset` plus the minimum unit
of encoded text, which is 4 for B-encoding and (for simplicity) 3 for
Q-encoding.  We also cater to the possibility that we need further
encoded words, which would be split by the `line-break-chars` followed
by a space character.  Obviously, the former `out_charset_len + 12` is
too simplistic and wrong in the given case (where the magic number
would be 13).

These simplifications are somewhat wasteful, but iconv_mime_encode()
with Q-encoding is wasteful anyway (see bug 66828[1]), and the proper
solution to convert the whole input to the desired output charset
upfront, and applying the encoding afterwards appears too much a change
for the stable releases.

[1] <https://bugs.php.net/66828>
This commit is contained in:
Christoph M. Becker 2018-08-12 15:03:47 +02:00
parent 692e5d5c88
commit eb03290754
3 changed files with 27 additions and 1 deletions

3
NEWS
View File

@ -16,6 +16,9 @@ PHP NEWS
. Fixed bug #76285 (DOMDocument::formatOutput attribute sometimes ignored).
(Andrew Nester, Laruence, Anatol)
- iconv:
. Fixed bug #53891 (iconv_mime_encode() fails to Q-encode UTF-8 string). (cmb)
- libxml:
. Fixed bug #76777 ("public id" parameter of libxml_set_external_entity_loader
callback undefined). (Ville Hukkamäki)

View File

@ -1224,8 +1224,9 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn
do {
size_t prev_in_left;
size_t out_size;
size_t encoded_word_min_len = sizeof("=??X??=")-1 + out_charset_len + (enc_scheme == PHP_ICONV_ENC_SCHEME_BASE64 ? 4 : 3);
if (char_cnt < (out_charset_len + 12)) {
if (char_cnt < encoded_word_min_len + lfchars_len + 1) {
/* lfchars must be encoded in ASCII here*/
smart_str_appendl(pretval, lfchars, lfchars_len);
smart_str_appendc(pretval, ' ');

View File

@ -0,0 +1,22 @@
--TEST--
Bug #53891 (iconv_mime_encode() fails to Q-encode UTF-8 string)
--SKIPIF--
<?php
if (!extension_loaded('iconv')) die('skip iconv extension not available');
?>
--FILE--
<?php
$preferences = array(
'scheme' => 'Q',
'input-charset' => 'utf-8',
'output-charset' => 'utf-8',
'line-length' => 74,
'line-break-chars' => "\r\n",
);
var_dump(iconv_mime_encode('subject', "d obeybiubrsfqllpdtpge…", $preferences));
?>
===DONE===
--EXPECT--
string(81) "subject: =?utf-8?Q?d=20obeybiubrsfqllp?==?utf-8?Q?dtpge?=
=?utf-8?Q?=E2=80=A6?="
===DONE===