Skip to content

Commit 33594b7

Browse files
committed
Merge branch 'PHP-5.5' into PHP-5.6
* PHP-5.5: Fix #48147 - implement manual handling of //IGNORE for broken libc
2 parents 329513c + 473ec53 commit 33594b7

File tree

4 files changed

+95
-4
lines changed

4 files changed

+95
-4
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ PHP NEWS
2020
. Fixed bug #69472 (php_sys_readlink ignores misc errors from
2121
GetFinalPathNameByHandleA). (Jan Starke)
2222

23+
- Iconv:
24+
. Fixed bug #48147 (iconv with //IGNORE cuts the string). (Stas)
25+
2326
- ODBC:
2427
. Fixed bug #69354 (Incorrect use of SQLColAttributes with ODBC 3.0).
2528
(Anatol)

ext/iconv/config.m4

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ if test "$PHP_ICONV" != "no"; then
3535
PHP_ICONV_H_PATH="$PHP_ICONV_PREFIX/include/giconv.h"
3636
else
3737
PHP_ICONV_H_PATH="$PHP_ICONV_PREFIX/include/iconv.h"
38-
fi
38+
fi
3939

4040
AC_MSG_CHECKING([if iconv is glibc's])
4141
AC_TRY_LINK([#include <gnu/libc-version.h>],[gnu_get_libc_version();],
@@ -53,8 +53,8 @@ if test "$PHP_ICONV" != "no"; then
5353
AC_TRY_RUN([
5454
#include <$PHP_ICONV_H_PATH>
5555
int main() {
56-
printf("%d", _libiconv_version);
57-
return 0;
56+
printf("%d", _libiconv_version);
57+
return 0;
5858
}
5959
],[
6060
AC_MSG_RESULT(yes)
@@ -138,7 +138,7 @@ int main() {
138138
if (cd == (iconv_t)(-1)) {
139139
if (errno == EINVAL) {
140140
return 0;
141-
} else {
141+
} else {
142142
return 1;
143143
}
144144
}
@@ -159,6 +159,37 @@ int main() {
159159
AC_DEFINE([ICONV_SUPPORTS_ERRNO],0,[Whether iconv supports error no or not])
160160
])
161161

162+
AC_MSG_CHECKING([if iconv supports //IGNORE])
163+
AC_TRY_RUN([
164+
#include <$PHP_ICONV_H_PATH>
165+
#include <stdlib.h>
166+
167+
int main() {
168+
iconv_t cd = iconv_open( "UTF-8//IGNORE", "UTF-8" );
169+
char *in_p = "\xC3\xC3\xC3\xB8";
170+
size_t in_left = 4, out_left = 4096;
171+
char *out = malloc(out_left);
172+
char *out_p = out;
173+
size_t result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
174+
if(result == (size_t)-1) {
175+
return 1;
176+
}
177+
return 0;
178+
}
179+
],[
180+
AC_MSG_RESULT(yes)
181+
PHP_DEFINE([ICONV_BROKEN_IGNORE],0,[ext/iconv])
182+
AC_DEFINE([ICONV_BROKEN_IGNORE],0,[Whether iconv supports IGNORE])
183+
],[
184+
AC_MSG_RESULT(no)
185+
PHP_DEFINE([ICONV_BROKEN_IGNORE],1,[ext/iconv])
186+
AC_DEFINE([ICONV_BROKEN_IGNORE],1,[Whether iconv supports IGNORE])
187+
],[
188+
AC_MSG_RESULT(no, cross-compiling)
189+
PHP_DEFINE([ICONV_SUPPORTS_ERRNO],0,[ext/iconv])
190+
AC_DEFINE([ICONV_SUPPORTS_ERRNO],0,[Whether iconv supports IGNORE])
191+
])
192+
162193
AC_MSG_CHECKING([if your cpp allows macro usage in include lines])
163194
AC_TRY_COMPILE([
164195
#define FOO <$PHP_ICONV_H_PATH>

ext/iconv/iconv.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,24 @@ static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd
529529
}
530530
/* }}} */
531531

532+
/* {{{ */
533+
#if ICONV_BROKEN_IGNORE
534+
static int _php_check_ignore(const char *charset)
535+
{
536+
size_t clen = strlen(charset);
537+
if (clen >= 9 && strcmp("//IGNORE", charset+clen-8) == 0) {
538+
return 1;
539+
}
540+
if (clen >= 19 && strcmp("//IGNORE//TRANSLIT", charset+clen-18) == 0) {
541+
return 1;
542+
}
543+
return 0;
544+
}
545+
#else
546+
#define _php_check_ignore(x) (0)
547+
#endif
548+
/* }}} */
549+
532550
/* {{{ php_iconv_string()
533551
*/
534552
PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
@@ -610,6 +628,7 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
610628
char *out_p, *out_buf, *tmp_buf;
611629
size_t bsz, result = 0;
612630
php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS;
631+
int ignore_ilseq = _php_check_ignore(out_charset);
613632

614633
*out = NULL;
615634
*out_len = 0;
@@ -634,6 +653,17 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
634653
result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
635654
out_size = bsz - out_left;
636655
if (result == (size_t)(-1)) {
656+
if (ignore_ilseq && errno == EILSEQ) {
657+
if (in_left <= 1) {
658+
result = 0;
659+
} else {
660+
errno = 0;
661+
in_p++;
662+
in_left--;
663+
continue;
664+
}
665+
}
666+
637667
if (errno == E2BIG && in_left > 0) {
638668
/* converted string is longer than out buffer */
639669
bsz += in_len;

ext/iconv/tests/bug48147.phpt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Bug #48147 (iconv with //IGNORE cuts the string)
3+
--SKIPIF--
4+
<?php extension_loaded('iconv') or die('skip iconv extension is not available'); ?>
5+
--FILE--
6+
<?php
7+
$text = "aa\xC3\xC3\xC3\xB8aa";
8+
var_dump(iconv("UTF-8", "UTF-8", $text));
9+
var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", $text)));
10+
// only invalid
11+
var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "\xC3")));
12+
// start invalid
13+
var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "\xC3\xC3\xC3\xB8aa")));
14+
// finish invalid
15+
var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "aa\xC3\xC3\xC3")));
16+
?>
17+
--EXPECTF--
18+
Notice: iconv(): Detected an illegal character in input string in %s on line %d
19+
bool(false)
20+
string(10) "aa%C3%B8aa"
21+
22+
Notice: iconv(): Detected an incomplete multibyte character in input string in %s on line %d
23+
string(0) ""
24+
string(8) "%C3%B8aa"
25+
26+
Notice: iconv(): Detected an incomplete multibyte character in input string in %s on line %d
27+
string(0) ""

0 commit comments

Comments
 (0)