MediaWiki  1.33.0
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() {
168  global $wgLanguageCode;
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() {
289  global $wgOut, $wgVaryOnXFP;
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() {
314  global $wgRequest;
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() {
359  global $wgVersion;
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() {
430  global $wgVersion;
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() {
464  global $wgRequest;
465  return htmlspecialchars( $wgRequest->getFullRequestURL() );
466  }
467 
472  function outItem( $item ) {
473  global $wgMimeType;
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 }
FeedItem
A base class for basic support for outputting syndication feeds in RSS and other formats.
Definition: Feed.php:38
FeedItem\$url
$url
Definition: Feed.php:44
FeedItem\$description
$description
Definition: Feed.php:42
$wgMimeType
$wgMimeType
The default Content-Type header.
Definition: DefaultSettings.php:3207
FeedItem\$rssIsPermalink
$rssIsPermalink
Definition: Feed.php:54
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1912
$wgVersion
$wgVersion
MediaWiki version number.
Definition: DefaultSettings.php:75
FeedItem\getDescriptionUnescaped
getDescriptionUnescaped()
Get the description of this item without any escaping.
Definition: Feed.php:158
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:35
FeedItem\getAuthor
getAuthor()
Get the author of this item; already xml-encoded.
Definition: Feed.php:186
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:925
PROTO_CURRENT
const PROTO_CURRENT
Definition: Defines.php:222
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:2732
FeedItem\getAuthorUnescaped
getAuthorUnescaped()
Get the author of this item without any escaping.
Definition: Feed.php:195
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:1941
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:124
FeedItem\setUniqueId
setUniqueId( $uniqueId, $rssIsPermalink=false)
Set the unique id of an item.
Definition: Feed.php:113
$templateParser
$templateParser
Definition: NoLocalSettings.php:47
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
title
title
Definition: parserTests.txt:245
FeedItem\getUrl
getUrl()
Get the URL of this item; already xml-encoded.
Definition: Feed.php:132
$wgLanguageCode
$wgLanguageCode
Site language code.
Definition: DefaultSettings.php:2912
FeedItem\$comments
$comments
Definition: Feed.php:52
FeedItem\__construct
__construct( $title, $description, $url, $date='', $author='', $comments='')
Definition: Feed.php:64
Title
Represents a title within MediaWiki.
Definition: Title.php:40
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:179
$ext
if(!is_readable( $file)) $ext
Definition: router.php:48
FeedItem\$author
$author
Definition: Feed.php:48
$wgRequest
if(! $wgDBerrorLogTZ) $wgRequest
Definition: Setup.php:728
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:880
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:515
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