]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - includes/Feed.php
MediaWiki 1.17.0
[autoinstallsdev/mediawiki.git] / includes / Feed.php
1 <?php
2 /**
3  * Basic support for outputting syndication feeds in RSS, other formats.
4  *
5  * Contain a feed class as well as classes to build rss / atom ... feeds
6  * Available feeds are defined in Defines.php
7  *
8  * Copyright © 2004 Brion Vibber <brion@pobox.com>
9  * http://www.mediawiki.org/
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  * http://www.gnu.org/copyleft/gpl.html
25  *
26  * @file
27  */
28
29 /**
30  * @defgroup Feed Feed
31  */
32
33 /**
34  * A base class for basic support for outputting syndication feeds in RSS and other formats.
35  *
36  * @ingroup Feed
37  */
38 class FeedItem {
39         /**#@+
40          * @var string
41          * @private
42          */
43         var $Title = 'Wiki';
44         var $Description = '';
45         var $Url = '';
46         var $Date = '';
47         var $Author = '';
48         var $UniqueId = '';
49         var $RSSIsPermalink;
50         /**#@-*/
51
52         /**
53          * Constructor
54          *
55          * @param $Title String: Item's title
56          * @param $Description String
57          * @param $Url String: URL uniquely designating the item.
58          * @param $Date String: Item's date
59          * @param $Author String: Author's user name
60          * @param $Comments String
61          */
62         function __construct( $Title, $Description, $Url, $Date = '', $Author = '', $Comments = '' ) {
63                 $this->Title = $Title;
64                 $this->Description = $Description;
65                 $this->Url = $Url;
66                 $this->UniqueId = $Url;
67                 $this->RSSIsPermalink = false;
68                 $this->Date = $Date;
69                 $this->Author = $Author;
70                 $this->Comments = $Comments;
71         }
72
73         /**
74          * Encode $string so that it can be safely embedded in a XML document
75          *
76          * @param $string String: string to encode
77          * @return String
78          */
79         public function xmlEncode( $string ) {
80                 $string = str_replace( "\r\n", "\n", $string );
81                 $string = preg_replace( '/[\x00-\x08\x0b\x0c\x0e-\x1f]/', '', $string );
82                 return htmlspecialchars( $string );
83         }
84
85         /**
86          * Get the unique id of this item
87          *
88          * @return String
89          */
90         public function getUniqueId() {
91                 if ( $this->UniqueId ) {
92                         return $this->xmlEncode( $this->UniqueId );
93                 }
94         }
95
96         /**
97          * set the unique id of an item
98          *
99          * @param $uniqueId String: unique id for the item
100          * @param $RSSisPermalink Boolean: set to true if the guid (unique id) is a permalink (RSS feeds only)
101          */
102         public function setUniqueId($uniqueId, $RSSisPermalink = False) {
103                 $this->UniqueId = $uniqueId;
104                 $this->RSSIsPermalink = $RSSisPermalink;
105         }
106
107         /**
108          * Get the title of this item; already xml-encoded
109          *
110          * @return String
111          */
112         public function getTitle() {
113                 return $this->xmlEncode( $this->Title );
114         }
115
116         /**
117          * Get the URL of this item; already xml-encoded
118          *
119          * @return String
120          */
121         public function getUrl() {
122                 return $this->xmlEncode( $this->Url );
123         }
124
125         /**
126          * Get the description of this item; already xml-encoded
127          *
128          * @return String
129          */
130         public function getDescription() {
131                 return $this->xmlEncode( $this->Description );
132         }
133
134         /**
135          * Get the language of this item
136          *
137          * @return String
138          */
139         public function getLanguage() {
140                 global $wgLanguageCode;
141                 return $wgLanguageCode;
142         }
143
144         /**
145          * Get the title of this item
146          *
147          * @return String
148          */
149         public function getDate() {
150                 return $this->Date;
151         }
152
153         /**
154          * Get the author of this item; already xml-encoded
155          *
156          * @return String
157          */
158         public function getAuthor() {
159                 return $this->xmlEncode( $this->Author );
160         }
161
162         /**
163          * Get the comment of this item; already xml-encoded
164          *
165          * @return String
166          */
167         public function getComments() {
168                 return $this->xmlEncode( $this->Comments );
169         }
170
171         /**
172          * Quickie hack... strip out wikilinks to more legible form from the comment.
173          *
174          * @param $text String: wikitext
175          * @return String
176          */
177         public static function stripComment( $text ) {
178                 return preg_replace( '/\[\[([^]]*\|)?([^]]+)\]\]/', '\2', $text );
179         }
180         /**#@-*/
181 }
182
183 /**
184  * @todo document (needs one-sentence top-level class description).
185  * @ingroup Feed
186  */
187 class ChannelFeed extends FeedItem {
188         /**#@+
189          * Abstract function, override!
190          * @abstract
191          */
192
193         /**
194          * Generate Header of the feed
195          */
196         function outHeader() {
197                 # print "<feed>";
198         }
199
200         /**
201          * Generate an item
202          * @param $item
203          */
204         function outItem( $item ) {
205                 # print "<item>...</item>";
206         }
207
208         /**
209          * Generate Footer of the feed
210          */
211         function outFooter() {
212                 # print "</feed>";
213         }
214         /**#@-*/
215
216         /**
217          * Setup and send HTTP headers. Don't send any content;
218          * content might end up being cached and re-sent with
219          * these same headers later.
220          *
221          * This should be called from the outHeader() method,
222          * but can also be called separately.
223          */
224         public function httpHeaders() {
225                 global $wgOut;
226
227                 # We take over from $wgOut, excepting its cache header info
228                 $wgOut->disable();
229                 $mimetype = $this->contentType();
230                 header( "Content-type: $mimetype; charset=UTF-8" );
231                 $wgOut->sendCacheControl();
232
233         }
234
235         /**
236          * Return an internet media type to be sent in the headers.
237          *
238          * @return string
239          * @private
240          */
241         function contentType() {
242                 global $wgRequest;
243                 $ctype = $wgRequest->getVal('ctype','application/xml');
244                 $allowedctypes = array('application/xml','text/xml','application/rss+xml','application/atom+xml');
245                 return (in_array($ctype, $allowedctypes) ? $ctype : 'application/xml');
246         }
247
248         /**
249          * Output the initial XML headers with a stylesheet for legibility
250          * if someone finds it in a browser.
251          * @private
252          */
253         function outXmlHeader() {
254                 global $wgStylePath, $wgStyleVersion;
255
256                 $this->httpHeaders();
257                 echo '<?xml version="1.0"?>' . "\n";
258                 echo '<?xml-stylesheet type="text/css" href="' .
259                         htmlspecialchars( wfExpandUrl( "$wgStylePath/common/feed.css?$wgStyleVersion" ) ) .
260                         '"?' . ">\n";
261         }
262 }
263
264 /**
265  * Generate a RSS feed
266  *
267  * @ingroup Feed
268  */
269 class RSSFeed extends ChannelFeed {
270
271         /**
272          * Format a date given a timestamp
273          *
274          * @param $ts Integer: timestamp
275          * @return String: date string
276          */
277         function formatTime( $ts ) {
278                 return gmdate( 'D, d M Y H:i:s \G\M\T', wfTimestamp( TS_UNIX, $ts ) );
279         }
280
281         /**
282          * Ouput an RSS 2.0 header
283          */
284         function outHeader() {
285                 global $wgVersion;
286
287                 $this->outXmlHeader();
288                 ?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
289         <channel>
290                 <title><?php print $this->getTitle() ?></title>
291                 <link><?php print $this->getUrl() ?></link>
292                 <description><?php print $this->getDescription() ?></description>
293                 <language><?php print $this->getLanguage() ?></language>
294                 <generator>MediaWiki <?php print $wgVersion ?></generator>
295                 <lastBuildDate><?php print $this->formatTime( wfTimestampNow() ) ?></lastBuildDate>
296 <?php
297         }
298
299         /**
300          * Output an RSS 2.0 item
301          * @param $item FeedItem: item to be output
302          */
303         function outItem( $item ) {
304         ?>
305                 <item>
306                         <title><?php print $item->getTitle() ?></title>
307                         <link><?php print $item->getUrl() ?></link>
308                         <guid<?php if( !$item->RSSIsPermalink ) print ' isPermaLink="false"' ?>><?php print $item->getUniqueId() ?></guid>
309                         <description><?php print $item->getDescription() ?></description>
310                         <?php if( $item->getDate() ) { ?><pubDate><?php print $this->formatTime( $item->getDate() ) ?></pubDate><?php } ?>
311                         <?php if( $item->getAuthor() ) { ?><dc:creator><?php print $item->getAuthor() ?></dc:creator><?php }?>
312                         <?php if( $item->getComments() ) { ?><comments><?php print $item->getComments() ?></comments><?php }?>
313                 </item>
314 <?php
315         }
316
317         /**
318          * Ouput an RSS 2.0 footer
319          */
320         function outFooter() {
321         ?>
322         </channel>
323 </rss><?php
324         }
325 }
326
327 /**
328  * Generate an Atom feed
329  *
330  * @ingroup Feed
331  */
332 class AtomFeed extends ChannelFeed {
333         /**
334          * @todo document
335          */
336         function formatTime( $ts ) {
337                 // need to use RFC 822 time format at least for rss2.0
338                 return gmdate( 'Y-m-d\TH:i:s', wfTimestamp( TS_UNIX, $ts ) );
339         }
340
341         /**
342          * Outputs a basic header for Atom 1.0 feeds.
343          */
344         function outHeader() {
345                 global $wgVersion;
346
347                 $this->outXmlHeader();
348                 ?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="<?php print $this->getLanguage() ?>">
349                 <id><?php print $this->getFeedId() ?></id>
350                 <title><?php print $this->getTitle() ?></title>
351                 <link rel="self" type="application/atom+xml" href="<?php print $this->getSelfUrl() ?>"/>
352                 <link rel="alternate" type="text/html" href="<?php print $this->getUrl() ?>"/>
353                 <updated><?php print $this->formatTime( wfTimestampNow() ) ?>Z</updated>
354                 <subtitle><?php print $this->getDescription() ?></subtitle>
355                 <generator>MediaWiki <?php print $wgVersion ?></generator>
356
357 <?php
358         }
359
360         /**
361          * Atom 1.0 requires a unique, opaque IRI as a unique indentifier
362          * for every feed we create. For now just use the URL, but who
363          * can tell if that's right? If we put options on the feed, do we
364          * have to change the id? Maybe? Maybe not.
365          *
366          * @return string
367          * @private
368          */
369         function getFeedId() {
370                 return $this->getSelfUrl();
371         }
372
373         /**
374          * Atom 1.0 requests a self-reference to the feed.
375          * @return string
376          * @private
377          */
378         function getSelfUrl() {
379                 global $wgRequest;
380                 return htmlspecialchars( $wgRequest->getFullRequestURL() );
381         }
382
383         /**
384          * Output a given item.
385          * @param $item
386          */
387         function outItem( $item ) {
388                 global $wgMimeType;
389         ?>
390         <entry>
391                 <id><?php print $item->getUniqueId() ?></id>
392                 <title><?php print $item->getTitle() ?></title>
393                 <link rel="alternate" type="<?php print $wgMimeType ?>" href="<?php print $item->getUrl() ?>"/>
394                 <?php if( $item->getDate() ) { ?>
395                 <updated><?php print $this->formatTime( $item->getDate() ) ?>Z</updated>
396                 <?php } ?>
397
398                 <summary type="html"><?php print $item->getDescription() ?></summary>
399                 <?php if( $item->getAuthor() ) { ?><author><name><?php print $item->getAuthor() ?></name></author><?php }?>
400         </entry>
401
402 <?php /* FIXME need to add comments
403         <?php if( $item->getComments() ) { ?><dc:comment><?php print $item->getComments() ?></dc:comment><?php }?>
404       */
405         }
406
407         /**
408          * Outputs the footer for Atom 1.0 feed (basicly '\</feed\>').
409          */
410         function outFooter() {?>
411         </feed><?php
412         }
413 }