Page 1 of 1

[SOLVED] Setlocale() and sprintf() string representation (Paypal Gateway)

Posted: Thu Nov 12, 2009 5:45 pm
by Sonya
I have discovered a weird PHP problem described here: http://dev.cmsmadesimple.org/bug/view/4300

The bug applies to the module Paypal Gateway, but the problem is general:

Code: Select all

<?php
  setlocale (LC_ALL, 'de_DE.UTF8');
  $key = "field";  
  $value = 2.4;
  $fmt = 'key="%s" value="%s"';     
  echo sprintf($fmt,$key,$value);
?>
This piece of code does format numbers to decimal even if according to the PHP documentation:
s - the argument is treated as and presented as a string.
The output is:

Code: Select all

key="field" value="2,4"
If you comment setlocale() then the string is correct:

Code: Select all

key="field" value="2.4"
1. Can somebody explain, why the argument %s of the sprintf() formats numbers and does not take them as string representation?
2. How to convert the variable $value in the given example to string? Assume that the values come from database or _REQUEST, so that the direct assignment $value = "2.4" is NOT possible.

----------------------------------------------------
The above code is tested on this environment:

Server OS: Linux 2.6.24-etchnhalf.1-686 On i686
Server Software: Apache/2.2.3 (Debian) mod_python/3.2.10 Python/2.4.4 mod_ssl/2.2.3 OpenSSL/0.9.8c


Php Information:
   * phpversion: 5.2.0-8+etch13
   * md5_function: On (True)
   * gd_version: 2
   * tempnam_function: On (True)
   * magic_quotes_runtime: Off (False)
   * memory_limit: 100000000
   * max_execution_time: 30
   * safe_mode: Off (False)
   * session_save_path: /var/lib/php5 (1733)
   * session.use_cookies: On (True)


Server Information:

   * Server Api: cgi-fcgi
   * Server Db Type: MySQL (mysql)
   * Server Db Version: 5.0.32

Re: Setlocale() and sprintf() string representation (Paypal Gateway)

Posted: Thu Nov 12, 2009 7:51 pm
by Peciura
Probably you need to set US locale to deal with PayPal.

Code: Select all

setlocale(LC_MONETARY, 'en_US');
BTW why not use ?

Code: Select all

$value = number_format($value, 2, '.', '');

Re: Setlocale() and sprintf() string representation (Paypal Gateway)

Posted: Fri Nov 13, 2009 12:54 pm
by Sonya
Thank you for the answer.
Peciura wrote: Probably you need to set US locale to deal with PayPal.

Code: Select all

setlocale(LC_MONETARY, 'en_US');
Does not change anything.
Peciura wrote: BTW why not use ?

Code: Select all

$value = number_format($value, 2, '.', '');
This would not help in the module as all numbers are already formatted with sprintf throughout the module. It is even more weird:

Code: Select all

<?php
  setlocale (LC_ALL, 'de_DE.UTF8');
  $key = "field";  
  $value = 2.4;  
  $value = sprintf("%.2f",$value);   
  echo "$value<br>";   // output 2,40
  echo number_format($value,2,'.',','); // output 2.00

This way the number is converted to integer, decimal are just cutted.  It depends on locale, if it is not set, everything works as desired, if you set locale there is no more logic.  ???

Re: Setlocale() and sprintf() string representation (Paypal Gateway)

Posted: Fri Nov 13, 2009 1:12 pm
by Sonya
Peciura wrote: BTW why not use ?

Code: Select all

$value = number_format($value, 2, '.', '');
Now, I have just replaced all sprintf() with number_format() and it works for the module. My solution is not to use sprintf() for the other locale at all  :)

Thank you!

Re: [SOLVED] Setlocale() and sprintf() string representation (Paypal Gateway)

Posted: Fri Nov 13, 2009 1:22 pm
by Peciura
Still i will add this one.

Code: Select all

<?php
setlocale (LC_ALL, 'de_DE.UTF8');
  $key = "field";  
  $value = 2.4;  

echo 'output1<br/>';
$fmt = 'key="%s" value="%s"';     
  echo sprintf($fmt,$key,$value).'<br/><br/>'; /* key="field" value="2,4" */

echo 'output2<br/> ';
$value = number_format($value,2,'.','');/*imiportant*/
$fmt = 'key="%s" value="%s"';     
  echo sprintf($fmt,$key,$value).'<br/><br/>';/* key="field" value="2.40" */

echo 'output3<br/> ';
$fmt = 'key="'.$key.'" value="'.$value."\"\n";  
echo $fmt; /* key="field" value="2.40" */
?>

Re: [SOLVED] Setlocale() and sprintf() string representation (Paypal Gateway)

Posted: Fri Nov 13, 2009 2:13 pm
by Sonya
Peciura wrote: Still i will add this one.

Code: Select all

...
This would work for my test.php above, but not in the module. In the module all numbers are alreday preformatted with:

Code: Select all

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

I did not find any possibility to get rid of decimal comma after the line above is applied to the number, except of adding ugly

Code: Select all

str_replace(',' ,'.', $value)
However, str_replace() can not be a general solution. It would be fatal if $config['locale'] once changed. 1,000 USD will be quickly replaced by 1 USD. What a wonderful discount!  :D

Therefore my solution was to replace sprintf() in the entire module with number_format().

Re: [SOLVED] Setlocale() and sprintf() string representation (Paypal Gateway)

Posted: Fri Nov 13, 2009 3:30 pm
by Peciura
Calguy1000 just submitted new revision to svn.