CakePHP Currency Conversion Component

Published: on 23/6/08 | Comments (11)

Ever needed a reliable currency converter, that you can just drop into your application and never worry about manually updating the rates for.

Well I do for a current application I have been developing and I decided that it would make an ideal example for demonstrating how easy it is to create usefull CakePHP components.

So after a little Googling, I found that the Central European Bank, rather conveniently publishes an XML feed of rates against the Euro that is updated nightly, by using the HttpSocket class, the XML class and a little bit of code, I created the following component which you are welcome to copy and use in any way you please.

Using the component

To use the component, simply copy the code into a file called currency.php and place that in your app/controllers/components folder, add 'Currency' to the $components array of the controller you need the functionality within (or app_controller if you want it avaliable site wide) then use:

    $result = $this->Currency->convert($amount,$fromCurrency,$toCurrency,$decimalPlaces);

Where $amount is the amount of money you want to convert, $fromCurrency is a 3 Character currency code from the table shown at the bottom of this article that you are converting from, $toCurrency is the 3 Character currency code that you want to convert to, and decimalPlaces is the number of decimal places you want the result returned to, so for example:

    $result = $this->Currency->convert(2.5, 'EUR', 'USD');

will give the US Dollar value for €2.50.

I have added a second function called table which returns an array of rates where each rate is expressed against a given base rate, for example:

    $result = $this->currency->table('USD',4);

Will return an array of currencies compared to US Dollars and to 4 decimal places.

O.K. so explaination over, here is the code and a table of currency codes, there are 35 different currencies all told so should be enough to cover most needs.

