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