CurrencyLib.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. <?php
  2. /**
  3. * Other webservices:
  4. * - http://www.webservicex.net/WS/WSDetails.aspx?WSID=10 (XML)
  5. * - http://www.webserviceshare.com/business/financial/currency/service/Noon-Foreign-Exchange-Rates.htm (XML)
  6. */
  7. App::uses('HttpSocket', 'Network/Http');
  8. App::uses('Xml', 'Utility');
  9. /**
  10. * Component to retreive calculate currencies
  11. *
  12. * example:
  13. * $result = $this->Currency->convert(2.5, 'EUR', 'USD');
  14. *
  15. * from: http://www.studiocanaria.com/articles/cakephp_currency_conversion_component
  16. * alternativly: http://www.currencyserver.de/webservice/CurrencyServerWebService.asmx/getXmlStream?provider=AVERAGE
  17. *
  18. * @author Mark Scherer
  19. * @license MIT
  20. * @cakephp 2.x
  21. */
  22. class CurrencyLib {
  23. const URL = 'http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml';
  24. const URL_HISTORY = 'http://www.ecb.int/stats/eurofxref/eurofxref-hist.xml';
  25. //TODO: get information about a currency (name, ...)
  26. const URL_TABLE = 'http://www.ecb.int/rss/fxref-{currency}.html';
  27. public $baseCurrency = 'EUR';
  28. public $includeBitcoin = true;
  29. public $cacheFileUsed = false;
  30. public $cacheTime = DAY;
  31. /**
  32. * Converts the $amount from $fromCurrency to $toCurrency, formatted to
  33. * $decimals decimal places.
  34. *
  35. * @return float [Converted Currency Amount] or boolean FALSE on failure
  36. * @param $amount float
  37. * @param $fromCurrency string
  38. * @param $toCurrency string
  39. * @param $decimals integer[optional]default=2
  40. */
  41. public function convert($amount, $fromCurrency, $toCurrency, $decimals = 2) {
  42. //Get the rate table
  43. $rates = $this->_retrieveCurrencies();
  44. //Return result of conversion
  45. if (!array_key_exists($fromCurrency, $rates) || !array_key_exists($toCurrency, $rates)) {
  46. return false;
  47. }
  48. return number_format($amount / $rates[$fromCurrency] * $rates[$toCurrency], $decimals);
  49. }
  50. /**
  51. * Returns an array of rates in comparison the the $base currency given to $decimals
  52. * number of decimal places.
  53. *
  54. * @param $base string[optional]default='EUR'
  55. * @param $decimals integer[optional]default=2
  56. * @return array table or boolean FALSE on failure
  57. */
  58. public function table($base = 'EUR', $decimals = 2) {
  59. //Create array to holds rates
  60. $rateTable = array();
  61. //Get rate table array
  62. $rates = $this->_retrieveCurrencies();
  63. if (!array_key_exists($base, $rates)) {
  64. return false;
  65. }
  66. //Iterate throught each rate converting it against $base
  67. foreach ($rates as $key => $value) {
  68. $rate = 0;
  69. if ($value > 0) {
  70. $rate = 1 / $rates[$base] * $rates[$key];
  71. }
  72. $rateTable[$key] = number_format($rate, $decimals);
  73. }
  74. //Return result array
  75. return $rateTable;
  76. }
  77. /**
  78. * CurrencyLib::history()
  79. *
  80. * @param string $date Date in Format XXXX-XX-XX
  81. * @return array
  82. */
  83. public function history($date = null) {
  84. $history = $this->_retrieveHistory();
  85. if ($date) {
  86. if (!empty($history[$date])) {
  87. return $history[$date];
  88. }
  89. return array();
  90. }
  91. return $history;
  92. }
  93. /**
  94. * CurrencyComponent::isAvailable()
  95. *
  96. * @param mixed $currency
  97. * @return bool Success.
  98. */
  99. public function isAvailable($currency) {
  100. $rates = $this->_retrieveCurrencies();
  101. return array_key_exists($currency, $rates);
  102. }
  103. /**
  104. * @param string $name: "" (none), "history", "full" (both)
  105. * @return bool Success.
  106. */
  107. public function reset($name = 'full') {
  108. if ($name === 'full') {
  109. $name = '';
  110. Cache::delete('currencyListHistory');
  111. }
  112. return Cache::delete('currencyList' . ucfirst($name));
  113. }
  114. public function cacheFileUsed() {
  115. return $this->cacheFileUsed;
  116. }
  117. /**
  118. * @param string $code (3digit - e.g. EUR)
  119. * @param mixed $default (defaults to bool false)
  120. */
  121. public function getName($currency, $default = false) {
  122. if (empty($currency)) {
  123. return $default;
  124. }
  125. $currency = strtoupper($currency);
  126. $currencies = $this->currencies;
  127. if ($this->includeBitcoin) {
  128. $currencies['BTC'] = 'Bitcoin';
  129. }
  130. if (array_key_exists($currency, $currencies)) {
  131. return $currencies[$currency];
  132. }
  133. return $default;
  134. }
  135. /**
  136. * CurrencyComponent::_retrieveHistory()
  137. *
  138. * @return array
  139. */
  140. protected function _retrieveHistory() {
  141. if ($historyList = $this->_retrieve('history')) {
  142. return $historyList;
  143. }
  144. $currencies = $this->_loadXml(self::URL_HISTORY);
  145. // Filter down to just the rates
  146. $dates = $currencies['Envelope']['Cube']['Cube'];
  147. $historyList = array();
  148. foreach ($dates as $date) {
  149. $time = $date['@time'];
  150. foreach ($date['Cube'] as $currency) {
  151. $historyList[$time][$currency['@currency']] = $currency['@rate'];
  152. // European Central bank gives us everything against Euro so add this manually
  153. $historyList[$time][$this->baseCurrency] = 1;
  154. }
  155. }
  156. $this->_store($historyList, 'history');
  157. return $historyList;
  158. }
  159. /**
  160. * CurrencyComponent::_retrieveCurrencies()
  161. *
  162. * @return array
  163. */
  164. protected function _retrieveCurrencies() {
  165. if ($currencyList = $this->_retrieve()) {
  166. return $currencyList;
  167. }
  168. // Retrieve rates as an XML object
  169. $currencies = $this->_loadXml(self::URL);
  170. //Filter down to just the rates
  171. $currencies = $currencies['Envelope']['Cube']['Cube']['Cube'];
  172. //Create an array to hold the rates
  173. $currencyList = array();
  174. //European Central bank gives us everything against Euro so add this manually
  175. $currencyList[$this->baseCurrency] = 1;
  176. //Now iterate through and add the rates provided
  177. foreach ($currencies as $currency) {
  178. $currencyList[$currency['@currency']] = $currency['@rate'];
  179. }
  180. if ($this->includeBitcoin && ($res = $this->_getBitcoin())) {
  181. $currencyList['BTC'] = $res;
  182. }
  183. //Cache
  184. $this->_store($currencyList);
  185. return $currencyList;
  186. }
  187. protected function _getBitcoin() {
  188. App::uses('CurrencyBitcoinLib', 'Tools.Lib');
  189. $Btc = new CurrencyBitcoinLib();
  190. return $Btc->rate(array('currency' => $this->baseCurrency));
  191. }
  192. /**
  193. * @param string $name: "" (none), "history", "full" (both)
  194. */
  195. protected function _store($currencyList, $name = '') {
  196. $this->cacheFileUsed = false;
  197. Cache::write('currencyList' . ucfirst($name), serialize($currencyList));
  198. }
  199. /**
  200. * @param string $name: "" (none), "history", "full" (both)
  201. */
  202. protected function _retrieve($name = '') {
  203. $res = Cache::read('currencyList' . ucfirst($name));
  204. if ($res !== false) {
  205. $this->cacheFileUsed = true;
  206. return unserialize($res);
  207. }
  208. return false;
  209. }
  210. /**
  211. * CurrencyLib::_loadXml()
  212. *
  213. * @param string $url
  214. * @return array
  215. */
  216. protected function _loadXml($url) {
  217. $CurrencyXml = Xml::build($url);
  218. return Xml::toArray($CurrencyXml);
  219. }
  220. public $currencies = array(
  221. 'AFA' => 'Afghanistan Afghani',
  222. 'ALL' => 'Albanian Lek',
  223. 'DZD' => 'Algerian Dinar',
  224. 'ARS' => 'Argentine Peso',
  225. 'AWG' => 'Aruba Florin',
  226. 'AUD' => 'Australian Dollar',
  227. 'BSD' => 'Bahamian Dollar',
  228. 'BHD' => 'Bahraini Dinar',
  229. 'BDT' => 'Bangladesh Taka',
  230. 'BBD' => 'Barbados Dollar',
  231. 'BZD' => 'Belize Dollar',
  232. 'BMD' => 'Bermuda Dollar',
  233. 'BTN' => 'Bhutan Ngultrum',
  234. 'BOB' => 'Bolivian Boliviano',
  235. 'BWP' => 'Botswana Pula',
  236. 'BRL' => 'Brazilian Real',
  237. 'GBP' => 'British Pound',
  238. 'BND' => 'Brunei Dollar',
  239. 'BIF' => 'Burundi Franc',
  240. 'XOF' => 'CFA Franc (BCEAO)',
  241. 'XAF' => 'CFA Franc (BEAC)',
  242. 'KHR' => 'Cambodia Riel',
  243. 'CAD' => 'Canadian Dollar',
  244. 'CVE' => 'Cape Verde Escudo',
  245. 'KYD' => 'Cayman Islands Dollar',
  246. 'CLP' => 'Chilean Peso',
  247. 'CNY' => 'Chinese Yuan',
  248. 'COP' => 'Colombian Peso',
  249. 'KMF' => 'Comoros Franc',
  250. 'CRC' => 'Costa Rica Colon',
  251. 'HRK' => 'Croatian Kuna',
  252. 'CUP' => 'Cuban Peso',
  253. 'CYP' => 'Cyprus Pound',
  254. 'CZK' => 'Czech Koruna',
  255. 'DKK' => 'Danish Krone',
  256. 'DJF' => 'Dijibouti Franc',
  257. 'DOP' => 'Dominican Peso',
  258. 'XCD' => 'East Caribbean Dollar',
  259. 'EGP' => 'Egyptian Pound',
  260. 'SVC' => 'El Salvador Colon',
  261. 'EEK' => 'Estonian Kroon',
  262. 'ETB' => 'Ethiopian Birr',
  263. 'EUR' => 'Euro',
  264. 'FKP' => 'Falkland Islands Pound',
  265. 'GMD' => 'Gambian Dalasi',
  266. 'GHC' => 'Ghanian Cedi',
  267. 'GIP' => 'Gibraltar Pound',
  268. 'XAU' => 'Gold Ounces',
  269. 'GTQ' => 'Guatemala Quetzal',
  270. 'GNF' => 'Guinea Franc',
  271. 'GYD' => 'Guyana Dollar',
  272. 'HTG' => 'Haiti Gourde',
  273. 'HNL' => 'Honduras Lempira',
  274. 'HKD' => 'Hong Kong Dollar',
  275. 'HUF' => 'Hungarian Forint',
  276. 'ISK' => 'Iceland Krona',
  277. 'INR' => 'Indian Rupee',
  278. 'IDR' => 'Indonesian Rupiah',
  279. 'IQD' => 'Iraqi Dinar',
  280. 'ILS' => 'Israeli Shekel',
  281. 'JMD' => 'Jamaican Dollar',
  282. 'JPY' => 'Japanese Yen',
  283. 'JOD' => 'Jordanian Dinar',
  284. 'KZT' => 'Kazakhstan Tenge',
  285. 'KES' => 'Kenyan Shilling',
  286. 'KRW' => 'Korean Won',
  287. 'KWD' => 'Kuwaiti Dinar',
  288. 'LAK' => 'Lao Kip',
  289. 'LVL' => 'Latvian Lat',
  290. 'LBP' => 'Lebanese Pound',
  291. 'LSL' => 'Lesotho Loti',
  292. 'LRD' => 'Liberian Dollar',
  293. 'LYD' => 'Libyan Dinar',
  294. 'LTL' => 'Lithuanian Lita',
  295. 'MOP' => 'Macau Pataca',
  296. 'MKD' => 'Macedonian Denar',
  297. 'MGF' => 'Malagasy Franc',
  298. 'MWK' => 'Malawi Kwacha',
  299. 'MYR' => 'Malaysian Ringgit',
  300. 'MVR' => 'Maldives Rufiyaa',
  301. 'MTL' => 'Maltese Lira',
  302. 'MRO' => 'Mauritania Ougulya',
  303. 'MUR' => 'Mauritius Rupee',
  304. 'MXN' => 'Mexican Peso',
  305. 'MDL' => 'Moldovan Leu',
  306. 'MNT' => 'Mongolian Tugrik',
  307. 'MAD' => 'Moroccan Dirham',
  308. 'MZM' => 'Mozambique Metical',
  309. 'MMK' => 'Myanmar Kyat',
  310. 'NAD' => 'Namibian Dollar',
  311. 'NPR' => 'Nepalese Rupee',
  312. 'ANG' => 'Neth Antilles Guilder',
  313. 'NZD' => 'New Zealand Dollar',
  314. 'NIO' => 'Nicaragua Cordoba',
  315. 'NGN' => 'Nigerian Naira',
  316. 'KPW' => 'North Korean Won',
  317. 'NOK' => 'Norwegian Krone',
  318. 'OMR' => 'Omani Rial',
  319. 'XPF' => 'Pacific Franc',
  320. 'PKR' => 'Pakistani Rupee',
  321. 'XPD' => 'Palladium Ounces',
  322. 'PAB' => 'Panama Balboa',
  323. 'PGK' => 'Papua New Guinea Kina',
  324. 'PYG' => 'Paraguayan Guarani',
  325. 'PEN' => 'Peruvian Nuevo Sol',
  326. 'PHP' => 'Philippine Peso',
  327. 'XPT' => 'Platinum Ounces',
  328. 'PLN' => 'Polish Zloty',
  329. 'QAR' => 'Qatar Rial',
  330. 'ROL' => 'Romanian Leu',
  331. 'RUB' => 'Russian Rouble',
  332. 'WST' => 'Samoa Tala',
  333. 'STD' => 'Sao Tome Dobra',
  334. 'SAR' => 'Saudi Arabian Riyal',
  335. 'SCR' => 'Seychelles Rupee',
  336. 'SLL' => 'Sierra Leone Leone',
  337. 'XAG' => 'Silver Ounces',
  338. 'SGD' => 'Singapore Dollar',
  339. 'SKK' => 'Slovak Koruna',
  340. 'SIT' => 'Slovenian Tolar',
  341. 'SBD' => 'Solomon Islands Dollar',
  342. 'SOS' => 'Somali Shilling',
  343. 'ZAR' => 'South African Rand',
  344. 'LKR' => 'Sri Lanka Rupee',
  345. 'SHP' => 'St Helena Pound',
  346. 'SDD' => 'Sudanese Dinar',
  347. 'SRG' => 'Surinam Guilder',
  348. 'SZL' => 'Swaziland Lilageni',
  349. 'SEK' => 'Swedish Krona',
  350. 'TRY' => 'Turkey Lira',
  351. 'CHF' => 'Swiss Franc',
  352. 'SYP' => 'Syrian Pound',
  353. 'TWD' => 'Taiwan Dollar',
  354. 'TZS' => 'Tanzanian Shilling',
  355. 'THB' => 'Thai Baht',
  356. 'TOP' => 'Tonga Pa\'anga',
  357. 'TTD' => 'Trinidad & Tobago Dollar',
  358. 'TND' => 'Tunisian Dinar',
  359. 'TRL' => 'Turkish Lira',
  360. 'USD' => 'U.S. Dollar',
  361. 'AED' => 'UAE Dirham',
  362. 'UGX' => 'Ugandan Shilling',
  363. 'UAH' => 'Ukraine Hryvnia',
  364. 'UYU' => 'Uruguayan New Peso',
  365. 'VUV' => 'Vanuatu Vatu',
  366. 'VEB' => 'Venezuelan Bolivar',
  367. 'VND' => 'Vietnam Dong',
  368. 'YER' => 'Yemen Riyal',
  369. 'YUM' => 'Yugoslav Dinar',
  370. 'ZMK' => 'Zambian Kwacha',
  371. 'ZWD' => 'Zimbabwe Dollar',
  372. );
  373. }