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

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

Поэтому сейчас мы сделаем парсер курса валют на 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, который содержит сразу все валюты.

Если вам понравилась статья, подписывайтесь на обновления блога по rss или присоединяйтесь в twitter

Поделиться ссылкой с друзьями:

Метки: , ,

Категории: Bitrix

Комментарии (2)

  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 например?