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