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