PHP скрипт - получение курса валют с сайта Центрального банка Российской Федерации

Класс PHP для получения курса валют с официального сайта ЦБ РФ

PHP скрипт - получение курса валют с сайта Центрального банка Российской Федерации
V-Blog

С помощью данного PHP класса можно быстро определить курс валюты с официального сайта ЦБ РФ.

Ниже сам класс для получения данных.

/**
 * Получение курсов валют с сайта Центробанка РФ.
 *
 * Работает с официальным XML:
 * https://www.cbr.ru/scripts/XML_daily.asp
 *
 * Пример с сайта V-Blog.ru
 * 
 * PHP 8.4+
 */

final class CbrCurrencyRate
{
    private const CBR_DAILY_URL = 'https://www.cbr.ru/scripts/XML_daily.asp';

    /**
     * Получить все курсы валют.
     *
     * @param DateTimeInterface|null $date Дата курса. Если null — последняя доступная дата.
     * @return array<string, array<string, mixed>>
     * @throws RuntimeException
     */
    public static function getRates(?DateTimeInterface $date = null): array
    {
        $url = self::CBR_DAILY_URL;

        if ($date !== null) {
            $url .= '?date_req=' . urlencode($date->format('d/m/Y'));
        }

        $xmlString = self::loadXml($url);

        libxml_use_internal_errors(true);

        $xml = simplexml_load_string($xmlString);

        if ($xml === false) {
            $errors = libxml_get_errors();
            libxml_clear_errors();

            throw new RuntimeException('Не удалось разобрать XML от ЦБ РФ.');
        }

        $rates = [];

        foreach ($xml->Valute as $valute) {
            $charCode = (string) $valute->CharCode;

            $nominal = (int) $valute->Nominal;
            $value = self::parseCbrNumber((string) $valute->Value);

            $rates[$charCode] = [
                'id'       => (string) $valute['ID'],
                'num_code' => (string) $valute->NumCode,
                'char_code'=> $charCode,
                'nominal'  => $nominal,
                'name'     => (string) $valute->Name,
                'value'    => $value,

                // Удобно: курс за 1 единицу валюты.
                // Например, если Nominal = 100, то делим курс на 100.
                'rate_for_one' => $value / $nominal,
            ];
        }

        return $rates;
    }

    /**
     * Получить одну валюту по буквенному коду: USD, EUR, CNY и т.д.
     *
     * @throws RuntimeException
     */
    public static function getRate(string $code, ?DateTimeInterface $date = null): array
    {
        $code = strtoupper(trim($code));
        $rates = self::getRates($date);

        if (!isset($rates[$code])) {
            throw new RuntimeException("Валюта {$code} не найдена в ответе ЦБ РФ.");
        }

        return $rates[$code];
    }

    /**
     * Загрузка XML через cURL.
     *
     * @throws RuntimeException
     */
    private static function loadXml(string $url): string
    {
        $ch = curl_init($url);

        if ($ch === false) {
            throw new RuntimeException('Не удалось инициализировать cURL.');
        }

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => 20,
            CURLOPT_TIMEOUT        => 50,
            CURLOPT_USERAGENT      => 'Mozilla/5.0 PHP CBR Parser',
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
        ]);

        $response = curl_exec($ch);

        if ($response === false) {
            $error = curl_error($ch);
            curl_close($ch);

            throw new RuntimeException('Ошибка cURL: ' . $error);
        }

        $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode !== 200) {
            throw new RuntimeException('ЦБ РФ вернул HTTP-код: ' . $httpCode);
        }

        return $response;
    }

    /**
     * ЦБ РФ в XML отдает числа с запятой:
     * 90,1234
     *
     * PHP нужен формат с точкой:
     * 90.1234
     */
    private static function parseCbrNumber(string $value): float
    {
        return (float) str_replace(',', '.', $value);
    }
}

Пример получения нескольких валют:

try {
    $usd = CbrCurrencyRate::getRate('USD');
    $eur = CbrCurrencyRate::getRate('EUR');
    $cny = CbrCurrencyRate::getRate('CNY');

    echo 'USD: ' . $usd['rate_for_one'] . ' руб.' . PHP_EOL;
    echo 'EUR: ' . $eur['rate_for_one'] . ' руб.' . PHP_EOL;
    echo 'CNY: ' . $cny['rate_for_one'] . ' руб.' . PHP_EOL;

} catch (Throwable $e) {
    echo 'Ошибка: ' . $e->getMessage();
}

Пример получения курса на конкретную дату:

try {
    $date = new DateTimeImmutable('2025-12-30');

    $usd = CbrCurrencyRate::getRate('USD', $date);

    echo 'USD на ' . $date->format('d.m.Y') . ': ';
    echo $usd['rate_for_one'] . ' руб.';

} catch (Throwable $e) {
    echo 'Ошибка: ' . $e->getMessage();
}

Красивый вывод с округлением

try {
    $usd = CbrCurrencyRate::getRate('USD');

    echo '1 USD = ' . number_format($usd['rate_for_one'], 2, '.', ' ') . ' руб.';

// если надо 4 знака после запятой то number_format($usd['rate_for_one'], 4, '.', ' ')


} catch (Throwable $e) {
    echo 'Ошибка: ' . $e->getMessage();
}

Пример таблицы валют

try {
    $rates = CbrCurrencyRate::getRates();

    $neededCurrencies = ['USD', 'EUR', 'CNY', 'GBP'];

    echo '<table border="1" cellpadding="8" cellspacing="0">';
    echo '<tr>';
    echo '<th>Валюта</th>';
    echo '<th>Название</th>';
    echo '<th>Курс за 1 единицу</th>';
    echo '</tr>';

    foreach ($neededCurrencies as $code) {
        if (!isset($rates[$code])) {
            continue;
        }

        $currency = $rates[$code];

        echo '<tr>';
        echo '<td>' . htmlspecialchars($currency['char_code']) . '</td>';
        echo '<td>' . htmlspecialchars($currency['name']) . '</td>';
        echo '<td>' . number_format($currency['rate_for_one'], 4, '.', ' ') . ' руб.</td>';
        echo '</tr>';
    }

    echo '</table>';

} catch (Throwable $e) {
    echo 'Ошибка: ' . $e->getMessage();
}

Как сделать конвертер валют

// Например, нужно посчитать, сколько рублей будет за 100 долларов:

try {
    $usd = CbrCurrencyRate::getRate('USD');

    $amount = 100;
    $rubles = $amount * $usd['rate_for_one'];

    echo $amount . ' USD = ';
    echo number_format($rubles, 2, '.', ' ');
    echo ' руб.';

} catch (Throwable $e) {
    echo 'Ошибка: ' . $e->getMessage();
}

Конвертер из рублей в валюту

// Например, есть 10 000 рублей, нужно узнать сколько это долларов:

try {
    $usd = CbrCurrencyRate::getRate('USD');

    $rubles = 10000;
    $dollars = $rubles / $usd['rate_for_one'];

    echo $rubles . ' руб. = ';
    echo number_format($dollars, 2, '.', ' ');
    echo ' USD';

} catch (Throwable $e) {
    echo 'Ошибка: ' . $e->getMessage();
}

Не делайте слишком много запросов к сервису, так как ЦБ РФ может временно заблокировать ваш IP.