summaryrefslogtreecommitdiff
path: root/ext/iconv
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2015-05-08 00:03:54 -0700
committerStanislav Malyshev <stas@php.net>2015-05-09 18:54:40 -0700
commit473ec539a1c3d242c8b171dd6a5a98fa17e05c13 (patch)
tree3cee3463971709735b037dc12ca7527d2612a118 /ext/iconv
parent8026001943109dea3f908b8dd0720a0de9781af6 (diff)
downloadphp-git-473ec539a1c3d242c8b171dd6a5a98fa17e05c13.tar.gz
Fix #48147 - implement manual handling of //IGNORE for broken libc
Conflicts: ext/iconv/iconv.c
Diffstat (limited to 'ext/iconv')
-rw-r--r--ext/iconv/config.m439
-rw-r--r--ext/iconv/iconv.c30
-rw-r--r--ext/iconv/tests/bug48147.phpt27
3 files changed, 92 insertions, 4 deletions
diff --git a/ext/iconv/config.m4 b/ext/iconv/config.m4
index 10d21ccc6d..fce59931b9 100644
--- a/ext/iconv/config.m4
+++ b/ext/iconv/config.m4
@@ -35,7 +35,7 @@ if test "$PHP_ICONV" != "no"; then
PHP_ICONV_H_PATH="$PHP_ICONV_PREFIX/include/giconv.h"
else
PHP_ICONV_H_PATH="$PHP_ICONV_PREFIX/include/iconv.h"
- fi
+ fi
AC_MSG_CHECKING([if iconv is glibc's])
AC_TRY_LINK([#include <gnu/libc-version.h>],[gnu_get_libc_version();],
@@ -53,8 +53,8 @@ if test "$PHP_ICONV" != "no"; then
AC_TRY_RUN([
#include <$PHP_ICONV_H_PATH>
int main() {
- printf("%d", _libiconv_version);
- return 0;
+ printf("%d", _libiconv_version);
+ return 0;
}
],[
AC_MSG_RESULT(yes)
@@ -138,7 +138,7 @@ int main() {
if (cd == (iconv_t)(-1)) {
if (errno == EINVAL) {
return 0;
- } else {
+ } else {
return 1;
}
}
@@ -159,6 +159,37 @@ int main() {
AC_DEFINE([ICONV_SUPPORTS_ERRNO],0,[Whether iconv supports error no or not])
])
+ AC_MSG_CHECKING([if iconv supports //IGNORE])
+ AC_TRY_RUN([
+#include <$PHP_ICONV_H_PATH>
+#include <stdlib.h>
+
+int main() {
+ iconv_t cd = iconv_open( "UTF-8//IGNORE", "UTF-8" );
+ char *in_p = "\xC3\xC3\xC3\xB8";
+ size_t in_left = 4, out_left = 4096;
+ char *out = malloc(out_left);
+ char *out_p = out;
+ size_t result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
+ if(result == (size_t)-1) {
+ return 1;
+ }
+ return 0;
+}
+ ],[
+ AC_MSG_RESULT(yes)
+ PHP_DEFINE([ICONV_BROKEN_IGNORE],0,[ext/iconv])
+ AC_DEFINE([ICONV_BROKEN_IGNORE],0,[Whether iconv supports IGNORE])
+ ],[
+ AC_MSG_RESULT(no)
+ PHP_DEFINE([ICONV_BROKEN_IGNORE],1,[ext/iconv])
+ AC_DEFINE([ICONV_BROKEN_IGNORE],1,[Whether iconv supports IGNORE])
+ ],[
+ AC_MSG_RESULT(no, cross-compiling)
+ PHP_DEFINE([ICONV_SUPPORTS_ERRNO],0,[ext/iconv])
+ AC_DEFINE([ICONV_SUPPORTS_ERRNO],0,[Whether iconv supports IGNORE])
+ ])
+
AC_MSG_CHECKING([if your cpp allows macro usage in include lines])
AC_TRY_COMPILE([
#define FOO <$PHP_ICONV_H_PATH>
diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c
index 12127d8c8f..5921d47597 100644
--- a/ext/iconv/iconv.c
+++ b/ext/iconv/iconv.c
@@ -464,6 +464,24 @@ static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd
}
/* }}} */
+/* {{{ */
+#if ICONV_BROKEN_IGNORE
+static int _php_check_ignore(const char *charset)
+{
+ size_t clen = strlen(charset);
+ if (clen >= 9 && strcmp("//IGNORE", charset+clen-8) == 0) {
+ return 1;
+ }
+ if (clen >= 19 && strcmp("//IGNORE//TRANSLIT", charset+clen-18) == 0) {
+ return 1;
+ }
+ return 0;
+}
+#else
+#define _php_check_ignore(x) (0)
+#endif
+/* }}} */
+
/* {{{ php_iconv_string()
*/
PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
@@ -545,6 +563,7 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
char *out_p, *out_buf, *tmp_buf;
size_t bsz, result = 0;
php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS;
+ int ignore_ilseq = _php_check_ignore(out_charset);
*out = NULL;
*out_len = 0;
@@ -569,6 +588,17 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
out_size = bsz - out_left;
if (result == (size_t)(-1)) {
+ if (ignore_ilseq && errno == EILSEQ) {
+ if (in_left <= 1) {
+ result = 0;
+ } else {
+ errno = 0;
+ in_p++;
+ in_left--;
+ continue;
+ }
+ }
+
if (errno == E2BIG && in_left > 0) {
/* converted string is longer than out buffer */
bsz += in_len;
diff --git a/ext/iconv/tests/bug48147.phpt b/ext/iconv/tests/bug48147.phpt
new file mode 100644
index 0000000000..342f920093
--- /dev/null
+++ b/ext/iconv/tests/bug48147.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #48147 (iconv with //IGNORE cuts the string)
+--SKIPIF--
+<?php extension_loaded('iconv') or die('skip iconv extension is not available'); ?>
+--FILE--
+<?php
+$text = "aa\xC3\xC3\xC3\xB8aa";
+var_dump(iconv("UTF-8", "UTF-8", $text));
+var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", $text)));
+// only invalid
+var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "\xC3")));
+// start invalid
+var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "\xC3\xC3\xC3\xB8aa")));
+// finish invalid
+var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "aa\xC3\xC3\xC3")));
+?>
+--EXPECTF--
+Notice: iconv(): Detected an illegal character in input string in %s on line %d
+bool(false)
+string(10) "aa%C3%B8aa"
+
+Notice: iconv(): Detected an incomplete multibyte character in input string in %s on line %d
+string(0) ""
+string(8) "%C3%B8aa"
+
+Notice: iconv(): Detected an incomplete multibyte character in input string in %s on line %d
+string(0) ""