Персональный сайт
Романа Парпалака

Заметки
 
Блог
 
Программы
 
Фото
ГлавнаяЗаметкиТехнологииВеб-разработка → Правильная организация RSS

Правильная организация RSS

21 апреля 2007 года

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

Фактически формат RSS представляет собой веб-страницу, сформированную с применением определенных правил, которая содержит информацию о нескольких элементах, такую как заголовок, описание, ссылку, дату и т. д., и эту страницу можно создать обычными средствами. Например, сделать XML-файл примерно такого содержания:

<?xml version="1.0" encoding="windows-1251"?> <rss version="2.0"> <channel> <title>Название RSS-потока</title> <link>http://site.ru</link> <description>Описание RSS-потока</description> <item> <title>Название 1</title> <link>http://site.ru/articles/1</link> <description>Описание статьи 1</description> <author>Автор &lt;author@site.ru&gt;</author> <pubDate>Sun, 25 Mar 2007 00:00:00 +0300</pubDate> </item> <item> <title>Название 2</title> <link>http://site.ru/articles/2</link> <description>Описание статьи 2</description> <author>Автор &lt;author@site.ru&gt;</author> <pubDate>Sun, 18 Mar 2007 00:00:00 +0300</pubDate> </item> <item> <title>Название 3</title> <link>http://site.ru/articles/3</link> <description>Описание статьи 3</description> <author>Автор &lt;author@site.ru&gt;</author> <pubDate>Sun, 11 Mar 2007 00:00:00 +0300</pubDate> </item> </channel> </rss>

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

Понятно, что если на сайте есть хотя бы минимальная автоматизация, RSS может генерироваться скриптом, например, на PHP. Можно предложить два разумных способа работы этого скрипта:

  1. Скрипт вызывается при обновлении сайта и результаты своей работы сохраняет в обычный XML-файл, на который вы будете давать ссылки.
  2. Скрипт отрабатывает каждый раз, когда браузер (или иной пользовательский агент) обращается к RSS и отдает результаты браузеру.

Здесь нужно остановиться и обратить внимание на основные факты: зачем вы делаете RSS, большая ли аудитория у сайта и т. д. Различия между первым и вторым способом в основном связаны с особенностями работы протокола HTTP, а именно, с заголовками Last-Modified и If-Modified-Since (ознакомьтесь с описанием работы этих заголовков, повторяться смысла нет, а дальше они активно используются). Различия между этими двумя способами мы посмотрим на примере первого и повторных обращений к RSS-ленте, а потом я приведу одну из возможных реализаций.

Статический XML-файл

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

Динамический скрипт

При первом обращении он отдает информацию обо всех элементах. При повторных обращениях скрипт сообщает, что изменений не было, и ничего не отправляет. Однако если мы добавили, например, еще одну статью, то по содержимому заголовка If-Modified-Since скрипт определяет, когда было последнее обращение к RSS, и выдает только добавившиеся элементы (идея найдена на xpoint.ru). Именно здесь заключается то улучшение, которого можно добиться вторым способом.

Можно найти еще одно преимущество: если мы что-нибудь изменили на сайте, то RSS нужно сгенерировать заново. Что произойдет дальше, существенно зависит от программы, читающей RSS. Но в любом случае, если мы написали что-то ошибочное, эта ошибка попала в RSS и кто-то это уже прочел, исправить ситуацию мы не в состоянии. Максимум, что можно сделать, это отправлять новым пользователям исправленную версию. Именно так и поступит наш скрипт.

Описание скрипта

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

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

Функция get_last_modified() должна возвращать дату и время последней новости, экспортируемой через RSS, и это значение будет установлено в заголовке Last-Modified. Хотя здесь можно отдавать время внесения последних изменений в новости, экспортируемые через RSS в надежде на то, что программы для чтения RSS обновят ранее полученную информацию.

Следует отметить, что в некоторых полях отдаваемого XML, например, в поле description могут присутствовать html-теги, но они должны быть преобразованы в entities (знак < в комбинацию &lt; и т. д.), что делает функция PHP htmlspecialchars().

Итак, сам скрипт:

