Zend Framework

Problem with Zend_Locale_Format and setlocale()

Details

  • Type: Bug Bug
  • Status: Resolved Resolved
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: 0.8.0
  • Fix Version/s: 1.0.3
  • Component/s: Zend_Locale
  • Labels:
    None

Description

I've had some troubles using Zend_Locale_Format ::toFloat() along with setlocale().

Here is a sample code to illustrate the issue :

require_once('Zend/Loader.php');

Zend_Loader::loadClass('Zend_Locale');

// setlocale(LC_ALL, 'fr_FR@euro');
$locale_fr = new Zend_Locale('fr_FR');
$locale_en = new Zend_Locale('en_US');
$params_fr = array('precision' => 2, 'locale' => $locale_fr);
$params_en = array('precision' => 2, 'locale' => $locale_en);
$myFloat = 1234.5;
$test1 = Zend_Locale_Format::toFloat($myFloat, $params_fr);
$test2 = Zend_Locale_Format::toFloat($myFloat, $params_en);
var_dump($test1);
var_dump($test2);

The problem comes from the setlocale() call : if it is not present, everything goes fine but when I set PHP's locale to French, I can't get toFloat() to work.

Output without setlocale() :

string(9) "1 234,50" string(8) "1,234.50"

Output with setlocale() :

string(4) "0,00" string(4) "0.00"

The server I work on is a Linux box (Debian stable), and AFAIK, the standard locale is 'C'. I'm using PHP version 5.2.1 with the BCmath extension enabled. Regarding the framework, I had this problem while I was using the 0.8.0 version and it is still present in the 3912 SVN version.

Last thing, I quote a short part of Thomas' last answer on the mailing list :

So toNumberFormat does not have to parse for the decimal point, because the input is not a string but a integer/float value.

Are you 100% positive about that ? I'm saying that because when I see a piece of code like the following :

// get number parts
if (iconv_strpos($value, '.') !== false) {

in toNumberFormat(), my first guess would be that you are actually looking for the decimal separator in the input value.

This seems to be confirmed by a short trace I ran on this part of code :

--- Format.php.orig	2007-03-14 09:48:00.000000000 +0100
+++ Format.php	2007-03-14 10:37:43.000000000 +0100
@@ -385,10 +385,12 @@
                     $precstr = $precstr . str_pad("0", ($options['precision'] - iconv_strlen($precstr)), "0");
                 }
             }
+			die('strpos true : ' . $precstr);
         } else {
             if ($options['precision'] > 0) {
                 $precstr = str_pad("0", ($options['precision']), "0");
             }
+			die('strpos false : ' . $precstr);
         }
         if ($options['precision'] === null) {
             if (isset($precstr)) {

Output without setlocale() :

strpos true : 50

Output with setlocale() :

strpos false : 00

Behaviour of this part of code is different whether the locale is set to French or not.

Hopefully there's enough information in this description, if not just let me know

Issue Links

Activity

Hide
Thomas Weidner added a comment -

I am sure.

Please try this code so we can see if iconv_strpos works on your system:

$value = 12345.50;
print "\n".$value;
print "\n".iconv_strpos($value, '.');	
    setlocale(LC_ALL, 'fr_FR@euro');
print "\n".$value;
print "\n".iconv_strpos($value, '.');

I see 2 possible problems:
1.) setLocale has false settings on your OS.
2.) BCMath is set to precision 0 within php.ini.

Show
Thomas Weidner added a comment - I am sure. Please try this code so we can see if iconv_strpos works on your system:
$value = 12345.50;
print "\n".$value;
print "\n".iconv_strpos($value, '.');	
    setlocale(LC_ALL, 'fr_FR@euro');
print "\n".$value;
print "\n".iconv_strpos($value, '.');
I see 2 possible problems: 1.) setLocale has false settings on your OS. 2.) BCMath is set to precision 0 within php.ini.
Hide
Guillaume Millet added a comment -

Just tried your code, here is the result :

