Довольно часто владельцы сайтов просят поставить на свои проекты индикаторы курсов валют и их динамику. Можно воспользоваться готовыми информерами, но они не всегда позволяют должным образом настроить внешний вид.

Поэтому сейчас мы сделаем парсер курса валют на php с сайта cbr.ru, отобразим динамику изменения курса и в конце закешируем полученные данные для эффективного использования в 1с-Битрикс.

Получаем и обрабатываем данные

Самые свежие данные мы будем получать из xml-файла, который совершенно бесплатно предоставляет нам сайт cbr.ru. Адрес файла имеет вид — http://www.cbr.ru/scripts/XML_dynamic.asp?date_req1=10/02/2011&date_req2=26/02/2011&VAL_NM_RQ=R01235

Здесь date_req1 — дата начала периода; date_req2 — дата конца периода, за который нужна динамика; VAL_NM_RQ — идентификатор валюты (R01235 для USD, R01239 для EUR)

Структура полученного xml-файла такова:

<ValCurs ID="R01239" DateRange1="18/02/2011" DateRange2="19/02/2011" name="Foreign Currency Market Dynamic">
    <Record Date="18.02.2011" Id="R01239">
        <Nominal>
            1
        </Nominal>
        <Value>
            39,6821
        </Value>
    </Record>
    <Record Date="19.02.2011" Id="R01239">
        <Nominal>
            1
        </Nominal>
        <Value>
            39,7682
        </Value>
    </Record>
</ValCurs>

Как мы видим, записи идут в порядке возрастания даты и нужное значение хранится в теге и его легко получить регулярным выражением.

// формируем 2 даты - "завтра" и несколько дней назад
$curDate = date('d/m/Y', mktime(0,0,0,date("n"),date("j")+1,date("Y")));
$curDate2 = date('d/m/Y', mktime(0,0,0,date("n"),date("j")-10,date("Y")));

// xml с сайта ЦБ РФ
$currencyXML = file_get_contents('http://www.cbr.ru/scripts/XML_dynamic.asp?date_req1='.$curDate2.'&date_req2='.$curDate.'&VAL_NM_RQ=R01235');
// убираем переносы строк
$currencyXML = str_replace(Array("\r\n","\n","\r"),'',$currencyXML);

// регулярное выражение получает все значения тегов <Value> в массив $arValues
preg_match_all('#<Value>(.*?)</Value>#', $currencyXML, $arValues, PREG_PATTERN_ORDER);
// если совпадений больше одного, т.е. в xml были данные как минимум за 2 дня и можно отследить динамику
if(count($arValues[1])>=2) {
    // развернем массив, чтобы первыми шли свежие данные
    $arValues[1] = array_reverse($arValues[1]);
    // сделаем резделителем целой и дробной части точку
    $kurs = str_replace(",",".",$arValues[1][0]);
    // разница курсов, округленная до 4х знаков после запятой
    $diff = round(floatval(str_replace(",",".",$arValues[1][0])) - floatval(str_replace(",",".",$arValues[1][1])), 4);
}

«Завтра» и «несколько дней назад» выбраны не просто так — курс валюты иногда появляется заранее, а иногда не появляется вообще, например по воскресеньям или праздникам.
Теперь можно вывести в нужном месте значения переменных $kurs и $diff и радоваться полученному результату:)

Но дергать xml на каждом хите пользователя нехорошо, поэтому все это дело нужно закешировать

Кешируем результат в 1с-Битрикс

Кешировать будем результирующий html-код, для этого используем класс CPageCache.

<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();

// создаем объект
$obCache = new CPageCache; 

// время кеширования - 6 часов
$life_time = 60*60*6; 

// формируем идентификатор кеша в зависимости от всех параметров 
// которые могут повлиять на результирующий HTML
$cache_id = "iammegacachhhhhhhhhhhe"; 

