Problem/Motivation

In #614124: Bootstrap should reset locale settings a line was added to set the locale to a sane default: setlocale(LC_ALL, 'C');

Since that time however, C.UTF-8 has been officially adopted as the C locale with UTF-8 encoding. See e.g. https://sourceware.org/glibc/wiki/Proposals/C.UTF-8 (C.UTF-8 has also been adopted by non-Linux operating systems such as FreeBSD, and other programming languages such as Python.)

One place where the C locale fails is the PHP function escapeshellarg(): non-ASCII characters will be removed unless a UTF-8 locale is set. See https://bugs.php.net/bug.php?id=44945

Steps to reproduce

Call an affected function such as escapeshellarg() or escapeshellcmd() with a string containing non-ASCII UTF-8 characters; they will be silently removed.

Proposed resolution

Update setlocale(LC_ALL, 'C'); to setlocale(LC_ALL, 'C.UTF-8', 'C');

Meaning, if the environment does not have the C.UTF-8 locale installed, the C locale will be used as a fallback.

Remaining tasks

Test in various environments and use cases, including macOS. If macOS does not have C.UTF-8 installed, we could try setlocale(LC_ALL, 'C.UTF-8', 'UTF-8', 'C');

User interface changes

API changes

The locale will be set to C.UTF-8 if available, otherwise the C locale will continue to be used.

Data model changes

N/A

Release notes snippet

TBD

Issue fork drupal-1561214

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

fietserwin’s picture

Status: Active » Needs review
StatusFileSize
new406 bytes

Let's see what the tests say.

drzraf’s picture

StatusFileSize
new373 bytes

Drupal should not affect the locale except for the bare minimum like LC_NUMERIC to work around some PHP bugs.
First, let's see if this line is needed at all (eg : if tests about floats are here)

fietserwin’s picture

This is a "PHP bug" (see my link) though classified as a feature: escapeshellarg works locale and codepage dependent.

Subsequently this is a Drupal bug, as Drupal provides a standardized environment where developers can do things independent from antique server settings. This ranges from anything like register globals to utf-8 all over the place.

When I am developing under Drupal, I am expected to work with UTF-8, from database to browser, and Drupal is the environment providing it. So If I pass on some UTF-8 strings to the database I may expect them to stay as they are. That's why Drupal does things like sending "SET NAMES utf8" to the database. If I send an UTF-8 string to the browser I may expect Drupal to have outputted a <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> meta tag.

Thus when I want to call some external commands and am using escapeshellarg(), I may expect Drupal to have called setlocale() in such a way that escapeshellarg() will leave my utf-8 string intact (except of course for the shell escaping I am asking for). Either this, or Drupal should provide its own escapeshellarg.

If you would want to reduce it to the bare minimum, we will thus also have to include LC_CTYPE with an 'UTF-8' "code page".

drzraf’s picture

I do agree on assuming (and setting) an UTF-8 character encoding. I only disagree on the LC_ALL + C combination.
I'm sorry but I can not take the time to provide patches for the testsuite (for which tests are missing as bugs currently *exist* on this subject), as illustrated by drush ev 'echo iconv("utf8", "ascii//translit", " héllô") . "\n";'.

fietserwin’s picture

I read about your iconv problems, and am pretty sure that with a (ok, probably any) utf-8 locale setting, thus the patch from #1, your problem will be solved.

sun’s picture

Title: Bootstrap should reset locale settings to UTF-8 » Bootstrap sets C locale, but does not set should reset locale settings to UTF-8
Issue tags: +Needs backport to D7
StatusFileSize
new1.56 KB
new1.12 KB

The patch in #2 is definitely wrong, which has been sufficiently discussed in #614124: Bootstrap should reset locale settings already.

Example bug report: #1502924: escapeshellarg() has problems with non-ASCII filenames

Clarifying the issue title.

I agree with the patch in #1.

But alas, it doesn't make a difference on my local Windows machine, which appears to retain UTF-8 correctly. Let's see what the testbot thinks.

sun’s picture

Title: Bootstrap sets C locale, but does not set should reset locale settings to UTF-8 » Bootstrap sets C locale, but does not set UTF-8 character encoding
sun’s picture

Issue summary: View changes

Updated issue summary.

Status: Needs review » Needs work

The last submitted patch, drupal8.setlocale-utf8.6.patch, failed testing.

hass’s picture

Issue tags: +Needs backport to D6

If this is the bugfix for #371495: Error message from drupal_http_request() not UTF8 encoded, this needs backport to D6, too.

fietserwin’s picture

#9: see #614124: Bootstrap should reset locale settings.

#6: Linux escapes with a single quote, Windows with a double quote. The test should pass on both systems I guess, thus need to take that into account.