<? // Запрет кеширования, см. описание function no_cache() { header("Expires: Mon, 26 Jul 1997 00:00:00 GMT"); header("Pragma: no-cache"); } // Перевод даты из формата RFC 2822 в unixstamp function date2unixstamp($s) { $months = array ( "Jan"=>1, "Feb"=>2, "Mar"=>3, "Apr"=>4, "May"=>5, "Jun"=>6, "Jul"=>7, "Aug"=>8, "Sep"=>9, "Oct"=>10, "Nov"=>11, "Dec"=>12); $a = explode(" ", $s); $b = explode(":", $a[4]); return gmmktime($b[0], $b[1], $b[2], $months[$a[2]], $a[1], $a[3]); } // Получение массива элементов function get_recent() { ... } // Дата и время последнего изменения function get_last_modified() { ... } $HTTP_HOST = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : "site.ru"; // ваш сайт no_cache(); $recent_articles = get_recent(); // Буферизация для установки заголовка Content-Length // и сжатия отправляемых данных ob_start(); ob_start("ob_gzhandler"); echo '<?xml version="1.0" encoding="windows-1251"?>'."\n"; ?><rss version="2.0"> <channel> <title>Название RSS</title> <link><?=$HTTP_HOST?></link> <description>Описание</description> <? $last_date = 0; if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) { $last_date = date2unixstamp($_SERVER["HTTP_IF_MODIFIED_SINCE"]); } $counter = 0; foreach($recent_articles as $recent) { if ($recent["date"] > $last_date) { $counter++; ?> <item> <title> <?=htmlspecialchars($recent["title"])?> </title> <link><?=$recent["link"]?></link> <description> <?=htmlspecialchars($recent["desc"])?> </description> <author>Автор &lt;author@site.ru&gt;</author> <guid><?=$recent["link"]?></guid> <pubDate><?=date("r", $recent["date"])?></pubDate> </item> <? } } ?> </channel> </rss> <? if (!$counter) { header("HTTP/1.1 304 Not Modified"); exit(); } ob_end_flush(); header("Content-Length: ".ob_get_length()); header("Last-Modified: ". gmdate("D, d M Y H:i:s", get_last_modified())." GMT"); header("Content-Type: text/xml; charset=WINDOWS-1251"); ob_end_flush(); ?>

Чтобы скрипт заработал, достаточно на него дать ссылку. Если вы хотите, чтобы у него было «красивое» имя вроде http://site.ru/rss.xml, пропишите в файл .htaccess следующее:

RewriteEngine on Options +FollowSymlinks RewriteBase / RewriteRule ^rss.xml$ some_path/php123/rss.php [L]

some_path/php123/rss.php — это «некрасивый» путь, по которому лежит наш скрипт. Если mod_rewrite не установлен, тогда пропишите туда же вот что:

AddType application/x-httpd-php xml

и поместите скрипт прямо в файл rss.xml. Будьте внимательны! В последнем случае все файлы с расширением xml будут обрабатываться парсером PHP.

Чтобы браузеры смогли определить, что на вашем сайте есть RSS, в разделе описаний страницы следует разместить тег <link>:

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251" /> <title>Заголовок страницы</title> <link rel="alternate" type="application/rss+xml" title="Название RSS" href="http://site.ru/rss.xml" /> </head> <body> ... </body> </html>

На этом всё. Пользуйтесь на здоровье.

Комментарии:

1. 8 мая 2007 года, 18:50. C пишет:
Отличная статья. И код читается хорошо, обычно я чужой код с трудом понимаю. Я давно хотел обмастерить RSS, скачал книжек про него, и думал, что это сильно сложная технология, раз там написано на несколько сот страниц, а это обычный xml! Ну, почитать более внимательно те книжки конечно стоит, но вообще с вашей помощью всё просто. Теперь я его уже не боюсь.

