PHP NumberFormatter: Decimal Digits bug - SOLVED - php
I'm new to using NumberFormatter (PHP) and right at the beginning I encountered a strange behavior that I consider a bug.
I have searched for a solution but have not found one.
I want to present prices according to customer conventions (correct decimal and thousands separators and correct currency marking), and I always want to present prices without the decimal part.
When I use the setAttribute(NumberFormatter::FRACTION_DIGITS, 0) and/or setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 0) settings, this only works for the currency intended for payments in that country. For prices in other currencies, it ignores the number of decimal places parameter.
Am I doing something wrong? How to force the given setting for all outputs?
Example code:
<?php
$val = 1234567.891234567890000;
$lngs = array("de_DE", "de_CH", "fr_CH", "nl_NL", "en_US", "en_GB", "cs_CZ");
$crncs = array("EUR", "CZK", "USD", "GBP", "CHF");
echo "<table border='1' style='width:auto;'>";
foreach($lngs as $lng) {
echo "<tr><th colspan='3' style='text-align: center;'>$lng</th>";
foreach ($crncs as $currency) {
$fmt = new NumberFormatter($lng, NumberFormatter::CURRENCY );
$fmt->setAttribute(NumberFormatter::FRACTION_DIGITS, 0); // this will be ignored everywhere except in a direct currency-language match
echo "<tr style='text-align: right;'><td>" . $currency . "</td><td>" . $fmt->formatCurrency($val, $currency) . "</td><td>" . $fmt->formatCurrency(-1 * $val, $currency) . "</td></tr>";
}
}
echo "</table>";
working example here
my output:
de_DE
EUR 1.234.568 € -1.234.568 €
CZK 1.234.567,89 CZK -1.234.567,89 CZK
USD 1.234.567,89 $ -1.234.567,89 $
GBP 1.234.567,89 £ -1.234.567,89 £
CHF 1.234.567,90 CHF -1.234.567,90 CHF
de_CH
EUR € 1'234'567.89 €-1'234'567.89
CZK CZK 1'234'567.89 CZK-1'234'567.89
USD $ 1'234'567.89 $-1'234'567.89
GBP £ 1'234'567.89 £-1'234'567.89
CHF CHF 1'234'568 CHF-1'234'568
fr_CH
EUR € 1'234'567.89 €-1'234'567.89
CZK CZK 1'234'567.89 CZK-1'234'567.89
USD $US 1'234'567.89 $US-1'234'567.89
GBP £UK 1'234'567.89 £UK-1'234'567.89
CHF CHF 1'234'568 CHF-1'234'568
nl_NL
EUR € 1.234.568 € 1.234.568-
CZK CZK 1.234.567,89 CZK 1.234.567,89-
USD US$ 1.234.567,89 US$ 1.234.567,89-
GBP £ 1.234.567,89 £ 1.234.567,89-
CHF CHF 1.234.567,90 CHF 1.234.567,90-
en_US
EUR €1,234,567.89 (€1,234,567.89)
CZK CZK1,234,567.89 (CZK1,234,567.89)
USD $1,234,568 ($1,234,568)
GBP £1,234,567.89 (£1,234,567.89)
CHF CHF1,234,567.90 (CHF1,234,567.90)
en_GB
EUR €1,234,567.89 -€1,234,567.89
CZK CZK1,234,567.89 -CZK1,234,567.89
USD $1,234,567.89 -$1,234,567.89
GBP £1,234,568 -£1,234,568
CHF CHF1,234,567.90 -CHF1,234,567.90
cs_CZ
EUR 1 234 567,89 € -1 234 567,89 €
CZK 1 234 568 Kč -1 234 568 Kč
USD 1 234 567,89 US$ -1 234 567,89 US$
GBP 1 234 567,89 £ -1 234 567,89 £
CHF 1 234 567,90 CHF -1 234 567,90 CHF
SOLUTION:
After further searching and elaboring I FOUND THE SOLUTION.
Before setting the number of decimal places, you still need to explicitly specify the currency:
$fmt->setTextAttribute(NumberFormatter::CURRENCY_CODE, $currency);
The function code is then:
<?php
$val = 1234567.891234567890000;
$lngs = array("de_DE", "de_CH", "fr_CH", "nl_NL", "en_US", "en_GB", "cs_CZ");
$crncs = array("EUR", "CZK", "USD", "GBP", "CHF");
echo "<table border='1' style='width:auto;'>";
foreach($lngs as $lng) {
echo "<tr><th colspan='3' style='text-align: center;'>$lng</th>";
foreach ($crncs as $currency) {
$fmt = new NumberFormatter($lng, NumberFormatter::CURRENCY );
// new line of code that solves the problem
$fmt->setTextAttribute(NumberFormatter::CURRENCY_CODE, $currency);
$fmt->setAttribute(NumberFormatter::FRACTION_DIGITS, 0);
echo "<tr style='text-align: right;'><td>" . $currency . "</td><td>" . $fmt->formatCurrency($val, $currency) . "</td><td>" . $fmt->formatCurrency(-1 * $val, $currency) . "</td></tr>";
}
}
echo "</table>";
Related
RegEx for extracting mobile numbers with a specific format
I have an sms text from mysql. The text contains 5 types of text. Firstly a 11 mobile number ( 01***********) format. And two amounts of money, One transaction ID with 10 digit uppercase letters and number and a date-time. I need to extract each of the text and store it in different variables. Example text: Cash In Tk 500.00 from 01789788881 successful. Fee Tk 0.00. Balance Tk 4,145.08. TrxID 6E63D2OS4R at 06/05/2019 20:24. So far i tried to extract the phone number $sms_text = $result['sms_text']; preg_match('/\b\d{3}\s*-\s*\d{3}\s*-\s*\d{4}\b/', $sms_text, $sms_from); echo $sms_from; echo $cash_in_amount; echo $fee; echo $ trx_id; echo $trx_time; How do I solve this problem?
You can use this regex, and extract the three values from group1, group2 and group3 and of course I can assume here that your SMS text would be in same format. from\s+(\d+).*([a-zA-Z0-9]{10})\s+at\s+(.*) Regex Demo 1 PHP Code Demo $sms = 'Cash In Tk 500.00 from 01789788881 successful. Fee Tk 0.00. Balance Tk 4,145.08. TrxID 6E63D2OS4R at 06/05/2019 20:24'; preg_match_all('/from\s+(\d+).*([a-zA-Z0-9]{10})\s+at\s+(.*)/', $sms, $matches); print('Mobile Number: '.$matches[1][0]."\n"); print('Transaction Id: '.$matches[2][0]."\n"); print('Date Time: '.$matches[3][0]."\n"); Output, Mobile Number: 01789788881 Transaction Id: 6E63D2OS4R Date Time: 06/05/2019 20:24 Edit: For getting Cash In Tk 500.00 and Fee Tk 0.00 you can use following regex, (\S+)\s+from\s+(\d+).*Fee\s+Tk\s+(\S+)\..*([a-zA-Z0-9]{10})\s+at\s+(.*) Regex Demo 2 Updated PHP Demo $sms = 'Cash In Tk 500.00 from 01789788881 successful. Fee Tk 0.00. Balance Tk 4,145.08. TrxID 6E63D2OS4R at 06/05/2019 20:24'; preg_match_all('/(\S+)\s+from\s+(\d+).*Fee\s+Tk\s+(\S+)\..*([a-zA-Z0-9]{10})\s+at\s+(.*)/', $sms, $matches); print('Cash In Tk: '.$matches[1][0]."\n"); print('Mobile Number: '.$matches[2][0]."\n"); print('Fee Tk: '.$matches[3][0]."\n"); print('Transaction Id: '.$matches[4][0]."\n"); print('Date Time: '.$matches[5][0]."\n"); Prints, Cash In Tk: 500.00 Mobile Number: 01789788881 Fee Tk: 0.00 Transaction Id: 6E63D2OS4R Date Time: 06/05/2019 20:24
How to convert rupee as paise with php
What is the correct way to display rupee as paise with php? eg, 552.25 rupee = 55225 paise 100.00 rupee = 1000 paise
1 Rupees is equal to 100 Paise (paise is an indian & pakistan currency) So, you should used this formula $paise=your_currency*100; if you have simple 552.25 rupees $rs=552.25; $paise=$rs*100; if you have 552.25 rupee. then $rs=`552.25 rupee`; preg_match('/([0-9]+\.[0-9]+)/', $rs, $matches); $float_val= (float) $matches[1]; $paise=$float_val*100;
Simple, You can do it by this way. Like below : $rs = 100*100. " paise"; Output : 10000 paise
Adjust cell data in CSV file, PHP
I am writing header in CSV by using this fputcsv($fp, $columns); It writes the header in CSV as follow AED AFN ALL AMD ANG AOA ARS AUD AWG AZN BAM BBD BDT BGN BHD BIF BMD BND BOB BRL BSD BTC BTN BWP BYR BZD CAD CDF CHF CLF CLP CNY COP CRC CUC CUP CVE CZK DJF DKK DOP DZD EEK EGP ERN ETB EUR FJD FKP GBP GEL GGP GHS GIP GMD GNF GTQ GYD HKD HNL HRK HTG HUF IDR ILS IMP INR IQD IRR ISK JEP JMD JOD JPY KES KGS KHR KMF KPW KRW KWD KYD KZT LAK LBP LKR LRD LSL LTL LVL LYD MAD MDL MGA MKD MMK MNT MOP MRO MUR MVR MWK MXN MYR MZN NAD NGN NIO NOK NPR NZD OMR PAB PEN PGK PHP PKR PLN PYG QAR RON RSD RUB RWF SAR SBD SCR SDG SEK SGD SHP SLL SOS SRD STD SVC SYP SZL THB TJS TMT TND TOP TRY TTD TWD TZS UAH UGX USD UYU UZS VEF VND VUV WST XAF XAG XAU XCD XDR XOF XPF YER ZAR ZMK ZMW ZWL above data is in $columns array. Using above data there is 168 columns. Now i am using for loop to fetch data $num_records=count($columns); for($z=1;$z<$num_records;$z++){ $rowData=fetchData($columns[$z] ,$columns[$z],1); fputcsv($fp, $rowData); } Here is fetchData function function fetchData($from,$to,$amount){ $access_key = 'MYKEY'; $endpoint = 'live'; // initialize CURL: if($from=="GNF"){ $url='http://apilayer.net/api/'.$endpoint.'?access_key='.$access_key.'&from='.$from.'&to='.$to.'&amount='.$amount.'&source='.$from.""; $ch = curl_init($url); //echo $url;exit; curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // get the (still encoded) JSON data: $json = curl_exec($ch); curl_close($ch); // Decode JSON response: $conversionResult = json_decode($json, true); $tmpArray=$conversionResult['quotes']; if($from=="") $from="USD"; array_unshift($tmpArray, $from); } return $tmpArray; } For GNF its returning 166 data. means less then header. Now my problem is because for GNF array has 166 conversion, And we have 168 columns. So its not showing as per header in CSV. Please tell me how i can fix this so it will show data as per header. Here is the generated CSV. You can see its not showing data correctly. https://www.dropbox.com/s/oo0a6ni4xkebat9/currency.csv?dl=0&s=sl
You're missing 2 columns because your FOR loop for($z=1; $z < $num_records; $z++) ignores the element [0] and the last element [167]. This should fix: $num_records=count($columns); for($z=0; $z <= $num_records; $z++){ $rowData=fetchData($columns[$z] ,$columns[$z],1); fputcsv($fp, $rowData); }
Convert Euro in Dogecoin
SO I am going to integrate the dogecoin in to the my busniess website. My Products are avilable to purchase in EURO currency and for avilable to provide it in doecoin I need to convert the EURO to Dogecoin. What I have DID: I have found the DOGECOIN API (https://www.dogeapi.com) in php. i have found that we can convert the DOGECOIN in BTC or USD. Using this : https://www.dogeapi.com/wow/?a=get_current_price&convert_to=USD&amount_doge=1000 The above URL gives me the total USD from DOGE AMOUNT.output is : 1.13949000 My Question is : How Can i convert the EURO in DOGEAMOUNT ? I have search alot and not found any solution . please help. Thanks in Advance.
A bit messy but does the work (it uses another url to get exchanges for USD,EUR) $doge2usd = file_get_contents("https://www.dogeapi.com/wow/?a=get_current_price&convert_to=USD&amount_doge=1"); echo sprintf("1 dogecoin => %f usd",$doge2usd); // 1 DOGE => USD 0.00115078 $eur2usd = file_get_contents("http://rate-exchange.appspot.com/currency?from=EUR&to=USD"); $j = json_decode($eur2usd,TRUE); $doge2eur = $doge2usd * (1 / $j["rate"]); // 1 DOGE => 0.00083941557920536 EUR echo sprintf("<br>1 dogecoins => %f euro, 5 dogecoins => %f euro",$doge2eur,$doge2eur*5); $eur2doge = 1 / $doge2eur; // 1 EUR => DOGE 1197.29 echo sprintf("<br>1 euro => %f dogecoins, 5 euro => %f dogecoins",$eur2doge,$eur2doge*5);
The dogeapi.com API can only give you the exchange rate in BTC or USD. To get the exchange rate from XDG (is that the inofficial three-letter-code for Dogecoin? Let's just assume that) to EUR, you'll have to take two steps: Get the exchange rate from XDG to USD. Get the exchange rate from USD to EUR. For the first one, we have DogeAPI. For the second one, I'm going to use Yahoo's API. <?php // how much is 1 dogecoin worth in USD? $xdgusd = (double)file_get_contents("https://www.dogeapi.com/wow/?a=get_current_price&convert_to=USD&amount_doge=1"); // how much is 1 EUR worth in USD? $yahoo_result = json_decode(file_get_contents("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20=%20%22EURUSD%22&format=json&env=store://datatables.org/alltableswithkeys&callback=")); $eurusd = (double)$yahoo_result->query->results->rate->Rate; // how much is 1 dogecoin worth in EUR? $xdgeur = $xdgusd / $eurusd; echo "Doge in USD: " . $xdgusd . "\n"; echo "EUR in USD: " . $eurusd . "\n"; echo "Doge in EUR: " . $xdgeur . "\n"; This prints: Doge in USD: 0.00113941 EUR in USD: 1.3713 Doge in EUR: 0.00083089768832495 Please note that this example doesn't cover details like bis/ask spread. Also, in a real system, you shouldn't query the web services with every request, but cache the result on your machine. And check if you got sane values back from the APIs.
How do you get number_format() to add two decimal points on integers less than 10?
The price is in cents, but whenever the price is less than $10 its not adding .00! $price = (float)($cents/100); $price = number_format($price,2); I want to be able to represent 0.00 and 0.01 and 1.01 not sure how to do this if number_format() doesnt work!
Take a look at money_format. <?php $prices = array(100, 10, 1, 0.10, 0.01); foreach ($prices as $price) { echo money_format('%.2n', $price) . "\n"; } // 100.00 // 10.00 // 1.00 // 0.10 // 0.01 ?>