]> granicus.if.org Git - php/commitdiff
Fix internal_encoding fallback in mbstring
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 16 Apr 2019 14:35:35 +0000 (16:35 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 17 Apr 2019 12:05:53 +0000 (14:05 +0200)
By introducing a hook that is called whenever one of
internal_encoding / input_encoding / output_encoding changes, so
that mbstring can adjust it's internal state.

This also makes internal_encoding work with zend multibyte.

16 files changed:
NEWS
Zend/tests/multibyte/bug68665.phpt
Zend/tests/multibyte/multibyte_encoding_001.phpt
Zend/tests/multibyte/multibyte_encoding_002.phpt
Zend/tests/multibyte/multibyte_encoding_003.phpt
Zend/tests/multibyte/multibyte_encoding_004.phpt
Zend/tests/multibyte/multibyte_encoding_005.phpt
ext/iconv/iconv.c
ext/mbstring/mb_gpc.c
ext/mbstring/mbstring.c
ext/mbstring/mbstring.h
ext/mbstring/tests/ini_encoding2.phpt
ext/mbstring/tests/internal_encoding.phpt [new file with mode: 0644]
ext/mbstring/tests/mb_internal_encoding_basic2.phpt
main/main.c
main/php.h

diff --git a/NEWS b/NEWS
index 63f7704f050f290be04c15d0d1c88bb8fb407ea2..08340c8536b051b3af8090cb5fdf3390ff3dd335 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -60,6 +60,9 @@ PHP                                                                        NEWS
 - LDAP:
   . Deprecated ldap_control_paged_result_response and ldap_control_paged_result
 
+- Mbstring:
+  . Fixed bug #77907 (mb-functions do not respect default_encoding). (Nikita)
+
 - Opcache:
   . Implemented preloading RFC: https://wiki.php.net/rfc/preload. (Dmitry)
 
index 74ff01da332d7e9cf419dbaadec6487c4a78e2ef..68467765709c6966262c34e4340d71a118b9aef7 100644 (file)
@@ -11,7 +11,7 @@ if (!extension_loaded("mbstring")) {
 ?>
 --INI--
 zend.multibyte=1
-mbstring.internal_encoding=big5
+internal_encoding=big5
 --FILE--
 <?php
 echo '\'hello';
index 38aa80a40a4266b7a56da91f0af5d73d9712e71e..1a094814ec2aa04b72967878417dc19deccbcff4 100644 (file)
@@ -11,7 +11,7 @@ if (!extension_loaded("mbstring")) {
 ?>
 --INI--
 zend.multibyte=1
-mbstring.internal_encoding=SJIS
+internal_encoding=SJIS
 --FILE--
 <?php
 declare(encoding='Shift_JIS');
index 6e1ad80c9f6ab25028193764c5e34bf23230273f..58ea015a6f230fc1cf51fc0f4b35beb09333a438 100644 (file)
@@ -11,7 +11,7 @@ if (!extension_loaded("mbstring")) {
 ?>
 --INI--
 zend.multibyte=1
-mbstring.internal_encoding=iso-8859-1
+internal_encoding=iso-8859-1
 --FILE--
 <?php
 print "Hello World\n";
index 0f873dd07cd13ec3e9f9877d41056d8604d459e7..ee861dbcc482bb117f7f09a8c35d7ddf620bc2c3 100644 (file)
Binary files a/Zend/tests/multibyte/multibyte_encoding_003.phpt and b/Zend/tests/multibyte/multibyte_encoding_003.phpt differ
index 6d121d668020098e666cfca48fdc2e614f907f55..1b4f4fecef2e0191c763be4e1e6cc1d0995955a0 100644 (file)
@@ -12,7 +12,7 @@ if (!extension_loaded("mbstring")) {
 --INI--
 zend.multibyte=1
 zend.script_encoding=Shift_JIS
-mbstring.internal_encoding=Shift_JIS
+internal_encoding=Shift_JIS
 --FILE--
 <?php
        function \97\\8e\\94\($\88ø\90\94)
index 6fee687483bbe12b8bb552e46e150e8f89f3d1d2..305175d0ccaebfbb8fbe4e5fa7ab00514acb6212 100644 (file)
@@ -13,7 +13,7 @@ if (!extension_loaded("mbstring")) {
 zend.multibyte=1
 mbstring.encoding_translation = On
 zend.script_encoding=Shift_JIS
-mbstring.internal_encoding=UTF-8
+internal_encoding=UTF-8
 --FILE--
 <?php
        function \97\\8e\\94\($\88ø\90\94)
index 62f7cb3af14974c1c075a5c3bf2f5766f343c136..7e8852cc47019ce41a2f81730e1dddb0df43e095 100644 (file)
@@ -338,37 +338,25 @@ PHP_MINFO_FUNCTION(miconv)
 }
 /* }}} */
 
-static char *get_internal_encoding(void) {
+static const char *get_internal_encoding(void) {
        if (ICONVG(internal_encoding) && ICONVG(internal_encoding)[0]) {
                return ICONVG(internal_encoding);
-       } else if (PG(internal_encoding) && PG(internal_encoding)[0]) {
-               return PG(internal_encoding);
-       } else if (SG(default_charset)) {
-               return SG(default_charset);
        }
-       return "";
+       return php_get_internal_encoding();
 }
 
-static char *get_input_encoding(void) {
+static const char *get_input_encoding(void) {
        if (ICONVG(input_encoding) && ICONVG(input_encoding)[0]) {
                return ICONVG(input_encoding);
-       } else if (PG(input_encoding) && PG(input_encoding)[0]) {
-               return PG(input_encoding);
-       } else if (SG(default_charset)) {
-               return SG(default_charset);
        }
-       return "";
+       return php_get_input_encoding();
 }
 
-static char *get_output_encoding(void) {
+static const char *get_output_encoding(void) {
        if (ICONVG(output_encoding) && ICONVG(output_encoding)[0]) {
                return ICONVG(output_encoding);
-       } else if (PG(output_encoding) && PG(output_encoding)[0]) {
-               return PG(output_encoding);
-       } else if (SG(default_charset)) {
-               return SG(default_charset);
        }
-       return "";
+       return php_get_output_encoding();
 }
 
 
@@ -2064,7 +2052,7 @@ static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset,
    Returns the character count of str */
 PHP_FUNCTION(iconv_strlen)
 {
-       char *charset = get_internal_encoding();
+       const char *charset = get_internal_encoding();
        size_t charset_len = 0;
        zend_string *str;
 
@@ -2096,7 +2084,7 @@ PHP_FUNCTION(iconv_strlen)
    Returns specified part of a string */
 PHP_FUNCTION(iconv_substr)
 {
-       char *charset = get_internal_encoding();
+       const char *charset = get_internal_encoding();
        size_t charset_len = 0;
        zend_string *str;
        zend_long offset, length = 0;
@@ -2135,7 +2123,7 @@ PHP_FUNCTION(iconv_substr)
    Finds position of first occurrence of needle within part of haystack beginning with offset */
 PHP_FUNCTION(iconv_strpos)
 {
-       char *charset = get_internal_encoding();
+       const char *charset = get_internal_encoding();
        size_t charset_len = 0, haystk_len;
        zend_string *haystk;
        zend_string *ndl;
@@ -2190,7 +2178,7 @@ PHP_FUNCTION(iconv_strpos)
    Finds position of last occurrence of needle within part of haystack beginning with offset */
 PHP_FUNCTION(iconv_strrpos)
 {
-       char *charset = get_internal_encoding();
+       const char *charset = get_internal_encoding();
        size_t charset_len = 0;
        zend_string *haystk;
        zend_string *ndl;
@@ -2331,7 +2319,7 @@ PHP_FUNCTION(iconv_mime_encode)
 PHP_FUNCTION(iconv_mime_decode)
 {
        zend_string *encoded_str;
-       char *charset = get_internal_encoding();
+       const char *charset = get_internal_encoding();
        size_t charset_len = 0;
        zend_long mode = 0;
 
@@ -2371,7 +2359,7 @@ PHP_FUNCTION(iconv_mime_decode)
 PHP_FUNCTION(iconv_mime_decode_headers)
 {
        zend_string *encoded_str;
-       char *charset = get_internal_encoding();
+       const char *charset = get_internal_encoding();
        size_t charset_len = 0;
        zend_long mode = 0;
        char *enc_str_tmp;
index 2a6a9b23bb96581271a8693bcc5f4b9e54629514..c57e2b6be1b95baca3762de14e76a12edc41bea6 100644 (file)
@@ -58,11 +58,6 @@ MBSTRING_API SAPI_TREAT_DATA_FUNC(mbstr_treat_data)
        const mbfl_encoding *detected;
        php_mb_encoding_handler_info_t info;
 
-       if (arg != PARSE_STRING) {
-               char *value = MBSTRG(internal_encoding_name);
-               _php_mb_ini_mbstring_internal_encoding_set(value, value ? strlen(value): 0);
-       }
-
        if (!MBSTRG(encoding_translation)) {
                php_default_treat_data(arg, str, destArray);
                return;
index ee65b4107be20cc78881538f4da4e81c658db85b..61e47630efd51931d960984ffbf023ef403e7310 100644 (file)
@@ -615,34 +615,6 @@ ZEND_TSRMLS_CACHE_DEFINE()
 ZEND_GET_MODULE(mbstring)
 #endif
 
-static char *get_internal_encoding(void) {
-       if (PG(internal_encoding) && PG(internal_encoding)[0]) {
-               return PG(internal_encoding);
-       } else if (SG(default_charset)) {
-               return SG(default_charset);
-       }
-       return "";
-}
-
-static char *get_input_encoding(void) {
-       if (PG(input_encoding) && PG(input_encoding)[0]) {
-               return PG(input_encoding);
-       } else if (SG(default_charset)) {
-               return SG(default_charset);
-       }
-       return "";
-}
-
-static char *get_output_encoding(void) {
-       if (PG(output_encoding) && PG(output_encoding)[0]) {
-               return PG(output_encoding);
-       } else if (SG(default_charset)) {
-               return SG(default_charset);
-       }
-       return "";
-}
-
-
 /* {{{ allocators */
 static void *_php_mb_allocators_malloc(size_t sz)
 {
@@ -1289,77 +1261,70 @@ static PHP_INI_MH(OnUpdate_mbstring_detect_order)
 }
 /* }}} */
 
-/* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_input) */
-static PHP_INI_MH(OnUpdate_mbstring_http_input)
-{
+static int _php_mb_ini_mbstring_http_input_set(const char *new_value, size_t new_value_length) {
        const mbfl_encoding **list;
        size_t size;
-
-       if (!new_value || !ZSTR_VAL(new_value)) {
-               if (MBSTRG(http_input_list)) {
-                       pefree(MBSTRG(http_input_list), 1);
-               }
-               if (SUCCESS == php_mb_parse_encoding_list(get_input_encoding(), strlen(get_input_encoding())+1, &list, &size, 1)) {
-                       MBSTRG(http_input_list) = list;
-                       MBSTRG(http_input_list_size) = size;
-                       return SUCCESS;
-               }
-               MBSTRG(http_input_list) = NULL;
-               MBSTRG(http_input_list_size) = 0;
-               return SUCCESS;
-       }
-
-       if (FAILURE == php_mb_parse_encoding_list(ZSTR_VAL(new_value), ZSTR_LEN(new_value), &list, &size, 1)) {
+       if (FAILURE == php_mb_parse_encoding_list(new_value, new_value_length, &list, &size, 1)) {
                return FAILURE;
        }
-
        if (MBSTRG(http_input_list)) {
                pefree(MBSTRG(http_input_list), 1);
        }
        MBSTRG(http_input_list) = list;
        MBSTRG(http_input_list_size) = size;
+       return SUCCESS;
+}
 
+/* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_input) */
+static PHP_INI_MH(OnUpdate_mbstring_http_input)
+{
        if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
                php_error_docref("ref.mbstring", E_DEPRECATED, "Use of mbstring.http_input is deprecated");
        }
 
-       return SUCCESS;
+       if (!new_value || !ZSTR_VAL(new_value)) {
+               const char *encoding = php_get_input_encoding();
+               MBSTRG(http_input_set) = 0;
+               _php_mb_ini_mbstring_http_input_set(encoding, strlen(encoding));
+               return SUCCESS;
+       }
+
+       MBSTRG(http_input_set) = 1;
+       return _php_mb_ini_mbstring_http_input_set(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
 }
 /* }}} */
 
-/* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_output) */
-static PHP_INI_MH(OnUpdate_mbstring_http_output)
-{
-       const mbfl_encoding *encoding;
-
-       if (new_value == NULL || ZSTR_LEN(new_value) == 0) {
-               encoding = mbfl_name2encoding(get_output_encoding());
-               if (!encoding) {
-                       MBSTRG(http_output_encoding) = &mbfl_encoding_pass;
-                       MBSTRG(current_http_output_encoding) = &mbfl_encoding_pass;
-                       return SUCCESS;
-               }
-       } else {
-               encoding = mbfl_name2encoding(ZSTR_VAL(new_value));
-               if (!encoding) {
-                       MBSTRG(http_output_encoding) = &mbfl_encoding_pass;
-                       MBSTRG(current_http_output_encoding) = &mbfl_encoding_pass;
-                       return FAILURE;
-               }
+static int _php_mb_ini_mbstring_http_output_set(const char *new_value) {
+       const mbfl_encoding *encoding = mbfl_name2encoding(new_value);
+       if (!encoding) {
+               return FAILURE;
        }
+
        MBSTRG(http_output_encoding) = encoding;
        MBSTRG(current_http_output_encoding) = encoding;
+       return SUCCESS;
+}
 
+/* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_output) */
+static PHP_INI_MH(OnUpdate_mbstring_http_output)
+{
        if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
                php_error_docref("ref.mbstring", E_DEPRECATED, "Use of mbstring.http_output is deprecated");
        }
 
-       return SUCCESS;
+       if (new_value == NULL || ZSTR_LEN(new_value) == 0) {
+               MBSTRG(http_output_set) = 0;
+               _php_mb_ini_mbstring_http_output_set(php_get_output_encoding());
+               return SUCCESS;
+       }
+
+       MBSTRG(http_output_set) = 1;
+       return _php_mb_ini_mbstring_http_output_set(ZSTR_VAL(new_value));
 }
 /* }}} */
 
 /* {{{ static _php_mb_ini_mbstring_internal_encoding_set */
-int _php_mb_ini_mbstring_internal_encoding_set(const char *new_value, size_t new_value_length)
+static int _php_mb_ini_mbstring_internal_encoding_set(const char *new_value, size_t new_value_length)
 {
        const mbfl_encoding *encoding;
 
@@ -1395,20 +1360,13 @@ static PHP_INI_MH(OnUpdate_mbstring_internal_encoding)
                return FAILURE;
        }
 
-       if (stage & (PHP_INI_STAGE_STARTUP | PHP_INI_STAGE_SHUTDOWN | PHP_INI_STAGE_RUNTIME)) {
-               if (new_value && ZSTR_LEN(new_value)) {
-                       return _php_mb_ini_mbstring_internal_encoding_set(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
-               } else {
-                       return _php_mb_ini_mbstring_internal_encoding_set(get_internal_encoding(), strlen(get_internal_encoding())+1);
-               }
+       if (new_value && ZSTR_LEN(new_value)) {
+               MBSTRG(internal_encoding_set) = 1;
+               return _php_mb_ini_mbstring_internal_encoding_set(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
        } else {
-               /* the corresponding mbstring globals needs to be set according to the
-                * ini value in the later stage because it never falls back to the
-                * default value if 1. no value for mbstring.internal_encoding is given,
-                * 2. mbstring.language directive is processed in per-dir or runtime
-                * context and 3. call to the handler for mbstring.language is done
-                * after mbstring.internal_encoding is handled. */
-               return SUCCESS;
+               const char *encoding = php_get_internal_encoding();
+               MBSTRG(internal_encoding_set) = 0;
+               return _php_mb_ini_mbstring_internal_encoding_set(encoding, strlen(encoding));
        }
 }
 /* }}} */
@@ -1532,6 +1490,24 @@ PHP_INI_BEGIN()
 PHP_INI_END()
 /* }}} */
 
+static void mbstring_internal_encoding_changed_hook() {
+       /* One of the internal_encoding / input_encoding / output_encoding ini settings changed. */
+       if (!MBSTRG(internal_encoding_set)) {
+               const char *encoding = php_get_internal_encoding();
+               _php_mb_ini_mbstring_internal_encoding_set(encoding, strlen(encoding));
+       }
+
+       if (!MBSTRG(http_output_set)) {
+               const char *encoding = php_get_output_encoding();
+               _php_mb_ini_mbstring_http_output_set(encoding);
+       }
+
+       if (!MBSTRG(http_input_set)) {
+               const char *encoding = php_get_input_encoding();
+               _php_mb_ini_mbstring_http_input_set(encoding, strlen(encoding));
+       }
+}
+
 /* {{{ module global initialize handler */
 static PHP_GINIT_FUNCTION(mbstring)
 {
@@ -1572,6 +1548,9 @@ ZEND_TSRMLS_CACHE_UPDATE();
 #endif
        mbstring_globals->last_used_encoding_name = NULL;
        mbstring_globals->last_used_encoding = NULL;
+       mbstring_globals->internal_encoding_set = 0;
+       mbstring_globals->http_output_set = 0;
+       mbstring_globals->http_input_set = 0;
 }
 /* }}} */
 
@@ -1603,6 +1582,11 @@ ZEND_TSRMLS_CACHE_UPDATE();
 
        REGISTER_INI_ENTRIES();
 
+       /* We assume that we're the only user of the hook. */
+       ZEND_ASSERT(php_internal_encoding_changed == NULL);
+       php_internal_encoding_changed = mbstring_internal_encoding_changed_hook;
+       mbstring_internal_encoding_changed_hook();
+
        /* This is a global handler. Should not be set in a per-request handler. */
        sapi_register_treat_data(mbstr_treat_data);
 
@@ -1763,6 +1747,10 @@ PHP_RSHUTDOWN_FUNCTION(mbstring)
                MBSTRG(last_used_encoding_name) = NULL;
        }
 
+       MBSTRG(internal_encoding_set) = 0;
+       MBSTRG(http_output_set) = 0;
+       MBSTRG(http_input_set) = 0;
+
 #if HAVE_MBREGEX
        PHP_RSHUTDOWN(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
 #endif
@@ -1846,6 +1834,7 @@ PHP_FUNCTION(mb_internal_encoding)
                        RETURN_FALSE;
                } else {
                        MBSTRG(current_internal_encoding) = encoding;
+                       MBSTRG(internal_encoding_set) = 1;
                        RETURN_TRUE;
                }
        }
@@ -1969,6 +1958,7 @@ PHP_FUNCTION(mb_http_output)
                        php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", name);
                        RETURN_FALSE;
                } else {
+                       MBSTRG(http_output_set) = 1;
                        MBSTRG(current_http_output_encoding) = encoding;
                        RETURN_TRUE;
                }
index cd882c1c03cc7292c196210cf92b72dfafa85303..5a713e549693c6e0eae4b8a4d50c95c13a5d8e62 100644 (file)
@@ -130,9 +130,6 @@ MBSTRING_API size_t php_mb_mbchar_bytes(const char *s);
 MBSTRING_API size_t php_mb_stripos(int mode, const char *old_haystack, size_t old_haystack_len, const char *old_needle, size_t old_needle_len, zend_long offset, zend_string *from_encoding);
 MBSTRING_API int php_mb_check_encoding(const char *input, size_t length, const char *enc);
 
-/* internal use only */
-int _php_mb_ini_mbstring_internal_encoding_set(const char *new_value, size_t new_value_length);
-
 ZEND_BEGIN_MODULE_GLOBALS(mbstring)
        char *internal_encoding_name;
        const mbfl_encoding *internal_encoding;
@@ -169,6 +166,10 @@ ZEND_BEGIN_MODULE_GLOBALS(mbstring)
 #endif
        zend_string *last_used_encoding_name;
        const mbfl_encoding *last_used_encoding;
+       /* Whether an explicit internal_encoding / http_output / http_input encoding was set. */
+       zend_bool internal_encoding_set;
+       zend_bool http_output_set;
+       zend_bool http_input_set;
 ZEND_END_MODULE_GLOBALS(mbstring)
 
 #define MB_OVERLOAD_MAIL 1
index f3728486aec9a361332e289c8a4454aa5ce0ae27..64cc23ec91f8adf7453edbb29ffc3cef17eb38c2 100644 (file)
@@ -50,7 +50,7 @@ string(6) "EUC-JP"
 string(0) ""
 string(0) ""
 string(0) ""
-string(5) "UTF-8"
+string(6) "EUC-JP"
 string(0) ""
 string(0) ""
 Setting INI
diff --git a/ext/mbstring/tests/internal_encoding.phpt b/ext/mbstring/tests/internal_encoding.phpt
new file mode 100644 (file)
index 0000000..3d097ac
--- /dev/null
@@ -0,0 +1,66 @@
+--TEST--
+Check that "internal_encoding" ini is picked up by mbstring
+--INI--
+internal_encoding=iso-8859-1
+--FILE--
+<?php
+
+var_dump(mb_internal_encoding());
+var_dump(mb_strlen("\xc3\xb6"));
+
+ini_set('mbstring.internal_encoding', 'utf-8');
+
+var_dump(mb_internal_encoding());
+var_dump(mb_strlen("\xc3\xb6"));
+
+// mbstring.internal_encoding is set, this has no effect
+ini_set('internal_encoding', 'iso-8859-2');
+
+var_dump(mb_internal_encoding());
+var_dump(mb_strlen("\xc3\xb6"));
+
+// mbstring.internal_encoding is unset, pick up internal_encoding again
+ini_set('mbstring.internal_encoding', '');
+
+var_dump(mb_internal_encoding());
+var_dump(mb_strlen("\xc3\xb6"));
+
+mb_internal_encoding('utf-8');
+
+var_dump(mb_internal_encoding());
+var_dump(mb_strlen("\xc3\xb6"));
+
+// mb_internal_encoding() is set, this has no effect
+ini_set('internal_encoding', 'iso-8859-3');
+
+var_dump(mb_internal_encoding());
+var_dump(mb_strlen("\xc3\xb6"));
+
+// mbstring.internal_encoding is unset, pick up internal_encoding again
+ini_set('mbstring.internal_encoding', '');
+
+var_dump(mb_internal_encoding());
+var_dump(mb_strlen("\xc3\xb6"));
+
+?>
+--EXPECTF--
+string(10) "ISO-8859-1"
+int(2)
+
+Deprecated: ini_set(): Use of mbstring.internal_encoding is deprecated in %s on line %d
+string(5) "UTF-8"
+int(1)
+string(5) "UTF-8"
+int(1)
+
+Deprecated: ini_set(): Use of mbstring.internal_encoding is deprecated in %s on line %d
+string(10) "ISO-8859-2"
+int(2)
+string(5) "UTF-8"
+int(1)
+string(5) "UTF-8"
+int(1)
+
+Deprecated: ini_set(): Use of mbstring.internal_encoding is deprecated in %s on line %d
+string(10) "ISO-8859-3"
+int(2)
index 8090b47be58f640288e7130b171718a2a3155d01..99b92027e9058c903dc1dcf8278ff792b31f7699 100644 (file)
@@ -47,7 +47,7 @@ string(10) "ISO-8859-1"
 string(0) ""
 string(0) ""
 string(0) ""
-string(5) "UTF-8"
+string(10) "ISO-8859-1"
 bool(true)
 string(5) "UTF-8"
 Done
index 5eb34b7fa4e95f0124d85d9974419c9d5fabf524..f021f22af5b72ba61b4eb6f75073d7d5e5003e87 100644 (file)
@@ -578,12 +578,44 @@ static PHP_INI_DISP(display_errors_mode)
 }
 /* }}} */
 
+PHPAPI const char *php_get_internal_encoding() {
+       if (PG(internal_encoding) && PG(internal_encoding)[0]) {
+               return PG(internal_encoding);
+       } else if (SG(default_charset)) {
+               return SG(default_charset);
+       }
+       return "";
+}
+
+PHPAPI const char *php_get_input_encoding() {
+       if (PG(input_encoding) && PG(input_encoding)[0]) {
+               return PG(input_encoding);
+       } else if (SG(default_charset)) {
+               return SG(default_charset);
+       }
+       return "";
+}
+
+PHPAPI const char *php_get_output_encoding() {
+       if (PG(output_encoding) && PG(output_encoding)[0]) {
+               return PG(output_encoding);
+       } else if (SG(default_charset)) {
+               return SG(default_charset);
+       }
+       return "";
+}
+
+PHPAPI void (*php_internal_encoding_changed)(void) = NULL;
+
 /* {{{ PHP_INI_MH
  */
 static PHP_INI_MH(OnUpdateDefaultCharset)
 {
        if (new_value) {
                OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
+               if (php_internal_encoding_changed) {
+                       php_internal_encoding_changed();
+               }
 #ifdef PHP_WIN32
                php_win32_cp_do_update(ZSTR_VAL(new_value));
 #endif
@@ -598,6 +630,9 @@ static PHP_INI_MH(OnUpdateInternalEncoding)
 {
        if (new_value) {
                OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
+               if (php_internal_encoding_changed) {
+                       php_internal_encoding_changed();
+               }
 #ifdef PHP_WIN32
                php_win32_cp_do_update(ZSTR_VAL(new_value));
 #endif
@@ -612,6 +647,9 @@ static PHP_INI_MH(OnUpdateInputEncoding)
 {
        if (new_value) {
                OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
+               if (php_internal_encoding_changed) {
+                       php_internal_encoding_changed();
+               }
 #ifdef PHP_WIN32
                php_win32_cp_do_update(NULL);
 #endif
@@ -626,6 +664,9 @@ static PHP_INI_MH(OnUpdateOutputEncoding)
 {
        if (new_value) {
                OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
+               if (php_internal_encoding_changed) {
+                       php_internal_encoding_changed();
+               }
 #ifdef PHP_WIN32
                php_win32_cp_do_update(NULL);
 #endif
index 48b4633879c03d215a1737a7fc44fc2044ff0ea5..be9917922a3d78ae6d426fc472de5ff7dd971ca6 100644 (file)
@@ -371,6 +371,11 @@ PHPAPI int php_mergesort(void *base, size_t nmemb, size_t size, int (*cmp)(const
 PHPAPI void php_register_pre_request_shutdown(void (*func)(void *), void *userdata);
 PHPAPI void php_com_initialize(void);
 PHPAPI char *php_get_current_user(void);
+
+PHPAPI const char *php_get_internal_encoding(void);
+PHPAPI const char *php_get_input_encoding(void);
+PHPAPI const char *php_get_output_encoding(void);
+PHPAPI extern void (*php_internal_encoding_changed)(void);
 END_EXTERN_C()
 
 /* PHP-named Zend macro wrappers */