Skip to content

Commit f07c193

Browse files
committed
mb_convert_encoding will not auto-detect input string as UUEncode, Base64, QPrint
In a2bc57e, mb_detect_encoding was modified to ensure it would never return 'UUENCODE', 'QPrint', or other non-encodings as the "detected text encoding". Before mb_detect_encoding was enhanced so that it could detect any supported text encoding, those were never returned, and they are not desired. Actually, we want to eventually remove them completely from mbstring, since PHP already contains other implementations of UUEncode, QPrint, Base64, and HTML entities. For more clarity on why we need to suppress UUEncode, etc. from being detected by mb_detect_encoding, the existing UUEncode implementation in mbstring *never* treats any input as erroneous. It just accepts everything. This means that it would *always* be treated as a valid choice by mb_detect_encoding, and would be returned in many, many cases where the input is obviously not UUEncoded. It turns out that the form of mb_convert_encoding where the user passes multiple candidate encodings (and mbstring auto-detects which one to use) was also affected by the same issue. Apply the same fix.
1 parent 069bbf3 commit f07c193

File tree

2 files changed

+30
-33
lines changed

2 files changed

+30
-33
lines changed

ext/mbstring/mbstring.c

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2491,6 +2491,23 @@ MBSTRING_API HashTable *php_mb_convert_encoding_recursive(HashTable *input, cons
24912491
}
24922492
/* }}} */
24932493

2494+
static void remove_non_encodings_from_elist(const mbfl_encoding **elist, size_t *size)
2495+
{
2496+
/* mbstring supports some 'text encodings' which aren't really text encodings
2497+
* at all, but really 'byte encodings', like Base64, QPrint, and so on.
2498+
* These should never be returned by `mb_detect_encoding`. */
2499+
int shift = 0;
2500+
for (int i = 0; i < *size; i++) {
2501+
const mbfl_encoding *encoding = elist[i];
2502+
if (encoding->no_encoding <= mbfl_no_encoding_charset_min) {
2503+
shift++; /* Remove this encoding from the list */
2504+
} else if (shift) {
2505+
elist[i - shift] = encoding;
2506+
}
2507+
}
2508+
*size -= shift;
2509+
}
2510+
24942511
/* {{{ Returns converted string in desired encoding */
24952512
PHP_FUNCTION(mb_convert_encoding)
24962513
{
@@ -2531,6 +2548,10 @@ PHP_FUNCTION(mb_convert_encoding)
25312548
free_from_encodings = 0;
25322549
}
25332550

2551+
if (num_from_encodings > 1) {
2552+
remove_non_encodings_from_elist(from_encodings, &num_from_encodings);
2553+
}
2554+
25342555
if (!num_from_encodings) {
25352556
efree(ZEND_VOIDP(from_encodings));
25362557
zend_argument_value_error(3, "must specify at least one encoding");
@@ -2664,23 +2685,6 @@ PHP_FUNCTION(mb_strtolower)
26642685
}
26652686
/* }}} */
26662687

