summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2015-05-09 18:59:10 -0700
committerStanislav Malyshev <stas@php.net>2015-05-09 18:59:10 -0700
commit1ceacc813aecb07fbda18f8c63c7a76792886d3d (patch)
treeec6c0bcba60165be85ed0de76dd9f77dffb1d75f
parentdd2692621dcc236fd463d045e737f4914ab53612 (diff)
parentf8f1d275cfb90744e7387db72ab1857c63c352d8 (diff)
downloadphp-git-1ceacc813aecb07fbda18f8c63c7a76792886d3d.tar.gz
Merge branch 'fix48147'
* fix48147: Fix #48147 - implement manual handling of //IGNORE for broken libc
-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 88e5abf97e..efde95e038 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 35e4d943d5..8042916c0d 100644
--- a/ext/iconv/iconv.c
+++ b/ext/iconv/iconv.c
@@ -535,6 +535,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, zend_string **out, const char *out_charset, const char *in_charset)
@@ -613,6 +631,7 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
size_t bsz, result = 0;
php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS;
zend_string *out_buf;
+ int ignore_ilseq = _php_check_ignore(out_charset);
*out = NULL;
@@ -636,6 +655,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) ""