Nukeface Nukeface - 5 months ago 27
PHP Question

How to get numeric float (not string!) when json_encoding?

I need to have a numeric float using a dot separator, that stays a numeric after (json) encoding for sending in the POST headers to a third-party API.

However, have been trying for a few hours, but cannot get it to work.

What I need is:

"price": 17.95,
"price": "17.95" OR 17,95

Why? Because the receiving API endpoint does a check for the first but throws a
error on the latter 2 values.

Now, we're in Holland. So our "locale" uses a comma separator. Working around that by setting the locale from
gives the
function the correct format, however, as a string.

Casting a comma or dot separated string using
causes it to lose any value from the point of separation. (

Updating the product details is a function taking a few arguments that passes them on without modification to cURL. Which encodes the array of POST variables into what it should be above. I'm limited in passing the following:

$client->updateShopItem($shopId, $articleNumber, $updateArray)

= int
= string
= array

Complete, correct, call looks like:

$client->updateShopItem(12345, "a1b2c3", [
"price" => 17.95,
"sale_price" => 12.99,
//... other values

Values to use instead of the ones in example above are string type: "17,95".

Have tried:

$price = "17,95" //Starting point (locale = nl_NL)

number_format($price, 2) // "17.00" - incorrect type and value
number_format(str_replace(',', '.', $price), 2) // "17.95" - string
(float) str_replace(',', '.', $price); // 17,95 - comma
(float) number_format(str_replace(',', '.', $price), 2) //17,95 - comma

setLocale(LC_ALL, 'en_US'); //Changing locale here, US uses dot separator

$check = locale_get_default(); // "en_US"

number_format($price, 2) // "17.00" - incorrect type and value
number_format(str_replace(',', '.', $price), 2) // "17.95" - string
(float) number_format(str_replace(',', '.', $price), 2) // 17,95 - comma
(float) str_replace(',', '.', $price); // 17,95 (can't figure why comma with US locale)

Extra test to see what
makes of the different types/values:

json_encode(["test1" => "17,95", "test2" => 17.95]);

//Results in:

UPDATE: to avoid confusion: full code, only removed non-relevant stuff, otherwise unedited. Has included locale se

setlocale(LC_ALL, 'nl_NL');
ini_set('intl.default_locale', 'nl-NL');
$update = [
'price' => ((float)number_format(str_replace(',', '.', $prijs), 2)),
'discount_price' => (float) str_replace(',', '.', $actieprijs),

setlocale(LC_ALL, 'en_US');
ini_set('intl.default_locale', 'en-US');
// Update a shopitem
$update2 = [
'price' => ((float)number_format(str_replace(',', '.', $prijs), 2)),
'discount_price' => (float) str_replace(',', '.', $actieprijs),

enter image description here

After some comments back 'n' forth with @KevinStich about his answer found that the problem when trying to change the locale was in the fact that I'm on Windows.

His answer solves it, after adding the following code above where it needs to get set:

if (!setlocale(LC_ALL, 'en_US.utf8')) { //Works on "normal" server/Linux stuff
setlocale(LC_ALL, 'us'); //Windows is special

Found in the docs that the
function returns
if it didn't set a new locale, or else returns the new locale. Which led to the above and that @KevinStich's answer worked.


It looks like there's something odd going on with the scoping of your cast. I've seen this issue before and am not sure what to chalk it up to, I solved it with more parenthesis.

This worked for me in the REPL

    ((float)number_format(str_replace(',', '.', $price), 2))

To make sure it's not a json_encode issue:

$price = "17,95";
$a = array();
$a[] = $price;
$a[] = ((float)number_format(str_replace(',', '.', $price), 2));

echo json_encode($a); // Prints ["17,95",17.95]