// инициализируем буферизирование вывода
if($obCache->StartDataCache($life_time, $cache_id, "/")):

    // формируем 2 даты - "завтра" и несколько дней назад
    $curDate = date('d/m/Y', mktime(0,0,0,date("n"),date("j")+1,date("Y")));
    $curDate2 = date('d/m/Y', mktime(0,0,0,date("n"),date("j")-10,date("Y")));

    // xml с сайта ЦБ РФ
    $currencyXML = file_get_contents('http://www.cbr.ru/scripts/XML_dynamic.asp?date_req1='.$curDate2.'&date_req2='.$curDate.'&VAL_NM_RQ=R01235');
    // убираем переносы строк
    $currencyXML = str_replace(Array("\r\n","\n","\r"),'',$currencyXML);

    // регулярное выражение получает все значения тегов <Value> в массив $arValues
    preg_match_all('#<Value>(.*?)</Value>#', $currencyXML, $arValues, PREG_PATTERN_ORDER);
    // если совпадений больше одного, т.е. в xml были данные как минимум за 2 дня и можно отследить динамику
    if(count($arValues[1])>=2) {
        // развернем массив, чтобы первыми шли свежие данные
        $arValues[1] = array_reverse($arValues[1]);
        // сделаем резделителем целой и дробной части точку
        $kurs = str_replace(",",".",$arValues[1][0]);
        // разница курсов, округленная до 4х знаков после запятой
        $diff = round(floatval(str_replace(",",".",$arValues[1][0])) - floatval(str_replace(",",".",$arValues[1][1])), 4);
    } else {
        $kurs = "";
        $diff = "";
    }?>
USD: <?=$kurs?><br />
Изменение: <?=$diff?>
<?
    // записываем предварительно буферизированный вывод в файл кеша
    $obCache->EndDataCache(); 
endif;
?>

Пара слов о выборе времени кеширования и идентификатора кеша. Так как на всех страницах сайта результат работы скрипта одинаковый, то есть смысл оставить идентификатором константу, тогда будет один периодически обновляемый (6 часов в примере) файл кеша. Также можно привязать идентификатор к дате и увеличить время жизни кеша, тогда новые данные будут тянуться ровно 1 раз в сутки, но на каждый день появится отдельный файл.

Это не единственный способ получить данные о курсах валют и направлен, в первую очередь, на определение динамики их изменения. Если нужны только текущие значения, то логичнее его парсить из xml-файла http://www.cbr.ru/scripts/XML_daily.asp, который содержит сразу все валюты.

Больше статей и материалов по web-разработке в tg-канале - подписывайтесь!

Подписаться в telegram

2 комментария “Парсим курсы валют на php и кешируем их в 1с-Битрикс

  1. Николай

    Еще можно перед $obCache->EndDataCache(); вставить такое:

    if(CModule::IncludeModule(«currency»))
    {
    $arFields = array(
    «RATE» => floatval($kurs),
    «RATE_CNT» => 1,
    «CURRENCY» => «USD»,
    «DATE_RATE» => $curDate,
    );

    $arFilter = array(
    «CURRENCY» => «USD»,
    «DATE» => $curDate,
    );

    $by = «date»;
    $order = «desc»;

    $db_rate = CCurrencyRates::GetList($by, $order, $arFilter);
    if($ar_rate = $db_rate->Fetch())
    {
    if (!CCurrencyRates::Update($ar_rate[«ID»], $arFields))
    echo «<div class=’errortext’>Ошибка обновления курса</div>»;
    }
    else
    {
    if (!CCurrencyRates::Add($arFields))
    echo «<div class=’errortext’>Ошибка добавления курса</div>»;
    }
    }
    else echo «<div class=’errortext’>Ошибка подключения модуля валют.</div>»;

    Тогда курс будет сохранятся в Настройки->Валюты->Курсы Валют и использоваться при конвертации валют при оформлении заказов на сайте, и срабатывать в соответствии с кэшированием. Хотя, по хорошему нужно это в компонент оформить.
    А вот, еще нашел более продвинутый вариант — http://dev.1c-bitrix.ru/community/webdev/user/3420/blog/653/ .

  2. Влад

    Это не очень круто — прег-матчить файл, почему бы не использовать simplexml например?

Добавить комментарий

Ваш адрес email не будет опубликован.