#6: I ran the test below on different systems. The results are a bit strange to put it mildly. I cannot understand how I got this to work on Linux variant 3: See the accented characters in the polaroids on http://www.locations-mont-dore.fr/. these are created by Imagemagick (thus the texts got passed to Imagemagick via a shell command).

Anyway, it looks that choosing 'en_US' as locale gives the best results.

Test code

Everybody can run this on his/her own system to see which locale gives good results. If you have different results please post them. Save this code to, e.g., phpinfo.php and run the test by visiting the page in your browser.

$utf8_string = 'äöüß';

$r = setlocale(LC_ALL, '0');
$s = escapeshellarg($utf8_string);
echo "$r: $s<br/>\n";

$r = setlocale(LC_ALL, 'C');
$s = escapeshellarg($utf8_string);
echo "$r: $s<br/>\n";

$r = setlocale(LC_ALL, 'C.UTF-8');
$s = escapeshellarg($utf8_string);
echo "$r: $s<br/>\n";

$r = setlocale(LC_ALL, 'C.utf8');
$s = escapeshellarg($utf8_string);
echo "$r: $s<br/>\n";

$r = setlocale(LC_ALL, 'en_US.utf8');
$s = escapeshellarg($utf8_string);
echo "$r: $s<br/>\n";

$r = setlocale(LC_ALL, 'en_US');
$s = escapeshellarg($utf8_string);
echo "$r: $s<br/>\n";

phpinfo();

Results

Windows

LC_COLLATE=C;LC_CTYPE=Dutch_Netherlands.1252;LC_MONETARY=C;LC_NUMERIC=C;LC_TIME=C: "äöüß"
C: "äöüß"
: "äöüß"
: "äöüß"
: "äöüß"
: "äöüß"

PHP Version 5.3.8-ZS5.5.0
System 	Windows NT ERWINSLAPTOP 6.0 build 6002 (Windows Vista Business Edition Service Pack 2) i586

Linux variant

C: ''
C: ''
: ''
: ''
en_US.utf8: ''
en_US: 'äöüß'

PHP Version 5.2.17
System 	Linux ds193.haisoft.net 2.6.33.5-1ikl #2 SMP Mon Jun 28 11:44:13 CEST 2010 i686

Linux variant 2

C: ''
C: ''
C.UTF-8: ''
: ''
en_US.utf8: ''
en_US: 'äöüß'
PHP Version 5.3.10-2
System 	Linux s6.infralutions.com 2.6.39-2-686-pae #1 SMP Wed Jun 8 11:33:14 UTC 2011 i686

Linux variant 3

C: ''
C: ''
C.UTF-8: ''
: ''
en_US.utf8: ''
en_US: '����'

PHP Version 5.3.10-2
System 	Linux s7.infralutions.com 3.2.0-2-amd64 #1 SMP Sun Mar 4 22:48:17 UTC 2012 x86_64
drzraf’s picture

According to this post, C.UTF-8 does not appear to be a valid locale : there's no non-ascii "POSIX" locale. The most standard being en_EN (http://sources.redhat.com/ml/libc-alpha/2009-09/msg00042.html)
Anyway :
php -r "setlocale(LC_CTYPE, 'C.UTF-8'); echo escapeshellarg('äöüß');"
'äöüß'
php -r "setlocale(LC_CTYPE, 'C'); echo escapeshellarg('äöüß');"
''

I'm personally fine with UTF-8 LC_ALL, but more theoretically, once again, why use LC_ALL if LC_CTYPE is sufficient.
To fix both this and #614124: Bootstrap should reset locale settings, I'd replace the setlocale() line by

 // fixes #1561214 : escapeshellarg()
setlocale(LC_CTYPE, "C.UTF-8");
// fixes #614124 : workaround float php bugs
if(  localeconv() [ "decimal_point" ] != "." )
  setlocale(LC_NUMERIC, "C");
OnkelTem’s picture

Damn PHP...
It is 2012 outside and we still have this backward issues with stripping non-latin characters.
I vote for a PHP independent solution, like implementing our own escapeshellarg() (drupal_escapeshellarg()) to not couple with PHP anymore.

Just for reference, this is PHP implemenation of escapeshellarg:

/* {{{ php_escape_shell_arg
 */
PHPAPI char *php_escape_shell_arg(char *str)
{
	int x, y = 0, l = strlen(str);
	char *cmd;
	size_t estimate = (4 * l) + 3;

	TSRMLS_FETCH();

	cmd = safe_emalloc(4, l, 3); /* worst case */

#ifdef PHP_WIN32
	cmd[y++] = '"';
#else
	cmd[y++] = '\'';
#endif

	for (x = 0; x < l; x++) {
		int mb_len = php_mblen(str + x, (l - x));

		/* skip non-valid multibyte characters */
		if (mb_len < 0) {
			continue;
		} else if (mb_len > 1) {
			memcpy(cmd + y, str + x, mb_len);
			y += mb_len;
			x += mb_len - 1;
			continue;
		}

		switch (str[x]) {
#ifdef PHP_WIN32
		case '"':
		case '%':
			cmd[y++] = ' ';
			break;
#else
		case '\'':
			cmd[y++] = '\'';
			cmd[y++] = '\\';
			cmd[y++] = '\'';
#endif
			/* fall-through */
		default:
			cmd[y++] = str[x];
		}
	}
#ifdef PHP_WIN32
	cmd[y++] = '"';
#else
	cmd[y++] = '\'';
#endif
	cmd[y] = '\0';

	if ((estimate - y) > 4096) {
		/* realloc if the estimate was way overill
		 * Arbitrary cutoff point of 4096 */
		cmd = erealloc(cmd, y + 1);
	}
	return cmd;
}
/* }}} */
sdrycroft’s picture

It is worth noting that on a Debian 6.0.6 system the C.UTF-8 locale is not provided by default, but can be generated using the following command.

sudo localedef -c -i POSIX -f UTF-8 C.UTF-8

This may be of issue on other systems, and may require picking a locale that is available e.g. en_GB.UTF-8.

sdrycroft’s picture

Issue summary: View changes

Updated issue summary.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

juliencarnot’s picture

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

quietone’s picture

Status: Needs work » Postponed (maintainer needs more info)
Issue tags: +Bug Smash Initiative

It has been 7 years since there has been discussion here.

Is this still relevant to Drupal 10?

Since we need more information to move forward with this issue, I am setting the status to Postponed (maintainer needs more info). If we don't receive additional information to help with the issue, it may be closed after three months.

Thanks!

mfb made their first commit to this issue’s fork.

mfb’s picture

AFAIK this is still a valid issue as originally described. I created a merge request with the setlocale() change to see if tests pass. The test from the patch would still need to be ported, however.

mfb’s picture

Status: Postponed (maintainer needs more info) » Needs work

Setting to needs work as the test still needs to be ported from patch to merge request.

mfb’s picture

Status: Needs work » Needs review

I added a test so this is ready for review.

Since this issue was created, a C.UTF-8 locale was officially added so should be even more common across different environments.

However, I changed the setlocale() to use good ol' C as a fallback for older systems: setlocale(LC_ALL, 'C.UTF-8', 'C');

As a result there will be some behavioral differences across environments, but it seems like a net win to enable correct UTF-8 handling on newer systems, while still supporting older systems.

mfb’s picture

Hiding obsolete patch files

smustgrave’s picture

Issue summary: View changes
Status: Needs review » Needs work
Issue tags: +Needs issue summary update

Got the issue summary started but seems original summary was written for D7 if that could be cleaned up some.

Wonder if this kind of change will require a CR or be disruptive?

Clearly an old issue so will keep on my radar

mfb’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs issue summary update

Updated the summary. I think this issue makes more sense now than when originally proposed, as C.UTF-8 has been much more widely standardized and adopted than it was back then. However, should still be thoroughly tested.

mfb’s picture

Issue summary: View changes
smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs backport to D6, -Needs backport to D7

Doubt we are backporting to D6 or D7

Applied locally and did random things like create content, media, views, etc. But didn't see any issues. Not sure how else to test.

mfb’s picture

@smustgrave were you able to run the newly-added test on macOS - that would be the main thing worth testing.

smustgrave’s picture

It's a ddev setup on my mac but ran DrupalKernelTest without issue if that's what you mean.

mfb’s picture

Ok, but that might essentially be Linux if docker-based? Would be excellent if someone could test directly on raw macOS

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs change record

We definitely should have a change record for this. I can run Kernel tests fine on a Mac.

mfb’s picture

Status: Needs work » Needs review

Change record ready for review.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs change record

Since it was just a CR was needed going to put back into RTBC.

quietone’s picture

@smustgrave, The change record should be reviewed before setting to RTBC. Has that been done?

nicxvan’s picture

I reviewed the CR and the code, I did tweak the CR a little for clarity. I think this looks good!

I'll let @smustgrave respond to your question, but I've independently reviewed it so RTBC should be good either way.

  • longwave committed dcfd0488 on 10.3.x
    Issue #1561214 by mfb, sun, fietserwin, drzraf, sdrycroft, nicxvan:...

  • longwave committed 79eed4ac on 11.x
    Issue #1561214 by mfb, sun, fietserwin, drzraf, sdrycroft, nicxvan:...
longwave’s picture

Version: 11.x-dev » 10.3.x-dev
Status: Reviewed & tested by the community » Fixed

Committed and pushed 79eed4acc5 to 11.x and dcfd0488b8 to 10.3.x. Thanks!

Also published the change record.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.