]> granicus.if.org Git - php/commitdiff
Fixed bug #52941 (The 'iconv_mime_decode_headers' function is skipping
authorAdam Harvey <aharvey@php.net>
Thu, 30 Sep 2010 11:04:21 +0000 (11:04 +0000)
committerAdam Harvey <aharvey@php.net>
Thu, 30 Sep 2010 11:04:21 +0000 (11:04 +0000)
headers).

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

index c119612c943bcf1e0c585baa75f963b897df6f83..2a272b49aba667299b8f69aba691abe391ee5e21 100644 (file)
@@ -1521,16 +1521,43 @@ static php_iconv_err_t _php_iconv_mime_decode(smart_str *pretval, const char *st
 
                                        if (cd == (iconv_t)(-1)) {
                                                if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
+                                                       /* Bad character set, but the user wants us to
+                                                        * press on. In this case, we'll just insert the
+                                                        * undecoded encoded word, since there isn't really
+                                                        * a more sensible behaviour available; the only
+                                                        * other options are to swallow the encoded word
+                                                        * entirely or decode it with an arbitrarily chosen
+                                                        * single byte encoding, both of which seem to have
+                                                        * a higher WTF factor than leaving it undecoded.
+                                                        *
+                                                        * Given this approach, we need to skip ahead to
+                                                        * the end of the encoded word. */
+                                                       int qmarks = 2;
+                                                       while (qmarks > 0 && str_left > 1) {
+                                                               if (*(++p1) == '?') {
+                                                                       --qmarks;
+                                                               }
+                                                               --str_left;
+                                                       }
+
+                                                       /* Look ahead to check for the terminating = that
+                                                        * should be there as well; if it's there, we'll
+                                                        * also include that. If it's not, there isn't much
+                                                        * we can do at this point. */
+                                                       if (*(p1 + 1) == '=') {
+                                                               ++p1;
+                                                               --str_left;
+                                                       }
+
                                                        err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl); 
                                                        if (err != PHP_ICONV_ERR_SUCCESS) {
                                                                goto out;
                                                        }
-                                                       encoded_word = NULL;
-                                                       if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
-                                                               scan_stat = 12;
-                                                       } else {
-                                                               scan_stat = 0;
-                                                       }
+
+                                                       /* Let's go back and see if there are further
+                                                        * encoded words or bare content, and hope they
+                                                        * might actually have a valid character set. */
+                                                       scan_stat = 12;
                                                        break;
                                                } else {
 #if ICONV_SUPPORTS_ERRNO
diff --git a/ext/iconv/tests/bug52941.phpt b/ext/iconv/tests/bug52941.phpt
new file mode 100644 (file)
index 0000000..753c9ad
--- /dev/null
@@ -0,0 +1,41 @@
+--TEST--
+Bug #52941 (The 'iconv_mime_decode_headers' function is skipping headers)
+--SKIPIF--
+<?php extension_loaded('iconv') or die('skip iconv extension is not available'); ?>
+--FILE--
+<?php
+$headers = <<<HEADERS
+From: =?UTF-8?B?PGZvb0BleGFtcGxlLmNvbT4=?=
+Subject: =?ks_c_5601-1987?B?UkU6odk=?=
+X-Foo: =?ks_c_5601-1987?B?UkU6odk=?= Foo
+X-Bar: =?ks_c_5601-1987?B?UkU6odk=?= =?UTF-8?Q?Foo?=
+To: <test@example.com>
+HEADERS;
+
+$decoded = iconv_mime_decode_headers($headers, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, 'UTF-8');
+
+var_dump($decoded['From']);
+var_dump($decoded['Subject']);
+var_dump($decoded['X-Foo']);
+var_dump($decoded['X-Bar']);
+var_dump($decoded['To']);
+
+$decoded = iconv_mime_decode_headers($headers, ICONV_MIME_DECODE_CONTINUE_ON_ERROR | ICONV_MIME_DECODE_STRICT, 'UTF-8');
+
+var_dump($decoded['From']);
+var_dump($decoded['Subject']);
+var_dump($decoded['X-Foo']);
+var_dump($decoded['X-Bar']);
+var_dump($decoded['To']);
+?>
+--EXPECT--
+string(17) "<foo@example.com>"
+string(29) "=?ks_c_5601-1987?B?UkU6odk=?="
+string(33) "=?ks_c_5601-1987?B?UkU6odk=?= Foo"
+string(32) "=?ks_c_5601-1987?B?UkU6odk=?=Foo"
+string(18) "<test@example.com>"
+string(17) "<foo@example.com>"
+string(29) "=?ks_c_5601-1987?B?UkU6odk=?="
+string(33) "=?ks_c_5601-1987?B?UkU6odk=?= Foo"
+string(32) "=?ks_c_5601-1987?B?UkU6odk=?=Foo"
+string(18) "<test@example.com>"