views:

122

answers:

2

I've run into a strange problem on a WAMP server setup (PHP version 5.3.0, Apache 2.2.11). When using sprintf to output a number, I occasionally get erroneous characters in the output string.

Example: (not trimmed from anything, this is the only code in the script)

$dt1 = new DateTime('now');
$dt2 = new DateTime('now - 10 min');

$interval = $dt1->diff($dt2);

$number = 10.0;
$string = sprintf("%.1f", $number);
echo "number: $number, string: $string\n";

If I run this at the command prompt with PHP CLI, I get the expected output:

number: 10, string: 10.0

However, if I serve it using Apache, in the browser I get

number: 10, string: :.0

with a colon where '10' should be. (Note that ':' is the next ascii character in sequence after '9', if $number is 0-9, everything works. Numbers greater than 10 appear to use ascii equivalents - so 11 is ';', 12 is '<', etc.)

The strangest part is that the first four lines in the above code sample seem to affect the results. Logically, those statements should have no impact, but if I comment them out or remove them the problem goes away.

Any ideas? Anyone else able to replicate this?

Notes:

  • I've tried php 5.3.1 and 5.3.2, both behave the same way
  • The above script works fine, even in the browser, for 5-6 page refreshes after restarting Apache. Then the error, as described, returns
A: 

Try adding this above the code setlocale(LC_ALL, 'en_US');

James Roth
Good thought, but unfortunately no change in the results.
potatoe
A: 

Try this:

Change echo "number: $number, string: $string\n"; to:

for ($i = 0, $n = strlen($string); $i < $n; $i++) {
    echo ord($string[$i]).' ';
}

It will basically give you the numeric character code for each byte in the string. Note that I said byte. If it's a character set problem, or a problem with Apache mangling bytes, you should see that here. Expected output is: 49 48 46 48. If you instead see 58 46 48, then you indeed may have found a bug with php and should submit a bug report. You also should try upgrading your php version (5.3.2 is out)...

ircmaxell
Excellent idea, thanks. I do indeed see "58 46 48" in the browser, but "49 48 46 48" at the command line (as expected, since it's always been working there).If it were a php bug, is there a mechanism by which it could manifest itself only when run by Apache?
potatoe
Add a `var_dump($interval);` in there to see what interval is giving out in each case. If that's different, then the problem may be in the date routines. If it's identical, try setting $interval to that value (for example `float: 10.0` would yield `$interval = 10.0`) and seeing if you can reproduce the bug...
ircmaxell
$interval always has the same value, a DateInterval object whose fields (y,m,d,h,i,s,invert,days) appear to have the correct values. Setting $interval to any constant that avoids executing DateTime::diff seems to solve the problem. (DateInterval::format doesn't affect the outcome)I upgraded to php 5.3.1 with no change in outcome, and will try 5.3.2 next. While doing that, I learned that after restarting Apache, the output in the browser IS correct for about 5-6 reloads of this script, after which the ':' reappears until the next Apache restart.
potatoe