]> granicus.if.org Git - php/commitdiff
Fix #53891: iconv_mime_encode() fails to Q-encode UTF-8 string
authorChristoph M. Becker <cmbecker69@gmx.de>
Sun, 12 Aug 2018 13:03:47 +0000 (15:03 +0200)
committerChristoph M. Becker <cmbecker69@gmx.de>
Sat, 25 Aug 2018 12:30:07 +0000 (14:30 +0200)
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>

NEWS
ext/iconv/iconv.c
ext/iconv/tests/bug53891.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index bf8fe5b9af1f1dbb6a26d27790ee8d34a701cf74..c61eff85236b9dbfd3e9b18cff2b0d782e814195 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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)
index 2915e97be7ca2c15fe10cc58519281c5f3878aef..6f05e47bade66b45a54286dd8e7441e32a561ca3 100644 (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, ' ');
diff --git a/ext/iconv/tests/bug53891.phpt b/ext/iconv/tests/bug53891.phpt
new file mode 100644 (file)
index 0000000..86ae9a9
--- /dev/null
@@ -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\r
+$preferences = array(\r
+    'scheme' => 'Q',\r
+    'input-charset'  => 'utf-8',\r
+    'output-charset' => 'utf-8',\r
+    'line-length' => 74,\r
+    'line-break-chars' => "\r\n",\r
+);\r
+var_dump(iconv_mime_encode('subject', "d obeybiubrsfqllpdtpge…", $preferences));\r
+?>
+===DONE===
+--EXPECT--
+string(81) "subject: =?utf-8?Q?d=20obeybiubrsfqllp?==?utf-8?Q?dtpge?=
+ =?utf-8?Q?=E2=80=A6?="
+===DONE===