1 Вступление
Все большую популярность среди пользователей интернета приобретает ведение
личных онлайновых дневников. Существует множество сайтов, которые позволяют
публиковать свои откровения в интернете легко и непринужденно, без какого-либо
знания специальных языков программирования и разметки гипертекста. Один из таких
сайтов — LiveJournal (www.livejournal.com), интернет-сервис, где каждый желающий
может завести себе личный дневник.
2 Задача
Создать программный комплекс, который позволит интегрировать журнал из
Livejournal в персональный сайт, предусмотреть возможность отображения постов и
комментариев с использованием предустановленного шаблона.
3 Существующие решения
Существует несколько методов решения данной задачи, которые описаны
непосредственно на сайте LiveJournal
(http://www.livejournal.com/developer/embedding.bml?method=all):
1. Самый простой путь встроить ваш журнал в персональный сайт — это вставить
JavaScript в HTML-код страницы. В браузерах, где JavaScript отключен, возможно
отображение ссылки на журнал:
<script language=»JavaScript»
src=»http://www.livejournal.com/customview.cgi?username=username&styleid=101&enc=js»>
<noscript><a href=»http://username.livejournal.com/»>View
my LiveJournal</a></noscript>
</script>
2. Встраивание Livejournal при помощи фреймов. Данный метод будет работать
только в том случае, если браузер поддерживает отображение фрейм-структур:
<center>
<iframe name=»livejournal»
src=»http://www.livejournal.com/users/username/»
frameborder=»0″
scrolling=»auto» height=»400″ width=»460″>
<a href=»http://username.livejournal.com/»>View my LiveJournal</a>
</iframe>
</center>
3. Интеграция при помощи CGI-скриптов или PHP. Средствами языка программирования
производится чтение данных с удаленного ресурса и затем последующий вывод в
браузер без обработки информации:
<?php
$fp = fsockopen(«www.livejournal.com», 80, &$errno, &$errstr, 30);
if($fp) {
fputs($fp,»GET /customview.cgi?».
«username=username&styleid=101 HTTP/1.0\n\n»);
while(!feof($fp)) {
echo fgets($fp,128);
}
fclose($fp);
}
?>
Очевидное преимущество всех существующих решений — простота реализации. Подобная
интеграция займет не более 10 минут с минимальным увеличением скорости загрузки
страницы.
Недостатки: все вышеописанные способы интеграции доступны только для
пользователей с платными экаунтами. В случае же их модификации под бесплатные
журналы на вашей странице появится реклама которую необходимо будет
дополнительно фильтровать. Так же появляется проблема несоответствия дизайна
станицы и встраиваемого журнала. Вывод: ни один из способов внедрения от
Livejournal не предоставляет гибкости в настройках отображения записей и
комментариев журнала.
4 Решение
Суть предлагаемого метода — парсинг записей и комментариев журнала Livejournal и
последующий вывод результатов с использованием предустановленного шаблона.
5 Используемые технологии
PHP, MYSQL, RSS, Sockets
6 Кросс-браузерность
Internet Explorer 5.0,6.0,7.0; FireFox 1.0,2.0; Opera 9.0; Safari 2.0;
7 Входные и выходные параметры
Входные параметры:
$user — имя пользователя Livejournal, журнал которого будет интегрироватся в
персональный сайт;
$postCount — количество записей, отображаемых на странице;
Выходные параметры:
Структура данных, содержащая в себе записи и комментарии журнала Livejournal.
Фрагмент HTML-кода, отображающий записи и комментарии журнала Livejournal с
использованием предустановленного шаблона.
8 Реализация
Для начала нам необходимо получить ленту записей (постов) пользователя. К
счастью Livejournal выдает по RSS-каналу всю необходимую информацию о дневнике и
последних 25 записях. Ниже приведен фрагмент RSS-потока одного из журналов
<?xml version=’1.0′ encoding=’utf-8′ ?>
<rss version=’2.0′ xmlns:lj=’http://www.livejournal.org/rss/lj/1.0/’>
<channel>
<title>второе, что пришло в го…</title>
<link>http://shtepka.livejournal.com/</link>
<description>второе, что пришло в го… — LiveJournal.com</description>
<lastBuildDate>Thu, 24 May 2007 12:26:15 GMT</lastBuildDate>
<generator>LiveJournal / LiveJournal.com</generator>
<image>
<url>http://userpic.livejournal.com/61827888/6441793</url>
<title>второе, что пришло в го…</title>
<link>http://shtepka.livejournal.com/</link>
<width>100</width>
<height>100</height>
</image>
<item>
<guid isPermaLink=’true’>http://shtepka.livejournal.com/196544.html</guid>
<pubDate>Thu, 24 May 2007 12:26:15 GMT</pubDate>
<title>Вопрос</title>
<link>http://shtepka.livejournal.com/196544.html</link>
<description>В Windows нельзя создать файл или папку под названием
«Con», ибо у Билла Гейтса в детстве была прозвище «Con»
то есть «ботаник». И он постарался чтобы в его системе отсутствовали
такие файлы и папки.<br /><br />есть ли этому РАУМНОЕ объяснение?</description>
<comments>http://shtepka.livejournal.com/196544.html</comments>
<lj:security>public</lj:security>
</item>
<item>
<guid isPermaLink=’true’>http://shtepka.livejournal.com/196104.html</guid>
<pubDate>Wed, 23 May 2007 13:12:18 GMT</pubDate>
<title>Ветер знает, где меня искать!</title>
<link>http://shtepka.livejournal.com/196104.html</link>
<description>На обеденном перерыве пускали змея с мальчиком Феем или мальчиком
Тимой, ну<br />вообщем с Тимофеем из Мира Детства!!! Мы шли на речку,
несли змея в руках с катушкой, очень похож он на удочки, а у прохожих возникал
вопрос при виде змея и нас: «Что ловить будете?»,- а мы хором
думали: «Ветер».<br />Тима поймал ветер, а ветер поймал змея,
а змей поймал Тиму и мы понеслись по мосту над рекой вниз, расправив руки и
крылья, а под нами летали чайки, именно под нами и именно ЧАЙКИ, оказывается
эти птицы бывают и в Москве, только надо очень хотеть их увидеть и
услышать.</description>
<comments>http://shtepka.livejournal.com/196104.html</comments>
<lj:security>public</lj:security>
</item>
<item>
<guid isPermaLink=’true’>http://shtepka.livejournal.com/195985.html</guid>
<pubDate>Tue, 22 May 2007 12:52:17 GMT</pubDate>
<title>игра слов</title>
<link>http://shtepka.livejournal.com/195985.html</link>
<description>Пойду домой… дойду — помой!<br /><span class=’ljuser’
lj:user=’zero_result’ style=’white-space: nowrap;’><a
href=’http://zero-result.livejournal.com/profile’><img
src=’http://stat.livejournal.com/img/userinfo.gif’ alt=’[info]‘
width=’17′ height=’17′ style=’vertical-align: bottom;
border: 0;’ /></a><a href=’http://zero-result.livejournal.com/
‘><b>zero_result<
/b></a></span></description>
<comments>http://shtepka.livejournal.com/195985.html</comments>
<category>слова</category>
<lj:security>public</lj:security>
</item>
:
</channel>
</rss>
Поскольку одним из самых распространенных языков написания скриптов в сети
является PHP, мы воспользуемся именно этим интерпретатором для интегрирования
дневника в сайт.
Широко распространенных способов обработки XML-документов существует два -
Event-based APIs и Document Object Model (DOM) APIs. В PHP стандартная поддержка
XML организована с помощью Event-based API (основана на событиях).
Сперва создадим класс RSSParser, внутри которого будет выполняться вся работа по
разбору XML. После создания класса, получим RSS-данные от сервиса LiveJournal и
инициализируем обработчик XML, который будет использовать для событийной
обработки (Event-based API) класс RSSParser. Код класса RSSParser приведен ниже:
//RSSParser class
class RSSParser
{
var $postCurrentNumb = 0;
var $postCount = 0;
var $insideItem = false;
var $tag = «»;
var $maxPostSize = 999999;
var $imageURL = «»;
var $lastBuildDate = «»;
var $lbd = «»;
var $userPic = «»;
var $title = «»;
var $dt = «»;
var $text = «»;
var $category = «»;
var $comments = «»;
var $lj = array();
function startElement($parser, $tagName, $attrs)
{
if($this->insideItem)
{
$this->tag = $tagName;
}
elseif($tagName == «ITEM»)
{
$this->insideItem = true;
}
elseif($tagName == «IMAGE»)
{
$this->insideItem = true;
}
elseif($tagName == «LASTBUILDDATE»)
{
$this->tag = $tagName;
$this->insideItem = false;
}
}
function endElement($parser, $tagName)
{
if($tagName == «IMAGE»)
{
$this->userPic=$this->imageURL;
$this->title = «»;
$this->insideItem = false;
}
if($tagName == «ITEM»)
{
if ($this->postCurrentNumb<$this->postCount)
{
$this->lj[$this->postCurrentNumb][title]=UtoW($this->title);
$this->text=UtoW($this->text);
if (strlen($this->text)>$this->maxPostSize)
$this->text=substr($this->text,0,$this->maxPostSize);
$this->lj[$this->postCurrentNumb][text]=$this->text;
$this->lj[$this->postCurrentNumb][comments]=trim($this->comments);
$this->lj[$this->postCurrentNumb][tag]=UtoW($this->category);
$this->lj[$this->postCurrentNumb][dt]=dateConvert($this->dt);
}
$this->title = «»;
$this->text= «»;
$this->comments = «»;
$this->category = «»;
$this->dt = «»;
$this->postCurrentNumb++;
$this->insideItem = false;
}
if($tagName == «LASTBUILDDATE»)
{
$this->lbd=dateConvert($this->lastBuildDate);
$this->insideItem = false;
}
}
function characterData($parser, $data)
{
if($this->insideItem)
{
switch($this->tag)
{
case «TITLE»: $this->title .= $data; break;
case «DESCRIPTION»: $this->text .= $data; break;
case «COMMENTS»: $this->comments .= $data; break;
case «CATEGORY»: $this->category .= $data; break;
case «PUBDATE»: $this->dt .= $data; break;
case «URL»: $this->imageURL .= $data; break;
}
}
else
{
switch($this->tag)
{
case «LASTBUILDDATE»: $this->lastBuildDate .= $data; break;
}
}
}
}
Стоит учитывать, что чаще всего XML-документы хранятся в Unicode кодировке
UTF-8, а в рунете наиболее часто используемой кодировкой является Windows-1251,
т.е. приходится решать проблему перекодировки.
<—PAGEBREAK—>
Для перекодировки используется функция UtoW()
//convert Unicode to Windows-1251
function UtoW($str)
{
return (mb_convert_encoding($str,»windows-1251″,»UTF-8″));
}
Кроме того, для переформатирования даты используется функция dateConvert()
//convert date
function dateConvert($str)
{
return (date(«Y-m-d H:i:s», strtotime($str)));
}
Теперь создадим функцию, которая будет выполнять инициализацию обработчика RSS и
его запуск.
//generate posts
function generatePostData($postCount)
{
$this->postsCount=$postCount;
$xml_parser=xml_parser_create(«UTF-8″);
$rss_parser=new RSSParser();
$rss_parser->postCount=$this->postsCount;
$rss_parser->maxPostSize=$this->maxPostSize;
xml_set_object($xml_parser, &$rss_parser);
xml_set_element_handler($xml_parser, «startElement», «endElement»);
xml_set_character_data_handler($xml_parser, «characterData»);
$fp = fopen(«http://».$this->user.».livejournal.com/data/rss», «r»)
or die(«Error reading RSS data from
http://».$this->user.».livejournal.com/data/rss !»);
while(($data = fread($fp, 4096)) &&
($rss_parser->postCurrentNumb<$rss_parser->postCount))
{
xml_parse($xml_parser, $data, feof($fp))
or die(«Error parsing RSS data from http://».$this->user.».
livejournal.com/data/rss !»);
}
fclose($fp);
xml_parser_free($xml_parser);
$this->posts=$rss_parser->lj;
$this->userPic=$rss_parser->userPic;
$this->lastBuildDate=$rss_parser->lbd;
if ($this->delcuts)
$this->clearLivejournalCuts();
}
Данная функция является одним из методов класса Livejournal. Параметр
$this->postsCount определяет количество записей, которые будут считаны,
$this->maxPostSize — максимальный размер поста в байтах. Как результат
выполнения функции generatePostData() мы получаем двухмерный массив
$this->posts, в котором находятся записи журнала разбитые на элементы:
Заголовок, Дата, Текст, Ссылка на комментарии.
Следующий шаг — получение комментариев для каждой из записей. Все было бы так же
просто, если Livejournal выдавал ленту комментариев по RSS. К сожалению, такой
услуги нет ни для платных, ни для бесплатных экаунтов. Комментарии придется
получать при помощи HTML-парсера.
Существует две системы стилей (http://www.livejournal.com/customize/)
Livejournal при помощи которых происходит отображение журналов — S1 (для
пользователей, знакомых с CSS и HTML) и S2 (для остальных). Кроме того,
существует несколько стилей для просмотра журналов Livejournal
(http://www.livejournal.com/manage/settings/): Horizon, XCalibur, Dystopia,
Lynx. Самым «легким» из них является Lynx. Именно в этом стиле мы будем
считывать страницы с комментариями пользователей. Кроме того, это позволит нам
написать универсальный парсер для всех стилевых отображений журналов.
Метод getSocketData() считывает HTML-данные со страницы с комментариями. Для
того, чтоб использовать стиль Lynx необходимо в конце адресной строки дописать
параметр «?format=light».
//get socket data
function getSocketData($host,$request)
{
if ($fp = fsockopen($host, 80, $errno, $errstr, 5))
{
fputs($fp,$request);
$data=»";
while(!feof($fp))
$data.=fgets($fp,2048);
fclose($fp);
}
return ($data);
}
//get livejournal comments
function getLJCommentsSock($ljUser, $commentsId)
{
$commentsPath=$commentsId.».html?format=light»;
$host=»livejournal.com»;
$commonRequest= «Accept: */*».»\r\n».
«Accept-Language: ru».»\r\n».
«User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT)».»\r\n».
«Connection: Keep-Alive».»\r\n»;
// Get request
$request= «GET /».$commentsPath.» HTTP/1.0″.»\r\n».
$commonRequest.
«Cookie: «.$cookie.»\r\n».
«Host: «.$ljUser.».livejournal.com\r\n».»\r\n».
«Pragma: no-cache».»\r\n»;
$data=$this->getSocketData($host, $request);
$temp1=strpos($data,»/><a name=’»)+2;
$temp2=strpos($data,»<hr />»,$temp1);
if ($temp1 && $temp2)
$data = substr($data, $temp1, $temp2-$temp1);
else
$data=»";
$this->commentsData=UtoW($data);
}
Необходимый для нас блок информации находится между фрагментами текста «/><a
name=’» и «<hr />»
Следующий шаг — передаем текстовый блок с комментариями для парсинга методу
parseComments(). Обработку HTML выполняет экземпляр класса HtmlParser.
//parse livejournal comments
function parseComments()
{
$j=0;
$prevName=»";
$parser = new HtmlParser($this->commentsData);
while ($parser->parse())
{
if ($parser->iNodeName==»span» && $parser->iNodeType == NODE_TYPE_ELEMENT)
{
$attrValues = $parser->iNodeAttributes;
$attrNames = array_keys($attrValues);
$size = count($attrNames);
for ($i = 0; $i < $size; $i++)
{
$name = $attrNames[$i];
if ($attrNames[$i]==»lj:user»)
$this->comments[$j][user]=UtoW($attrValues[$name]);
}
};
if ($parser->iNodeName==»Text» && ($parser->iNodeType ==
NODE_TYPE_TEXT || $parser->iNodeType == NODE_TYPE_COMMENT))
{
if (strpos($parser->iNodeValue,»UTC»))
$this->comments[$j][dt]=dateConvert($parser->iNodeValue);
if ($prevName==»td» && trim($parser->iNodeValue))
$this->comments[$j][text].=$parser->iNodeValue;
if ($prevName==»br»)
$this->comments[$j][text].=»<BR>».$parser->iNodeValue;
if ($prevName==»b» && !$this->comments[$j][user] && $parser->iNodeValue!=»(«)
$this->comments[$j][subj]=$parser->iNodeValue;
};
if ($parser->iNodeName==»img» && $parser->iNodeType == NODE_TYPE_ELEMENT)
{
$attrValues = $parser->iNodeAttributes;
$attrNames = array_keys($attrValues);
$size = count($attrNames);
for ($i = 0; $i < $size; $i++)
{
$name = $attrNames[$i];
if ($name==»src» && strpos($attrValues[$name],»userpic»))
$this->comments[$j][pic]=$attrValues[$name];
}
}
if ($parser->iNodeName==»a» && $parser->iNodeType == NODE_TYPE_ELEMENT)
{
$attrValues = $parser->iNodeAttributes;
$attrNames = array_keys($attrValues);
$size = count($attrNames);
for ($i = 0; $i < $size; $i++)
{
$name = $attrNames[$i];
if ($name==»href» && strpos($attrValues[$name],»replyto»))
{
$this->comments[$j][reply]=$attrValues[$name];
$j++;
$this->comments[$j][text]=»";
}
}
}
$prevName=$parser->iNodeName;
};
$this->commentsCount=$j;
}
Как результат выполнения функции parseComments() мы получаем двухмерный массив
$this->comments, в котором находятся комментарии к текущей записи журнала
разбитые на элементы: Имя пользователя, Адрес юзерпика, Заголовок, Дата, Текст,
Ссылка на ответ.
В качестве дополнительных параметров можно установить максимальный размер записи
(var $maxPostSize = 999999) и возможность удаления катов (var $delcuts = true);
9 Пример работы
В качестве примера работы программного комплекса создадим произвольный шаблон
для отображения записей и комментариев журнала Livejournal.
<?php
require_once(‘inc/function.inc.php’);
require_once(‘class/rssparser.class.php’);
require_once(‘class/htmlparser.class.php’);
require_once(‘class/lj.class.php’);
connect_to_db($host,$login,$pass,$db_name);
$user=»shtepka»;
$postCount=10;
$lj=new Livejournal($user);
if ($_GET[comment])
{
$lj->generateCommentsData($lj->user, $_GET[comment]);
$query=»SELECT value FROM info WHERE name=’userpic’ OR name=’lastbuilddate’
ORDER BY name ASC»;
$result=mysql_query($query);
$row=mysql_fetch_array($result);
$lbd=$row[value];
$row=mysql_fetch_array($result);
$userpic=$row[value];
$postOut=’<table width=»600px» align=»center» cellpadding=»10″>’;
$query=»SELECT text, textfull FROM posts WHERE commentid=’$_GET[comment]‘»;
$result=mysql_query($query);
$row=mysql_fetch_array($result);
if ($row[textfull])
$row[text]=$row[textfull];
$postOut.=’<tr><td><table width=»100%» style=»border: 1px dashed #000000;
background: url(‘/img/back2.jpg’);»><tr>’;
$postOut.=’<td style=»padding: 20px» valign=»top»><img
src=»‘.$userpic.’»></td>’;
$postOut.=’<td width=»100%» style=»padding: 20px 20px 20px 0px»><p
class=»text»>’.
str_replace(«’»,»‘»,$row[text]).’</p></td>’;
$postOut.=’</tr><tr><td colspan=»2″ align=»right» style=»padding-right: 10px»><A
href=»http://’.
$lj->user.’.livejournal.com/’.$_GET[comment].’.html?mode=reply»
target=»_blank»>reply…</A></td></tr></table></td></tr>’;
for ($i=0; $i<$lj->commentsCount; $i++)
{
$imgOut = ($lj->comments[$i][pic]) ? ‘<img src=»‘.$lj->comments[$i][pic].’»><BR>
<img src=»/img/lj.gif» hspace=»2″>
<A href=»http://’.$lj->comments[$i][user].’.livejournal.com»
target=»_blank» style=»line-height: 0″><b>’.$lj->comments[$i][user].’</b>
</A>’ : ‘<b>anonymous</b>’;
$postOut.=’<tr><td><table width=»100%» style=»border: 1px dashed #000000;
background: url(‘/img/back.gif’); height: 100%»>’;
$postOut.=’<tr><td style=»padding: 20px» align=»center»>’.$imgOut.’</td><td
width=»100%» valign=»top» style=»height: 100%»
><table width=»100%» style=»height: 100%»>’;
$dateOut=substr($lj->comments[$i][dt],8,2).»-».
substr($lj->comments[$i][dt],5,2).»-».substr($lj->comments[$i][dt],0,4).» |
«.substr($lj->comments[$i][dt],11,5);
$postOut.=’<tr><td align=»right» style=»padding: 4px»>
<span>['.$dateOut.']</span></td></tr>’;
$postOut.=’<tr><td colspan=»2″ align=»left»><span>’.
$lj->comments[$i][subj].’</span></td></tr>’;
$postOut.=’<tr><td colspan=»2″ style=»padding: 10px 10px 10px 0px;
height: 100%» valign=»top»><p
class=»text»>’.$lj->comments[$i][text].’</p></td></tr>’;
$postOut.=’<tr><td colspan=»2″ align=»right» style=»padding-right:
10px»><A href=»‘.$lj->comments[$i][reply].’»>reply…</A></td></tr>’;
$postOut.=’</table></td></table></td></tr>’;
}
$postOut.=’<tr><td><table width=»100%» style=»border: 1px dashed #000000;
background: url(‘/img/back2.jpg’);»><tr>’;
$postOut.=’<td style=»padding: 10px» align=»center»><A href=»/’.$lj->path.’
/»><<< back</A></td></tr></table></td></tr>’;
$postOut.=’</table>’;
}
else
{
$lj->generatePostData($postCount);
$query=»UPDATE info SET value=’».$lj->userPic.»‘ WHERE name=’userpic’»;
$result=mysql_query($query);
$query=»UPDATE info SET value=’».$lj->lastBuildDate.»‘ WHERE
name=’lastbuilddate’»;
$result=mysql_query($query);
$postOut=’<table width=»600px» align=»center» cellpadding=»10″>’;
$postOut.=’<tr><td><table width=»100%» style=»border: 1px dashed #000000;
background: url(‘/img/back2.jpg’);»><tr>’;
$postOut.=’<td style=»padding: 20px»><img src=»‘.$lj->userPic.’»></td>’;
$postOut.=’<td width=»100%» style=»padding: 20px»><b>’.$user.»s
livejournal</b></td>’;
$postOut.=’</tr></table></td></tr>’;
for ($i=0; $i<$lj->postsCount; $i++)
{
$commentId=$lj->getCommentId($lj->posts[$i][comments]);
$query=»SELECT id FROM posts WHERE commentid=’$commentId’»;
$result=mysql_query($query);
$row_count=mysql_num_rows($result);
if ($row_count==0)
$query=»INSERT INTO posts (commentid, text, textfull) VALUES
(‘$commentId’, ‘».str_replace(«‘»,’’’,$lj->posts[$i][text]).»‘ ,
‘».str_replace(«‘»,’’’,$lj->posts[$i][textfull]).»‘)»;
else
$query=»UPDATE posts SET text=’».str_replace(«‘»,’’’,
$lj->posts[$i][text]).»‘, textfull=’».str_replace(«‘»,’’’,
$lj->posts[$i][textfull]).»‘ WHERE commentid=’$commentId’»;
$result=mysql_query($query);
$postOut.=’<tr><td><table width=»100%» style=»border: 1px dashed
#000000; background: url(‘/img/back.gif’);»>’;
$dateOut=substr($lj->posts[$i][dt],8,2).»-».substr($lj->posts[$i][dt],5,2).
«-».substr($lj->posts[$i][dt],0,4).» | «.substr($lj->posts[$i][dt],11,5);
$postOut.=’<tr><td align=»right» style=»padding: 4px»>
<span>['.$dateOut.']</span></td></tr>’;
$postOut.=’<tr><td colspan=»2″ align=»center»><span>’.
$lj->posts[$i][title].’</span></td></tr>’;
$postOut.=’<tr><td colspan=»2″ style=»padding: 10px»><p>’.
$lj->posts[$i][text].’</p></td></tr>’;
$postOut.=’<tr><td colspan=»2″ align=»right» style=»padding-right: 10px»>
<A href=»/’.$lj->path.’/’.$commentId.’/»>comments…</A></td></tr>’;
$postOut.=’</table></td></tr>’;
}
$postOut.=’</table>’;
}
?>
<!DOCTYPE HTML PUBLIC «-//W3C//DTD HTML 4.01 Transitional//EN»>
<html>
<head>
<title>Livejournal Integrator Sample</title>
<meta http-equiv=»Content-Type» content=»text/html; charset=windows-1251″>
<style type=»text/css»>
html, body
{
margin: 0;
padding: 0;
height: 100%;
background: url(‘/img/back.jpg’);
}
.dt
{
font: 13px Arial;
}
.text
{
font: 14px Tahoma;
color: #FFF;
}
.title
{
font: 14px Tahoma;
}
a
{
color: #1C1FA7;
}
a:hover
{
color: #1C1FA7;
text-decoration: none;
}
</style>
</head>
<body>
<?=$postOut?>
</body>
</html>
Для просмотра онлайн-демонстрации работы скрипта кликните по ссылке -
Демонстрация
10 Ссылки
Обработка LiveJournal RSS стандартными средствами PHP -
http://bikman.ru/texts/techarticle/ljrssphp/
HTML Parser — http://php-html.sourceforge.net/
Livejournal FAQ — http://www.livejournal.com/support/faq.bml
Источник: codingrus.ru