Создаём валютный информер с помощь PHP и JavaScript

Владимир | | Ajax, HTML, JavaScript, PHP, Web разработка.

exchange rates

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

Сразу хочу уточнить, что в этой статье под термином «информер» я имею в виду блок на странице, содержащий информацию, полученную с другого ресурса. Информация может быть какая угодно: курсы валют, погода, данные счетчиков, последние твиты и т.п.

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

Source

Подключение информера


Существует два основных варианта.

1) Ресурс, который является источником информации, предоставляет код для вставки на вашем сайте. Обычно это JS код, который подгружает данные и формирует внешний вид информера. При этом, иногда владельцы запрещают менять оформление и содержимое информера. В этом случае выбор у вас небольшой: либо пользоваться тем, что дают, либо нет.

2) Данные можно получить в XML или JSON формате. Этот вариант гораздо интереснее, т.к. вы полностью контролируете внешний вид информера и можете выводить только те данные, которые вам нужны. Кроме того, появляется выбор между вариантами загрузки данных.

Т.к. по первому варианту обсуждать, в общем-то, нечего, остановимся на втором.

Получение данных

Тут тоже два варианта.

1) Отправить запрос из PHP скрипта при формировании страницы.

В этом случае не нужно использовать JavaScript, но могут возникнуть задержки при получении данных, которые увеличат общее время формирования страницы. Частично устранить эту проблему можно с помощью кеширования.

2) Получать данные с помощью AJAX запроса.

При этом поддержка JavaScript на стороне клиента обязательна, а время формирования страницы немного уменьшится. Точнее данные в информер будут загружаться после того как посетитель увидит основное содержимое страницы.

Сразу хочу отметить, что оба подхода имеют много общего.

Дело в том, что запрос к стороннему серверу в любом случае придётся отправлять из PHP скрипта. Причина – Same Origin Policy, которую используют все современные браузеры. Эта политика не позволяет JS коду получить доступ к данным, загруженным с другого домена.

Обойти это ограничение можно с помощью JSONP, но реализовать его поддержку должны разработчики сервиса, от которого вы хотите получить данные. Подробнее на эту тему вы можете почитать здесь, здесь и здесь.

В общем, я покажу пример создания информера с использованием JavaScript, но, при желании, его несложно будет переделать под первый вариант.

Источник данных

Для этого примера используем данные о курсах валют, которые предоставляет ресурс pfsoft.com.ua в XML формате. Посмотреть их можно здесь.

Разметка информера

Тут всё просто.

<ul id="rates"><li>Загрузка данных...</li></ul>

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

Клиентский скрипт

Принцип работы следующий. После загрузки страницы отправляем AJAX запрос на свой сервер. PHP скрипт получает данные от сервера pfsoft.com.ua и отправляет их браузеру.

JS код получает XML строку с данными, находит в ней нужные элементы и добавляет их в список (исходные данные содержат курсы примерно двух десятков валют, но вряд ли имеет смысл выводить их все).

var curCodes = ['RUB', 'USD', 'EUR'];
$(document).ready(function() {
	$.get('getrates.php', function(data) {
		if (data != 'ERR') {
			var rates = '';
			$(data).find('Valute').each(function(key, value) {
				var curCode = $(value).find('CharCode').html();
				if (-1 != $.inArray(curCode, curCodes)) {
					rates += '<li>' + $(value).find('Nominal').html()
						+ ' ' + curCode
						+ ' = ' + $(value).find('Value').html() + ' грн.' + '</li>';
				}
				$('#rates').html(rates);
			});
		}
		else {
			$('#rates').html('<li>Данные не доступны</li>');
		}
	});
});

Прежде всего, создаём массив с кодами валют, которые нужно показать в информере.

Затем, отправляем AJAX запрос (строка 3). PHP скрипт, который выполняет загрузку данных, называется getrates.php.

Если при получении данных возникли ошибки, выводим соответствующее сообщение (строка 17), в противном случае – начинаем обработку XML строки.

Обратите внимание! Мы можем работать с XML данными точно так же, как и с HTML страницей.

Просто создаём объект jQuery ($(data)) и получаем возможность использовать методы find, html, each и т.д.

Здесь мы находим все теги Valute, которые содержат данные об отдельной валюте, а затем из них выбираем код валюты, её курс и формируем элемент списка.

