You are here:  » Currency Conversion Filter


Currency Conversion Filter

Submitted by support on Fri, 2012-12-14 16:03 in

Hi everyone,

Although not that common a requirement, there are some Price Tapestry users creating sites targeting a particular country (or rather currency) using data from product feeds where prices are quoted in a different currency - typically from merchants who deliver internationally, or for digitally delivered products.

The following filter takes daily EURO cross-reference rates from the ECB to enable import time currency conversion between any of the rates provided in the feed.

For backup purposes, the code first copies the exchange rates XML feed to your feeds folder, so it must be writable by PHP (if you are already using the Automation Tool this should already be set-up, otherwise you can enable WRITE access for all users using your FTP program). This means that if there is any problem accessing the feed at import time the last good copy is used instead. You should confirm that the cc_rates.xml is being regularly updated by keeping an eye on its Modified time on the /admin/ home page.

To use, copy the code from the PHP section below (excluding the PHP tags) and paste into the end of includes/filter.php. You can then add a new Currency Conversion filter to the Price field of a feed that is not in the same currency as your site and choose from and to currencies for conversion.

Note: Always ensure that your use of converted prices is made clear to users and is acceptable under the terms of the affiliate program being used!

<?php
  
/*************************************************/
  /* Currency Conversion                           */
  /*************************************************/
  
$filter_names["cc"] = "Currency Conversion";
  function 
