]> git.immae.eu Git - github/wallabag/wallabag.git/blob - inc/3rdparty/feedwriter/FeedWriter.php
[add] add RSS feed for archive
[github/wallabag/wallabag.git] / inc / 3rdparty / feedwriter / FeedWriter.php
1 <?php
2 // RSS 0.90 Officially obsoleted by 1.0
3 // RSS 0.91, 0.92, 0.93 and 0.94 Officially obsoleted by 2.0
4 // So, define constants for RSS 1.0, RSS 2.0 and ATOM
5
6 define('RSS1', 'RSS 1.0', true);
7 define('RSS2', 'RSS 2.0', true);
8 define('ATOM', 'ATOM', true);
9
10 /**
11 * Univarsel Feed Writer class
12 *
13 * Genarate RSS 1.0, RSS2.0 and ATOM Feed
14 *
15 * @package UnivarselFeedWriter
16 * @author Anis uddin Ahmad <anisniit@gmail.com>
17 * @link http://www.ajaxray.com/projects/rss
18 */
19 class FeedWriter
20 {
21 private $channels = array(); // Collection of channel elements
22 private $items = array(); // Collection of items as object of FeedItem class.
23 private $data = array(); // Store some other version wise data
24 private $CDATAEncoding = array(); // The tag names which have to encoded as CDATA
25
26 private $version = null;
27
28 /**
29 * Constructor
30 *
31 * @param constant the version constant (RSS1/RSS2/ATOM).
32 */
33 function __construct($version = RSS2)
34 {
35 $this->version = $version;
36
37 // Setting default value for assential channel elements
38 $this->channels['title'] = $version . ' Feed';
39 $this->channels['link'] = 'http://www.ajaxray.com/blog';
40
41 //Tag names to encode in CDATA
42 $this->CDATAEncoding = array('description', 'content:encoded', 'summary');
43 }
44
45 // Start # public functions ---------------------------------------------
46
47 /**
48 * Set a channel element
49 * @access public
50 * @param srting name of the channel tag
51 * @param string content of the channel tag
52 * @return void
53 */
54 public function setChannelElement($elementName, $content)
55 {
56 $this->channels[$elementName] = $content ;
57 }
58
59 /**
60 * Set multiple channel elements from an array. Array elements
61 * should be 'channelName' => 'channelContent' format.
62 *
63 * @access public
64 * @param array array of channels
65 * @return void
66 */
67 public function setChannelElementsFromArray($elementArray)
68 {
69 if(! is_array($elementArray)) return;
70 foreach ($elementArray as $elementName => $content)
71 {
72 $this->setChannelElement($elementName, $content);
73 }
74 }
75
76 /**
77 * Genarate the actual RSS/ATOM file
78 *
79 * @access public
80 * @return void
81 */
82 public function genarateFeed()
83 {
84 header("Content-type: text/xml");
85
86 $this->printHead();
87 $this->printChannels();
88 $this->printItems();
89 $this->printTale();
90 }
91
92 /**
93 * Create a new FeedItem.
94 *
95 * @access public
96 * @return object instance of FeedItem class
97 */
98 public function createNewItem()
99 {
100 $Item = new FeedItem($this->version);
101 return $Item;
102 }
103
104 /**
105 * Add a FeedItem to the main class
106 *
107 * @access public
108 * @param object instance of FeedItem class
109 * @return void
110 */
111 public function addItem($feedItem)
112 {
113 $this->items[] = $feedItem;
114 }
115
116
117 // Wrapper functions -------------------------------------------------------------------
118
119 /**
120 * Set the 'title' channel element
121 *
122 * @access public
123 * @param srting value of 'title' channel tag
124 * @return void
125 */
126 public function setTitle($title)
127 {
128 $this->setChannelElement('title', $title);
129 }
130
131 /**
132 * Set the 'description' channel element
133 *
134 * @access public
135 * @param srting value of 'description' channel tag
136 * @return void
137 */
138 public function setDescription($desciption)
139 {
140 $this->setChannelElement('description', $desciption);
141 }
142
143 /**
144 * Set the 'link' channel element
145 *
146 * @access public
147 * @param srting value of 'link' channel tag
148 * @return void
149 */
150 public function setLink($link)
151 {
152 $this->setChannelElement('link', $link);
153 }
154
155 /**
156 * Set the 'image' channel element
157 *
158 * @access public
159 * @param srting title of image
160 * @param srting link url of the imahe
161 * @param srting path url of the image
162 * @return void
163 */
164 public function setImage($title, $link, $url)
165 {
166 $this->setChannelElement('image', array('title'=>$title, 'link'=>$link, 'url'=>$url));
167 }
168
169 /**
170 * Set the 'about' channel element. Only for RSS 1.0
171 *
172 * @access public
173 * @param srting value of 'about' channel tag
174 * @return void
175 */
176 public function setChannelAbout($url)
177 {
178 $this->data['ChannelAbout'] = $url;
179 }
180
181 /**
182 * Genarates an UUID
183 * @author Anis uddin Ahmad <admin@ajaxray.com>
184 * @param string an optional prefix
185 * @return string the formated uuid
186 */
187 public static function uuid($key = null, $prefix = '')
188 {
189 $key = ($key == null)? uniqid(rand()) : $key;
190 $chars = md5($key);
191 $uuid = substr($chars,0,8) . '-';
192 $uuid .= substr($chars,8,4) . '-';
193 $uuid .= substr($chars,12,4) . '-';
194 $uuid .= substr($chars,16,4) . '-';
195 $uuid .= substr($chars,20,12);
196
197 return $prefix . $uuid;
198 }
199 // End # public functions ----------------------------------------------
200
201 // Start # private functions ----------------------------------------------
202
203 /**
204 * Prints the xml and rss namespace
205 *
206 * @access private
207 * @return void
208 */
209 private function printHead()
210 {
211 $out = '<?xml version="1.0" encoding="utf-8"?>' . "\n";
212
213 if($this->version == RSS2)
214 {
215 $out .= '<rss version="2.0"
216 xmlns:content="http://purl.org/rss/1.0/modules/content/"
217 xmlns:wfw="http://wellformedweb.org/CommentAPI/"
218 >' . PHP_EOL;
219 }
220 elseif($this->version == RSS1)
221 {
222 $out .= '<rdf:RDF
223 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
224 xmlns="http://purl.org/rss/1.0/"
225 xmlns:dc="http://purl.org/dc/elements/1.1/"
226 >' . PHP_EOL;;
227 }
228 else if($this->version == ATOM)
229 {
230 $out .= '<feed xmlns="http://www.w3.org/2005/Atom">' . PHP_EOL;;
231 }
232 echo $out;
233 }
234
235 /**
236 * Closes the open tags at the end of file
237 *
238 * @access private
239 * @return void
240 */
241 private function printTale()
242 {
243 if($this->version == RSS2)
244 {
245 echo '</channel>' . PHP_EOL . '</rss>';
246 }
247 elseif($this->version == RSS1)
248 {
249 echo '</rdf:RDF>';
250 }
251 else if($this->version == ATOM)
252 {
253 echo '</feed>';
254 }
255
256 }
257
258 /**
259 * Creates a single node as xml format
260 *
261 * @access private
262 * @param srting name of the tag
263 * @param mixed tag value as string or array of nested tags in 'tagName' => 'tagValue' format
264 * @param array Attributes(if any) in 'attrName' => 'attrValue' format
265 * @return string formatted xml tag
266 */
267 private function makeNode($tagName, $tagContent, $attributes = null)
268 {
269 $nodeText = '';
270 $attrText = '';
271
272 if(is_array($attributes))
273 {
274 foreach ($attributes as $key => $value)
275 {
276 $attrText .= " $key=\"$value\" ";
277 }
278 }
279
280 if(is_array($tagContent) && $this->version == RSS1)
281 {
282 $attrText = ' rdf:parseType="Resource"';
283 }
284
285
286 $attrText .= (in_array($tagName, $this->CDATAEncoding) && $this->version == ATOM)? ' type="html" ' : '';
287 $nodeText .= (in_array($tagName, $this->CDATAEncoding))? "<{$tagName}{$attrText}><![CDATA[" : "<{$tagName}{$attrText}>";
288
289 if(is_array($tagContent))
290 {
291 foreach ($tagContent as $key => $value)
292 {
293 $nodeText .= $this->makeNode($key, $value);
294 }
295 }
296 else
297 {
298 $nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : htmlentities($tagContent);
299 }
300
301 $nodeText .= (in_array($tagName, $this->CDATAEncoding))? "]]></$tagName>" : "</$tagName>";
302
303 return $nodeText . PHP_EOL;
304 }
305
306 /**
307 * @desc Print channels
308 * @access private
309 * @return void
310 */
311 private function printChannels()
312 {
313 //Start channel tag
314 switch ($this->version)
315 {
316 case RSS2:
317 echo '<channel>' . PHP_EOL;
318 break;
319 case RSS1:
320 echo (isset($this->data['ChannelAbout']))? "<channel rdf:about=\"{$this->data['ChannelAbout']}\">" : "<channel rdf:about=\"{$this->channels['link']}\">";
321 break;
322 }
323
324 //Print Items of channel
325 foreach ($this->channels as $key => $value)
326 {
327 if($this->version == ATOM && $key == 'link')
328 {
329 // ATOM prints link element as href attribute
330 echo $this->makeNode($key,'',array('href'=>$value));
331 //Add the id for ATOM
332 echo $this->makeNode('id',self::uuid($value,'urn:uuid:'));
333 }
334 else
335 {
336 echo $this->makeNode($key, $value);
337 }
338
339 }
340
341 //RSS 1.0 have special tag <rdf:Seq> with channel
342 if($this->version == RSS1)
343 {
344 echo "<items>" . PHP_EOL . "<rdf:Seq>" . PHP_EOL;
345 foreach ($this->items as $item)
346 {
347 $thisItems = $item->getElements();
348 echo "<rdf:li resource=\"{$thisItems['link']['content']}\"/>" . PHP_EOL;
349 }
350 echo "</rdf:Seq>" . PHP_EOL . "</items>" . PHP_EOL . "</channel>" . PHP_EOL;
351 }
352 }
353
354 /**
355 * Prints formatted feed items
356 *
357 * @access private
358 * @return void
359 */
360 private function printItems()
361 {
362 foreach ($this->items as $item)
363 {
364 $thisItems = $item->getElements();
365
366 //the argument is printed as rdf:about attribute of item in rss 1.0
367 echo $this->startItem($thisItems['link']['content']);
368
369 foreach ($thisItems as $feedItem )
370 {
371 echo $this->makeNode($feedItem['name'], $feedItem['content'], $feedItem['attributes']);
372 }
373 echo $this->endItem();
374 }
375 }
376
377 /**
378 * Make the starting tag of channels
379 *
380 * @access private
381 * @param srting The vale of about tag which is used for only RSS 1.0
382 * @return void
383 */
384 private function startItem($about = false)
385 {
386 if($this->version == RSS2)
387 {
388 echo '<item>' . PHP_EOL;
389 }
390 elseif($this->version == RSS1)
391 {
392 if($about)
393 {
394 echo "<item rdf:about=\"$about\">" . PHP_EOL;
395 }
396 else
397 {
398 die('link element is not set .\n It\'s required for RSS 1.0 to be used as about attribute of item');
399 }
400 }
401 else if($this->version == ATOM)
402 {
403 echo "<entry>" . PHP_EOL;
404 }
405 }
406
407 /**
408 * Closes feed item tag
409 *
410 * @access private
411 * @return void
412 */
413 private function endItem()
414 {
415 if($this->version == RSS2 || $this->version == RSS1)
416 {
417 echo '</item>' . PHP_EOL;
418 }
419 else if($this->version == ATOM)
420 {
421 echo "</entry>" . PHP_EOL;
422 }
423 }
424
425
426
427 // End # private functions ----------------------------------------------
428
429 } // end of class FeedWriter
430
431 // autoload classes
432 function __autoload($class_name)
433 {
434 require_once $class_name . '.php';
435 }