12345.5
5
12345,5

You were also right, bcmath's scale was indeed set to 0. My sysadmin changed it to 10 but the output stayed the same.

Show
Guillaume Millet added a comment - Just tried your code, here is the result :
12345.5
5
12345,5
You were also right, bcmath's scale was indeed set to 0. My sysadmin changed it to 10 but the output stayed the same.
Hide
Thomas Weidner added a comment -

I know...

You have 2 problems.
One which your sysadmin fixed. And one which I will fix

Show
Thomas Weidner added a comment - I know... You have 2 problems. One which your sysadmin fixed. And one which I will fix
Hide
Thomas Weidner added a comment -

I just committed a new version which should solve your problem if the php.ini settings are correct. (maximum precision settings)
Please try SVN 3926 or higher.

Show
Thomas Weidner added a comment - I just committed a new version which should solve your problem if the php.ini settings are correct. (maximum precision settings) Please try SVN 3926 or higher.
Hide
Guillaume Millet added a comment -

I just tried with SVN version 3953.

Problem seems to be fixed, at least for the part in toNumberFormat(). However, I still can't get it to work when the locale is set to French.

I ran a few tests and it seems to me that Gavin's new implementation of the Zend_Locale_Math::round() method, which is called in toNumber(), may have broken your fix. For example, the value of $op1 after this block :

if (($decPos = strpos($op1, '.')) === false) {
            $op1 .= '.0';
            $decPos = $length;
            $length += 2;
}

is 1234,5.0 with setlocale() and 1234.5 without and this is the value that is used in toNumberFormat().

Show
Guillaume Millet added a comment - I just tried with SVN version 3953. Problem seems to be fixed, at least for the part in toNumberFormat(). However, I still can't get it to work when the locale is set to French. I ran a few tests and it seems to me that Gavin's new implementation of the Zend_Locale_Math::round() method, which is called in toNumber(), may have broken your fix. For example, the value of $op1 after this block :
if (($decPos = strpos($op1, '.')) === false) {
            $op1 .= '.0';
            $decPos = $length;
            $length += 2;
}
is 1234,5.0 with setlocale() and 1234.5 without and this is the value that is used in toNumberFormat().
Hide
Thomas Weidner added a comment -

I know this... I've seen the problem after gavin changed my "tiny" implementation.
I already wrote gavin about his fault... he will change it to work the same way like the old implementation.

Show
Thomas Weidner added a comment - I know this... I've seen the problem after gavin changed my "tiny" implementation. I already wrote gavin about his fault... he will change it to work the same way like the old implementation.
Hide
Thomas Weidner added a comment -

Fix has been broken due to changes for ZF-1054.
Please fix your fix.

Show
Thomas Weidner added a comment - Fix has been broken due to changes for ZF-1054. Please fix your fix.
Hide
Gavin added a comment -

The Zend_Locale_Math class is not locale-aware, nor should it be locale-aware.
The Zend_Locale_Math class is a simple proxy between PHP functions and BCMath.
BCMath is not locale-aware, and does not support thousands separator characters, or decimal separator characters other than a period ('.').

The previous implementation of Zend_Locale_Math::round() method failed on many cases (see unit test).
The new implementation produces correct results for more than 200,000 test cases I tried.

Also, usually we should add a unit test before closing an issue.

Show
Gavin added a comment - The Zend_Locale_Math class is not locale-aware, nor should it be locale-aware. The Zend_Locale_Math class is a simple proxy between PHP functions and BCMath. BCMath is not locale-aware, and does not support thousands separator characters, or decimal separator characters other than a period ('.'). The previous implementation of Zend_Locale_Math::round() method failed on many cases (see unit test). The new implementation produces correct results for more than 200,000 test cases I tried. Also, usually we should add a unit test before closing an issue.
Hide
Thomas Weidner added a comment -

Problem not reproducable.

Probably fixed with 3972. Changed internal handling of toNumber/-Format.
See previous additionally comments from the devteam.

