[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
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 <[email protected]> 9 * https://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 /** @var Title */ 40 public $title; 41 42 public $description; 43 44 public $url; 45 46 public $date; 47 48 public $author; 49 50 public $uniqueId; 51 52 public $comments; 53 54 public $rssIsPermalink = false; 55 56 /** 57 * Constructor 58 * 59 * @param string|Title $title Item's title 60 * @param string $description 61 * @param string $url URL uniquely designating the item. 62 * @param string $date Item's date 63 * @param string $author Author's user name 64 * @param string $comments 65 */ 66 function __construct( $title, $description, $url, $date = '', $author = '', $comments = '' ) { 67 $this->title = $title; 68 $this->description = $description; 69 $this->url = $url; 70 $this->uniqueId = $url; 71 $this->date = $date; 72 $this->author = $author; 73 $this->comments = $comments; 74 } 75 76 /** 77 * Encode $string so that it can be safely embedded in a XML document 78 * 79 * @param string $string String to encode 80 * @return string 81 */ 82 public function xmlEncode( $string ) { 83 $string = str_replace( "\r\n", "\n", $string ); 84 $string = preg_replace( '/[\x00-\x08\x0b\x0c\x0e-\x1f]/', '', $string ); 85 return htmlspecialchars( $string ); 86 } 87 88 /** 89 * Get the unique id of this item 90 * 91 * @return string 92 */ 93 public function getUniqueId() { 94 if ( $this->uniqueId ) { 95 return $this->xmlEncode( $this->uniqueId ); 96 } 97 } 98 99 /** 100 * Set the unique id of an item 101 * 102 * @param string $uniqueId Unique id for the item 103 * @param bool $rssIsPermalink Set to true if the guid (unique id) is a permalink (RSS feeds only) 104 */ 105 public function setUniqueId( $uniqueId, $rssIsPermalink = false ) { 106 $this->uniqueId = $uniqueId; 107 $this->rssIsPermalink = $rssIsPermalink; 108 } 109 110 /** 111 * Get the title of this item; already xml-encoded 112 * 113 * @return string 114 */ 115 public function getTitle() { 116 return $this->xmlEncode( $this->title ); 117 } 118 119 /** 120 * Get the URL of this item; already xml-encoded 121 * 122 * @return string 123 */ 124 public function getUrl() { 125 return $this->xmlEncode( $this->url ); 126 } 127 128 /** 129 * Get the description of this item; already xml-encoded 130 * 131 * @return string 132 */ 133 public function getDescription() { 134 return $this->xmlEncode( $this->description ); 135 } 136 137 /** 138 * Get the language of this item 139 * 140 * @return string 141 */ 142 public function getLanguage() { 143 global $wgLanguageCode; 144 return $wgLanguageCode; 145 } 146 147 /** 148 * Get the date of this item 149 * 150 * @return string 151 */ 152 public function getDate() { 153 return $this->date; 154 } 155 156 /** 157 * Get the author of this item; already xml-encoded 158 * 159 * @return string 160 */ 161 public function getAuthor() { 162 return $this->xmlEncode( $this->author ); 163 } 164 165 /** 166 * Get the comment of this item; already xml-encoded 167 * 168 * @return string 169 */ 170 public function getComments() { 171 return $this->xmlEncode( $this->comments ); 172 } 173 174 /** 175 * Quickie hack... strip out wikilinks to more legible form from the comment. 176 * 177 * @param string $text Wikitext 178 * @return string 179 */ 180 public static function stripComment( $text ) { 181 return preg_replace( '/\[\[([^]]*\|)?([^]]+)\]\]/', '\2', $text ); 182 } 183 /**#@-*/ 184 } 185 186 /** 187 * @todo document (needs one-sentence top-level class description). 188 * @ingroup Feed 189 */ 190 abstract class ChannelFeed extends FeedItem { 191 /** 192 * Generate Header of the feed 193 * @par Example: 194 * @code 195 * print "<feed>"; 196 * @endcode 197 */ 198 abstract public function outHeader(); 199 200 /** 201 * Generate an item 202 * @par Example: 203 * @code 204 * print "<item>...</item>"; 205 * @endcode 206 * @param FeedItem $item 207 */ 208 abstract public function outItem( $item ); 209 210 /** 211 * Generate Footer of the feed 212 * @par Example: 213 * @code 214 * print "</feed>"; 215 * @endcode 216 */ 217 abstract public function outFooter(); 218 219 /** 220 * Setup and send HTTP headers. Don't send any content; 221 * content might end up being cached and re-sent with 222 * these same headers later. 223 * 224 * This should be called from the outHeader() method, 225 * but can also be called separately. 226 */ 227 public function httpHeaders() { 228 global $wgOut, $wgVaryOnXFP; 229 230 # We take over from $wgOut, excepting its cache header info 231 $wgOut->disable(); 232 $mimetype = $this->contentType(); 233 header( "Content-type: $mimetype; charset=UTF-8" ); 234 if ( $wgVaryOnXFP ) { 235 $wgOut->addVaryHeader( 'X-Forwarded-Proto' ); 236 } 237 $wgOut->sendCacheControl(); 238 239 } 240 241 /** 242 * Return an internet media type to be sent in the headers. 243 * 244 * @return string 245 */ 246 private function contentType() { 247 global $wgRequest; 248 249 $ctype = $wgRequest->getVal( 'ctype', 'application/xml' ); 250 $allowedctypes = array( 251 'application/xml', 252 'text/xml', 253 'application/rss+xml', 254 'application/atom+xml' 255 ); 256 257 return ( in_array( $ctype, $allowedctypes ) ? $ctype : 'application/xml' ); 258 } 259 260 /** 261 * Output the initial XML headers. 262 */ 263 protected function outXmlHeader() { 264 $this->httpHeaders(); 265 echo '<?xml version="1.0"?>' . "\n"; 266 } 267 } 268 269 /** 270 * Generate a RSS feed 271 * 272 * @ingroup Feed 273 */ 274 class RSSFeed extends ChannelFeed { 275 276 /** 277 * Format a date given a timestamp 278 * 279 * @param int $ts Timestamp 280 * @return string Date string 281 */ 282 function formatTime( $ts ) { 283 return gmdate( 'D, d M Y H:i:s \G\M\T', wfTimestamp( TS_UNIX, $ts ) ); 284 } 285 286 /** 287 * Output an RSS 2.0 header 288 */ 289 function outHeader() { 290 global $wgVersion; 291 292 $this->outXmlHeader(); 293 ?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"> 294 <channel> 295 <title><?php print $this->getTitle() ?></title> 296 <link><?php print wfExpandUrl( $this->getUrl(), PROTO_CURRENT ) ?></link> 297 <description><?php print $this->getDescription() ?></description> 298 <language><?php print $this->getLanguage() ?></language> 299 <generator>MediaWiki <?php print $wgVersion ?></generator> 300 <lastBuildDate><?php print $this->formatTime( wfTimestampNow() ) ?></lastBuildDate> 301 <?php 302 } 303 304 /** 305 * Output an RSS 2.0 item 306 * @param FeedItem $item Item to be output 307 */ 308 function outItem( $item ) { 309 // @codingStandardsIgnoreStart Ignore long lines and formatting issues. 310 ?> 311 <item> 312 <title><?php print $item->getTitle(); ?></title> 313 <link><?php print wfExpandUrl( $item->getUrl(), PROTO_CURRENT ); ?></link> 314 <guid<?php if ( !$item->rssIsPermalink ) { print ' isPermaLink="false"'; } ?>><?php print $item->getUniqueId(); ?></guid> 315 <description><?php print $item->getDescription() ?></description> 316 <?php if ( $item->getDate() ) { ?><pubDate><?php print $this->formatTime( $item->getDate() ); ?></pubDate><?php } ?> 317 <?php if ( $item->getAuthor() ) { ?><dc:creator><?php print $item->getAuthor(); ?></dc:creator><?php }?> 318 <?php if ( $item->getComments() ) { ?><comments><?php print wfExpandUrl( $item->getComments(), PROTO_CURRENT ); ?></comments><?php }?> 319 </item> 320 <?php 321 // @codingStandardsIgnoreEnd 322 } 323 324 /** 325 * Output an RSS 2.0 footer 326 */ 327 function outFooter() { 328 ?> 329 </channel> 330 </rss><?php 331 } 332 } 333 334 /** 335 * Generate an Atom feed 336 * 337 * @ingroup Feed 338 */ 339 class AtomFeed extends ChannelFeed { 340 /** 341 * @todo document 342 * @param string|int $ts 343 * @return string 344 */ 345 function formatTime( $ts ) { 346 // need to use RFC 822 time format at least for rss2.0 347 return gmdate( 'Y-m-d\TH:i:s', wfTimestamp( TS_UNIX, $ts ) ); 348 } 349 350 /** 351 * Outputs a basic header for Atom 1.0 feeds. 352 */ 353 function outHeader() { 354 global $wgVersion; 355 356 $this->outXmlHeader(); 357 // @codingStandardsIgnoreStart Ignore long lines and formatting issues. 358 ?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="<?php print $this->getLanguage() ?>"> 359 <id><?php print $this->getFeedId() ?></id> 360 <title><?php print $this->getTitle() ?></title> 361 <link rel="self" type="application/atom+xml" href="<?php print wfExpandUrl( $this->getSelfUrl(), PROTO_CURRENT ) ?>"/> 362 <link rel="alternate" type="text/html" href="<?php print wfExpandUrl( $this->getUrl(), PROTO_CURRENT ) ?>"/> 363 <updated><?php print $this->formatTime( wfTimestampNow() ) ?>Z</updated> 364 <subtitle><?php print $this->getDescription() ?></subtitle> 365 <generator>MediaWiki <?php print $wgVersion ?></generator> 366 367 <?php 368 // @codingStandardsIgnoreEnd 369 } 370 371 /** 372 * Atom 1.0 requires a unique, opaque IRI as a unique identifier 373 * for every feed we create. For now just use the URL, but who 374 * can tell if that's right? If we put options on the feed, do we 375 * have to change the id? Maybe? Maybe not. 376 * 377 * @return string 378 */ 379 private function getFeedId() { 380 return $this->getSelfUrl(); 381 } 382 383 /** 384 * Atom 1.0 requests a self-reference to the feed. 385 * @return string 386 */ 387 private function getSelfUrl() { 388 global $wgRequest; 389 return htmlspecialchars( $wgRequest->getFullRequestURL() ); 390 } 391 392 /** 393 * Output a given item. 394 * @param FeedItem $item 395 */ 396 function outItem( $item ) { 397 global $wgMimeType; 398 // @codingStandardsIgnoreStart Ignore long lines and formatting issues. 399 ?> 400 <entry> 401 <id><?php print $item->getUniqueId(); ?></id> 402 <title><?php print $item->getTitle(); ?></title> 403 <link rel="alternate" type="<?php print $wgMimeType ?>" href="<?php print wfExpandUrl( $item->getUrl(), PROTO_CURRENT ); ?>"/> 404 <?php if ( $item->getDate() ) { ?> 405 <updated><?php print $this->formatTime( $item->getDate() ); ?>Z</updated> 406 <?php } ?> 407 408 <summary type="html"><?php print $item->getDescription() ?></summary> 409 <?php if ( $item->getAuthor() ) { ?><author><name><?php print $item->getAuthor(); ?></name></author><?php }?> 410 </entry> 411 412 <?php /* @todo FIXME: Need to add comments 413 <?php if( $item->getComments() ) { ?><dc:comment><?php print $item->getComments() ?></dc:comment><?php }?> 414 */ 415 } 416 417 /** 418 * Outputs the footer for Atom 1.0 feed (basically '\</feed\>'). 419 */ 420 function outFooter() {?> 421 </feed><?php 422 // @codingStandardsIgnoreEnd 423 } 424 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |