]>
Commit | Line | Data |
---|---|---|
ec397236 | 1 | <?php |
39cc09df NL |
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); | |
ec397236 NL |
9 | |
10 | /** | |
11 | * Univarsel Feed Writer class | |
12 | * | |
39cc09df | 13 | * Genarate RSS 1.0, RSS2.0 and ATOM Feed |
ec397236 NL |
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 | { | |
ec397236 NL |
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 | |
ec397236 NL |
25 | |
26 | private $version = null; | |
27 | ||
28 | /** | |
29 | * Constructor | |
30 | * | |
39cc09df | 31 | * @param constant the version constant (RSS1/RSS2/ATOM). |
ec397236 NL |
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 | |
39cc09df | 42 | $this->CDATAEncoding = array('description', 'content:encoded', 'summary'); |
ec397236 NL |
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 | /** | |
39cc09df | 77 | * Genarate the actual RSS/ATOM file |
ec397236 NL |
78 | * |
79 | * @access public | |
80 | * @return void | |
81 | */ | |
82 | public function genarateFeed() | |
83 | { | |
39cc09df NL |
84 | header("Content-type: text/xml"); |
85 | ||
ec397236 NL |
86 | $this->printHead(); |
87 | $this->printChannels(); | |
88 | $this->printItems(); | |
89 | $this->printTale(); | |
ec397236 NL |
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 | ||
39cc09df | 116 | |
ec397236 NL |
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 | ||
ec397236 NL |
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 | { | |
39cc09df | 140 | $this->setChannelElement('description', $desciption); |
ec397236 NL |
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 | ||
39cc09df NL |
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 | } | |
ec397236 NL |
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 | { | |
39cc09df NL |
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) | |
ec397236 | 221 | { |
39cc09df NL |
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;; | |
ec397236 | 227 | } |
39cc09df | 228 | else if($this->version == ATOM) |
ec397236 | 229 | { |
39cc09df | 230 | $out .= '<feed xmlns="http://www.w3.org/2005/Atom">' . PHP_EOL;; |
ec397236 | 231 | } |
39cc09df | 232 | echo $out; |
ec397236 NL |
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 | { | |
39cc09df | 243 | if($this->version == RSS2) |
ec397236 | 244 | { |
39cc09df | 245 | echo '</channel>' . PHP_EOL . '</rss>'; |
ec397236 | 246 | } |
39cc09df NL |
247 | elseif($this->version == RSS1) |
248 | { | |
249 | echo '</rdf:RDF>'; | |
250 | } | |
251 | else if($this->version == ATOM) | |
252 | { | |
253 | echo '</feed>'; | |
254 | } | |
255 | ||
ec397236 NL |
256 | } |
257 | ||
258 | /** | |
259 | * Creates a single node as xml format | |
260 | * | |
261 | * @access private | |
39cc09df | 262 | * @param srting name of the tag |
ec397236 NL |
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 | { | |
39cc09df NL |
269 | $nodeText = ''; |
270 | $attrText = ''; | |
271 | ||
272 | if(is_array($attributes)) | |
ec397236 | 273 | { |
39cc09df | 274 | foreach ($attributes as $key => $value) |
ec397236 | 275 | { |
39cc09df | 276 | $attrText .= " $key=\"$value\" "; |
ec397236 | 277 | } |
ec397236 | 278 | } |
39cc09df NL |
279 | |
280 | if(is_array($tagContent) && $this->version == RSS1) | |
ec397236 | 281 | { |
39cc09df | 282 | $attrText = ' rdf:parseType="Resource"'; |
ec397236 | 283 | } |
39cc09df NL |
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); | |
ec397236 NL |
294 | } |
295 | } | |
39cc09df NL |
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; | |
ec397236 NL |
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: | |
39cc09df | 317 | echo '<channel>' . PHP_EOL; |
ec397236 | 318 | break; |
39cc09df NL |
319 | case RSS1: |
320 | echo (isset($this->data['ChannelAbout']))? "<channel rdf:about=\"{$this->data['ChannelAbout']}\">" : "<channel rdf:about=\"{$this->channels['link']}\">"; | |
ec397236 NL |
321 | break; |
322 | } | |
39cc09df NL |
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 | } | |
ec397236 NL |
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 | ||
39cc09df NL |
366 | //the argument is printed as rdf:about attribute of item in rss 1.0 |
367 | echo $this->startItem($thisItems['link']['content']); | |
ec397236 NL |
368 | |
369 | foreach ($thisItems as $feedItem ) | |
370 | { | |
39cc09df | 371 | echo $this->makeNode($feedItem['name'], $feedItem['content'], $feedItem['attributes']); |
ec397236 NL |
372 | } |
373 | echo $this->endItem(); | |
ec397236 NL |
374 | } |
375 | } | |
376 | ||
377 | /** | |
378 | * Make the starting tag of channels | |
379 | * | |
380 | * @access private | |
39cc09df | 381 | * @param srting The vale of about tag which is used for only RSS 1.0 |
ec397236 NL |
382 | * @return void |
383 | */ | |
39cc09df | 384 | private function startItem($about = false) |
ec397236 | 385 | { |
39cc09df | 386 | if($this->version == RSS2) |
ec397236 NL |
387 | { |
388 | echo '<item>' . PHP_EOL; | |
389 | } | |
39cc09df NL |
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 | } | |
ec397236 NL |
405 | } |
406 | ||
407 | /** | |
408 | * Closes feed item tag | |
409 | * | |
410 | * @access private | |
411 | * @return void | |
412 | */ | |
413 | private function endItem() | |
414 | { | |
39cc09df | 415 | if($this->version == RSS2 || $this->version == RSS1) |
ec397236 NL |
416 | { |
417 | echo '</item>' . PHP_EOL; | |
418 | } | |
39cc09df NL |
419 | else if($this->version == ATOM) |
420 | { | |
421 | echo "</entry>" . PHP_EOL; | |
422 | } | |
ec397236 NL |
423 | } |
424 | ||
39cc09df NL |
425 | |
426 | ||
ec397236 | 427 | // End # private functions ---------------------------------------------- |
39cc09df NL |
428 | |
429 | } // end of class FeedWriter | |
430 | ||
431 | // autoload classes | |
432 | function __autoload($class_name) | |
433 | { | |
434 | require_once $class_name . '.php'; | |
435 | } |