Those of you who know me well know that I'm not a huge fan of PHP. While I don't really enjoy it, I use it on a daily basis for sites that I maintain and develop both personally and at work. Recently a client of ours (a private airline) needed to update some pricing on their site for the first of the month. To make this and future updates easier, I rewrote a bit of the logic behind the pricing system and in-turn, started to store the prices as integers rather than strings. While checking the site this morning to make sure everything updated this weekend, I noticed that while the new prices were there, they weren't being displayed properly! Instead of something like "$2,500" the prices were simply "2500". Clearly there was an issue with money_format not working correctly.

Luckily I had ran into this issue before and was partially familiar with the fix. Being a bit rusty, I turned to google and the network of blogs and fellow geeks out there for a solid answer. I couldn't find any valid advice anywhere, except for one lonely comment on the PHP documentation for money_format. Jeremy says:

If money_format doesn't seem to be working properly, make sure you are defining a valid locale. For example, on Debian, 'en_US' is not a valid locale - you need 'en_US.UTF-8' or 'en_US.ISO-8559-1'.

This was frustrating me for a while. Debian has a list of valid locales at /usr/share/i18n/SUPPORTED; find yours there if it's not working properly.

This got the wheels turning in my head and reminded me that there was an issue with the locale. The first step to solving this issue is adding the following line to the top of the PHP file which will be using money_format():

<?php
setlocale(LC_MONETARY, 'en_US.utf8');
?>

Of course, if you'd like to have your money formatted differently, you're going to want to use a different locale. I'm in the US and so is this particular client, so this is the locale we've chosen. Adding this bit of code didn't do anything to the result of money_format, so I needed to look deeper.

The next step is running the command locale on your server to find out your dealing with in that regard:

mwhalen@meerkat:~$ locale
LANG=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

This tells me that I haven't set any locales yet. Luckily on Debian and Ubuntu systems, this is also an easy fix. Simply run these two commands, answering the questions for the second command as you're prompted. Once this is finished, you can log out of your box and log back in. Running the locale command again will show that you've set a new locale across the board:

mwhalen@meerkat:~$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

Now that my locale is correct, I just needed to restart my fast_cgi processes so that PHP would reflect these changes as well. After doing that, everything was good to go! Prices displayed correctly, and everyone is happy. All in a day's work.