Reputation: 3468
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,
// BUT NOT:
"price": "17.95" OR 17,95
}
Why? Because the receiving API endpoint does a check for the first but throws a non-numeric
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 nl_NL
to en_US
gives the number_format
function the correct format, however, as a string.
Casting a comma or dot separated string using (float)
causes it to lose any value from the point of separation. ("17.95"
becomes 17
)
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)
$shopId
= int
$articleNumber
= string
$updateArray
= 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 json_encode()
makes of the different types/values:
json_encode(["test1" => "17,95", "test2" => 17.95]);
//Results in:
{"test1":"17,95","test2":17.95}
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),
];
UPDATE 2: SOLUTION FOUND 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 setlocale()
function returns false
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.
Upvotes: 4
Views: 1468
Reputation: 783
@Nukeface's issue was related to the locale setting and different variables passed to setlocale()
based on platform; specifically that Windows uses different locale names from unix systems.
setlocale's return value can help you diagnose if the call worked at all, and you can use localeconv()
to see some of your current locale settings.
It's likely you want to only do this specific to json_encode()
'd information, so consider wrapping a setlocale to the right locale, the encode, and a setlocale back to your standard in its own function.
Here are the old answers that led to the discussion in the comments:
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
var_dump(
((float)number_format(str_replace(',', '.', $price), 2))
);
float(17.95)
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]
Upvotes: 2