При этом проверяем, указана ли данная валюта в массиве curCodes (строка 8). Кстати, обратите внимание, метод $.inArray возвращает -1 если указанный элемент отсутствует в массиве.

После этого вставляем данные в список (строка 13).

Серверная часть

Рассмотрим скрипт getrates.php.

require_once('ratescache.php');

$rCache = new RatesCache();
//$rCache->expired = 30;

//пробуем получить данные из кеша
if (FALSE === ($data = $rCache->get())) {
	//если данные в кеше устарели, пытаемся получить их от сервера pfsoft.com.ua
	$data = @file_get_contents('http://pfsoft.com.ua/service/currency/');
	//если сервер недоступен, пробуем получить данные из устаревшего кеша
	if (FALSE === $data) {
		$data = $rCache->get(TRUE);
	}
	else {
		//обновляем данные в кеше, предварительно изменяем кодировку на UTF-8
		$rCache->save(iconv('windows-1251','utf-8',$data));
	}
}

if (FALSE !== $data) {
	//отправляем данные
	echo $data;
	exit;
}
//отправляем сообщение об ошибке
echo 'ERR';

Логика работы довольно простая. Получить данные и отправить их браузеру, но при этом используется немного не стандартный кеш.

Прежде всего, хочу объяснить зачем нужен кеш.

Во-первых, его использование сокращает время загрузки данных.

Во-вторых, если у вас посещаемый сайт, и вы будете запрашивать данные для каждого посетителя, то администраторы источника данных могут вас просто забанить (за нагрузку).

В-третьих, кеш позволит получить данные для информера даже если pfsoft.com.ua не доступен.

Итак, алгоритм работы следующий.

1) Создаём экземпляр класса кеша (строка 3) и пробуем получить данные из него (строка 7).

2) Если данные в нём устарели, пробуем получить их от сервера pfsoft.com.ua (строка 9).

3) Если и сервер не отвечает, пытаемся получить данные из устаревшего кеша (строка 12). Кстати, это единственная причина, из-за которой я написал собственную реализацию кеша. Класс RatesCache содержит два метода get и set, причем вызов get(true) вернёт данные, даже если кеш устарел.

4) Если сервер pfsoft.com.ua вернул данные, то обновляем кеш и отправляем их браузеру (строка 16).

5) Если данные получить не удалось (кеш не существует и сервер не отвечает), отправляем сообщение об ошибке (строка 26).

Приводить класс кеша здесь я не буду. Вы всегда можете посмотреть его в исходниках (там, на мой взгляд, достаточно комментариев). К тому же класс довольно простой и написан в основном для этого примера. Если вы используете какой-нибудь фреймворк, то проще будет использовать встроенную библиотеку кеширования.

Результаты

На мой взгляд, показанный здесь вариант создания информера один из самых удобных. С одной стороны он не замедляет формирование страницы (за счет AJAX загрузки), с другой – формируется достаточно быстро (за счет использования кеша).

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

Как всегда, я буду рад ответить на ваши вопросы и замечания!

Интересно почитать

Необычный пример рекламы ресторана от практичных японцев.