filter_ccConfigure($filter_data)
  {
    
$cc = array(
      
'AUD','BGN','BRL','CAD','CHF','CNY','CZK','DKK','EUR','GBP',
      
'HKD','HRK','HUF','IDR','ILS','INR','JPY','KRW','LTL','LVL',
      
'MXN','MYR','NOK','NZD','PHP','PLN','RON','RUB','SEK','SGD',
      
'THB','TRY','USD','ZAR'
       
);
    
$cco = array();
    
$cco[""] = "Select Currency...";
    foreach(
$cc as $c$cco[$c] = $c;
    
widget_selectArray("From Currency","cc_from",TRUE,$filter_data["cc_from"],$cco);
    
widget_selectArray("To Currency","cc_to",TRUE,$filter_data["cc_to"],$cco);
  }
  function 
filter_ccValidate($filter_data)
  {
    if (!
$filter_data["cc_from"])
    {
      
widget_errorSet("cc_from","required field");
    }
    if (!
$filter_data["cc_to"])
    {
      
widget_errorSet("cc_to","required field");
    }
  }
  function 
filter_ccExec($filter_data,$text)
  {
    global 
$config_feedDirectory;
    global 
$filter_ccRates;
    if (!isset(
$filter_ccRates))
    {
      
$filename $config_feedDirectory."cc_rates.xml";
      
copy("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml",$filename);
      
$parser xml_parser_create();
      
xml_set_element_handler($parser"filter_ccElement""");
      
$cc_xml file_get_contents($filename);
      
$filter_ccRates = array();
      
$filter_ccRates["EUR"] = "1";
      
xml_parse($parser,$cc_xml,TRUE);
    }
    
$text tapestry_decimalise($text);
    
$EUR $text * (1/$filter_ccRates[$filter_data["cc_from"]]);
    return 
tapestry_decimalise($EUR $filter_ccRates[$filter_data["cc_to"]]);
  }
  function 
filter_ccElement($parser,$name,$attribs)
  {
    global 
$filter_ccRates;
    if (isset(
$attribs["CURRENCY"]))
    {
      
$filter_ccRates[$attribs["CURRENCY"]] = $attribs["RATE"];
    }
  }
?>

Submitted by Fuzzy on Mon, 2015-07-13 04:31

Hi David

Is it possible to get a curl version of this script as I have allow_url_fopen=0 for security reasons.

Submitted by support on Mon, 2015-07-13 09:08

Hi Fuzzy,

Sure - in place of this line:

  copy("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml",$filename);

use:

{see below}

Cheers,
David.
--
PriceTapestry.com

Submitted by Fuzzy on Tue, 2015-07-14 00:26

Thanks for that David - almost there.

The script now brings in cc_rates.xml into the feeds folder but now I am getting this error:

Warning: Division by zero in /xxxx/xxxx/xxxx/includes/filter.php on line 403

Prior to this I could import the feed by manually placing the cc_rates.xml into the feeds folder.

Line 403 is:  $EUR = $text * (1/$filter_ccRates[$filter_data["cc_from"]]);

Submitted by support on Tue, 2015-07-14 08:38

Hi,

Is your /feeds/ folder writable by PHP? This would normally be the case, for example if using the Automation Tool to fetch feeds but it would be the first thing to check. The easiest way is normally using your FTP program. In the remote window right-click on the feeds/ folder and then look for Permissions... or maybe Properties... and then Permissions, and then give WRITE access to all users (owner / group / world).

Once that's in place, or already the case, if you could first delete the cc_rates.xml file in case it was present but created by another user and then run an import process that would trigger the filter and see if the file appears.

If not, let me know and I'll check it out further with you...

Cheers,
David.
--
PriceTapestry.com

Submitted by Fuzzy on Tue, 2015-07-14 23:54

Thanks David

Permissions and the automation tool work fine. I removed the cc_rates.xml file from the feeds folder and when invoking an import, The error appears due to the fact cc_rates.xml has a filesize of 0.

Submitted by support on Wed, 2015-07-15 08:27

Hello Fuzzy,

My apologies, the feed location has moved which I had not realised, and CURL doesn't follow redirections by default - please have a go with the following replacement using the new URL:

  $fp = fopen($filename,"w");
  $ch = curl_init("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");
  curl_setopt($ch,CURLOPT_HEADER,0);
  curl_setopt($ch,CURLOPT_FILE,$fp);
  curl_exec($ch);
  fclose($fp);

(original post updated also)

Cheers,
David.
--
PriceTapestry.com

Submitted by Fuzzy on Mon, 2015-07-20 11:29

Sorry, forgot to get back to you.

All working, thanks again!

Submitted by ZILZAL on Wed, 2015-08-19 21:31

Hi David,
i used this method, the cc_rates file is there , but when apply the filter on feed all prices on that feed turns into 0.00.
what are you suggesting ?

PS: do i have to register the cc_rates as a feed ?
Regards.

Submitted by support on Thu, 2015-08-20 07:48

Hi,

There's no need to register the cc_rates.xml file - the feeds/ folder is only used by the above code as it would typically be already writeable by PHP, that's all.

If you browse to feeds/cc_rates.xml directly, do you see the table of conversion rates as expected, and specifically, are there rates shown for the currencies you are converting from / to?

Cheers,
David.
--
PriceTapestry.com

Submitted by ZILZAL on Fri, 2015-08-21 10:23

yes , the table of conversion rates are there as expected.and the rates shown for all currencies not just these i want.

Submitted by support on Fri, 2015-08-21 10:48

Hi,

I've just double checked the updated version in the original post on my test server and is working as expected, which currencies are you converting between, and can you give me an idea of the price range of the original (feed) price values so I can test your exact scenario?

Thanks,
David.
--
PriceTapestry.com

Submitted by ZILZAL on Fri, 2015-08-21 13:08

i will send you email with link to my website and other related info

Submitted by support on Fri, 2015-08-21 13:35

Thanks for the email,

All it was, is that the format of the price in your source feed contained the currency so was not a purely decimal number, and filters are applied before the decimalise() process that normally handles this scenario.

No problem, the incoming price value can be decimalised as the filter is applied, and I have updated the code in the original post to include this - see this line:

  $text = tapestry_decimalise($text);

Cheers,
David.
--
PriceTapestry.com

Submitted by ZILZAL on Thu, 2015-08-27 14:30

Thanks , the adjustments let it work as intended.

sorry for late reply.

Submitted by Pep on Fri, 2016-05-20 22:39

Hi David
Currency converter worked great.
Thanks

Submitted by sirmanu on Thu, 2016-09-22 13:44

I have a few merchants which use this filter.
However, always, with the merchant that uses for first time, I get this warning:
"importing merchant.xml...[0/8876]PHP Warning: copy(../feeds/cc_rates.xml): failed to open stream: Permission denied in /var/www/example.com/public_html/includes/filter.php on line 390"

Line 390 is copy("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml",$filename) and my feed folder is 777. As I say, the filter is working great even with that warning.

Submitted by support on Thu, 2016-09-22 14:23

Hi,

If the /feeds/ folder is mode 777, any process should be able to overwrite any file, but if the filter is working yet this warning appears, that would indicate that the file exists but cannot be overwritten, so the conversions may not be current but applied against an older version of the file.

What I would suggest is, using your FTP program, navigate to the /feeds/ folder in the remote window and DELETE the cc_rates.xml file, and then let the process run again. If the problem persists, let me know and I'll check it out further with you...

Cheers,
David.
--
PriceTapestry.com

Submitted by falmeida on Fri, 2017-08-25 11:44

hi david

i was thinking if its possible to use a converter like this but for bitcoin so that i could display on the website something like:

GBP Price
Bitcoin price

Submitted by falmeida on Fri, 2017-08-25 12:15

following my previous post i found that coinbase api might be better:
https://api.coinbase.com/v2/exchange-rates?currency=BTC
in https://developers.coinbase.com/api/v2#exchange-rates

Submitted by support on Sat, 2017-08-26 10:13

Hi,

The coinbase API is straight forward to use - as a display time conversion rather than as a filter (as I presume you still wish to have database price field in GBP). First, enable .json as a permitted feed filename extension by editing the value of $config_filenameRegExp at line 94 of config.advanced.php as follows:

  $config_filenameRegExp = "/^([0-9A-Za-z_\-\.]+)(\.xml|\.csv|\.json)$/";

With that in place, create a new Automation Tool job using URL:

https://api.coinbase.com/v2/exchange-rates?currency=BTC

...and Filename to save as:

btc.json

Run the job initially to download the conversion data, and then the file will be subsequently updated as your cronjob runs.

Next, edit html/prices.php and add the following PHP code at the top of the file:

<?php
  
function prices_btc($price,$currency)
  {
    global 
$prices_btc_data;
    if (!isset(
$prices_btc_data))
    {
      
$prices_btc_data json_decode(file_get_contents("feeds/btc.json"));
    }
    return 
sprintf("%.8f",$price/($prices_btc_data->data->rates->$currency));
  }
?>

And finally to add a BTC column to the price comparison table, look for the following code at (now) line 40:

          <th><?php print translate("Price"); ?></th>

...and REPLACE with:

          <th><?php print translate("Price"); ?></th>
          <th>BTC</th>

And then the following code at (now) line 74:

            <td class='pt_pr_price'><?php print tapestry_price($product["price"]); ?></td>

...and REPLACE with:

            <td class='pt_pr_price'><?php print tapestry_price($product["price"]); ?></td>
            <td class='pt_pr_price'><?php print prices_btc($product["price"],"GBP"); ?></td>

Cheers,
David.
--
PriceTapestry.com

Submitted by falmeida on Sat, 2017-08-26 15:16

Thank you David looks very nice !!

Submitted by sirmanu on Fri, 2019-01-25 19:08

Hi David.

Do you know why I am getting this warning sometimes?

PHP Warning: A non-numeric value encountered in /home/example/public_html/includes/filter.php on line 444

I mark you line 444 with strong

  /*************************************************/
  /* Currency Conversion */
  /*************************************************/
  $filter_names["cc"] = "Currency Conversion";
  function filter_ccConfigure($filter_data)
  {
    $cc = array(
      'AUD','BGN','BRL','CAD','CHF','CNY','CZK','DKK','EUR','GBP',
      'HKD','HRK','HUF','IDR','ILS','INR','JPY','KRW','LTL','LVL',
      'MXN','MYR','NOK','NZD','PHP','PLN','RON','RUB','SEK','SGD',
      'THB','TRY','USD','ZAR'
       );
    $cco = array();
    $cco[""] = "Select Currency...";
    foreach($cc as $c) $cco[$c] = $c;
    widget_selectArray("From Currency","cc_from",TRUE,$filter_data["cc_from"],$cco);
    widget_selectArray("To Currency","cc_to",TRUE,$filter_data["cc_to"],$cco);
  }
  function filter_ccValidate($filter_data)
  {
    if (!$filter_data["cc_from"])
    {
      widget_errorSet("cc_from","required field");
    }
    if (!$filter_data["cc_to"])
    {
      widget_errorSet("cc_to","required field");
    }
  }
  function filter_ccExec($filter_data,$text)
  {
    global $config_feedDirectory;
    global $filter_ccRates;
    if (!isset($filter_ccRates))
    {
      $filename = $config_feedDirectory."cc_rates.xml";
      if (!file_exists($filename))
      {
        $filename = "feeds/cc_rates.xml";
      }
      // copy("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml",$filename);
      $parser = xml_parser_create();
      xml_set_element_handler($parser, "filter_ccElement", "");
      $cc_xml = file_get_contents($filename);
      $filter_ccRates = array();
      $filter_ccRates["EUR"] = "1";
      xml_parse($parser,$cc_xml,TRUE);
    }
    $text = tapestry_decimalise($text);
    LINE 444: $EUR = $text * (1/$filter_ccRates[$filter_data["cc_from"]]);
    return tapestry_decimalise($EUR * $filter_ccRates[$filter_data["cc_to"]]);
  }
  function filter_ccElement($parser,$name,$attribs)
  {
    global $filter_ccRates;
    if (isset($attribs["CURRENCY"]))
    {
      $filter_ccRates[$attribs["CURRENCY"]] = $attribs["RATE"];
    }
  }

Submitted by support on Mon, 2019-01-28 09:12

Hi,

That implies that there is no rate for the selected from currency however the filter should not be working as expected in that case so I would leave the code unchanged for now and the next time you see the error check your site and if the conversion hasn't been applied (or all prices are 0 for example) let me know and I'll check that out further with you.

It could occur of course if there was a temporary connectivity issue accessing the ECB feed. I see that the fetch is commented out indicating that you are using an Automation Tool job to fetch the feed so that would be another thing to check the next time you see the warning (does jobs show OK status)...

Cheers,
David.
--
PriceTapestry.com