Skip to content

Commit

Permalink
Fix bug #81598: Use C.UTF-8 as LC_CTYPE locale by default
Browse files Browse the repository at this point in the history
Unfortunately, libedit is locale based and does not accept UTF-8
input when the C locale is used. This patch switches the default
locale to C.UTF-8 instead (if it is available). This makes libedit
work and I believe it shouldn't affect behavior of single-byte
locale-dependent functions that PHP otherwise uses.

Closes GH-7635.
  • Loading branch information
nikic committed Dec 5, 2021
1 parent 15e7e57 commit 26e4244
Show file tree
Hide file tree
Showing 7 changed files with 20 additions and 3 deletions.
4 changes: 4 additions & 0 deletions NEWS
Expand Up @@ -15,6 +15,10 @@ PHP NEWS
(devnexen)
. Introduced MYSQLI_IS_MARIADB. (devnexen)

- Readline:
. Fixed bug #81598 (Cannot input unicode characters in PHP 8 interactive
shell). (Nikita)

- Reflection:
. Fixed bug #81681 (ReflectionEnum throwing exceptions). (cmb)

Expand Down
4 changes: 2 additions & 2 deletions Zend/tests/lc_ctype_inheritance.phpt
Expand Up @@ -16,8 +16,8 @@ var_dump(setlocale(LC_CTYPE, "de_DE", "de-DE") !== false);
var_dump(bin2hex(strtoupper("\xe4")));
var_dump(preg_match('/\w/', "\xe4"));
?>
--EXPECT--
string(1) "C"
--EXPECTF--
string(%d) "C%r(\.UTF-8)?%r"
string(2) "e4"
int(0)
bool(true)
Expand Down
9 changes: 9 additions & 0 deletions Zend/zend_operators.c
Expand Up @@ -2662,6 +2662,15 @@ ZEND_API void zend_update_current_locale(void) /* {{{ */
}
/* }}} */

ZEND_API void zend_reset_lc_ctype_locale(void)
{
/* Use the C.UTF-8 locale so that readline can process UTF-8 input, while not interfering
* with single-byte locale-dependent functions used by PHP. */
if (!setlocale(LC_CTYPE, "C.UTF-8")) {
setlocale(LC_CTYPE, "C");
}
}

static zend_always_inline void zend_str_tolower_impl(char *dest, const char *str, size_t length) /* {{{ */ {
unsigned char *p = (unsigned char*)str;
unsigned char *q = (unsigned char*)dest;
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_operators.h
Expand Up @@ -472,6 +472,8 @@ ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len);

ZEND_API void zend_update_current_locale(void);

ZEND_API void zend_reset_lc_ctype_locale(void);

/* The offset in bytes between the value and type fields of a zval */
#define ZVAL_OFFSETOF_TYPE \
(offsetof(zval, u1.type_info) - offsetof(zval, value))
Expand Down
2 changes: 1 addition & 1 deletion ext/snmp/snmp.c
Expand Up @@ -1999,7 +1999,7 @@ PHP_MINIT_FUNCTION(snmp)

init_snmp("snmpapp");
/* net-snmp corrupts the CTYPE locale during initialization. */
setlocale(LC_CTYPE, "C");
zend_reset_lc_ctype_locale();

#ifdef NETSNMP_DS_LIB_DONT_PERSIST_STATE
/* Prevent update of the snmpapp.conf file */
Expand Down
1 change: 1 addition & 0 deletions ext/standard/basic_functions.c
Expand Up @@ -528,6 +528,7 @@ PHP_RSHUTDOWN_FUNCTION(basic) /* {{{ */
* to the value in startup environment */
if (BG(locale_changed)) {
setlocale(LC_ALL, "C");
zend_reset_lc_ctype_locale();
zend_update_current_locale();
if (BG(ctype_string)) {
zend_string_release_ex(BG(ctype_string), 0);
Expand Down
1 change: 1 addition & 0 deletions main/main.c
Expand Up @@ -2087,6 +2087,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
zuf.getenv_function = sapi_getenv;
zuf.resolve_path_function = php_resolve_path_for_zend;
zend_startup(&zuf);
zend_reset_lc_ctype_locale();
zend_update_current_locale();

zend_observer_startup();
Expand Down

0 comments on commit 26e4244

Please sign in to comment.