Show
Thomas Weidner added a comment - Problem not reproducable. Probably fixed with 3972. Changed internal handling of toNumber/-Format. See previous additionally comments from the devteam.
Hide
Gavin added a comment -

Reproducible on the ZF Community Server.
Post request to fw-server@lists.zend.com to obtain an account.

Unit test testToFloatSetlocale() committed to FormatTest.php

Show
Gavin added a comment - Reproducible on the ZF Community Server. Post request to fw-server@lists.zend.com to obtain an account. Unit test testToFloatSetlocale() committed to FormatTest.php
Hide
Gavin added a comment -

$ php AllTests.php
X-Powered-By: PHP/5.1.6
Content-type: text/html

PHPUnit 3.0.0 by Sebastian Bergmann.

.......................F.

Time: 00:08

There was 1 failure:

1) testToFloatSetlocale(Zend_Locale_FormatTest)
Failed asserting that <string:1Â 234,50> is equal to <string:0,00>.
/var/www/html/zftrunk/tests/Zend/Locale/FormatTest.php:758
/var/www/html/zftrunk/tests/Zend/Locale/AllTests.php:44
/var/www/html/zftrunk/tests/Zend/Locale/AllTests.php:60

FAILURES!
Tests: 25, Failures: 1.

zfdev Locale 701$ svn update
At revision 3991.

zfdev Locale 702$ uname -a
Linux www.zfdev.com 2.6.9-42.EL #1 Wed Jul 12 23:16:43 EDT 2006 i686 i686 i386 GNU/Linux

zfdev Locale 703$ php -v
PHP 5.1.6 (cgi-fcgi) (built: Oct 24 2006 19:38:28)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies

Show
Gavin added a comment -
$ php AllTests.php X-Powered-By: PHP/5.1.6 Content-type: text/html PHPUnit 3.0.0 by Sebastian Bergmann. .......................F. Time: 00:08 There was 1 failure: 1) testToFloatSetlocale(Zend_Locale_FormatTest) Failed asserting that <string:1Â 234,50> is equal to <string:0,00>. /var/www/html/zftrunk/tests/Zend/Locale/FormatTest.php:758 /var/www/html/zftrunk/tests/Zend/Locale/AllTests.php:44 /var/www/html/zftrunk/tests/Zend/Locale/AllTests.php:60 FAILURES! Tests: 25, Failures: 1. zfdev Locale 701$ svn update At revision 3991. zfdev Locale 702$ uname -a Linux www.zfdev.com 2.6.9-42.EL #1 Wed Jul 12 23:16:43 EDT 2006 i686 i686 i386 GNU/Linux zfdev Locale 703$ php -v PHP 5.1.6 (cgi-fcgi) (built: Oct 24 2006 19:38:28) Copyright (c) 1997-2006 The PHP Group Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies
Hide
Gavin added a comment -

Guillaume Millet, would you have time to test the patch attached to ZF-1061?

Show
Gavin added a comment - Guillaume Millet, would you have time to test the patch attached to ZF-1061?
Hide
Guillaume Millet added a comment -

I can, but which version should I apply the patch on ?

Anyway, I gave a try at the SVN version 4108 and now the output of my test file changes from :

string(9) "1 234,50" string(8) "1,234.50"
without setlocale() to :
string(9) "1 234,00" string(8) "1,234.00"
with setlocale().

Show
Guillaume Millet added a comment - I can, but which version should I apply the patch on ? Anyway, I gave a try at the SVN version 4108 and now the output of my test file changes from :
string(9) "1 234,50" string(8) "1,234.50"
without setlocale() to :
string(9) "1 234,00" string(8) "1,234.00"
with setlocale().
Hide
Thomas Weidner added a comment -

Problems are solved with SVN 5806.

Could you please verify if it's working for you ?

Show
Thomas Weidner added a comment - Problems are solved with SVN 5806. Could you please verify if it's working for you ?

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: