Project

General

Profile

Actions

Bug #75141

closed

config.locale_all does not set LC_ALL

Added by Christian Welzel about 8 years ago. Updated over 5 years ago.

Status:
Closed
Priority:
Should have
Assignee:
-
Category:
-
Target version:
-
Start date:
2016-03-16
Due date:
% Done:

100%

Estimated time:
TYPO3 Version:
7
PHP Version:
Tags:
Complexity:
Is Regression:
No
Sprint Focus:

Description

Using the following code in my php code i get not the correct output:

$s = sprintf("%.2f", 5.00);

config.locale_all is set to "de_DE.utf-8", so i would expect sprintf to return "5,00" but "5.00" is returned.
Looking into TypoScriptFrontendController.php::settingLocale() reveals, that only LC_CTYPE, LC_MONETARY and LC_TIME are set
to the value given to locale_all. But not LC_NUMERIC.

A comment in the file says: There's a problem that PHP parses float values in scripts wrong if the locale LC_NUMERIC is set
to something with a comma as decimal point Do we set all except LC_NUMERIC

Is this still true in PHP 5.5+?
If yes, than documentation should be updated, as it says "PHP: setlocale(“LC_ALL”, [value]);"
If not, the code should be updated to set LC_ALL instead of only a subset.


Related issues 1 (0 open1 closed)

Related to TYPO3 Core - Bug #75780: Invalid number format because of miscellaneous decimal separatorClosedNicole Cordes2016-04-19

Actions
Actions #1

Updated by Xavier Perseguers about 8 years ago

Short test script:

<?php
$locale = 'de_DE.UTF-8';

// Standard from TSFE:
setlocale(LC_CTYPE, $locale);
setlocale(LC_MONETARY, $locale);
setlocale(LC_TIME, $locale);

$float = 5.00;
$str = '5.00';

echo 'Formatting float: ' . sprintf('%.2f', $float) . "\n";
echo 'Formatting string: ' . sprintf('%.2f', $str) . "\n";
echo 'Formatting parsed string: ' . sprintf('%.2f', (float)$str) . "\n";

// Additional setlocale
setlocale(LC_NUMERIC, $locale);
echo 'Formatting float: ' . sprintf('%.2f', $float) . "\n";
echo 'Formatting string: ' . sprintf('%.2f', $str) . "\n";
echo 'Formatting parsed string: ' . sprintf('%.2f', (float)$str) . "\n";

Testing with PHP 5.3.29

Formatting float: 5.00
Formatting string: 5.00
Formatting parsed string: 5.00
Formatting float: 5,00
Formatting string: 5,00
Formatting parsed string: 5,00

Testing with PHP 7.0.0

same

  • Tested with PHP 5.1 as well, same.

Using git blame on this file shows that the last this part was modified was when we switch to namespace, 461225, before the file was located under typo3/sysext/cms/tslib/class.tslib_fe.php. git blaming on this file:

git blame 461225^ -- typo3/sysext/cms/tslib/class.tslib_fe.php

gives nothing interesting, just a formating issue on those lines, which leads us to the previous change:

git blame 1b738d21^ -- typo3/sysext/cms/tslib/class.tslib_fe.php

and 57dc9dd0, still nothing but next one is ok: f460d462 which is:

+               if ($this->config['config']['locale_all'])      {
+                       # Change by Rene Fritz, 22/10 2002
+                       # there`s the problem that PHP parses float values in scripts wrong if the locale LC_NUMERIC is set to something with a komma as decimal point
+                       # this does not work in php 4.2.3
+                       #setlocale('LC_ALL',$this->config['config']['locale_all']);
+                       #setlocale('LC_NUMERIC','en_US');
+
+                       # so we set all except LC_NUMERIC
+                       setlocale(LC_COLLATE,$this->config['config']['locale_all']);
+                       setlocale(LC_CTYPE,$this->config['config']['locale_all']);
+                       setlocale(LC_MONETARY,$this->config['config']['locale_all']);
+                       setlocale(LC_TIME,$this->config['config']['locale_all']);
+
+                       $this->localeCharset = $this->csConvObj->get_locale_charset($this->config['config']['locale_all']);
+               }

so the problem seems to have been related to PHP 4.3 (http://grokbase.com/t/php/php-internals/034a3v22yz/locale-bug-from-php4-3-0) and is fixed since at least PHP 5.1.

Actions #2

Updated by Gerrit Code Review about 8 years ago

  • Status changed from New to Under Review

Patch set 1 for branch master of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/47455

Actions #3

Updated by Gerrit Code Review about 8 years ago

Patch set 2 for branch master of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/47455

Actions #4

Updated by Gerrit Code Review about 8 years ago

Patch set 1 for branch TYPO3_7-6 of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/47457

Actions #5

Updated by Gerrit Code Review about 8 years ago

Patch set 2 for branch TYPO3_7-6 of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/47457

Actions #6

Updated by Xavier Perseguers about 8 years ago

  • Status changed from Under Review to Resolved
  • % Done changed from 0 to 100
Actions #7

Updated by Antoine Bouet about 8 years ago

Hi all,

There is a side effect of this patch.

With a french locale 'fr_FR.UTF-8', the json_decode method change all point separated numeric values in comma separeted numeric values.

For example :
This URL (http://maps.google.com/maps/api/geocode/json?address=champs-elysees-75000-paris) returns location values : "48.8695862"

With a json_decode, this value returns : "48,8695862" and it breaks all the Google Maps :(

I patched my code with a str_replace but it's a little bit ugly ...

Actions #8

Updated by Christian Welzel about 8 years ago

Hi there,

your problem is not json_decode(), but your output code.

php -r 'setlocale(LC_ALL, "de_DE"); $json = json_decode("[2.1]"); var_dump($json); echo $json[0]; setlocale(LC_ALL, 'en_US'); var_dump($json); echo $json[0];'

returns

array(1) {
  [0]=> float(2,1)
}
2,1
array(1) {
  [0]=> float(2.1)
}
2.1

The json input is parsed while german locale is active, but the output is under different locales.
And the output code is locale aware.

So either you force the locale to be 'C' or 'en', or you use the more correct solution: number_format().
This would be correct, as you want to force a special number format: number_format($i, 7, '.', '')
Relying on the implicit float conversation is an error in this case.

Actions #9

Updated by Timo Pfeffer about 8 years ago

Fix didn't work for me as well.

Database got a field as Double Datatype.
Model defined this field as Float Datatype.
Controller gets the field and create a SQL-Query with it.
Because of the comma instead of the dot in the field value, the SQL-Query is failing.

This ticket should be reopened.

Actions #10

Updated by Guido S. about 8 years ago

Same problem like Timo, but without SQL Mode the value was saved with a wrong value.

Model, SQL String etc. the value was 17,65
In Database: 17,00

PHP Version: 5.6.19-1~dotdeb+7.1
MySQL Version: 5.5.47 (Also in 5.6)

Actions #11

Updated by Felix Rauch about 8 years ago

Same problem, did some investigating.

When the Extbase PersistenceManager calls DataMapper and it convert the float value into a string for the database request, it is just casted to a string formatted according to locale. SQL doesn't seem to like that, and truncates a value of "17,65" to "17" before it stores it in a 'double' column.

In my opinion, DataMapper should be aware of that, and not cast float values in a way that leads to locale-specific results.

Actions #12

Updated by Xavier Perseguers about 8 years ago

Thanks to Felix Rauch investigation, it looks like this is related to these posts:

Maybe we need something like that (untested):

diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php
index c168fbf..f8a092f 100755
--- a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php
+++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php
@@ -182,6 +182,11 @@ class DataMapper implements \TYPO3\CMS\Core\SingletonInterface {
         if (!empty($row['_ORIG_uid']) && !empty($GLOBALS['TCA'][$dataMap->getTableName()]['ctrl']['versioningWS'])) {
             $object->_setProperty('_versionedUid', (int)$row['_ORIG_uid']);
         }
+
+        if (($backupLocale = setlocale(LC_NUMERIC, 0)) !== false) {
+            setlocale(LC_NUMERIC, 'C');
+        }
+
         $properties = $object->_getProperties();
         foreach ($properties as $propertyName => $propertyValue) {
             if (!$dataMap->isPersistableProperty($propertyName)) {
@@ -236,6 +241,10 @@ class DataMapper implements \TYPO3\CMS\Core\SingletonInterface {
                 $object->_setProperty($propertyName, $propertyValue);
             }
         }
+
+        if ($backupLocale !== false) {
+            setlocale(LC_NUMERIC, $backupLocale);
+        }
     }

     /**
Actions #13

Updated by Benni Mack over 5 years ago

  • Status changed from Resolved to Closed
Actions

Also available in: Atom PDF