Commit 0056d013bf5 for php.net

commit 0056d013bf505302e2477e02d795627709842327
Author: Yuya Hamada <youkidearitai@gmail.com>
Date:   Wed Dec 10 21:16:44 2025 +0900

    Fix GH-20674 mb_decode_mimeheader does not handle separator

    `?=  =?` is skipped if long term, so skip space character.
    Add test case from RFC2047 and fix last pattern
    See: https://www.ietf.org/rfc/rfc2047#section-8

diff --git a/NEWS b/NEWS
index 4e301bdbc8b..5103b4a9679 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,10 @@ PHP                                                                        NEWS
 - LDAP:
   . Fix memory leak in ldap_set_options(). (ndossche)

+- Mbstring
+  . Fixed bug GH-20674 (Fix GH-20674 mb_decode_mimeheader does not handle
+    separator). (Yuya Hamada)
+
 - SPL:
   . Fixed bug GH-20678 (resource created by GlobIterator crashes with fclose()).
     (David Carlier)
diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c
index 1d5c27a2a38..5839945d475 100644
--- a/ext/mbstring/mbstring.c
+++ b/ext/mbstring/mbstring.c
@@ -6395,13 +6395,15 @@ static zend_string* mb_mime_header_decode(zend_string *input, const mbfl_encodin
 					p = temp;
 					/* Decoding of MIME encoded word was successful;
 					 * Try to collapse a run of whitespace */
-					if (p < e && (*p == '\n' || *p == '\r')) {
+					if (p < e && (*p == '\n' || *p == '\r' || *p == '\t' || *p == ' ')) {
 						do {
 							p++;
 						} while (p < e && (*p == '\n' || *p == '\r' || *p == '\t' || *p == ' '));
 						/* We will only actually output a space if this is not immediately followed
 						 * by another valid encoded word */
 						space_pending = true;
+					} else {
+						space_pending = false;
 					}
 					continue;
 				}
diff --git a/ext/mbstring/tests/gh20674.phpt b/ext/mbstring/tests/gh20674.phpt
new file mode 100644
index 00000000000..2fb8206037d
--- /dev/null
+++ b/ext/mbstring/tests/gh20674.phpt
@@ -0,0 +1,40 @@
+--TEST--
+GH-20674 (mb_decode_mimeheader does not handle separator)
+--EXTENSIONS--
+mbstring
+--FILE--
+<?php
+
+$subject = '=?us-ascii?Q?The_PH?=  =?us-ascii?Q?P_8.5?=';
+var_dump(mb_decode_mimeheader($subject));
+
+// mb_decode_mimeheader's backward compatible for TAB(\t)
+$subject = "=?us-ascii?Q?The_PH?=\t=?us-ascii?Q?P_8.5?=";
+var_dump(mb_decode_mimeheader($subject));
+
+$subject = "=?us-ascii?Q?The_PH?=\t =?us-ascii?Q?P_8.5?=";
+var_dump(mb_decode_mimeheader($subject));
+
+$subject = "=?us-ascii?Q?The_PH?= \t =?us-ascii?Q?P_8.5?=";
+var_dump(mb_decode_mimeheader($subject));
+
+// from RFC 2047 https://www.ietf.org/rfc/rfc2047#section-8
+var_dump(mb_decode_mimeheader("(=?ISO-8859-1?Q?a?=)"));
+var_dump(mb_decode_mimeheader("(=?ISO-8859-1?Q?a?= b)"));
+var_dump(mb_decode_mimeheader("(=?ISO-8859-1?Q?a_b?=)"));
+var_dump(mb_decode_mimeheader("(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)"));
+var_dump(mb_decode_mimeheader("(=?ISO-8859-1?Q?a?=  =?ISO-8859-1?Q?b?=)"));
+var_dump(mb_decode_mimeheader("(=?ISO-8859-1?Q?a?=
+	=?ISO-8859-1?Q?b?=)"));
+?>
+--EXPECTF--
+string(11) "The PHP 8.5"
+string(11) "The PHP 8.5"
+string(11) "The PHP 8.5"
+string(11) "The PHP 8.5"
+string(3) "(a)"
+string(5) "(a b)"
+string(5) "(a b)"
+string(4) "(ab)"
+string(4) "(ab)"
+string(4) "(ab)"