I was wondering if there is a simple method in PHP to format currency correctly for the following tasks:
If a value is: 4.37 then the output will be $4.37
If a value is: 4.00 then the output will be $4
If a value is: 4.3 or 4.30 then the output will be $4.30
If a value is 0.37 then the output will be 37¢
I'm sure this is quite complicated to do (I'm a beginner in PHP), but if anyone has any suggestions it would be greatly appreciated.
function format_currency($val) {
if ($val < 1) return intval(round($val * 100)) . '¢';
if (fmod($val, 1.0) == 0) return '$' . intval($val);
return '$' . intval($val) . '.' . intval(round((fmod($val,1))*100));
}
// Call it like this
$val = 1.2;
echo 'Your total: ' . format_currency($val);
Although this function will work, it's generally a bad idea to encode dollar amounts in a float.
I know this might be a bit of an overkill but take a look at Zend_Currency, it will take care of many different types of currency for this, it's also simple to use. Do note that you don't have to use the whole framework, just the currency class and the file it requires
http://framework.zend.com/manual/en/zend.currency.html
Related
This question already has answers here:
Compare floats in php
(17 answers)
Closed 4 years ago.
This piece of code:
$total=$o->cart->getTotalSum();
$subTotal=$o->cart->getSubTotal();
if(floatval($r['sum_total']) != floatval($total) ||
floatval($r['sum_sub']) != floatval($subTotal)) {
echo 'Differs on #' . $r['id'];
echo 'Total: ' . $total . ' / ' . $r['sum_total'];
echo 'Sub: ' . $subTotal . ' / ' . $r['sum_sub'];
}
Gives me this output:
Differs on #697
Total: 19.6 / 19.6
Sub: 19.6 / 19.6
Why? How is that even possible?
I make sure that all values compared are of type float, so no strings could have slipped in.
I must be missing something.
My apologies for not providing really reproducible code, but i wouldn't know how in this case.
If you do it like this they should be the same. But note that a characteristic of floating-point values is that calculations which
seem to result in the same value do not need to actually be identical.
So if $a is a literal .17 and $b arrives there through a calculation
it can well be that they are different, albeit both display the same
value.
Usually you never compare floating-point values for equality like
this, you need to use a smallest acceptable difference:
if (abs(($a-$b)/$b) < 0.00001) { echo "same"; } Something like that.
I think someone else had the exact same problem.
https://stackoverflow.com/a/3148991/2725502
I am using phpBB as a forum platform. I'm using a Mutualised Linux server with PHP Version 5.6.31 and MySQL(i) 5.7.19-log.
And I've found a bug that doesn't happen on others servers, since some phpbb team members as some friend of mine couldnt reproduce the problem. But there is more people with the same problem.
For people that want to check by themselves:
Basically with a fresh install of phpBB 3.2.1, we can go to ACP - Forums - Your first category - Your first forum.
There we confirmed that the option "Enable quick reply" is marked as "No"
Then we go to ACP - Posting - Messages - Post Settings and click on "Submit and enable quick reply in all forums".
After that we go again to the "your first forum" to check the "Enable quick reply" and its still as "No".
And it should be "Yes".
I've try to DEBUG and on the .php file that have the function that will create the SQL query that will be sent to database, I've put:
print(1 << 6); and it gives me 64.
So I've put too: print($bit); and it gives me 6.
So the code (1 << $bit) that is on the php should be correct, and should give me 64 BUT if I put: print(1 << $bit); it gives me 32!
I've put the 3 prints:
print(1 << 6);
print($bit);
print(1 << $bit);
And the result was: 64 6 32
Wtf?! Why the hell when we've an variable with 6 as value, it assumes as 5?!, or it assumes as the 6th position the representation of a byte?
Anyone have any idea why this is happening? Maybe PHP versin bug? Or can any type of configuration mess with this?
Let me explain better.
In /includes/constants.php we can find:
define('FORUM_FLAG_QUICK_REPLY', 64);
That value will be use to create the $bit value.
And on /includes/acp/acp_board.php we've a function that will create the $bit variable:
$config->set($config_name, $config_value);
if ($config_name == 'allow_quick_reply' && isset($_POST['allow_quick_reply_enable']))
{
enable_bitfield_column_flag(FORUMS_TABLE, 'forum_flags', log(FORUM_FLAG_QUICK_REPLY, 2));
}
This _enable_bitfield_column_flag_ function is what will create the sql code.
And the log(FORUM_FLAG_QUICK_REPLY, 2) = Log2(64) = 6.
So that's why the $bit is 6.
And in includes/functions_admin.php we've:
function enable_bitfield_column_flag($table_name, $column_name, $flag, $sql_more = '')
{
global $db;
$sql = 'UPDATE ' . $table_name . '
SET ' . $column_name . ' = ' . $db->sql_bit_or($column_name, $flag) . '
' . $sql_more;
$db->sql_query($sql);
}
We can see here the sql code being created by php code.
And finally on /phpbb/db/driver/driver.php we've:
return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : '');
And before that line I've put the 3 prints, and the values were 64 6 32... and it doesnt make sense, why print $bit gives 6 and 1 << $bit gives 32...
Thanks in advance!
Based on our exchanges in comment, and assuming $bit is indeed log2(64), I ran some tests and proved my initial idea :
$bit = log(64,2);
echo gettype(6)."\n"; // integer
echo gettype($bit)."\n"; // double
echo (int)$bit."\n"; // prints 6, but might as well have been 5
echo round($bit)."\n"; // prints 6
demo here : https://3v4l.org/Zogme
In this demo, all php versions tested appear to cast the result to 6 when converting to integer type (as it is the case with bitwise shifting operators such as <<, which works with integer arguments), but that's not guaranteed.
Float/double values are not really safe to work with, better round() it explicitly to a proper integer just to be sure and avoid the bug you are seeing.
$bit = round($bit);
Kudos goes to #axiac for fact-checking and pushing me to write this as an answer. Let me know if I can improve it further.
I have a e-commerce shop and on the shopping cart page it gives me a separate price for every product, but I need total price.
in order to do that, I need to calculate all these values together and that's fine.
But, what bugs me is that I should calculate the sum of variables that are given in this format:
$455.00
What is the best way to extract the value "455" so I could add it to another value afterwards?
I hope I made myself clear...
Don't use float, but instead use an integer in cent. Floats are not precise (see Floating Point Precision), so the calculation tend to fail if you use floats. That's especially a burden if it is related to payments.
$str = '$455.00';
$r = sscanf($str, '$%d.%d', $dollar, $cent);
if ($r <> 2 or $cent > 99 or $cent < 0 or $dollar > 9999 or $dollar < 0) throw new Exception(sprintf('Invalid string "%s"', $str));
$amountInDollarCents = $dollar * 100 + $cent;
echo $str, ' -> ', $amountInDollarCents;
Demo
If you need only the dollar sign removed, use str_replace. To convert that to int or float, typecast it. However, using float results in non-exact calculations so be careful with it!
$newval = (int)str_replace('$', '', '$455.00');
I think that your ECommerce site only has $ (USD)
$price= substr($string_price,1);
This will convert your string to a float:
$price = (float)substr("$455.00", 1);
echo($price);
For more information, you can see this answer, which has a couple of good links for you in it.
What about the following:
$amount = array();
$amount[0] = '$455.15';
$amount[2] = '$85.75';
$total = 0;
foreach ($amount AS $value) {
$value = str_replace('$', '', $value);
$total += $value;
}
echo $total . "\n";
The cleaning operation is:
$value = str_replace('$', '', $value);
You might want to extract it in a function, especially if you need to use it in more than one place.
Another thing to think about is, why do you have the value in such way? It's a display format and such conversion should be the last to be done, ideally by the template. Maybe, if possible, you should consider to fix the code before, instead of applying a patch like this one.
It really looks like your program is doing it wrong. You should really represent all prices as (double) instead of a string. Then only when you need to show the price to the user you would prepend the $ sign to it, converting it to a string. But your program should really treat prices as numbers and not strings.
If you storing your price in the database as a string "$5.99" then you are really doing it wrong.
It's been a long time since I worked with PHP, so I don't know what the best practice would be for working with currency. One quick method would be to remove "$" and ".", and just add together the resulting as integers.
use str_replace() for instance, and replace "$" and "." with an empty string: http://se2.php.net/manual/en/function.str-replace.php
This will give you the whole sum in cents (thus avoiding some potential rounding problems). You can then divide it by 100 and format it however you like to display the sum as dollars.
I want to protect PHP source code at easy way.
here is a example.
$a = "\x46\122" . chr(578813952>>23) . "" . chr(0105) . "\x2d";
$b = "\x73" . chr(847249408>>23) . "" . chr(0162) . "\x69" . chr(0141) . "" . chr(905969664>>23) . "";
$c = "" . chr(0x53) . "" . chr(0105) . "\x52\x56" . chr(0105) . "\x52" . chr(796917760>>23) . "\x4e" . chr(545259520>>23) . "\x4d" . chr(0x45) . "";
it is.
$a="FREE-";
$b="serial";
$c="SERVER_NAME";
Please help me someone to convert this type of string ??
There is 3 type of encryption.
Type[1] : "\x46\122"
Type[2] : chr(0105)
Type[3] : chr(578813952>>23)
Please help me to create a convert function...from PHP string.
thank you !
------------------------ I update question-------------------
OK... I should change question..
I want to create a function.
function1.
$a = "FREE-";
echo function1($a);
---> output
"\x46\122" . chr(578813952>>23) . "" . chr(0105) . "\x2d";
in this function, Function use 3 type of logic at random.
here is 3 type.
Type[1] : "\x46\122"
Type[2] : chr(0105)
Type[3] : chr(578813952>>23)
Could you help me ....
This is a, frankly, stupid way of "protecting" your code. Hopefully you realize that once the code is delivered to the clients, they can simply undo all of this and extract the values themselves?
Use legal means to protect the code. "here's my code, you are not allowed to share it. If you do, I get $50 kazillion dollars and the Droit de Seigneur with your most beautiful daughter, or an extra 200 kazillion in lieue if they're all ugly".
An iron-clad licensing agreement will be far better protection than any cereal-box decoder-ring wet kleenex method you care to apply ever will be.
For further suggestions why this is a waste of your time:
Asked at 8:36, decoded at 8:44. Eight minutes of protection: https://stackoverflow.com/questions/5456462/what-does-this-php-code-do
Asked at 11:01, decoded at 11:17, and very-well analyzed at 11:47. Hacked, what does this piece of code do?
In the first case, I'm willing to bet the majority of the fastest poster's time was spent writing. So feel confident that however you try to obfuscate your code, it'll take only three or four minutes to undo whatever it is you've done.
How much time are you willing to put into obfuscating your code when it'll take someone only a few minutes to undo what you've done? Could that time have been better spent writing awesome features that your customers would love?
ord will get you a character's ASCII value, using that we can generate the 3 things you want.
Type 1: Use dechex to convert int to hex.
$chr = 's';
$hex = dechex(ord($chr)); // 73
Type 2: Use decoct to convert into to octal.
$chr = 'E';
$oct = decoct(ord($chr)); // 105
Type 3: Use the << (shift left) operator.
$chr = 'e';
$bin = ord($chr)<<23; // 847249408
Is it possible to have PHP format currency values, for example: $200 will output as: $200 (without decimals) but with a number like $200.50 it will correctly output $200.50 instead of $200.5?
Thanks! :)
$num_decimals = (intval($amt) == $amt) ? 0 :2;
print ("$".number_format($amt,$num_decimals);
If you don't mind handling the currency on your own, you can simply use the following on the number, to get the correct output.
This solution will always output trailing zeros (xx.x0 or xx.00 depending on the provided number)
$number = 1234
sprintf("%0.2f",$number);
// 1234.00
How about a custom function to handle the situation accordingly:
function my_number_format($number) {
if(strpos($number, '.')) {
return number_format($number, 2);
} else {
return $number;
}
}
you can use number_format to do this.
Example:
$Amount = 200.00;
echo "$" . number_format($Amount); //$200
There are a couple of ways. Probably the most universally supported and recommended method is sprintf.
sprintf("%01.2f", "200.5"); //200.50
sprintf("%01.2f", "10"); //10.00
number_format is good as well, and has all sorts of options, and it will add thousands separators and such if requested to do so.
There's also a money_format function, but it is unsupported on Windows servers.