2667-
static void remove_non_encodings_from_elist(const mbfl_encoding **elist, size_t *size)
2668-
{
2669-
/* mbstring supports some 'text encodings' which aren't really text encodings
2670-
* at all, but really 'byte encodings', like Base64, QPrint, and so on.
2671-
* These should never be returned by `mb_detect_encoding`. */
2672-
int shift = 0;
2673-
for (int i = 0; i < *size; i++) {
2674-
const mbfl_encoding *encoding = elist[i];
2675-
if (encoding->no_encoding <= mbfl_no_encoding_charset_min) {
2676-
shift++; /* Remove this encoding from the list */
2677-
} else if (shift) {
2678-
elist[i - shift] = encoding;
2679-
}
2680-
}
2681-
*size -= shift;
2682-
}
2683-
26842688
/* {{{ Encodings of the given string is returned (as a string) */
26852689
PHP_FUNCTION(mb_detect_encoding)
26862690
{

ext/mbstring/tests/mb_convert_encoding.phpt

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,24 @@ mbstring.language=Japanese
99
<?php
1010
// TODO: Add more tests
1111

12-
// SJIS string (BASE64 encoded)
1312
$sjis = base64_decode('k/qWe4zqg2WDTINYg2eCxYK3gUIwMTIzNIJUglWCVoJXgliBQg==');
14-
// JIS string (BASE64 encoded)
1513
$jis = base64_decode('GyRCRnxLXDhsJUYlLSU5JUgkRyQ5ISMbKEIwMTIzNBskQiM1IzYjNyM4IzkhIxsoQg==');
16-
// EUC-JP string
17-
$euc_jp = '日本語テキストです。0123456789。';
14+
$euc_jp = "\xC6\xFC\xCB\xDC\xB8\xEC\xA5\xC6\xA5\xAD\xA5\xB9\xA5\xC8\xA4\xC7\xA4\xB9\xA1\xA301234\xA3\xB5\xA3\xB6\xA3\xB7\xA3\xB8\xA3\xB9\xA1\xA3";
1815

1916
// Test with single "form encoding"
20-
// Note: For some reason it complains, results are different. Not researched.
2117
echo "== BASIC TEST ==\n";
22-
$s = $sjis;
23-
$s = bin2hex(mb_convert_encoding($s, 'EUC-JP', 'SJIS'));
18+
$s = bin2hex(mb_convert_encoding($sjis, 'EUC-JP', 'SJIS'));
2419
print("EUC-JP: $s\n"); // EUC-JP
2520

26-
$s = $jis;
27-
$s = bin2hex(mb_convert_encoding($s, 'EUC-JP', 'JIS'));
21+
$s = bin2hex(mb_convert_encoding($jis, 'EUC-JP', 'JIS'));
2822
print("EUC-JP: $s\n"); // EUC-JP
2923

30-
$s = $euc_jp;
31-
$s = mb_convert_encoding($s, 'SJIS', 'EUC-JP');
24+
$s = mb_convert_encoding($euc_jp, 'SJIS', 'EUC-JP');
3225
print("SJIS: ".base64_encode($s)."\n"); // SJIS
3326

34-
$s = $euc_jp;
35-
$s = mb_convert_encoding($s, 'JIS', 'EUC-JP');
27+
$s = mb_convert_encoding($euc_jp, 'JIS', 'EUC-JP');
3628
print("JIS: ".base64_encode($s)."\n"); // JIS
3729

38-
3930
// Using Encoding List Array
4031
echo "== STRING ENCODING LIST ==\n";
4132

@@ -52,11 +43,10 @@ $s = $euc_jp;
5243
$s = mb_convert_encoding($s, 'JIS', $a);
5344
print("JIS: ".base64_encode($s)."\n"); // JIS
5445

55-
5646
// Using Encoding List Array
5747
echo "== ARRAY ENCODING LIST ==\n";
5848

59-
$a = array(0=>'JIS', 1=>'UTF-8', 2=>'EUC-JP', 3=>'SJIS');
49+
$a = ['JIS', 'UTF-8', 'EUC-JP', 'SJIS'];
6050
$s = $jis;
6151
$s = bin2hex(mb_convert_encoding($s, 'EUC-JP', $a));
6252
print("EUC-JP: $s\n"); // EUC-JP
@@ -69,6 +59,8 @@ $s = $euc_jp;
6959
$s = mb_convert_encoding($s, 'JIS', $a);
7060
print("JIS: ".base64_encode($s)."\n"); // JIS
7161

62+
// Regression test for bug #81676
63+
echo "UTF-8: " . mb_convert_encoding('test', 'UTF-8', mb_list_encodings()), "\n";
7264

7365
// Using Detect Order
7466
echo "== DETECT ORDER ==\n";
@@ -117,6 +109,7 @@ JIS: GyRCRnxLXDhsJUYlLSU5JUgkRyQ5ISMbKEIwMTIzNBskQiM1IzYjNyM4IzkhIxsoQg==
117109
EUC-JP: c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3
118110
SJIS: k/qWe4zqg2WDTINYg2eCxYK3gUIwMTIzNIJUglWCVoJXgliBQg==
119111
JIS: GyRCRnxLXDhsJUYlLSU5JUgkRyQ5ISMbKEIwMTIzNBskQiM1IzYjNyM4IzkhIxsoQg==
112+
UTF-8: test
120113
== DETECT ORDER ==
121114
EUC-JP: c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3
122115
SJIS: k/qWe4zqg2WDTINYg2eCxYK3gUIwMTIzNIJUglWCVoJXgliBQg==

0 commit comments

Comments
 (0)