Пять способов привлечения клиентов для фирм на b2b-рынке

  • Для российских читателей можно указать ссылку с курсами валют ЦБ РФ http://www.cbr.ru/scripts/XML_daily.asp

    • Согласен. Вообще таких сервисов довольно много. Достаточно поискать
      «курсы валют XML»

  • Serator

    Как-то маловато способов получения данных. Порой сервисы предоставляют способ получния данных посредством плагина (к примеру флеш), аль изображением, ифреймом (?). Ну а конкретно в этом примере наверное будет красивее с точки зрения кода посылать вместо строки 'ERR' статус ответа отличный от 200-го, хоть это и не принципиально.
    + var rates = «; <<< Опечатка?
    + $('#rates') просит закэшировать себя 🙂
    + var curCodes = ['RUB', 'USD', 'EUR']; можно сунуть в функцию, дабы глобальную область видимости не засорять
    +
    echo $data;
    exit;
    Это же die($data);

    Ну и сея форма для добавления комментария, в которой сей текст набирался, неудобная. Из-за особенностей верстки применять по назначению "ползунок" для изменения размера поля невозможно :(.

  • Иван

    А я бы запускал этот скрипт несколько раз в сутки по крону, а на клиенте бы просто выводил всю информацию из базы!

    • Хороший вариант. Но установка будет немного сложнее. Т.к. пользователю
      придется решать в какой таблице хранить данные.

      А вообще идея интересная. Можно написать такой плагин для WP.
      Использовать wp-cron, сделать поддержку нескольких источников данных,
      данные можно хранить в таблице опций, фронтенд в виде виджета. Должно
      неплохо получиться.

  • Одноко нормальный скрипт, только почему сразу не поставить поля ввода сумм для перевода

    • Ставилась задача сделать информер, а не калькулятор.

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

  • Не хочет он активироваться, пишет: У плагина нет корректного заголовка.

    • Пришлите, пожалуйста, скриншот с этой ошибкой. Не пойму о каком плагине речь.

  • дубль

  • как уменьшить количество знаков после точки?
    у меня грн. кракозябрами выводит. header(«Content-type:text/html;charset=windows-1251»); не помагает, $rCache->save(iconv('windows-1251','utf-8',$data)); — тут тоже

    • Округлить значение можно так
      Math.round(parseFloat($(value).find('Value').html())*100)/100

      Замените заголовок наheader(«Content-type:text/html;charset=UTF-8»)

      •  Спасибо.
        Вот только изменение заголовка ничего не дало. на сайте у меня кодировка windows-1251.
        Решил иначе проблему — вместо грн. сделал UA )))

        • Тогда нужно в заголовке указать windows-1251, а iconv вообще убрать.
          $rCache->save($data);

  • Alex

    Ну чото вообще не работает… Выложил на сайт, рнр есть, атрибуты  777, висит: http://www.kurortkmv.ru/i/

    •  Какую версию PHP вы используете?

      • Alex

        5.0 А какую надо?

        • Странно, судя по описанию ошибки, у вас установлена 4-ая.
          Если конкретно, проблема в строке
          public $cachefile = 'cache/rates.xml';
          а это — обычное объявление свойства класса.

        • Alex

          Да, все работает, я ошибся с версией, поставил на сайт где 5.х, http://ско.рф/i2/ только сайт выдает в utf-8, попробую поправить кодировки. Но нужна выдача от ЦБРФ, это уже сложнее. Вы такой скрипт не делали?

        • ЦБРФ — особенности есть, но не на много сложнее, т.к. курсы доступны в xml-формате.

  • if

    А как сделать результат перевода в рублях а не гривнах???

  • if

    А еще как оставить одно поле а не три?

  • if

    да я уже все сам додумался, а как вставить в сайт, но не ифреймом?

    • Создайте на странице
      Загрузка данных…
      и подключите скрипт.

  • if

    Владимир, подскажите пожалуйста, чтобы скрипт брал информацию с ЦБР я поменял в скрипте урл на http://www.cbr.ru/scripts/XML_daily.asp, чтобы убрать три строки, я убрал в скрипте из строки var curCodes = ['RUB', 'USD', 'EUR']; рубли и доллары, но почему он стал округлять значения? изначально берет курс евро правильно (так же как в xml центробанка), а когда вводишь любое другое число он округляет курс евро до 38 рублей

  • if

    я тут продолжаю сам с собой )) похоже это из за того что xml файл ЦБР содержит в значениях валют запятые а не точки, как в предыдущем xml. Как исправить?

    • Используйте метод replace (замените запятую на точку). После этого можно использовать parseFloat.

      • if

        Владимир, где заменить? Я не очень силен в программировании )

  • Igor

    Владимир, здравствуйте. Разместил на сайте ваш информер. Не хочет обновляться информация в файле rates.xml. Папке и файлу назначил полные права, указал путь к XML файлу ЦБР. Может быть подскажите, где искать причину?

    • А данные от ЦБР вы получаете? Т.е. сам информер выводит правильные значения курса?
      rates.xml нужен только для того, чтобы уменьшить количество запросов к сайту ЦБР.

  • Alex

    $rCache->save(iconv('windows-1251','utf-8',$data));
    эта функция почему то у меня не сохраняет все.
    при перекодировке обрезаеться часть данных
    и в файл сохраняеться не все.
    при отключении перекодировки данные сохраняются все.
    В чем может быть причина?
    заранее спасибо!

  • Хотелось бы узнать, а как сделать операцию умножение что уже есть, на данный курс, и получить итоговое значение.

    Так же хотеось бы уточнить про округление