Rev 21 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
22 | daniel-mar | 1 | <?php |
2 | |||
3 | // PHP library for CurrencyLayer |
||
4 | // (C) 2017-2022 ViaThinkSoft, Daniel Marschall |
||
5 | // Revision: 2022-08-06 |
||
6 | // |
||
7 | // More information at https://currencylayer.com/documentation |
||
8 | |||
9 | # EXAMPLE |
||
10 | /* |
||
11 | $x = new CurCalc('cache.json', 'YOUR API KEY HERE', false); |
||
12 | if ($x->needs_download(1*60*60)) $x->download_exchange_rates(); // refresh data every hour |
||
13 | $val = $x->convert_cur(100, 'EUR', 'RUB'); |
||
14 | echo "100 EUR are $val RUB.\n"; |
||
15 | */ |
||
16 | |||
17 | # --- |
||
18 | |||
19 | class CurCalcException extends Exception {} |
||
20 | class CurrencyLayerException extends CurCalcException {} |
||
21 | |||
22 | class CurCalc { |
||
23 | |||
24 | protected $jsonfile = null; |
||
25 | protected $apikey = null; |
||
26 | protected $use_https = null; |
||
27 | function __construct($jsonfile, $apikey, $use_https=true) { |
||
28 | $this->jsonfile = $jsonfile; |
||
29 | $this->apikey = $apikey; |
||
30 | $this->use_https = $use_https; |
||
31 | } |
||
32 | |||
33 | public function exchange_rates_age() { |
||
34 | $this->check_json_file_exists(); |
||
35 | |||
36 | // return time() - filemtime($this->jsonfile); |
||
37 | |||
38 | $cont = file_get_contents($this->jsonfile); |
||
39 | $data = json_decode($cont, true); |
||
40 | $this->check_data_ok($data); |
||
41 | return time() - $data['timestamp']; |
||
42 | } |
||
43 | |||
44 | public function needs_download($max_age=-1) { |
||
45 | if (!$this->check_json_file_exists(false)) { |
||
46 | return true; |
||
47 | } else if (!$this->check_data_ok(null, false)) { |
||
48 | return true; |
||
49 | } else if ($max_age == -1) { |
||
50 | return false; |
||
51 | } else { |
||
52 | return $this->exchange_rates_age() > $max_age; |
||
53 | } |
||
54 | } |
||
55 | |||
56 | private function check_json_file_exists($raise_exception=true) { |
||
57 | if (!file_exists($this->jsonfile)) { |
||
58 | if ($raise_exception) { |
||
59 | throw new CurCalcException('JSON file '.$this->jsonfile.' not found. Please download it first.'); |
||
60 | } else { |
||
61 | return false; |
||
62 | } |
||
63 | } else { |
||
64 | return true; |
||
65 | } |
||
66 | } |
||
67 | |||
68 | private function check_data_ok($data, $raise_exception=true) { |
||
69 | if (is_null($data)) { |
||
70 | $ret = $this->check_json_file_exists($raise_exception); |
||
71 | if ((!$raise_exception) && (!$ret)) return $ret; |
||
72 | $cont = file_get_contents($this->jsonfile); |
||
73 | $data = json_decode($cont, true); |
||
74 | } |
||
75 | |||
76 | if ((!isset($data['success'])) || ($data['success'] !== true)) { |
||
77 | if ($raise_exception) { |
||
78 | if (isset($data['error'])) throw new CurrencyLayerException($data['error']['code'] . ' : ' . $data['error']['info']); |
||
79 | throw new CurCalcException('JSON file '.$this->jsonfile.' does not contain valid request data. Please download it again.'); |
||
80 | } else { |
||
81 | return false; |
||
82 | } |
||
83 | } |
||
84 | |||
85 | return true; |
||
86 | } |
||
87 | |||
88 | public function download_exchange_rates() { |
||
89 | // 1. Download |
||
90 | $protocol = $this->use_https ? 'https' : 'http'; |
||
91 | $cont = file_get_contents($protocol.'://www.apilayer.net/api/live?access_key='.$this->apikey); |
||
92 | if (!$cont) throw new CurCalcException('Failed to download from CurrencyLayer.'); |
||
93 | |||
94 | // 2. Test result |
||
95 | $test_data = json_decode($cont, true); |
||
96 | $this->check_data_ok($test_data); |
||
97 | |||
98 | // 3. Save |
||
99 | if (!file_put_contents($this->jsonfile, $cont)) throw new CurCalcException('Saving to '.$this->jsonfile.' failed.'); |
||
100 | |||
101 | // 4. OK |
||
102 | $this->cache_exchange_rates_ary = null; |
||
103 | return 0; |
||
104 | } |
||
105 | |||
106 | private $cache_exchange_rates_ary = null; |
||
107 | private function get_exchange_rates_ary() { |
||
108 | if (!is_null($this->cache_exchange_rates_ary)) return $this->cache_exchange_rates_ary; |
||
109 | |||
110 | $this->check_json_file_exists(); |
||
111 | $data = json_decode(file_get_contents($this->jsonfile), true); |
||
112 | $this->check_data_ok($data); |
||
113 | |||
114 | $exchange_rates_ary = array(); |
||
115 | $source = $data['source']; |
||
116 | $quotes = $data['quotes']; |
||
117 | $quotes['USDUSD'] = 1; // missing 06 Aug 2022. A bug?? Reported https://github.com/apilayer/currencylayer-API/issues/16 |
||
118 | foreach ($quotes as $n => $v) { |
||
119 | if ($source == substr($n, 0, 3)) { |
||
120 | $exchange_rates_ary[substr($n, 3, 3)] = $v; // key: USDxxx=12.345 |
||
121 | } |
||
122 | } |
||
123 | unset($quotes); |
||
124 | |||
125 | asort($exchange_rates_ary); |
||
126 | $this->cache_exchange_rates_ary = $exchange_rates_ary; |
||
127 | return $exchange_rates_ary; |
||
128 | } |
||
129 | |||
130 | public function get_supported_currencies() { |
||
131 | return array_keys($this->get_exchange_rates_ary()); |
||
132 | } |
||
133 | |||
134 | public function convert_cur($value, $from_cur, $to_cur) { |
||
135 | $from_cur = strtoupper(trim($from_cur)); |
||
136 | $to_cur = strtoupper(trim($to_cur)); |
||
137 | |||
138 | if ($from_cur == $to_cur) return $value; |
||
139 | |||
140 | $exchange_rates_ary = $this->get_exchange_rates_ary(); |
||
141 | |||
142 | if (!isset($exchange_rates_ary[$from_cur])) throw new CurCalcException("Source curreny $from_cur not found in exchange data."); |
||
143 | if (!isset($exchange_rates_ary[$to_cur])) throw new CurCalcException("Destination curreny $to_cur not found in exchange data."); |
||
144 | |||
145 | return $value * $exchange_rates_ary[$to_cur]/$exchange_rates_ary[$from_cur]; |
||
146 | } |
||
147 | |||
8 | daniel-mar | 148 | } |