source: trunk/lib/Currency.inc.php @ 411

Last change on this file since 411 was 411, checked in by anonymous, 12 years ago

Added ECB XML API to Currency.inc.php

File size: 10.3 KB
Line 
1<?php
2/**
3 * The Strangecode Codebase - a general application development framework for PHP
4 * For details visit the project site: <http://trac.strangecode.com/codebase/>
5 * Copyright 2001-2012 Strangecode, LLC
6 *
7 * This file is part of The Strangecode Codebase.
8 *
9 * The Strangecode Codebase is free software: you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your option)
12 * any later version.
13 *
14 * The Strangecode Codebase is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/**
24 * Currency.inc.php
25 *
26 * Class to convert currency values.
27 *
28 * @author  Quinn Comendant <quinn@strangecode.com>
29 * @version 1.5
30 *
31 * Example of use:
32---------------------------------------------------------------------
33$currency = new Currency();
34$currency->setParam(array('cache_dir' => COMMON_BASE . '/tmp/xcache'));
35echo $currency->getRage('eur', 'usd');
36echo $currency->getValue(125.50, 'eur', 'usd');
37---------------------------------------------------------------------
38 */
39 
40class Currency {
41
42    // Configuration parameters for this object.
43    var $_params = array(
44        'cache_result' => true,
45        'cache_dir' => '',
46        'cache_age' => 86400, // 24 hours.
47        'api' => 'ecb', // 'xurrency' or 'ecb'. Add other APIs under the _performAPICall() method.
48        'api_key' => '', // Used only by xurrency API.
49    );
50   
51    /**
52     * Cart constructor.
53     */
54    function Currency($params=array())
55    {
56        $app =& App::getInstance();
57
58        // Set custom parameters.
59        $this->setParam($params);
60       
61        // Setup cache directory.
62        if ($this->getParam('cache_result')) {
63            if ('' == $this->getParam('cache_dir')) {
64                // Use a sane default cache directory.
65                $this->setParam(array('cache_dir' => '/tmp/xcache_' . md5(COMMON_BASE)));
66            }
67            if (!is_dir($this->getParam('cache_dir'))) {
68                $app->logMsg(sprintf('Creating cache_dir: %s', $this->getParam('cache_dir')), LOG_INFO, __FILE__, __LINE__);               
69                if (!mkdir($this->getParam('cache_dir'))) {
70                    $app->logMsg(sprintf('Could not create cache_dir: %s', $this->getParam('cache_dir')), LOG_WARNING, __FILE__, __LINE__);               
71                }
72            }
73        }
74    }
75
76    /**
77     * Set the params of this object.
78     *
79     * @param  array $params   Array of param keys and values to set.
80     */
81    function setParam($params=null)
82    {
83        if (isset($params) && is_array($params)) {
84            // Merge new parameters with old overriding only those passed.
85            $this->_params = array_merge($this->_params, $params);
86        }
87    }
88
89    /**
90     * Return the value of a parameter, if it exists.
91     *
92     * @access public
93     * @param string $param        Which parameter to return.
94     * @return mixed               Configured parameter value.
95     */
96    function getParam($param)
97    {
98        $app =& App::getInstance();
99   
100        if (isset($this->_params[$param])) {
101            return $this->_params[$param];
102        } else {
103            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
104            return null;
105        }
106    }
107   
108    /*
109    * Return the exchange value between the two given currencies for given amount.
110    *
111    * @access   public
112    * @param    float   $amount Base amount to convert from.
113    * @param    string  $base   3-letter currency code to convert from.
114    * @param    string  $target 3-letter currency code to convert to.
115    * @return   mixed   Float converted currency value, or false on error.
116    * @author   Quinn Comendant <quinn@strangecode.com>
117    * @version  1.0
118    * @since    05 May 2008 23:50:59
119    */
120    function getValue($amount, $base, $target)
121    {
122        if (false !== $rate = $this->getRate($base, $target)) {
123            return abs($rate * $amount);           
124        } else {
125            return false;
126        }
127    }
128   
129    /*
130    * Return the currency conversion rate as a ratio.
131    *
132    * @access   public
133    * @param    string  $base   3-letter currency code to convert from.
134    * @param    string  $target 3-letter currency code to convert to.
135    * @return   mixed   Float exchange rate value, or false on error.
136    * @author   Quinn Comendant <quinn@strangecode.com>
137    * @version  1.0
138    * @since    25 May 2011 01:26:24
139    */
140    function getRate($base, $target)
141    {
142        $app =& App::getInstance();
143
144        $cache_file_path = sprintf('%s/%s-to-%s', $this->getParam('cache_dir'), $base, $target);
145        $cache_file_mtime = @filemtime($cache_file_path);
146        if (!$this->getParam('cache_result') || !$cache_file_mtime || $cache_file_mtime < time() - $this->getParam('cache_age')) {
147            // Get fresh data and create cached file if missing or expired.
148            $app->logMsg(sprintf('Getting fresh currency exchange rate: %s-to-%s', $base, $target), LOG_DEBUG, __FILE__, __LINE__);
149            $value = $this->_performAPICall(array(
150                'amount' => '1',
151                'base' => $base,
152                'target' => $target
153            ));
154            if (false === $value || !is_numeric($value)) {
155                // Failed retrieving value. Use cached copy for now.
156                $app->logMsg(sprintf('Failed getting currency exchange rate: %s-to-%s, using cached copy', $base, $target), LOG_NOTICE, __FILE__, __LINE__);
157                if (!$value = @file_get_contents($cache_file_path)) {
158                    $app->logMsg(sprintf('Failed reading cached exchange rate file: %s', $cache_file_path), LOG_ERR, __FILE__, __LINE__);
159                    return false;
160                }
161            } else if ($this->getParam('cache_result') && !filePutContents($cache_file_path, $value)) {
162                $app->logMsg(sprintf('Failed writing to target rate file: %s', $cache_file_path), LOG_ERR, __FILE__, __LINE__);
163                return false;
164            }
165        } else {
166            $app->logMsg(sprintf('Getting cached currency exchange rate: %s-to-%s', $base, $target), LOG_DEBUG, __FILE__, __LINE__);
167            if (!$value = file_get_contents($cache_file_path)) {
168                $app->logMsg(sprintf('Failed reading target rate file: %s', $cache_file_path), LOG_ERR, __FILE__, __LINE__);
169                return false;
170            }
171        }
172        $app->logMsg(sprintf('Found currency exchange rate: %s-to-%s = %s', $base, $target, $value), LOG_DEBUG, __FILE__, __LINE__);
173        return trim($value);
174    }
175   
176    /**
177     * @param  string
178     * @param  array
179     * @return mixed
180     * @access private
181     */
182    function _performAPICall($parameters=null)
183    {
184        $app =& App::getInstance();
185
186        switch ($this->getParam('api')) {
187        case 'xurrency' :
188            $api_url = 'http://xurrency.com/api/%s/%s/%s';
189            if ('' != $this->getParam('api_key')) {
190                $api_url .= '?key=' . $this->getParam('api_key');
191            }
192            $json_response = file_get_contents(sprintf($api_url, $parameters['base'], $parameters['target'], $parameters['amount']));
193            $json = json_decode($json_response);
194            if (null === $json) {
195                $app->logMsg(sprintf('Could not decode JSON response: %s', getDump($json_response)), LOG_WARNING, __FILE__, __LINE__);
196                return false;
197            } else if ($json->status === 'fail') {
198                if ($json->code == 3) {
199                    $app->logMsg(sprintf('Xurrency error LimitReachedException: %s', $json->message), LOG_WARNING, __FILE__, __LINE__);
200                } elseif ($json->code == 2) {
201                    $app->logMsg(sprintf('Xurrency error InvalidCurrencies: %s', $json->message), LOG_WARNING, __FILE__, __LINE__);
202                } elseif ($json->code == 4 || $json->code == 5) {
203                    $app->logMsg(sprintf('Xurrency error InvalidKey: %s', $json->message), LOG_WARNING, __FILE__, __LINE__);
204                } else {
205                    $app->logMsg(sprintf('Xurrency unknown error: %s', $json->message), LOG_WARNING, __FILE__, __LINE__);
206                }
207                return false;
208            } else {
209                return $json->result->value;
210            }
211            break;
212
213        case 'ecb' :
214            // Fetch XML from ECB <http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml>
215            $api_url = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml';
216            if (false === $sXML = file_get_contents($api_url)) {
217                $app->logMsg(sprintf('Failed to load ECB XML data from ', $api_url), LOG_WARNING, __FILE__, __LINE__);
218                return false;
219            }
220            if (false === $oXML = simplexml_load_string($sXML)) {
221                $app->logMsg(sprintf('Failed to decode ECB XML data: ', truncate($sXML, 200, 'end')), LOG_WARNING, __FILE__, __LINE__);
222                return false;
223            }
224            // Populate Array
225            foreach ($oXML->Cube->Cube->Cube as $oRate) {
226                foreach ($oRate->attributes() as $sKey => $sAttribute) {
227                    if ($sKey == 'currency') {
228                        $sCurrency = strtolower((string) $sAttribute);
229                    } else if ($sKey == 'rate') {
230                        $nRate = (string) $sAttribute;
231                    }
232                }
233                $aCurrencies['eur'][$sCurrency] = $nRate;
234                $aCurrencies[$sCurrency]['eur'] = 1 / $nRate;
235            }
236            // Check if requested rates are available.
237            if (isset($aCurrencies[$parameters['base']][$parameters['target']])) {
238                return (float) $aCurrencies[$parameters['base']][$parameters['target']];
239            } else {
240                $app->logMsg(sprintf('API %s does not have base %s or target %s', $this->getParam('api'), $parameters['base'], $parameters['target']), LOG_WARNING, __FILE__, __LINE__);
241                return false;
242            }
243
244        default :
245            trigger_error('Unknown API: ' . $this->getParam('api'), E_USER_ERROR);
246            die;
247            break;
248        }
249    }
250}
251
252
253?>
Note: See TracBrowser for help on using the repository browser.