jdrda / cnb-currency-converter
PHP currency converter using official Czech National Bank daily exchange rates and Symfony Cache.
Requires
- php: >=7.1.3
- psr/cache: ^1.0 || ^2.0 || ^3.0
- symfony/cache: ^4.4 || ^5.4 || ^6.4 || ^7.0
Requires (Dev)
- phpunit/phpunit: ^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.0
This package is auto-updated.
Last update: 2026-05-07 06:40:00 UTC
README
A small PHP currency converter using the official daily exchange-rate table published by the Czech National Bank (CNB).
It can:
- ✅ show the official CZK quote for a given currency,
- ✅ normalize CNB rates quoted for 1, 100 or 1000 units,
- ✅ convert any supported currency to any other supported currency through CZK,
- ✅ load the latest available CNB exchange-rate table,
- ✅ load a historical CNB table by date,
- ✅ cache downloaded tables for one day,
- ✅ use Symfony Cache out of the box,
- ✅ accept any PSR-6 cache pool,
- ✅ work in older PHP 7.1.3 systems and modern PHP 8.x projects.
Installation
composer require jdrda/cnb-currency-converter
Requirements
PHP >= 7.1.3
symfony/cache ^4.4 || ^5.4 || ^6.4 || ^7.0
psr/cache ^1.0 || ^2.0 || ^3.0
The package allows multiple Symfony Cache major versions, so Composer can choose a version that fits the PHP runtime:
- old PHP 7.1 projects can use Symfony Cache 4.4,
- newer PHP 7.2+ projects can use Symfony Cache 5.4,
- PHP 8.1+ projects can use Symfony Cache 6.4,
- modern PHP 8.2+ / 8.3+ / 8.4 projects can use Symfony Cache 7.x.
Basic usage
<?php require __DIR__ . '/vendor/autoload.php'; use CnbCurrencyConverter\CnbCurrencyConverter; $converter = new CnbCurrencyConverter(); // Official CNB quote: 1 EUR = 24.340 CZK, 100 JPY = 13.249 CZK, etc. echo $converter->rate('EUR')->formatQuote(); // Normalized CZK value for exactly one unit of a currency. echo $converter->czkPerUnit('JPY'); // 0.13249 when CNB quotes 100 JPY = 13.249 CZK // Convert EUR to USD through CZK. echo $converter->convert(100, 'EUR', 'USD'); // Convert JPY to EUR through CZK. Quoted amounts such as 100 JPY are handled correctly. echo $converter->convert(10000, 'JPY', 'EUR');
Historical rates
Pass a date to the constructor. The package accepts a parseable date string or a DateTimeInterface object.
<?php use CnbCurrencyConverter\CnbCurrencyConverter; $converter = new CnbCurrencyConverter('2026-05-06'); // Uses the CNB URL with ?date=06.05.2026 echo $converter->rate('USD')->formatQuote();
Dates before 1991 are rejected. Future dates are rejected as well.
Converting through CZK
The CNB table is a CZK-based table. It does not publish direct EUR/USD, GBP/JPY or CHF/PLN cross rates. This package therefore calculates every conversion like this:
source currency -> CZK -> target currency
Example:
<?php $usd = $converter->convert(100, 'EUR', 'USD');
Internally this is equivalent to:
100 EUR * CZK per 1 EUR / CZK per 1 USD
This matters because some CNB rows are not quoted for one unit:
Japonsko|jen|100|JPY|13,249
Indonesie|rupie|1000|IDR|1,191
For JPY, the normalized rate is therefore:
13.249 / 100 = 0.13249 CZK per 1 JPY
Rounding
By default, convert() returns a raw floating-point result.
$result = $converter->convert(100, 'EUR', 'USD');
Pass the fourth argument to round the result:
$result = $converter->convert(100, 'EUR', 'USD', 2);
CZK support
CZK is supported as a built-in synthetic currency even though it is not listed as a normal row in the CNB table.
$eur = $converter->convert(1000, 'CZK', 'EUR'); $czk = $converter->convert(100, 'EUR', 'CZK');
Cache
Downloaded CNB text files are cached for one day by default.
The default constructor uses Symfony's FilesystemAdapter:
$converter = new CnbCurrencyConverter();
You can inject any PSR-6 cache pool. This is usually the best option inside Symfony, Laravel or another framework, because your application can own the cache configuration.
<?php use CnbCurrencyConverter\CnbCurrencyConverter; use Symfony\Component\Cache\Adapter\FilesystemAdapter; $cache = new FilesystemAdapter('cnb_currency_converter'); $converter = new CnbCurrencyConverter(null, $cache);
You can also change the cache TTL:
$converter = new CnbCurrencyConverter(null, $cache, 3600); // one hour
Laravel example
Laravel does not expose a PSR-6 cache pool directly through its normal cache facade. The simplest option is to let this package use its default Symfony FilesystemAdapter, or register your own PSR-6 adapter in the container.
<?php use CnbCurrencyConverter\CnbCurrencyConverter; $converter = new CnbCurrencyConverter(); $amount = $converter->convert(100, 'EUR', 'USD', 2);
Symfony example
# config/services.yaml services: CnbCurrencyConverter\CnbCurrencyConverter: arguments: $date: null $cache: '@cache.app' $cacheTtl: 86400
Then inject it into your service or controller:
<?php use CnbCurrencyConverter\CnbCurrencyConverter; final class PriceController { private $converter; public function __construct(CnbCurrencyConverter $converter) { $this->converter = $converter; } }
API
__construct($date = null, CacheItemPoolInterface $cache = null, $cacheTtl = null)
Creates a converter.
$datemay benull, a date string or aDateTimeInterfaceobject.$cachemay benullor any PSR-6CacheItemPoolInterface.$cacheTtlis the cache lifetime in seconds.
rate($currencyCode)
Returns an ExchangeRate object.
$rate = $converter->rate('EUR'); echo $rate->getCountry(); // EMU echo $rate->getCurrencyName(); // euro echo $rate->getAmount(); // 1 echo $rate->getCode(); // EUR echo $rate->getQuote(); // 24.340 echo $rate->getCzkPerUnit(); // 24.340 echo $rate->formatQuote(); // 1 EUR = 24.34 CZK
rates()
Returns all loaded rates indexed by currency code.
$rates = $converter->rates(); echo $rates['USD']->formatQuote();
czkPerUnit($currencyCode)
Returns the normalized CZK value for one unit of the requested currency.
echo $converter->czkPerUnit('JPY');
convert($amount, $fromCurrency, $toCurrency, $precision = null)
Converts through CZK.
echo $converter->convert(100, 'EUR', 'USD'); echo $converter->convert(100, 'EUR', 'USD', 2);
getPublishedDate()
Returns the date published in the CNB file after the table has been loaded.
$date = $converter->getPublishedDate(); echo $date->format('Y-m-d');
getSequenceNumber()
Returns the CNB sequence number from the first line of the source file.
echo $converter->getSequenceNumber();
Exceptions
The package throws exceptions from the CnbCurrencyConverter\Exception namespace:
InvalidRateDateExceptionInvalidCurrencyExceptionFetchExceptionParseException
All package exceptions extend CurrencyConverterException.
<?php use CnbCurrencyConverter\CnbCurrencyConverter; use CnbCurrencyConverter\Exception\CurrencyConverterException; try { $converter = new CnbCurrencyConverter('2026-05-06'); echo $converter->convert(100, 'EUR', 'USD', 2); } catch (CurrencyConverterException $e) { // Handle package-level failure. }
Data source
The package uses the official CNB daily exchange-rate TXT endpoint:
https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/denni_kurz.txt
For historical rates it uses:
https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/denni_kurz.txt?date=DD.MM.YYYY
Development
composer install vendor/bin/phpunit
Run syntax checks manually if needed:
find src tests -name '*.php' -print0 | xargs -0 -n1 php -l
License
MIT. See LICENSE.