MediaWiki  REL1_31
Feed.php
Go to the documentation of this file.
1 <?php
38 class FeedItem {
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 
64  function __construct( $title, $description, $url, $date = '', $author = '', $comments = '' ) {
65  $this->title = $title;
66  $this->description = $description;
67  $this->url = $url;
68  $this->uniqueId = $url;
69  $this->date = $date;
70  $this->author = $author;
71  $this->comments = $comments;
72  }
73 
80  public function xmlEncode( $string ) {
81  $string = str_replace( "\r\n", "\n", $string );
82  $string = preg_replace( '/[\x00-\x08\x0b\x0c\x0e-\x1f]/', '', $string );
83  return htmlspecialchars( $string );
84  }
85 
90  public function getUniqueID() {
91  $id = $this->getUniqueIdUnescaped();
92  if ( $id ) {
93  return $this->xmlEncode( $id );
94  }
95  }
96 
101  public function getUniqueIdUnescaped() {
102  if ( $this->uniqueId ) {
103  return wfExpandUrl( $this->uniqueId, PROTO_CURRENT );
104  }
105  }
106 
113  public function setUniqueId( $uniqueId, $rssIsPermalink = false ) {
114  $this->uniqueId = $uniqueId;
115  $this->rssIsPermalink = $rssIsPermalink;
116  }
117 
123  public function getTitle() {
124  return $this->xmlEncode( $this->title );
125  }
126 
132  public function getUrl() {
133  return $this->xmlEncode( $this->url );
134  }
135 
140  public function getUrlUnescaped() {
141  return $this->url;
142  }
143 
149  public function getDescription() {
150  return $this->xmlEncode( $this->description );
151  }
152 
158  public function getDescriptionUnescaped() {
159  return $this->description;
160  }
161 
167  public function getLanguage() {
170  }
171 
177  public function getDate() {
178  return $this->date;
179  }
180 
186  public function getAuthor() {
187  return $this->xmlEncode( $this->author );
188  }
189 
195  public function getAuthorUnescaped() {
196  return $this->author;
197  }
198 
204  public function getComments() {
205  return $this->xmlEncode( $this->comments );
206  }
207 
213  public function getCommentsUnescaped() {
214  return $this->comments;
215  }
216 
223  public static function stripComment( $text ) {
224  return preg_replace( '/\[\[([^]]*\|)?([^]]+)\]\]/', '\2', $text );
225  }
227 }
228 
234 abstract class ChannelFeed extends FeedItem {
235 
237  protected $templateParser;
238 
247  function __construct( $title, $description, $url, $date = '', $author = '', $comments = '' ) {
248  parent::__construct( $title, $description, $url, $date, $author, $comments );
249  $this->templateParser = new TemplateParser();
250  }
251 
259  abstract public function outHeader();
260 
269  abstract public function outItem( $item );
270 
278  abstract public function outFooter();
279 
288  public function httpHeaders() {
290 
291  # We take over from $wgOut, excepting its cache header info
292  $wgOut->disable();
293  $mimetype = $this->contentType();
294  header( "Content-type: $mimetype; charset=UTF-8" );
295 
296  // Set a sane filename
297  $exts = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer()
298  ->getExtensionsForType( $mimetype );
299  $ext = $exts ? strtok( $exts, ' ' ) : 'xml';
300  header( "Content-Disposition: inline; filename=\"feed.{$ext}\"" );
301 
302  if ( $wgVaryOnXFP ) {
303  $wgOut->addVaryHeader( 'X-Forwarded-Proto' );
304  }
305  $wgOut->sendCacheControl();
306  }
307 
313  private function contentType() {
315 
316  $ctype = $wgRequest->getVal( 'ctype', 'application/xml' );
317  $allowedctypes = [
318  'application/xml',
319  'text/xml',
320  'application/rss+xml',
321  'application/atom+xml'
322  ];
323 
324  return ( in_array( $ctype, $allowedctypes ) ? $ctype : 'application/xml' );
325  }
326 
330  protected function outXmlHeader() {
331  $this->httpHeaders();
332  echo '<?xml version="1.0"?>' . "\n";
333  }
334 }
335 
341 class RSSFeed extends ChannelFeed {
342 
349  function formatTime( $ts ) {
350  if ( $ts ) {
351  return gmdate( 'D, d M Y H:i:s \G\M\T', wfTimestamp( TS_UNIX, $ts ) );
352  }
353  }
354 
358  function outHeader() {
360 
361  $this->outXmlHeader();
362  // Manually escaping rather than letting Mustache do it because Mustache
363  // uses htmlentities, which does not work with XML
364  $templateParams = [
365  'title' => $this->getTitle(),
366  'url' => $this->xmlEncode( wfExpandUrl( $this->getUrlUnescaped(), PROTO_CURRENT ) ),
367  'description' => $this->getDescription(),
368  'language' => $this->xmlEncode( $this->getLanguage() ),
369  'version' => $this->xmlEncode( $wgVersion ),
370  'timestamp' => $this->xmlEncode( $this->formatTime( wfTimestampNow() ) )
371  ];
372  print $this->templateParser->processTemplate( 'RSSHeader', $templateParams );
373  }
374 
379  function outItem( $item ) {
380  // Manually escaping rather than letting Mustache do it because Mustache
381  // uses htmlentities, which does not work with XML
382  $templateParams = [
383  "title" => $item->getTitle(),
384  "url" => $this->xmlEncode( wfExpandUrl( $item->getUrlUnescaped(), PROTO_CURRENT ) ),
385  "permalink" => $item->rssIsPermalink,
386  "uniqueID" => $item->getUniqueID(),
387  "description" => $item->getDescription(),
388  "date" => $this->xmlEncode( $this->formatTime( $item->getDate() ) ),
389  "author" => $item->getAuthor()
390  ];
391  $comments = $item->getCommentsUnescaped();
392  if ( $comments ) {
393  $commentsEscaped = $this->xmlEncode( wfExpandUrl( $comments, PROTO_CURRENT ) );
394  $templateParams["comments"] = $commentsEscaped;
395  }
396  print $this->templateParser->processTemplate( 'RSSItem', $templateParams );
397  }
398 
402  function outFooter() {
403  print "</channel></rss>";
404  }
405 }
406 
412 class AtomFeed extends ChannelFeed {
419  function formatTime( $timestamp ) {
420  if ( $timestamp ) {
421  // need to use RFC 822 time format at least for rss2.0
422  return gmdate( 'Y-m-d\TH:i:s', wfTimestamp( TS_UNIX, $timestamp ) );
423  }
424  }
425 
429  function outHeader() {
431  $this->outXmlHeader();
432  // Manually escaping rather than letting Mustache do it because Mustache
433  // uses htmlentities, which does not work with XML
434  $templateParams = [
435  'language' => $this->xmlEncode( $this->getLanguage() ),
436  'feedID' => $this->getFeedId(),
437  'title' => $this->getTitle(),
438  'url' => $this->xmlEncode( wfExpandUrl( $this->getUrlUnescaped(), PROTO_CURRENT ) ),
439  'selfUrl' => $this->getSelfUrl(),
440  'timestamp' => $this->xmlEncode( $this->formatTime( wfTimestampNow() ) ),
441  'description' => $this->getDescription(),
442  'version' => $this->xmlEncode( $wgVersion ),
443  ];
444  print $this->templateParser->processTemplate( 'AtomHeader', $templateParams );
445  }
446 
455  private function getFeedId() {
456  return $this->getSelfUrl();
457  }
458 
463  private function getSelfUrl() {
465  return htmlspecialchars( $wgRequest->getFullRequestURL() );
466  }
467 
472  function outItem( $item ) {
474  // Manually escaping rather than letting Mustache do it because Mustache
475  // uses htmlentities, which does not work with XML
476  $templateParams = [
477  "uniqueID" => $item->getUniqueID(),
478  "title" => $item->getTitle(),
479  "mimeType" => $this->xmlEncode( $wgMimeType ),
480  "url" => $this->xmlEncode( wfExpandUrl( $item->getUrlUnescaped(), PROTO_CURRENT ) ),
481  "date" => $this->xmlEncode( $this->formatTime( $item->getDate() ) ),
482  "description" => $item->getDescription(),
483  "author" => $item->getAuthor()
484  ];
485  print $this->templateParser->processTemplate( 'AtomItem', $templateParams );
486  }
487 
491  function outFooter() {
492  print "</feed>";
493  }
494 }
ChannelFeed\contentType
contentType()
Return an internet media type to be sent in the headers.
Definition: Feed.php:313
RSSFeed\outFooter
outFooter()
Output an RSS 2.0 footer.
Definition: Feed.php:402
RSSFeed\outItem
outItem( $item)
Output an RSS 2.0 item.
Definition: Feed.php:379
FeedItem
A base class for basic support for outputting syndication feeds in RSS and other formats.
Definition: Feed.php:38
ChannelFeed\outItem
outItem( $item)
Generate an item.
FeedItem\$url
$url
Definition: Feed.php:44
AtomFeed\getFeedId
getFeedId()
Atom 1.0 requires a unique, opaque IRI as a unique identifier for every feed we create.
Definition: Feed.php:455
AtomFeed\outHeader
outHeader()
Outputs a basic header for Atom 1.0 feeds.
Definition: Feed.php:429
FeedItem\$description
$description
Definition: Feed.php:42
$wgMimeType
$wgMimeType
The default Content-Type header.
Definition: DefaultSettings.php:3180
FeedItem\$rssIsPermalink
$rssIsPermalink
Definition: Feed.php:54
ChannelFeed\__construct
__construct( $title, $description, $url, $date='', $author='', $comments='')
Definition: Feed.php:247
ChannelFeed\httpHeaders
httpHeaders()
Setup and send HTTP headers.
Definition: Feed.php:288
RSSFeed\outHeader
outHeader()
Output an RSS 2.0 header.
Definition: Feed.php:358
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1980
ChannelFeed\outXmlHeader
outXmlHeader()
Output the initial XML headers.
Definition: Feed.php:330
$wgVersion
$wgVersion
MediaWiki version number.
Definition: DefaultSettings.php:75
AtomFeed
Generate an Atom feed.
Definition: Feed.php:412
FeedItem\getDescriptionUnescaped
getDescriptionUnescaped()
Get the description of this item without any escaping.
Definition: Feed.php:158
AtomFeed\outFooter
outFooter()
Outputs the footer for Atom 1.0 feed (basically '</feed>').
Definition: Feed.php:491
FeedItem\getLanguage
getLanguage()
Get the language of this item.
Definition: Feed.php:167
FeedItem\stripComment
static stripComment( $text)
Quickie hack...
Definition: Feed.php:223
FeedItem\getTitle
getTitle()
Get the title of this item; already xml-encoded.
Definition: Feed.php:123
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:37
FeedItem\getAuthor
getAuthor()
Get the author of this item; already xml-encoded.
Definition: Feed.php:186
ChannelFeed\$templateParser
TemplateParser $templateParser
Definition: Feed.php:237
title
title
Definition: parserTests.txt:219
PROTO_CURRENT
const PROTO_CURRENT
Definition: Defines.php:232
FeedItem\$date
$date
Definition: Feed.php:46
FeedItem\getDate
getDate()
Get the date of this item.
Definition: Feed.php:177
$wgVaryOnXFP
$wgVaryOnXFP
Add X-Forwarded-Proto to the Vary and Key headers for API requests and RSS/Atom feeds.
Definition: DefaultSettings.php:2703
FeedItem\getAuthorUnescaped
getAuthorUnescaped()
Get the author of this item without any escaping.
Definition: Feed.php:195
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:95
AtomFeed\getSelfUrl
getSelfUrl()
Atom 1.0 requests a self-reference to the feed.
Definition: Feed.php:463
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:2009
AtomFeed\formatTime
formatTime( $timestamp)
Format a date given timestamp, if one is given.
Definition: Feed.php:419
FeedItem\getCommentsUnescaped
getCommentsUnescaped()
Get the comment of this item without any escaping.
Definition: Feed.php:213
MediaWiki\MediaWikiServices\getInstance
static getInstance()
Returns the global default instance of the top level service locator.
Definition: MediaWikiServices.php:109
FeedItem\setUniqueId
setUniqueId( $uniqueId, $rssIsPermalink=false)
Set the unique id of an item.
Definition: Feed.php:113
FeedItem\getDescription
getDescription()
Get the description of this item; already xml-encoded.
Definition: Feed.php:149
FeedItem\getUniqueIdUnescaped
getUniqueIdUnescaped()
Get the unique id of this item, without any escaping.
Definition: Feed.php:101
FeedItem\getUrl
getUrl()
Get the URL of this item; already xml-encoded.
Definition: Feed.php:132
$wgLanguageCode
$wgLanguageCode
Site language code.
Definition: DefaultSettings.php:2887
FeedItem\$comments
$comments
Definition: Feed.php:52
FeedItem\__construct
__construct( $title, $description, $url, $date='', $author='', $comments='')
Definition: Feed.php:64
print
print
Definition: opensearch_desc.php:46
Title
Represents a title within MediaWiki.
Definition: Title.php:39
ChannelFeed
Class to support the outputting of syndication feeds in Atom and RSS format.
Definition: Feed.php:234
ChannelFeed\outFooter
outFooter()
Generate Footer of the feed.
FeedItem\xmlEncode
xmlEncode( $string)
Encode $string so that it can be safely embedded in a XML document.
Definition: Feed.php:80
LanguageCode\bcp47
static bcp47( $code)
Get the normalised IETF language tag See unit test for examples.
Definition: LanguageCode.php:94
RSSFeed\formatTime
formatTime( $ts)
Format a date given a timestamp.
Definition: Feed.php:349
ChannelFeed\outHeader
outHeader()
Generate Header of the feed.
FeedItem\$author
$author
Definition: Feed.php:48
$wgRequest
if(! $wgDBerrorLogTZ) $wgRequest
Definition: Setup.php:737
FeedItem\$title
Title $title
Definition: Feed.php:40
FeedItem\getComments
getComments()
Get the comment of this item; already xml-encoded.
Definition: Feed.php:204
$wgOut
$wgOut
Definition: Setup.php:912
RSSFeed
Generate a RSS feed.
Definition: Feed.php:341
AtomFeed\outItem
outItem( $item)
Output a given item.
Definition: Feed.php:472
$ext
$ext
Definition: router.php:55
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:521
FeedItem\getUrlUnescaped
getUrlUnescaped()
Get the URL of this item without any escaping.
Definition: Feed.php:140
FeedItem\getUniqueID
getUniqueID()
Get the unique id of this item; already xml-encoded.
Definition: Feed.php:90
FeedItem\$uniqueId
$uniqueId
Definition: Feed.php:50