├── .gitattributes
├── LICENSE
├── README.md
├── composer.json
└── src
├── Exception.php
├── ExchangeRatesAPI.php
└── Response.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Ben Major
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ExchangeRatesAPI - Currency Exchange Rates API SDK
2 |
3 | [](https://packagist.org/packages/benmajor/exchange-rates-api)
4 | [](https://packagist.org/packages/benmajor/exchange-rates-api)
5 | [](LICENSE.md)
6 |
7 |
8 | This is an unofficial wrapper for the awesome, free [ExchangeRatesAPI](https://exchangeratesapi.io/), which provides exchange rate lookups courtesy of the [Central European Bank](https://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html). It features a number of useful functions and can be installed easily using [Composer](https://getcomposer.org/).
9 |
10 | **4.0.0 update:**
11 | Following pricing changes for [ExchangeRatesAPI](https://exchangerate.host/), this project now uses ExchangeRates.host as its API provider. This should now be considered an unofficial SDK for . 4.0.0 should be backwards compatible with older versions which relied on the no-longer-free ExchangeRatesAPI.
12 |
13 | ## Table of Contents:
14 |
15 | 1. [Installation](#1-installation)
16 | 2. [Getting Started](#2-getting-started)
17 | 3. [API Reference](#3-api-reference)
18 | 4. [Supported Currencies](#4-supported-currencies)
19 | 5. [Requirements](#6-requirements)
20 | 6. [Bugs & Features](#7-bugs-features)
21 | 7. [License](#8-license)
22 |
23 | ---
24 |
25 | ### 1. Installation:
26 |
27 | The easiest installation method is to use Composer:
28 |
29 | ```
30 | $ composer require benmajor/exchange-rates-api
31 | ```
32 |
33 | Alternatively, you can download all files from the `src/` directory and include them in your project. **Important note:** if you're manually installing the SDK, you must also install [Guzzle Client](https://github.com/guzzle/guzzle).
34 |
35 | ### 2. Getting Started:
36 |
37 | Since the CurrencyExchangeAPI does not require API keys or authentication in order to access and interrogate its API, getting started with this library is easy. The following examples show how to achieve various functions using the library.
38 |
39 |
40 | **Basic usage:**
41 | Fetch the latest exchange rates from the European Central Bank:
42 |
43 | ```
44 | use \BenMajor\ExchangeRatesAPI\ExchangeRatesAPI;
45 | use \BenMajor\ExchangeRatesAPI\Response;
46 | use \BenMajor\ExchangeRatesAPI\Exception;
47 |
48 | $access_key = '';
49 | $use_ssl = false; # Free plans are restricted to non-SSL only.
50 |
51 | $lookup = new ExchangeRatesAPI($access_key, $use_ssl);
52 | $rates = $lookup->fetch();
53 | ```
54 |
55 | **Historical data:**
56 | Get historical rates for any day since 1999:
57 |
58 | ```
59 | $access_key = '';
60 |
61 | $lookup = new ExchangeRatesAPI($access_key);
62 | $rates = $lookup->setFetchDate('2015-01-20')->fetch();
63 | ```
64 |
65 | Get historical rates for a time period:
66 |
67 | ```
68 | $access_key = '';
69 |
70 | $lookup = new ExchangeRatesAPI($access_key);
71 | $rates = $lookup->addDateFrom('2015-01-20')->addDateTo('2015-01-21')->fetch();
72 | ```
73 |
74 | **Set the base currency:**
75 | By default, the base currency is set to Euro (EUR), but it can be changed:
76 |
77 | ```
78 | $access_key = '';
79 |
80 | $lookup = new ExchangeRatesAPI($access_key);
81 | $rates = $lookup->setBaseCurrency('GBP')->fetch();
82 | ```
83 |
84 | **Fetch specific rates:**
85 | If you do not want all current rates, it's possible to specify only the currencies you want using `addRate()`. The following code fetches only the exchange rate between GBP and EUR:
86 |
87 | ```
88 | $access_key = '';
89 |
90 | $lookup = new ExchangeRatesAPI($access_key);
91 | $rates = $lookup->addRate('EUR')->setBaseCurrency('GBP')->fetch();
92 | ```
93 |
94 | Please refer to the [API website](https://exchangeratesapi.io/) for further information and full API docs.
95 |
96 | **Please note:** By default, the `fetch()` method will return a new `ExchangeRatesAPI\Response` object. However, by passing a single argument of `true` to the `fetch()` method, you can retrieve a raw JSON resposne instead.
97 |
98 | ### 3. API Reference:
99 |
100 | The following API reference lists the publicly-available methods for the
101 |
102 | #### `ExchangeRatesAPI` Reference:
103 |
104 | `addDateFrom( string $from )`:
105 | Set the date from which to retrieve historic rates. `$from` should be a string containing an ISO 8601 date.
106 |
107 | `getDateFrom()`:
108 | Returns the specified date from which to retrieve historic rates. Returns `null` if none is specified.
109 |
110 | `removeDateFrom()`:
111 | Removes the specified start date for the retrieval of historic rates.
112 |
113 | `addDateTo( string $to )`:
114 | Set the end date for the retrieval of historic rates. `$to` should be a string containing an ISO 8601 date.
115 |
116 | `getDateTo()`:
117 | Returns the specified end date for the retrieval of historic rates. Returns `null` if none is specified.
118 |
119 | `getAccessKey()`:
120 | Returns the `access_key` that is currently in use.
121 |
122 | `getUseSSL()`:
123 | Returns a boolean flag that determines which API URL will be used to perform requests. Free plans are restricted to non-SSL usage.
124 |
125 | `removeDateTo()`:
126 | Removes the specified end date for the retrieval of historic rates.
127 |
128 | `currencyIsSupported( string $code )`:
129 | Checks if a specific currency code is supported. `$code` should be passed as an ISO 4217 code (e.g. `EUR`).
130 | Returns `true` if supported, or `false` if not.
131 |
132 | `setBaseCurrency( string $code )`:
133 | Set the base currency to be used for exchange rates. `$code` should be passed an ISO 4217 code (e.g. `EUR`).
134 | `$code` must be one of the [supported currency codes](#4-supported-currencies).
135 |
136 | `getBaseCurrency()`:
137 | Returns the currently specified base currency. If `setBaseCurrency()` hasn't been called, this will return the default base currency `EUR`.
138 |
139 | `addRates( array $codes )`:
140 | Adds multiple currencies to be retrieved. `$codes` should be an array of ISO 4217 codes (e.g. `["EUR", "GBP", "BGN"]`).
141 | Each code in the array must be of the [supported currency codes](#4-supported-currencies).
142 |
143 | `addRate( string $code )`:
144 | Adds a new currency to be retrieved. `$code` should be passed an ISO 4217 code (e.g. `EUR`).
145 | `$code` must be one of the [supported currency codes](#4-supported-currencies).
146 | If no rates are added, **all** rates will be returned.
147 |
148 | `removeRates( array $codes )`:
149 | Removes multiple currencies that has already been added to the retrieval list. `$codes` should be an array of ISO 4217 codes (e.g. `["EUR", "GBP", "BGN"]`).
150 | `$code` must be one of the [supported currency codes](#4-supported-currencies).
151 |
152 | `removeRate( string $code )`:
153 | Removes a currency that has already been added to the retrieval list. `$code` should be passed an ISO 4217 code (e.g. `EUR`).
154 | `$code` must be one of the [supported currency codes](#4-supported-currencies).
155 |
156 | `setAccessKey( string $access_key )`:
157 | Sets `access_key` to be used in all requests.
158 |
159 | `setUseSSL( bool $use_ssl )`:
160 | Sets the API URL according to the selected mode (SSL or non-SSL). Free plans are restricted to non-SSL usage.
161 |
162 | `fetch( bool $returnJSON = false, bool $parseJSON = true )`:
163 | Send off the request to the API and return either a `Response` object, or the raw JSON response. If `$returnJSON` is set to `true`, a standard PHP object will be returned, rather than the `ExchangeRatesAPI\Response` object.
164 |
165 | `convert( string $to, float $amount, int $rounding )`:
166 | A convenience function to combine several methods in order to quickly perform a currency conversion:
167 |
168 | `$to`: should be specified as the ISO 4217 currency code to convert to.
169 | `$amount`: the amount to be converted.
170 | `$rounding`: the amount to round the conversion. Default is `2`.
171 |
172 | This method call will return the converted currency amount in `$to` from the specified based currency.
173 |
174 | `getSupportedCurrencies( string $concat = null )`:
175 | Returns a list of supported currency codes. If `$concat` is `null`, an array of currency codes is returned. If `$concat` is specified as a string, a string will be returned, joined by `$concat`.
176 |
177 | `getRates( string $concat = null )`:
178 | Returns a list of the currently specified rates to retrieve. If `$concat` is `null`, an array of currency codes is returned. If `$concat` is specified as a string, a string will be returned, joined by `$concat`.
179 |
180 | #### `Response` Reference:
181 |
182 | This is the default object that is returned from the `fetch()`. Here is a list of the available methods on the `Response` object:
183 |
184 | `getStatusCode()`:
185 | Returns the status code of the request (generally `200`).
186 |
187 | `getTimestamp()`:
188 | Returns the timestamp (formatted in ISO 8601 notation) the response was generated.
189 |
190 | `getBaseCurrency()`:
191 | Returns the base currency of the request. If not base currency was specified using `setBaseCurrency` on the request, this will return the default (`EUR`).
192 |
193 | `getRates()`:
194 | Returns a key/value pair array of the exchange rates that match against the request, for example:
195 |
196 | ```
197 | [ 'GBP' => 1, 'EUR' => 1.1 ]
198 | ```
199 |
200 | `getRate( string $code )`:
201 | Retrieves the exchange rate for a specific currency, or returns the exchange rate if only one rate is present in the response.
202 |
203 | ### 4. Supported Currencies:
204 |
205 | The library supports any currency currently available on the European Central Bank's web service, which can be found [here](https://exchangeratesapi.io/currencies/).
206 |
207 | ### 5. Requirements:
208 |
209 | This library requires PHP >= 7.0. No other platform requirements exist, but the library is dependent on [Guzzle](https://github.com/guzzle/guzzle).
210 |
211 |
212 | ### 6. Bugs & Features:
213 |
214 | If you have spotted any bugs, or would like to request additional features from the library, please file an issue via the Issue Tracker on the project's Github page: [https://github.com/benmajor/ExchangeRatesAPI/issues](https://github.com/benmajor/ExchangeRatesAPI/issues).
215 |
216 | ### 7. License:
217 |
218 | Licensed under the **MIT License**:
219 |
220 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
221 |
222 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
223 |
224 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
225 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "benmajor/exchange-rates-api",
3 | "description": "An unofficial SDK for the ExchangeRatesAPI. (https://exchangeratesapi.io/)",
4 | "type": "library",
5 | "require": {
6 | "php": ">= 7.0",
7 | "guzzlehttp/guzzle": "^6.3 || ^7.0"
8 | },
9 | "license": "MIT",
10 | "authors": [
11 | {
12 | "name": "Ben Major",
13 | "email": "ben.major88@gmail.com"
14 | }
15 | ],
16 | "minimum-stability": "dev",
17 | "autoload": {
18 | "psr-4": {
19 | "BenMajor\\ExchangeRatesAPI\\": "src/"
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Exception.php:
--------------------------------------------------------------------------------
1 | 'The specified date is invalid. Please use ISO 8601 notation (e.g. YYYY-MM-DD).',
81 | 'format.invalid_currency_code' => 'The specified currency code is invalid. Please use ISO 4217 notation (e.g. EUR).',
82 | 'format.unsupported_currency' => 'The specified currency code is not currently supported.',
83 | 'format.invalid_amount' => 'Conversion amount must be specified as a numeric value.',
84 | 'format.invalid_rounding' => 'Rounding precision must be specified as a numeric value.'
85 | ];
86 |
87 | # ExchangeRatesAPI Access Key:
88 | private $access_key;
89 |
90 | function __construct( string $access_key = null, bool $use_ssl = true )
91 | {
92 | $this->setAccessKey($access_key);
93 | $this->setUseSSL($use_ssl);
94 |
95 | $this->client = new \GuzzleHttp\Client([ 'base_uri' => $this->apiURL ]);
96 | }
97 |
98 | /****************************/
99 | /* */
100 | /* GETTERS */
101 | /* */
102 | /****************************/
103 |
104 | # Get the fetch date date:
105 | public function getFetchDate()
106 | {
107 | return $this->dateFrom;
108 | }
109 |
110 | # Get the "from" date:
111 | public function getDateFrom()
112 | {
113 | return $this->dateFrom;
114 | }
115 |
116 | # Get the "to" date:
117 | public function getDateTo()
118 | {
119 | return $this->dateTo;
120 | }
121 |
122 | # Get the supported currencies:
123 | public function getSupportedCurrencies( string $concat = null )
124 | {
125 | return (is_null($concat)) ? $this->_currencies : implode($concat, $this->_currencies);
126 | }
127 |
128 | # Get the specified base currency:
129 | public function getBaseCurrency()
130 | {
131 | return (is_null($this->baseCurrency)) ? 'USD' : $this->baseCurrency;
132 | }
133 |
134 | # Get the rates:
135 | public function getRates( string $concat = null )
136 | {
137 | return (! is_null($concat) ) ? implode($concat, $this->rates) : $this->rates;
138 | }
139 |
140 | # Get access key:
141 | public function getAccessKey()
142 | {
143 | return $this->access_key;
144 | }
145 |
146 | # Get boolean flag for SSL usage:
147 | public function getUseSSL()
148 | {
149 | return ($this->apiURL == self::API_URL_SSL);
150 | }
151 |
152 | /****************************/
153 | /* */
154 | /* SETTERS / DATA METHODS */
155 | /* */
156 | /****************************/
157 |
158 | # set the fetch date
159 | public function setFetchDate( string $date )
160 | {
161 | if( $this->validateDateFormat($date) )
162 | {
163 | $this->fetchDate = $date;
164 |
165 | # Return object to preserve method-chaining:
166 | return $this;
167 | }
168 |
169 | throw new Exception( $this->_errors['format.invalid_date'] );
170 | }
171 |
172 | # Add a date-from:
173 | public function addDateFrom( string $from )
174 | {
175 | if( $this->validateDateFormat($from) )
176 | {
177 | $this->dateFrom = $from;
178 |
179 | # Return object to preserve method-chaining:
180 | return $this;
181 | }
182 |
183 | throw new Exception( $this->_errors['format.invalid_date'] );
184 | }
185 |
186 | # Remove a date-from:
187 | public function removeDateFrom()
188 | {
189 | $this->dateFrom = null;
190 |
191 | # Return object to preserve method-chaining:
192 | return $this;
193 | }
194 |
195 | # Add a date-to:
196 | public function addDateTo( string $to )
197 | {
198 | if( $this->validateDateFormat($to) )
199 | {
200 | $this->dateTo = $to;
201 |
202 | # Return object to preserve method-chaining:
203 | return $this;
204 | }
205 |
206 | throw new Exception( $this->_errors['format.invalid_date'] );
207 | }
208 |
209 | # Remove the date-to:
210 | public function removeDateTo()
211 | {
212 | $this->dateTo = null;
213 |
214 | # Return object to preserve method-chaining:
215 | return $this;
216 | }
217 |
218 | # Check if a currency code is in the supported range:
219 | public function currencyIsSupported( string $code )
220 | {
221 | $currencyCode = $this->sanitizeCurrencyCode($code);
222 |
223 | if( ! $this->validateCurrencyCodeFormat($currencyCode) )
224 | {
225 | throw new Exception( $this->_errors['format.invalid_currency_code'] );
226 | }
227 |
228 | return in_array( $currencyCode, $this->_currencies );
229 | }
230 |
231 | # Set the base currency:
232 | public function setBaseCurrency( string $currency )
233 | {
234 | # Sanitize the code:
235 | $currencyCode = $this->sanitizeCurrencyCode($currency);
236 |
237 | # Is it valid?
238 | $this->verifyCurrencyCode( $currencyCode );
239 |
240 | $this->baseCurrency = $currencyCode;
241 |
242 | # Return object to preserve method-chaining:
243 | return $this;
244 | }
245 |
246 | # Add multiple currencies at once
247 | public function addRates( array $currencies )
248 | {
249 | foreach ($currencies as $currency)
250 | {
251 | $this->addRate($currency);
252 | }
253 | return $this;
254 | }
255 |
256 | # Add a currency to the returned rates:
257 | public function addRate( string $currency )
258 | {
259 | # Sanitize the code:
260 | $currencyCode = $this->sanitizeCurrencyCode($currency);
261 |
262 | $this->verifyCurrencyCode($currencyCode);
263 |
264 | $this->rates[] = $currencyCode;
265 |
266 | # Return object to preserve method-chaining:
267 | return $this;
268 | }
269 |
270 | # Remove multiple currencies at once
271 | public function removeRates( array $currencies )
272 | {
273 | foreach ($currencies as $currency)
274 | {
275 | $this->removeRate($currency);
276 | }
277 | return $this;
278 | }
279 |
280 | # Remove a currency from the returned rates:
281 | public function removeRate( string $currency )
282 | {
283 | # Sanitize the code:
284 | $currencyCode = $this->sanitizeCurrencyCode($currency);
285 |
286 | # Verify it's valid:
287 | $this->verifyCurrencyCode($currencyCode);
288 |
289 | $newRates = [ ];
290 |
291 | # Loop over the rates and check them against the currency to remove:
292 | foreach( $this->getRates() as $rate )
293 | {
294 | if( $rate != $currencyCode )
295 | {
296 | $newRates[] = $rate;
297 | }
298 | }
299 |
300 | # Copy the temp array to the rates:
301 | $this->rates = $newRates;
302 |
303 | # Return object to preseve method chaining:
304 | return $this;
305 | }
306 |
307 | # Set access key:
308 | public function setAccessKey( string $access_key = null )
309 | {
310 | $this->access_key = $access_key;
311 |
312 | # Return object to preseve method chaining:
313 | return $this;
314 | }
315 |
316 | # Set SSL flag and API URL:
317 | public function setUseSSL( bool $use_ssl = true )
318 | {
319 | if ( $use_ssl )
320 | {
321 | $this->apiURL = self::API_URL_SSL;
322 | }
323 | else
324 | {
325 | $this->apiURL = self::API_URL_NON_SSL;
326 | }
327 |
328 | return $this;
329 | }
330 |
331 | /****************************/
332 | /* */
333 | /* API FUNCTION CALLS */
334 | /* */
335 | /****************************/
336 |
337 | # Static function to quickly make a conversion:
338 | public function convert( string $to, float $amount, $rounding = 2 )
339 | {
340 | $currencyTo = $this->sanitizeCurrencyCode($to);
341 |
342 | # Check it's an allowed currency:
343 | $this->verifyCurrencyCode($to);
344 |
345 | if( !is_numeric($amount) )
346 | {
347 | throw new Exception( $this->_errors['format.invalid_amount'] );
348 | }
349 |
350 | if( ! is_numeric($rounding) )
351 | {
352 | throw new Exception( $this->_errors['format.invalid_rounding'] );
353 | }
354 |
355 | # Now get the response:
356 | $rate = $this->addRate($currencyTo)->fetch()->getRate();
357 |
358 | return round(
359 | ($amount * $rate),
360 | $rounding
361 | );
362 | }
363 |
364 | # Send off the request:
365 | public function fetch( $returnJSON = false, $parseJSON = true )
366 | {
367 | # Build the URL:
368 | $params = [ ];
369 |
370 | # Set access key if available:
371 | if ( !is_null($this->getAccessKey()) )
372 | {
373 | $params['access_key'] = $this->getAccessKey();
374 | }
375 |
376 | # Set the relevant endpoint:
377 | if( is_null($this->dateFrom) )
378 | {
379 | $endpoint = is_null($this->fetchDate) ? self::ENDPOINT_MOST_RECENT_EXCHANGE_RATES : $this->fetchDate;
380 | }
381 | else
382 | {
383 | $endpoint = self::ENDPOINT_TIMEFRAME;
384 | }
385 |
386 | # Add dateFrom if specified:
387 | if( ! is_null($this->getDateFrom()) )
388 | {
389 | $params['start_date'] = $this->getDateFrom();
390 | }
391 |
392 | # Add a dateTo:
393 | if( ! is_null($this->getDateTo()) )
394 | {
395 | $params['end_date'] = $this->getDateTo();
396 | }
397 |
398 | # Set the base currency:
399 | if( ! is_null($this->getBaseCurrency()) )
400 | {
401 | $params['source'] = $this->getBaseCurrency();
402 | }
403 |
404 | # Are there any rates set?
405 | if( count($this->rates) > 0 )
406 | {
407 | $params['currencies'] = $this->getRates(',');
408 | }
409 |
410 | # Begin the sending:
411 | try
412 | {
413 | $guzzleResponse = $this->client->request('GET', $endpoint, [ 'query' => $params ]);
414 |
415 | $response = new Response( $guzzleResponse );
416 |
417 | if( $returnJSON )
418 | {
419 | $json = $response->toJSON();
420 |
421 | if( $parseJSON )
422 | {
423 | return json_decode( $json );
424 | }
425 |
426 | return $json;
427 | }
428 |
429 | return $response;
430 | }
431 | catch( \Exception $e )
432 | {
433 | throw new Exception( $e->getMessage() );
434 | }
435 | }
436 |
437 | /****************************/
438 | /* */
439 | /* INTERNAL VERIFICTATION */
440 | /* */
441 | /****************************/
442 |
443 | # Validate a date is in the correct format:
444 | private function validateDateFormat( string $date = null )
445 | {
446 | if( !is_null($date) )
447 | {
448 | return preg_match( $this->dateRegExp, $date);
449 | }
450 |
451 | return false;
452 | }
453 |
454 | # Validate a currency code is in the correct format:
455 | private function validateCurrencyCodeFormat( string $code = null )
456 | {
457 | if( !is_null($code) )
458 | {
459 | # Is the string longer than 3 characters?
460 | if( strlen($code) != 3 )
461 | {
462 | return false;
463 | }
464 |
465 | # Does it contain non-alphabetical characters?
466 | if( ! preg_match( $this->currencyRegExp, $code) )
467 | {
468 | return false;
469 | }
470 |
471 | return true;
472 | }
473 |
474 | return false;
475 | }
476 |
477 | # Runs tests to verify a currency code:
478 | private function verifyCurrencyCode( string $code )
479 | {
480 | $currencyCode = $this->sanitizeCurrencyCode($code);
481 |
482 | # Is the currency code in ISO 4217 format?
483 | if( ! $this->validateCurrencyCodeFormat($currencyCode) )
484 | {
485 | throw new Exception( $this->_errors['format.invalid_currency_code'] );
486 | }
487 |
488 | # Is it a supported currency?
489 | if( ! $this->currencyIsSupported($currencyCode) )
490 | {
491 | throw new Exception( $this->_errors['format.unsupported_currency'] );
492 | }
493 | }
494 |
495 | # Sanitize a currency code:
496 | private function sanitizeCurrencyCode( string $code )
497 | {
498 | return trim(
499 | strtoupper( $code )
500 | );
501 | }
502 | }
503 |
--------------------------------------------------------------------------------
/src/Response.php:
--------------------------------------------------------------------------------
1 | response = $response;
25 |
26 | $this->headers = $response->getHeaders();
27 | $this->bodyRaw = (string) $response->getBody();
28 | $this->body = json_decode( $this->bodyRaw );
29 |
30 | # Set our properties:
31 | $this->statusCode = $response->getStatusCode();
32 | $this->timestamp = $this->body->timestamp ?? null;
33 | $this->baseCurrency = $this->body->source;
34 | $this->rates = $this->body->quotes;
35 | }
36 |
37 | /****************************/
38 | /* */
39 | /* GETTERS */
40 | /* */
41 | /****************************/
42 |
43 | # Get the status code:
44 | public function getStatusCode()
45 | {
46 | return (int) $this->statusCode;
47 | }
48 |
49 | # Get the timestamp of the request:
50 | public function getTimestamp()
51 | {
52 | return $this->timestamp;
53 | }
54 |
55 | # Get the base currency:
56 | public function getBaseCurrency()
57 | {
58 | return $this->baseCurrency;
59 | }
60 |
61 | # Get the exchange rates:
62 | public function getRates()
63 | {
64 | # Convert the rates to a key / value array:
65 | return json_decode( json_encode($this->rates), true );
66 | }
67 |
68 | # Return a specific rate:
69 | public function getRate( $code = null )
70 | {
71 | $rates = $this->getRates();
72 |
73 | # If there's only one rate, and the code is null, return the first one:
74 | if( count($rates) == 1 && $code == null )
75 | {
76 | return reset( $rates );
77 | }
78 |
79 | if( $this->body->rates->{$code} )
80 | {
81 | return $this->body->rates->{$code};
82 | }
83 |
84 | return null;
85 | }
86 |
87 | # Convert the response to JSON:
88 | public function toJSON()
89 | {
90 | return json_encode([
91 | 'statusCode' => $this->getStatusCode(),
92 | 'timestamp' => $this->getTimestamp(),
93 | 'baseCurrency' => $this->getBaseCurrency(),
94 | 'rates' => $this->getRates()
95 | ]);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------