MediaWiki  master
FeedUtils.php
Go to the documentation of this file.
1 <?php
28 
34 class FeedUtils {
35 
45  public static function checkFeedOutput( $type, $output = null ) {
46  $feed = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::Feed );
47  $feedClasses = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::FeedClasses );
48  if ( $output === null ) {
49  // Todo update GoogleNewsSitemap and deprecate
50  global $wgOut;
51  $output = $wgOut;
52  }
53 
54  if ( !$feed ) {
55  $output->addWikiMsg( 'feed-unavailable' );
56  return false;
57  }
58 
59  if ( !isset( $feedClasses[$type] ) ) {
60  $output->addWikiMsg( 'feed-invalid' );
61  return false;
62  }
63 
64  return true;
65  }
66 
76  public static function formatDiff( $row, $formattedComment = null ) {
77  $titleObj = Title::makeTitle( $row->rc_namespace, $row->rc_title );
78  $timestamp = wfTimestamp( TS_MW, $row->rc_timestamp );
79  $actiontext = '';
80  if ( $row->rc_type == RC_LOG ) {
81  $rcRow = (array)$row; // newFromRow() only accepts arrays for RC rows
82  $actiontext = LogFormatter::newFromRow( $rcRow )->getActionText();
83  }
84  if ( $row->rc_deleted & RevisionRecord::DELETED_COMMENT ) {
85  $formattedComment = wfMessage( 'rev-deleted-comment' )->escaped();
86  } elseif ( $formattedComment === null ) {
87  $formattedComment = Linker::formatComment(
88  CommentStore::getStore()->getComment( 'rc_comment', $row )->text );
89  }
90  return self::formatDiffRow2( $titleObj,
91  $row->rc_last_oldid, $row->rc_this_oldid,
92  $timestamp,
93  $formattedComment,
94  $actiontext
95  );
96  }
97 
111  public static function formatDiffRow( $title, $oldid, $newid, $timestamp,
112  $comment, $actiontext = ''
113  ) {
114  $formattedComment = MediaWikiServices::getInstance()->getCommentFormatter()
115  ->format( $comment );
116  return self::formatDiffRow2( $title, $oldid, $newid, $timestamp,
117  $formattedComment, $actiontext );
118  }
119 
132  public static function formatDiffRow2( $title, $oldid, $newid, $timestamp,
133  $formattedComment, $actiontext = ''
134  ) {
135  $feedDiffCutoff = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::FeedDiffCutoff );
136 
137  // log entries
138  $unwrappedText = implode(
139  ' ',
140  array_filter( [ $actiontext, $formattedComment ] )
141  );
142  $completeText = Html::rawElement( 'p', [], $unwrappedText ) . "\n";
143 
144  // NOTE: Check permissions for anonymous users, not current user.
145  // No "privileged" version should end up in the cache.
146  // Most feed readers will not log in anyway.
147  $anon = new User();
148  $services = MediaWikiServices::getInstance();
149  $permManager = $services->getPermissionManager();
150  $accErrors = $permManager->getPermissionErrors(
151  'read',
152  $anon,
153  $title
154  );
155 
156  // Can't diff special pages, unreadable pages or pages with no new revision
157  // to compare against: just return the text.
158  if ( $title->getNamespace() < 0 || $accErrors || !$newid ) {
159  return $completeText;
160  }
161 
162  $revLookup = $services->getRevisionLookup();
163  $contentHandlerFactory = $services->getContentHandlerFactory();
164  if ( $oldid ) {
165  $diffText = '';
166  // Don't bother generating the diff if we won't be able to show it
167  if ( $feedDiffCutoff > 0 ) {
168  $revRecord = $revLookup->getRevisionById( $oldid );
169 
170  if ( !$revRecord ) {
171  $diffText = false;
172  } else {
173  $mainContext = RequestContext::getMain();
174  $context = clone RequestContext::getMain();
175  $context->setTitle( $title );
176 
177  $model = $revRecord->getSlot(
178  SlotRecord::MAIN,
179  RevisionRecord::RAW
180  )->getModel();
181  $contentHandler = $contentHandlerFactory->getContentHandler( $model );
182  $de = $contentHandler->createDifferenceEngine( $context, $oldid, $newid );
183  $lang = $mainContext->getLanguage();
184  $user = $mainContext->getUser();
185  $diffText = $de->getDiff(
186  $mainContext->msg( 'previousrevision' )->text(), // hack
187  $mainContext->msg( 'revisionasof',
188  $lang->userTimeAndDate( $timestamp, $user ),
189  $lang->userDate( $timestamp, $user ),
190  $lang->userTime( $timestamp, $user ) )->text() );
191  }
192  }
193 
194  if ( $feedDiffCutoff <= 0 || ( strlen( $diffText ) > $feedDiffCutoff ) ) {
195  // Omit large diffs
196  $diffText = self::getDiffLink( $title, $newid, $oldid );
197  } elseif ( $diffText === false ) {
198  // Error in diff engine, probably a missing revision
199  $diffText = Html::rawElement(
200  'p',
201  [],
202  "Can't load revision $newid"
203  );
204  } else {
205  // Diff output fine, clean up any illegal UTF-8
206  $diffText = UtfNormal\Validator::cleanUp( $diffText );
207  $diffText = self::applyDiffStyle( $diffText );
208  }
209  } else {
210  $revRecord = $revLookup->getRevisionById( $newid );
211  if ( $feedDiffCutoff <= 0 || $revRecord === null ) {
212  $newContent = $contentHandlerFactory
213  ->getContentHandler( $title->getContentModel() )
214  ->makeEmptyContent();
215  } else {
216  $newContent = $revRecord->getContent( SlotRecord::MAIN );
217  }
218 
219  if ( $newContent instanceof TextContent ) {
220  // only textual content has a "source view".
221  $text = $newContent->getText();
222 
223  if ( $feedDiffCutoff <= 0 || strlen( $text ) > $feedDiffCutoff ) {
224  $html = null;
225  } else {
226  $html = nl2br( htmlspecialchars( $text ) );
227  }
228  } else {
229  // XXX: we could get an HTML representation of the content via getParserOutput, but that may
230  // contain JS magic and generally may not be suitable for inclusion in a feed.
231  // Perhaps Content should have a getDescriptiveHtml method and/or a getSourceText method.
232  // Compare also ApiFeedContributions::feedItemDesc
233  $html = null;
234  }
235 
236  if ( $html === null ) {
237  // Omit large new page diffs, T31110
238  // Also use diff link for non-textual content
239  $diffText = self::getDiffLink( $title, $newid );
240  } else {
241  $diffText = Html::rawElement(
242  'p',
243  [],
244  Html::rawElement( 'b', [], wfMessage( 'newpage' )->text() )
245  );
246  $diffText .= Html::rawElement( 'div', [], $html );
247  }
248  }
249  $completeText .= $diffText;
250 
251  return $completeText;
252  }
253 
263  protected static function getDiffLink( Title $title, $newid, $oldid = null ) {
264  $queryParameters = [ 'diff' => $newid ];
265  if ( $oldid != null ) {
266  $queryParameters['oldid'] = $oldid;
267  }
268  $diffUrl = $title->getFullURL( $queryParameters );
269 
270  $diffLink = Html::element( 'a', [ 'href' => $diffUrl ],
271  wfMessage( 'showdiff' )->inContentLanguage()->text() );
272 
273  return $diffLink;
274  }
275 
284  public static function applyDiffStyle( $text ) {
285  $styles = [
286  'diff' => 'background-color: #fff; color: #202122;',
287  'diff-otitle' => 'background-color: #fff; color: #202122; text-align: center;',
288  'diff-ntitle' => 'background-color: #fff; color: #202122; text-align: center;',
289  'diff-addedline' => 'color: #202122; font-size: 88%; border-style: solid; '
290  . 'border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; '
291  . 'vertical-align: top; white-space: pre-wrap;',
292  'diff-deletedline' => 'color: #202122; font-size: 88%; border-style: solid; '
293  . 'border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; '
294  . 'vertical-align: top; white-space: pre-wrap;',
295  'diff-context' => 'background-color: #f8f9fa; color: #202122; font-size: 88%; '
296  . 'border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; '
297  . 'border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;',
298  'diffchange' => 'font-weight: bold; text-decoration: none;',
299  ];
300 
301  foreach ( $styles as $class => $style ) {
302  $text = preg_replace( '/(<\w+\b[^<>]*)\bclass=([\'"])(?:[^\'"]*\s)?' .
303  preg_quote( $class ) . '(?:\s[^\'"]*)?\2(?=[^<>]*>)/',
304  '$1style="' . $style . '"', $text );
305  }
306 
307  return $text;
308  }
309 
310 }
const RC_LOG
Definition: Defines.php:117
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined( 'MW_NO_SESSION') &&! $wgCommandLineMode) $wgOut
Definition: Setup.php:485
static getStore()
Helper functions for feeds.
Definition: FeedUtils.php:34
static formatDiffRow( $title, $oldid, $newid, $timestamp, $comment, $actiontext='')
Really format a diff for the newsfeed.
Definition: FeedUtils.php:111
static formatDiffRow2( $title, $oldid, $newid, $timestamp, $formattedComment, $actiontext='')
Really really format a diff for the newsfeed.
Definition: FeedUtils.php:132
static formatDiff( $row, $formattedComment=null)
Format a diff for the newsfeed.
Definition: FeedUtils.php:76
static applyDiffStyle( $text)
Hacky application of diff styles for the feeds.
Definition: FeedUtils.php:284
static getDiffLink(Title $title, $newid, $oldid=null)
Generates a diff link.
Definition: FeedUtils.php:263
static checkFeedOutput( $type, $output=null)
Check whether feeds can be used and that $type is a valid feed type.
Definition: FeedUtils.php:45
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:236
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:214
static formatComment( $comment, $title=null, $local=false, $wikiId=null)
This function is called by all recent changes variants, by the page history, and by the user contribu...
Definition: Linker.php:1424
static newFromRow( $row)
Handy shortcut for constructing a formatter directly from database row.
A class containing constants representing the names of configuration variables.
MediaWikiServices is the service locator for the application scope of MediaWiki.
Page revision base class.
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:40
static getMain()
Get the RequestContext object associated with the main request.
Content object implementation for representing flat text.
Definition: TextContent.php:40
Represents a title within MediaWiki.
Definition: Title.php:48
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:637
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:68
if(!isset( $args[0])) $lang