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