MediaWiki REL1_31
Feed.php
Go to the documentation of this file.
1<?php
38class FeedItem {
40 public $title;
41
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() {
169 return LanguageCode::bcp47( $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
234abstract class ChannelFeed extends FeedItem {
235
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
341class 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
412class 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}
$wgLanguageCode
Site language code.
$wgMimeType
The default Content-Type header.
$wgVersion
MediaWiki version number.
$wgVaryOnXFP
Add X-Forwarded-Proto to the Vary and Key headers for API requests and RSS/Atom feeds.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
$wgOut
Definition Setup.php:912
if(! $wgDBerrorLogTZ) $wgRequest
Definition Setup.php:737
Generate an Atom feed.
Definition Feed.php:412
outItem( $item)
Output a given item.
Definition Feed.php:472
outFooter()
Outputs the footer for Atom 1.0 feed (basically '</feed>').
Definition Feed.php:491
getFeedId()
Atom 1.0 requires a unique, opaque IRI as a unique identifier for every feed we create.
Definition Feed.php:455
formatTime( $timestamp)
Format a date given timestamp, if one is given.
Definition Feed.php:419
getSelfUrl()
Atom 1.0 requests a self-reference to the feed.
Definition Feed.php:463
outHeader()
Outputs a basic header for Atom 1.0 feeds.
Definition Feed.php:429
Class to support the outputting of syndication feeds in Atom and RSS format.
Definition Feed.php:234
outFooter()
Generate Footer of the feed.
TemplateParser $templateParser
Definition Feed.php:237
outHeader()
Generate Header of the feed.
__construct( $title, $description, $url, $date='', $author='', $comments='')
Definition Feed.php:247
contentType()
Return an internet media type to be sent in the headers.
Definition Feed.php:313
httpHeaders()
Setup and send HTTP headers.
Definition Feed.php:288
outItem( $item)
Generate an item.
outXmlHeader()
Output the initial XML headers.
Definition Feed.php:330
A base class for basic support for outputting syndication feeds in RSS and other formats.
Definition Feed.php:38
$description
Definition Feed.php:42
getLanguage()
Get the language of this item.
Definition Feed.php:167
setUniqueId( $uniqueId, $rssIsPermalink=false)
Set the unique id of an item.
Definition Feed.php:113
getDescription()
Get the description of this item; already xml-encoded.
Definition Feed.php:149
$rssIsPermalink
Definition Feed.php:54
getDescriptionUnescaped()
Get the description of this item without any escaping.
Definition Feed.php:158
getCommentsUnescaped()
Get the comment of this item without any escaping.
Definition Feed.php:213
getTitle()
Get the title of this item; already xml-encoded.
Definition Feed.php:123
getDate()
Get the date of this item.
Definition Feed.php:177
getUniqueIdUnescaped()
Get the unique id of this item, without any escaping.
Definition Feed.php:101
Title $title
Definition Feed.php:40
static stripComment( $text)
Quickie hack... strip out wikilinks to more legible form from the comment.
Definition Feed.php:223
$author
Definition Feed.php:48
$uniqueId
Definition Feed.php:50
getAuthor()
Get the author of this item; already xml-encoded.
Definition Feed.php:186
xmlEncode( $string)
Encode $string so that it can be safely embedded in a XML document.
Definition Feed.php:80
getComments()
Get the comment of this item; already xml-encoded.
Definition Feed.php:204
getAuthorUnescaped()
Get the author of this item without any escaping.
Definition Feed.php:195
$comments
Definition Feed.php:52
getUrlUnescaped()
Get the URL of this item without any escaping.
Definition Feed.php:140
__construct( $title, $description, $url, $date='', $author='', $comments='')
Definition Feed.php:64
getUniqueID()
Get the unique id of this item; already xml-encoded.
Definition Feed.php:90
getUrl()
Get the URL of this item; already xml-encoded.
Definition Feed.php:132
Generate a RSS feed.
Definition Feed.php:341
formatTime( $ts)
Format a date given a timestamp.
Definition Feed.php:349
outHeader()
Output an RSS 2.0 header.
Definition Feed.php:358
outItem( $item)
Output an RSS 2.0 item.
Definition Feed.php:379
outFooter()
Output an RSS 2.0 footer.
Definition Feed.php:402
Represents a title within MediaWiki.
Definition Title.php:39
when a variable name is used in a it is silently declared as a new local masking the global
Definition design.txt:95
while(( $__line=Maintenance::readconsole()) !==false) print
Definition eval.php:64
const PROTO_CURRENT
Definition Defines.php:232
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
title
if(!is_readable( $file)) $ext
Definition router.php:55