Ещё бы про этот mod_rewrite написали, как вы его понимаете. Я вот регулярки перловские в php замастерил, а вот этот mod_rewrite сильно сложен.
2. 8 мая 2007 года, 21:06. Роман Парпалак пишет:
Есть отличный перевод документации по mod_rewrite (http://www.egoroff.spb.ru/portfolio/apache/mod_rewrite.html). Первый результат в Яндексе по запросу mod_rewrite.
3. 15 мая 2007 года, 12:57. Владислав Сычев пишет:
  Отлично написаный материал. Прям очень хорошо. В коде разобрался. Хотя он и бех комментариев. Переделывал свой файл выдачи просто выдерая куски. Однакож вот вопрос пришлось ob_start();  отключать? это не смертельно?
4. 15 мая 2007 года, 13:48. Владислав Сычев пишет:
get_last_modified() функция неопределена ???
5. 15 мая 2007 года, 15:22. Роман Парпалак пишет:
Не совсем понятно, почему Вам пришлось отключить ob_start(), вроде всё должно работать. Если можете, опишите, в чем проблема.

Если выкинуть ob_start(), то данные перед отправкой браузеру не будут сжиматься, и еще возникнут трудности с установкой заголовка Content-Length (нужно будет по-другому считать объем отсылаемых данных). В принципе, конечно, всё останется работоспособным и без этого заголовка.

get_last_modified() должна возвращать дату последнего изменения информации, отсылаемой через RSS (например, дату последней новости). Вы правы, я про нее не написал. Исправлю.
6. 15 мая 2007 года, 18:41. Владислав Сычев пишет:
ну какие то проблемы с сжатием. убрал аргумент во втором вызове  od_start() и все стало нормально отдаваться. да я понимал что заголовок и прочее. в общем то у меня и так РСС работал но у вас именно упор на заголовок в статье собственно он позволяет снижать нагрузку на сайт и отдавать только обновленное. с датой да я так и поступил поставил дату последней новости.
7. 15 июня 2007 года, 12:29. Андрей пишет:
Здравствуйте! Пытался разобраться, все сделал, как вы написали, только вот какая ошибка получилась
"Не удается отобразить страницу XML
Не удается просмотреть ввод XML с использованием списка стилей . Исправьте ошибку и затем нажмите кнопку «Обновить»или повторите попытку позднее. "


8. 15 июня 2007 года, 14:21. Роман Парпалак пишет:
Как вы думаете, что можно понять из вашего описания проблемы? Правильно, очень немногое.

Насколько я понял, ваш RSS не открывается в браузере (каком, кстати?). Попробуйте проверить его, например, на feedvalidator.org. Если RSS доступен из Интернета, дайте ссылку на него, я посмотрю, что там не в порядке.
9. 15 июня 2007 года, 17:01. FreeZ пишет:
А я нифига не понял… Мне нужен скрипт, чтобы разместить его на странице и он показывал рсс поток, который прописать в нём же можно, но такого скрипта я не увидел…
10. 15 июня 2007 года, 19:28. Роман Парпалак пишет:
Я тоже нифига не понял, что вам нужно. Честно.
11. 9 июня 2008 года, 08:46. Sprin пишет:
Роман, в рсс имею (сам генерю) тег линк:
<link>http://la.sprin.ru/?pid=8&id=1212953573</link>
Любой парсер xml ругается на знак &, который в моем случае необходим для передачи доп. параметров. Как можно это разрулить именно в xml (rss), если учесть, что параметры передавать необходимо обязательно?
12. 9 июня 2008 года, 18:38. пишет:
По идее, в атрибуте href ссылок знак '&' должен заменяться своим html-эквивалентом '&amp;'. Это должно сработать и для тега <link>. Если не поможет, попробуйте провести такую замену еще раз, то есть написать туда '&amp;amp;'. Разумеется, надо будет проверить работоспособность в rss-читалках (я сам сейчас проверить не могу).
13. 7 января 2009 года, 18:13. пишет:
И эта статья актуальна, мне кажется…
Я помещу у себя со ссылкой на Ваш сайт.

Оставьте свой комментарий

Ваше имя:


Ваш e-mail:





Комментарий:

Для выделения используйте следующий код: [I]курсив[/I], [B]жирный[/B].
Цитату оформляйте так: [Q = имя автора]цитата[/Q] или [Q]еще цитата[/Q].
Ссылку начните с http://. Других команд или HTML-тегов здесь нет.


Сколько будет 40+2?


Еще в разделе «Веб-разработка»:
На тему «RSS»
наверх