<?php
class CurrencyComponent extends object{
    /**
     * $components
     * 
     * Array of components required
     * 
     * @var $components array
     * @access public
     */
    var $components = array('Session');
    /**
     * convert
     * 
     * Converts the $amount from $fromCurrency to $toCurrency, formatted to
     * $decimals decimal places
     * 
     * @return float [Converted Currency Amount] 
     * @param $amount float
     * @param $fromCurrency string
     * @param $toCurrency string
     * @param $decimals integer[optional]default=2
     */
    function convert($amount,$fromCurrency,$toCurrency,$decimals = 2){
        //Get the rate table
        $rates = $this->__retrieveCurrencies();
        //Return result of conversion
        return number_format($amount/$rates[$fromCurrency]*$rates[$toCurrency],$decimals);
} /** * table * * Returns an array of rates in comparison the the $base currency given to $decimals * number of decimal places * * @return array * @param $base string[optional]default='EUR' * @param $decimals integer[optional]default=2 */ function table($base='EUR',$decimals=2){ //Create array to holds rates $rateTable = array(); //Get rate table array $rates = $this->__retrieveCurrencies(); //Iterate throught each rate converting it against $base foreach($rates as $key=>$value){ $rateTable[$key]=number_format(1/$rates[$base]*$rates[$key],$decimals); } //Return result array return $rateTable; } function __retrieveCurrencies(){ //Check whther we have already cached the currencies this session... if(!$this->Session->check('Currencies')){ //...we haven't, so load utility classes needed App::import('HttpSocket'); App::import('Xml'); //Create an http socket $http =& new HttpSocket(); //And retrieve rates as an XML object $currencies =& new XML($http->get('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml')); //Convert XML to array $currencies = Set::reverse($currencies); //Filter down to just the rates $currencies = $currencies['Envelope']['Cube']['Cube']['Cube']; //Create an array to hold the rates $currencyList = array(); //European Central bank gives us everything against Euro so add this manually $currencyList['EUR']=1; //Now iterate through and add the rates provided foreach($currencies as $currency){ $currencyList[$currency['currency']]=$currency['rate']; } //Save to session $this->Session->write('Currencies',$currencyList); } //Return rates array from session return $this->Session->read('Currencies'); } } ?>
Currency Code
Euro EUR
US Dollar USD
Japanese Yen JPY
Bulgarian Lev BGN
Czech Koruna CZK
Danish Krone DKK
Estonian Kroon EEK
Pound Sterling GBP
Hungarian Forint HUF
Lithuanian Litas LTL
Latvian Lats LVL
Polish Zloty PLN
New Romanian Leu RON
Swedish Krona SEK
Slovak Koruna SKK
Swiss Franc CHF
Icelandic Krona ISK
Norwegian Krone NOK
Croatian Kuna HRK
Russian Rouble RUB
New Turkish Lira TRY
Australian Dollar AUD
Brasilian Real BRL
Canadian Dollar CAD
Chinese Yuan Renminbi CNY
Hong Kong Dollar HKD
Indonesian Rupiah IDR
South Korean Won KRW
Mexican Peso MXN
Malaysian Ringgit MYR
New Zealand Dollar NZD
Philippine Peso PHP
Singapore Dollar SGD
Thai Baht THB
South African Rand ZAR

Hope you find this component usefull, let me know if you come up with any additional functionality you'd like it to include and 'till next time

Happy Baking!


Comments

1: butters said

hey, nice idea, but i would prefer to cache the currency-xml-file not in a session but on the filesystem or database. your component have to ask the ecb once a day, not every new session-user ;)

bye, butters


2: Peter said

@butters: Valid point and if anyone would like me to alter the component to do this then let me know through these comments and I will make the changes to illustrate how this is done simply with cakephp.

Also if anyone has any requests or suggestions for other components or code snippets either drop me a line(see my contact page for email address) or leave a comment here.

Best Regards

Peter


3: Mike said

@Peter: Implementing a cache makes more sense for app speed, bandwidth, and to not getting everyone's access to the ECB rates blocked. Anything you could add about how to cache a non-view would be helpful. Off the top of my head I think it just requires adding the Cache helper and "var cacheAction = '+1 hour';" in your component and then calling "$this->cacheAction = $currencyList;" instead of "$this->Session->write('Currencies',$currencyList);". Will that work from within a component & not a controller?

@butters: Good idea about adding caching. I think caching to the filesystem makes more sense than to the DB, unless you want to write an extra model to handle that data. Any reason the DB would be better?


4: Jeff said

Im a beginner at php I wan to apply this component to my website...ive supplied you with a demo link below

can this component do the job like the site below

and can it be done without using cakephp and only using php

http://www.go2africa.com/south-africa/cape-town/accommodation


5: Fahad said

nice one. Set::reverse() is just magic! thanks


6: Alex said

Your blog is interesting!

Keep up the good work!


7: kebocyxa pornok said

sympathetic location! fine done!


8: Mike H. said

Here is an array of the currency codes that can be fed into a CakePHP select box.

array('EUR'=>'Euro', 'USD'=>'US Dollar', 'JPY'=>'Japanese Yen', 'BGN'=>'Bulgarian Lev', 'CZK'=>'Czech Koruna', 'DKK'=>'Danish Krone', 'EEK'=>'Estonian Kroon', 'GBP'=>'Pound Sterling', 'HUF'=>'Hungarian Forint', 'LTL'=>'Lithuanian Litas', 'LVL'=>'Latvian Lats', 'PLN'=>'Polish Zloty', 'RON'=>'New Romanian Leu', 'SEK'=>'Swedish Krona', 'SKK'=>'Slovak Koruna', 'CHF'=>'Swiss Franc', 'ISK'=>'Icelandic Krona', 'NOK'=>'Norwegian Krone', 'HRK'=>'Croatian Kuna', 'RUB'=>'Russian Rouble', 'TRY'=>'New Turkish Lira', 'AUD'=>'Australian Dollar', 'BRL'=>'Brasilian Real', 'CAD'=>'Canadian Dollar', 'CNY'=>'Chinese Yuan Renminbi', 'HKD'=>'Hong Kong Dollar', 'IDR'=>'Indonesian Rupiah', 'KRW'=>'South Korean Won', 'MXN'=>'Mexican Peso', 'MYR'=>'Malaysian Ringgit', 'NZD'=>'New Zealand Dollar', 'PHP'=>'Philippine Peso', 'SGD'=>'Singapore Dollar', 'THB'=>'Thai Baht', 'ZAR'=>'South African Rand' );


9: Mike H. said

I rewrote the __retrieveCurrencies function to cache the results to a file for 24 hours. See below:

function __retrieveCurrencies() { //Check whther we have already cached the currencies this session... Cache::config(null, array('engine'=>'File', 'path'=>CACHE)); $currencyList = stripslashes_deep(Cache::read('currencies'));
if(empty($currencyList)) { //...we haven't, so load utility classes needed App::import('HttpSocket'); App::import('Xml'); //Create an http socket $http =& new HttpSocket(); //And retrieve rates as an XML object $currencies =& new XML($http->get('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml')); //Convert XML to array $currencies = Set::reverse($currencies); //Filter down to just the rates $currencies = $currencies['Envelope']['Cube']['Cube']['Cube']; //Create an array to hold the rates $currencyList = array(); //European Central bank gives us everything against Euro so add this manually $currencyList['EUR']=1; //Now iterate through and add the rates provided foreach($currencies as $currency){ $currencyList[$currency['currency']]=$currency['rate']; }

                $cache = Cache::write('currencies', $currencyList, array('duration'=>86400, 'config'=>null)); 
            }

    //Return rates array from session
    return $currencyList;
}

10: jennecqm said

Hey everyone! :D I'm new to www.studiocanaria.com. Hope I can be a regular here!


11: KattyBlackyard said Hi, gr8 post thanks for posting. Information is useful!

Have Your Say

Comments are now closed for this article


About Studio Canaria

Studio Canaria is the web site of freelance web developer, Peter Butler. Articles on this site relate to designing, developing and marketing modern web applications.

Recent Comments

Dave on CakePHP Auth Component - Users, Groups & Permissions Revisited
I dont understand how you define permissions for each contoller to User. Do I have to manually...
SI on CakePHP Auth Component - Users, Groups & Permissions Revisited
Hi Peter,

I am having little issue logging into the application. I have 2 user groups both having...
Alig on CakePHP Auth Component - Users, Groups & Permissions Revisited
Thank you very much for this tutorial. After fighting for hours to get the cakephp ACL working,...
Benny on CakePHP Auth Component - Users, Groups & Permissions Revisited
thank you for your solution it's perfect , you are genius , thank you this is the best ( beside...
Gordon on CakePHP Auth Component - Users, Groups & Permissions Revisited
I'm having a similar problem to luis. I followed everything as instructed here up to the point...