[change] update FeedWriter class

This commit is contained in:
Nicolas Lœuillet 2013-12-03 10:39:00 +01:00
parent 678f2cb6ee
commit 39cc09dfc3
1 changed files with 171 additions and 170 deletions

View File

@ -1,16 +1,16 @@
<?php <?php
define('RSS2', 1, true); // RSS 0.90 Officially obsoleted by 1.0
define('JSON', 2, true); // RSS 0.91, 0.92, 0.93 and 0.94 Officially obsoleted by 2.0
define('ATOM', 3, true); // So, define constants for RSS 1.0, RSS 2.0 and ATOM
define('RSS1', 'RSS 1.0', true);
define('RSS2', 'RSS 2.0', true);
define('ATOM', 'ATOM', true);
/** /**
* Univarsel Feed Writer class * Univarsel Feed Writer class
* *
* Genarate RSS2 or JSON (original: RSS 1.0, RSS2.0 and ATOM Feed) * Genarate RSS 1.0, RSS2.0 and ATOM Feed
*
* Modified for FiveFilters.org's Full-Text RSS project
* to allow for inclusion of hubs, JSON output.
* Stripped RSS1 and ATOM support.
* *
* @package UnivarselFeedWriter * @package UnivarselFeedWriter
* @author Anis uddin Ahmad <anisniit@gmail.com> * @author Anis uddin Ahmad <anisniit@gmail.com>
@ -18,21 +18,17 @@ define('ATOM', 3, true);
*/ */
class FeedWriter class FeedWriter
{ {
private $self = null; // self URL - http://feed2.w3.org/docs/warning/MissingAtomSelfLink.html
private $hubs = array(); // PubSubHubbub hubs
private $channels = array(); // Collection of channel elements private $channels = array(); // Collection of channel elements
private $items = array(); // Collection of items as object of FeedItem class. private $items = array(); // Collection of items as object of FeedItem class.
private $data = array(); // Store some other version wise data private $data = array(); // Store some other version wise data
private $CDATAEncoding = array(); // The tag names which have to encoded as CDATA private $CDATAEncoding = array(); // The tag names which have to encoded as CDATA
private $xsl = null; // stylesheet to render RSS (used by Chrome)
private $json = null; // JSON object
private $version = null; private $version = null;
/** /**
* Constructor * Constructor
* *
* @param constant the version constant (RSS2 or JSON). * @param constant the version constant (RSS1/RSS2/ATOM).
*/ */
function __construct($version = RSS2) function __construct($version = RSS2)
{ {
@ -43,11 +39,7 @@ define('ATOM', 3, true);
$this->channels['link'] = 'http://www.ajaxray.com/blog'; $this->channels['link'] = 'http://www.ajaxray.com/blog';
//Tag names to encode in CDATA //Tag names to encode in CDATA
$this->CDATAEncoding = array('description', 'content:encoded', 'content', 'subtitle', 'summary'); $this->CDATAEncoding = array('description', 'content:encoded', 'summary');
}
public function setFormat($format) {
$this->version = $format;
} }
// Start # public functions --------------------------------------------- // Start # public functions ---------------------------------------------
@ -82,26 +74,19 @@ define('ATOM', 3, true);
} }
/** /**
* Genarate the actual RSS/JSON file * Genarate the actual RSS/ATOM file
* *
* @access public * @access public
* @return void * @return void
*/ */
public function genarateFeed() public function genarateFeed()
{ {
if ($this->version == RSS2) { header("Content-type: text/xml");
header('Content-type: text/xml; charset=UTF-8');
} elseif ($this->version == JSON) {
header('Content-type: application/json; charset=UTF-8');
$this->json = new stdClass();
}
$this->printHead(); $this->printHead();
$this->printChannels(); $this->printChannels();
$this->printItems(); $this->printItems();
$this->printTale(); $this->printTale();
if ($this->version == JSON) {
echo json_encode($this->json);
}
} }
/** /**
@ -128,6 +113,7 @@ define('ATOM', 3, true);
$this->items[] = $feedItem; $this->items[] = $feedItem;
} }
// Wrapper functions ------------------------------------------------------------------- // Wrapper functions -------------------------------------------------------------------
/** /**
@ -142,42 +128,6 @@ define('ATOM', 3, true);
$this->setChannelElement('title', $title); $this->setChannelElement('title', $title);
} }
/**
* Add a hub to the channel element
*
* @access public
* @param string URL
* @return void
*/
public function addHub($hub)
{
$this->hubs[] = $hub;
}
/**
* Set XSL URL
*
* @access public
* @param string URL
* @return void
*/
public function setXsl($xsl)
{
$this->xsl = $xsl;
}
/**
* Set self URL
*
* @access public
* @param string URL
* @return void
*/
public function setSelf($self)
{
$this->self = $self;
}
/** /**
* Set the 'description' channel element * Set the 'description' channel element
* *
@ -187,8 +137,7 @@ define('ATOM', 3, true);
*/ */
public function setDescription($desciption) public function setDescription($desciption)
{ {
$tag = ($this->version == ATOM)? 'subtitle' : 'description'; $this->setChannelElement('description', $desciption);
$this->setChannelElement($tag, $desciption);
} }
/** /**
@ -217,6 +166,36 @@ define('ATOM', 3, true);
$this->setChannelElement('image', array('title'=>$title, 'link'=>$link, 'url'=>$url)); $this->setChannelElement('image', array('title'=>$title, 'link'=>$link, 'url'=>$url));
} }
/**
* Set the 'about' channel element. Only for RSS 1.0
*
* @access public
* @param srting value of 'about' channel tag
* @return void
*/
public function setChannelAbout($url)
{
$this->data['ChannelAbout'] = $url;
}
/**
* Genarates an UUID
* @author Anis uddin Ahmad <admin@ajaxray.com>
* @param string an optional prefix
* @return string the formated uuid
*/
public static function uuid($key = null, $prefix = '')
{
$key = ($key == null)? uniqid(rand()) : $key;
$chars = md5($key);
$uuid = substr($chars,0,8) . '-';
$uuid .= substr($chars,8,4) . '-';
$uuid .= substr($chars,12,4) . '-';
$uuid .= substr($chars,16,4) . '-';
$uuid .= substr($chars,20,12);
return $prefix . $uuid;
}
// End # public functions ---------------------------------------------- // End # public functions ----------------------------------------------
// Start # private functions ---------------------------------------------- // Start # private functions ----------------------------------------------
@ -229,17 +208,28 @@ define('ATOM', 3, true);
*/ */
private function printHead() private function printHead()
{ {
if ($this->version == RSS2) $out = '<?xml version="1.0" encoding="utf-8"?>' . "\n";
if($this->version == RSS2)
{ {
$out = '<?xml version="1.0" encoding="utf-8"?>'."\n"; $out .= '<rss version="2.0"
if ($this->xsl) $out .= '<?xml-stylesheet type="text/xsl" href="'.htmlspecialchars($this->xsl).'"?>' . PHP_EOL; xmlns:content="http://purl.org/rss/1.0/modules/content/"
$out .= '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">' . PHP_EOL; xmlns:wfw="http://wellformedweb.org/CommentAPI/"
echo $out; >' . PHP_EOL;
} }
elseif ($this->version == JSON) elseif($this->version == RSS1)
{ {
$this->json->rss = array('@attributes' => array('version' => '2.0')); $out .= '<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
>' . PHP_EOL;;
} }
else if($this->version == ATOM)
{
$out .= '<feed xmlns="http://www.w3.org/2005/Atom">' . PHP_EOL;;
}
echo $out;
} }
/** /**
@ -250,83 +240,67 @@ define('ATOM', 3, true);
*/ */
private function printTale() private function printTale()
{ {
if ($this->version == RSS2) if($this->version == RSS2)
{ {
echo '</channel>',PHP_EOL,'</rss>'; echo '</channel>' . PHP_EOL . '</rss>';
} }
// do nothing for JSON elseif($this->version == RSS1)
{
echo '</rdf:RDF>';
}
else if($this->version == ATOM)
{
echo '</feed>';
}
} }
/** /**
* Creates a single node as xml format * Creates a single node as xml format
* *
* @access private * @access private
* @param string name of the tag * @param srting name of the tag
* @param mixed tag value as string or array of nested tags in 'tagName' => 'tagValue' format * @param mixed tag value as string or array of nested tags in 'tagName' => 'tagValue' format
* @param array Attributes(if any) in 'attrName' => 'attrValue' format * @param array Attributes(if any) in 'attrName' => 'attrValue' format
* @return string formatted xml tag * @return string formatted xml tag
*/ */
private function makeNode($tagName, $tagContent, $attributes = null) private function makeNode($tagName, $tagContent, $attributes = null)
{ {
if ($this->version == RSS2) $nodeText = '';
$attrText = '';
if(is_array($attributes))
{ {
$nodeText = ''; foreach ($attributes as $key => $value)
$attrText = '';
if (is_array($attributes))
{ {
foreach ($attributes as $key => $value) $attrText .= " $key=\"$value\" ";
{
$attrText .= " $key=\"$value\" ";
}
} }
$nodeText .= "<{$tagName}{$attrText}>";
if (is_array($tagContent))
{
foreach ($tagContent as $key => $value)
{
$nodeText .= $this->makeNode($key, $value);
}
}
else
{
//$nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : htmlentities($tagContent);
$nodeText .= htmlspecialchars($tagContent);
}
//$nodeText .= (in_array($tagName, $this->CDATAEncoding))? "]]></$tagName>" : "</$tagName>";
$nodeText .= "</$tagName>";
return $nodeText . PHP_EOL;
} }
elseif ($this->version == JSON)
if(is_array($tagContent) && $this->version == RSS1)
{ {
$tagName = (string)$tagName; $attrText = ' rdf:parseType="Resource"';
$tagName = strtr($tagName, ':', '_'); }
$node = null;
if (!$tagContent && is_array($attributes) && count($attributes))
$attrText .= (in_array($tagName, $this->CDATAEncoding) && $this->version == ATOM)? ' type="html" ' : '';
$nodeText .= (in_array($tagName, $this->CDATAEncoding))? "<{$tagName}{$attrText}><![CDATA[" : "<{$tagName}{$attrText}>";
if(is_array($tagContent))
{
foreach ($tagContent as $key => $value)
{ {
$node = array('@attributes' => $this->json_keys($attributes)); $nodeText .= $this->makeNode($key, $value);
} else {
if (is_array($tagContent)) {
$node = $this->json_keys($tagContent);
} else {
$node = $tagContent;
}
}
return $node;
}
return ''; // should not get here
}
private function json_keys(array $array) {
$new = array();
foreach ($array as $key => $val) {
if (is_string($key)) $key = strtr($key, ':', '_');
if (is_array($val)) {
$new[$key] = $this->json_keys($val);
} else {
$new[$key] = $val;
} }
} }
return $new; else
{
$nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : htmlentities($tagContent);
}
$nodeText .= (in_array($tagName, $this->CDATAEncoding))? "]]></$tagName>" : "</$tagName>";
return $nodeText . PHP_EOL;
} }
/** /**
@ -340,27 +314,41 @@ define('ATOM', 3, true);
switch ($this->version) switch ($this->version)
{ {
case RSS2: case RSS2:
echo '<channel>' . PHP_EOL; echo '<channel>' . PHP_EOL;
// add hubs
foreach ($this->hubs as $hub) {
//echo $this->makeNode('link', '', array('rel'=>'hub', 'href'=>$hub, 'xmlns'=>'http://www.w3.org/2005/Atom'));
echo '<link rel="hub" href="'.htmlspecialchars($hub).'" xmlns="http://www.w3.org/2005/Atom" />' . PHP_EOL;
}
// add self
if (isset($this->self)) {
//echo $this->makeNode('link', '', array('rel'=>'self', 'href'=>$this->self, 'xmlns'=>'http://www.w3.org/2005/Atom'));
echo '<link rel="self" href="'.htmlspecialchars($this->self).'" xmlns="http://www.w3.org/2005/Atom" />' . PHP_EOL;
}
//Print Items of channel
foreach ($this->channels as $key => $value)
{
echo $this->makeNode($key, $value);
}
break; break;
case JSON: case RSS1:
$this->json->rss['channel'] = (object)$this->json_keys($this->channels); echo (isset($this->data['ChannelAbout']))? "<channel rdf:about=\"{$this->data['ChannelAbout']}\">" : "<channel rdf:about=\"{$this->channels['link']}\">";
break; break;
} }
//Print Items of channel
foreach ($this->channels as $key => $value)
{
if($this->version == ATOM && $key == 'link')
{
// ATOM prints link element as href attribute
echo $this->makeNode($key,'',array('href'=>$value));
//Add the id for ATOM
echo $this->makeNode('id',self::uuid($value,'urn:uuid:'));
}
else
{
echo $this->makeNode($key, $value);
}
}
//RSS 1.0 have special tag <rdf:Seq> with channel
if($this->version == RSS1)
{
echo "<items>" . PHP_EOL . "<rdf:Seq>" . PHP_EOL;
foreach ($this->items as $item)
{
$thisItems = $item->getElements();
echo "<rdf:li resource=\"{$thisItems['link']['content']}\"/>" . PHP_EOL;
}
echo "</rdf:Seq>" . PHP_EOL . "</items>" . PHP_EOL . "</channel>" . PHP_EOL;
}
} }
/** /**
@ -375,28 +363,14 @@ define('ATOM', 3, true);
{ {
$thisItems = $item->getElements(); $thisItems = $item->getElements();
echo $this->startItem(); //the argument is printed as rdf:about attribute of item in rss 1.0
echo $this->startItem($thisItems['link']['content']);
if ($this->version == JSON) {
$json_item = array();
}
foreach ($thisItems as $feedItem ) foreach ($thisItems as $feedItem )
{ {
if ($this->version == RSS2) { echo $this->makeNode($feedItem['name'], $feedItem['content'], $feedItem['attributes']);
echo $this->makeNode($feedItem['name'], $feedItem['content'], $feedItem['attributes']);
} elseif ($this->version == JSON) {
$json_item[strtr($feedItem['name'], ':', '_')] = $this->makeNode($feedItem['name'], $feedItem['content'], $feedItem['attributes']);
}
} }
echo $this->endItem(); echo $this->endItem();
if ($this->version == JSON) {
if (count($this->items) > 1) {
$this->json->rss['channel']->item[] = $json_item;
} else {
$this->json->rss['channel']->item = $json_item;
}
}
} }
} }
@ -404,15 +378,30 @@ define('ATOM', 3, true);
* Make the starting tag of channels * Make the starting tag of channels
* *
* @access private * @access private
* @param srting The vale of about tag which is used for only RSS 1.0
* @return void * @return void
*/ */
private function startItem() private function startItem($about = false)
{ {
if ($this->version == RSS2) if($this->version == RSS2)
{ {
echo '<item>' . PHP_EOL; echo '<item>' . PHP_EOL;
} }
// nothing for JSON elseif($this->version == RSS1)
{
if($about)
{
echo "<item rdf:about=\"$about\">" . PHP_EOL;
}
else
{
die('link element is not set .\n It\'s required for RSS 1.0 to be used as about attribute of item');
}
}
else if($this->version == ATOM)
{
echo "<entry>" . PHP_EOL;
}
} }
/** /**
@ -423,12 +412,24 @@ define('ATOM', 3, true);
*/ */
private function endItem() private function endItem()
{ {
if ($this->version == RSS2) if($this->version == RSS2 || $this->version == RSS1)
{ {
echo '</item>' . PHP_EOL; echo '</item>' . PHP_EOL;
} }
// nothing for JSON else if($this->version == ATOM)
{
echo "</entry>" . PHP_EOL;
}
} }
// End # private functions ---------------------------------------------- // End # private functions ----------------------------------------------
}
} // end of class FeedWriter
// autoload classes
function __autoload($class_name)
{
require_once $class_name . '.php';
}