<?xml version='1.0' encoding='utf-8' ?>
<rss version='2.0' xmlns:lj='http://www.livejournal.org/rss/lj/1.0/'>
<channel>
<title>Every Thug Needs a Lady</title>
<link>http://idgiebay.livejournal.com/</link>
<description>Every Thug Needs a Lady - LiveJournal.com</description>
<lastBuildDate>Fri, 25 May 2007 01:04:48 GMT</lastBuildDate>
<generator>LiveJournal / LiveJournal.com</generator>
<image>
<url>http://userpic.livejournal.com/10996047/449659</url>
<title>Every Thug Needs a Lady</title>
<link>http://idgiebay.livejournal.com/</link>
<width>100</width>
<height>87</height>
</image>
<item>
<guid isPermaLink='true'>http://idgiebay.livejournal.com/335686.html</guid>
<pubDate>Fri, 25 May 2007 01:04:48 GMT</pubDate>
<title>GO GO TOTTLES</title>
<link>http://idgiebay.livejournal.com/335686.html</link>
<description><a name="cutid1"></a><a href="
http://photobucket.com" target="_blank"><img
src="http://img.photobucket.com/albums/v177/idgiebay/raphsample1.jpg"
border="0" alt="Photo Sharing and Video Hosting at
Photobucket"></a><br /><br />Used a screen grab for reference.
I'm glad I finally taught myself how to ink in
Illustrator. I luvs yew, Adobe.</description>
<comments>http://idgiebay.livejournal.com/335686.html</comments>
<category>artwork</category>
<category>tmnt</category>
<lj:mood>creative</lj:mood>
<lj:security>public</lj:security>
</item>
<item>
<guid isPermaLink='true'>http://idgiebay.livejournal.com/335451.html</guid>
<pubDate>Thu, 24 May 2007 21:42:50 GMT</pubDate>
<title>*____*</title>
<link>http://idgiebay.livejournal.com/335451.html</link>
<description>Oh, Adobe Illustrator, how could I have hated you so?</description>
<comments>http://idgiebay.livejournal.com/335451.html</comments>
<category>artwork</category>
<lj:mood>ecstatic</lj:mood>
<lj:security>public</lj:security>
</item>
<item>
<guid isPermaLink='true'>http://idgiebay.livejournal.com/334916.html</guid>
<pubDate>Thu, 17 May 2007 19:47:38 GMT</pubDate>
<title>there's nothing that a hundred men or more could ever do</title>
<link>http://idgiebay.livejournal.com/334916.html</link>
<description>Ever been a song that just made you all sorts of nostalgic and
melancholy and you had no idea why? This song does that to me. It's not
a sad song and it's not a song that brings back fond childhood memories,
so I have no idea what the deal is. I love it, though. &lt;3<br
/><br />But the chorus makes me want to cry.<br /><br /
>Oh well. Anyway.<br /><br />I have an interview tomorrow!
I'm not leaving VPI, but I am trying to transfer within the company.
I don't know if I'll get the position, but here's hoping.
I've not even been there six months, but my supervisor seems to think
I stand a good chance of getting it. She said she was going to write me up
just so she had a reason to keep me on her team... jokingly, of course. I
have mixed emotions. I really want the job because I know I'd be really
good at it and it would mean being off the phones, but at the same time, I
love my current job and Sara is, like, the coolest supervisor ever. So I
dunno. We'll see what happens. It's a coveted position among
the customer care folk, apparently.<br /><br />Off to shower.</description>
<comments>http://idgiebay.livejournal.com/334916.html</comments>
<category>job</category>
<lj:music>"Africa" - Toto</lj:music>
<lj:mood>okay</lj:mood>
<lj:security>public</lj:security>
</item>
<item>
<guid isPermaLink='true'>http://idgiebay.livejournal.com/334501.html</guid>
<pubDate>Sat, 05 May 2007 22:55:37 GMT</pubDate>
<title>moo</title>
<link>http://idgiebay.livejournal.com/334501.html</link>
<description>Man, am I exhausted... I haven't forgotten about that meme
thingie, I've just been non-stop busy since yesterday... I'll
probably get to it tomorrow, as I'm gonna go see Spidey 3 with Tif,
Bryan, Manda, and a bunch of people from work and I may spend the night
at Bryan's place, but I'm not sure about that yet.<br /><br
/>My head is freaking killing me.<br /><br />[Edit] By the way,
is anyone else having problems with Photobucket? I can upload stuff just fine,
but the pictures never load.</description>
<comments>http://idgiebay.livejournal.com/334501.html</comments>
<lj:music>something on the radio</lj:music>
<lj:mood>exhausted</lj:mood>
<lj:security>public</lj:security>
</item>
</channel>
</rss>
PHP is one of the most popular script languages, so we will take advantage of this interpreter for Livejournal embedding.
There are two widespread methods to work with XML documents - Event-based APIs and Document Object Model (DOM) APIs. In PHP standard support of XML is organized by Event-based API (based on events).
Firstly we will create the Rssparser class, into which all of work will be executed on the analysis of XML. After class creation, we will get RSS data from Livejournal feed and initialize XML handler, which will use Rssparser for event treatment (Event-based API). The code of RSSParser is situated below:
//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;
}
}
}
}
For strings decoding from Utf-8 to Windows-1251 we use UtoW() function:
//convert Unicode to Windows-1251
function UtoW($str)
{
return (mb_convert_encoding($str,"windows-1251","UTF-8"));
}
For date format converting we use dateConvert() function:
//convert date
function dateConvert($str)
{
return (date("Y-m-d H:i:s", strtotime($str)));
}
Now we'll create a function which initialize RSS handler.
//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();
}
This function is one of methods of Livejournal class. Parameter $this->postsCount determines the amount of records which will be proceed, $this->maxPostSize it is a maximal byte size of post. As a result of function generatepostdata() implementation we'll get an array $this->posts, in which journal's posts are stored by elements: Heading, Date, Text, Comment link.
A next step is a comments processing for each record. Unfortunately, Livejournal doesn't give out the RSS-feed for comments. Such feature isn't available even for paid accounts. Comments must be parsed with the help of Html-parser.
In Livejournal there are two stylesystems for journal displaying (http://www.livejournal.com/customize/) - S1 (for users with knowledge in CSS and HTML) and S2 (for other). In addition, there are a few styles for journal viewing (http://www.livejournal.com/manage/settings/): Horizon, Xcalibur, Dystopia, Lynx. We'll use Lynx style for comments page parsing. Also it will allow us to create universal parser for all display styles.
Getsocketdata() method reads HTML data from comments page. To use Lynx style for journal displaying we must append address string with parameter "?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);
}
Next step - parsing comments with parseComments() method.
//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;
}
As a result of parsecomments()function execution we'll get an array $this->comments with comments: Username, Userpic address, Heading, Date, Text, Answer link.
Some additional parameters are available: maximal size of record (var $maxPostSize = 999999) and cut deletion (var $delcuts = true);
9 Example
As an example of script work demonstration an arbitrary template was created.
<?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="idgiebay";
$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 class="dt">['.$dateOut.']</span></td></tr>';
$postOut.='<tr><td colspan="2" align="left"><span class="title">'.
$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 class="dt">['.$dateOut.']</span></td></tr>';
$postOut.='<tr><td colspan="2" align="center"><span class="title">'.
$lj->posts[$i][title].'</span></td></tr>';
$postOut.='<tr><td colspan="2" style="padding: 10px"><p class="text">'.
$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>
 
To watch online demonstration click here - PHP Livejournal Embedding
|
|