Правильная организация RSS
В пользе RSS уже давно никто не сомневается. Я позволю себе сказать пару слов о том, как правильно сделать RSS-канал на вашем сайте. В заметке я буду использовать вымышленные примеры для экспорта информации о новых статьях, хотя, разумеется, через RSS можно экспортировать вообще всё, что угодно: новости, прогноз погоды, курсы валют, записи в блоге. В случае появления дополнительных вопросов вы всегда сможете просмотреть рабочие варианты RSS моего сайта и блога.
Фактически формат RSS представляет
собой веб-страницу, сформированную с применением определенных правил, которая
содержит информацию о нескольких элементах, такую как заголовок, описание, ссылку, дату и
т. д., и эту страницу можно создать обычными средствами. Например, сделать
<?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>Автор <author@site.ru></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>Автор <author@site.ru></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>Автор <author@site.ru></author>
<pubDate>Sun, 11 Mar 2007 00:00:00 +0300</pubDate>
</item>
</channel>
</rss>
Для подобных целей подойдет текстовый редактор, или простейший скрипт (недостатки такого подхода очевидны, впрочем, я о них уже писал).
Понятно, что если на сайте есть хотя бы минимальная автоматизация, RSS может генерироваться скриптом, например, на PHP. Можно предложить два разумных способа работы этого скрипта:
- Скрипт вызывается при обновлении сайта и результаты своей работы сохраняет в обычный XML-файл, на который вы будете давать ссылки.
- Скрипт отрабатывает каждый раз, когда браузер (или иной пользовательский агент) обращается к 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 (знак < в комбинацию < и т. д.), что делает функция 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>Автор <author@site.ru></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>
На этом всё. Пользуйтесь на здоровье.
Комментарии
Ещё бы про этот mod_rewrite написали, как вы его понимаете. Я вот регулярки перловские в php замастерил, а вот этот mod_rewrite сильно сложен.
Если выкинуть ob_start(), то данные перед отправкой браузеру не будут сжиматься, и еще возникнут трудности с установкой заголовка Content-Length (нужно будет по-другому считать объем отсылаемых данных). В принципе, конечно, всё останется работоспособным и без этого заголовка.
get_last_modified() должна возвращать дату последнего изменения информации, отсылаемой через RSS (например, дату последней новости). Вы правы, я про нее не написал. Исправлю.
"Не удается отобразить страницу XML
Не удается просмотреть ввод XML с использованием списка стилей . Исправьте ошибку и затем нажмите кнопку «Обновить»или повторите попытку позднее. "
Насколько я понял, ваш RSS не открывается в браузере (каком, кстати?). Попробуйте проверить его, например, на feedvalidator.org. Если RSS доступен из Интернета, дайте ссылку на него, я посмотрю, что там не в порядке.
<link>
Любой парсер xml ругается на знак &, который в моем случае необходим для передачи доп. параметров. Как можно это разрулить именно в xml (rss), если учесть, что параметры передавать необходимо обязательно?
Я помещу у себя со ссылкой на Ваш сайт.
Оставьте свой комментарий