MediaWiki  1.29.1
DifferenceEngine.php
Go to the documentation of this file.
1 <?php
24 
26 define( 'MW_DIFF_VERSION', '1.11a' );
27 
40 
42  public $mOldid;
43 
45  public $mNewid;
46 
47  private $mOldTags;
48  private $mNewTags;
49 
51  public $mOldContent;
52 
54  public $mNewContent;
55 
57  protected $mDiffLang;
58 
60  public $mOldPage;
61 
63  public $mNewPage;
64 
66  public $mOldRev;
67 
69  public $mNewRev;
70 
72  private $mRevisionsIdsLoaded = false;
73 
75  public $mRevisionsLoaded = false;
76 
78  public $mTextLoaded = 0;
79 
81  public $mCacheHit = false;
82 
88  public $enableDebugComment = false;
89 
93  protected $mReducedLineNumbers = false;
94 
96  protected $mMarkPatrolledLink = null;
97 
99  protected $unhide = false;
100 
102  protected $mRefreshCache = false;
103 
115  public function __construct( $context = null, $old = 0, $new = 0, $rcid = 0,
116  $refreshCache = false, $unhide = false
117  ) {
118  if ( $context instanceof IContextSource ) {
119  $this->setContext( $context );
120  }
121 
122  wfDebug( "DifferenceEngine old '$old' new '$new' rcid '$rcid'\n" );
123 
124  $this->mOldid = $old;
125  $this->mNewid = $new;
126  $this->mRefreshCache = $refreshCache;
127  $this->unhide = $unhide;
128  }
129 
133  public function setReducedLineNumbers( $value = true ) {
134  $this->mReducedLineNumbers = $value;
135  }
136 
140  public function getDiffLang() {
141  if ( $this->mDiffLang === null ) {
142  # Default language in which the diff text is written.
143  $this->mDiffLang = $this->getTitle()->getPageLanguage();
144  }
145 
146  return $this->mDiffLang;
147  }
148 
152  public function wasCacheHit() {
153  return $this->mCacheHit;
154  }
155 
159  public function getOldid() {
160  $this->loadRevisionIds();
161 
162  return $this->mOldid;
163  }
164 
168  public function getNewid() {
169  $this->loadRevisionIds();
170 
171  return $this->mNewid;
172  }
173 
182  public function deletedLink( $id ) {
183  if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) {
184  $dbr = wfGetDB( DB_REPLICA );
185  $row = $dbr->selectRow( 'archive', '*',
186  [ 'ar_rev_id' => $id ],
187  __METHOD__ );
188  if ( $row ) {
190  $title = Title::makeTitleSafe( $row->ar_namespace, $row->ar_title );
191 
192  return SpecialPage::getTitleFor( 'Undelete' )->getFullURL( [
193  'target' => $title->getPrefixedText(),
194  'timestamp' => $rev->getTimestamp()
195  ] );
196  }
197  }
198 
199  return false;
200  }
201 
209  public function deletedIdMarker( $id ) {
210  $link = $this->deletedLink( $id );
211  if ( $link ) {
212  return "[$link $id]";
213  } else {
214  return (string)$id;
215  }
216  }
217 
218  private function showMissingRevision() {
219  $out = $this->getOutput();
220 
221  $missing = [];
222  if ( $this->mOldRev === null ||
223  ( $this->mOldRev && $this->mOldContent === null )
224  ) {
225  $missing[] = $this->deletedIdMarker( $this->mOldid );
226  }
227  if ( $this->mNewRev === null ||
228  ( $this->mNewRev && $this->mNewContent === null )
229  ) {
230  $missing[] = $this->deletedIdMarker( $this->mNewid );
231  }
232 
233  $out->setPageTitle( $this->msg( 'errorpagetitle' ) );
234  $msg = $this->msg( 'difference-missing-revision' )
235  ->params( $this->getLanguage()->listToText( $missing ) )
236  ->numParams( count( $missing ) )
237  ->parseAsBlock();
238  $out->addHTML( $msg );
239  }
240 
241  public function showDiffPage( $diffOnly = false ) {
242  # Allow frames except in certain special cases
243  $out = $this->getOutput();
244  $out->allowClickjacking();
245  $out->setRobotPolicy( 'noindex,nofollow' );
246 
247  // Allow extensions to add any extra output here
248  Hooks::run( 'DifferenceEngineShowDiffPage', [ $out ] );
249 
250  if ( !$this->loadRevisionData() ) {
251  if ( Hooks::run( 'DifferenceEngineShowDiffPageMaybeShowMissingRevision', [ $this ] ) ) {
252  $this->showMissingRevision();
253  }
254  return;
255  }
256 
257  $user = $this->getUser();
258  $permErrors = $this->mNewPage->getUserPermissionsErrors( 'read', $user );
259  if ( $this->mOldPage ) { # mOldPage might not be set, see below.
260  $permErrors = wfMergeErrorArrays( $permErrors,
261  $this->mOldPage->getUserPermissionsErrors( 'read', $user ) );
262  }
263  if ( count( $permErrors ) ) {
264  throw new PermissionsError( 'read', $permErrors );
265  }
266 
267  $rollback = '';
268 
269  $query = [];
270  # Carry over 'diffonly' param via navigation links
271  if ( $diffOnly != $user->getBoolOption( 'diffonly' ) ) {
272  $query['diffonly'] = $diffOnly;
273  }
274  # Cascade unhide param in links for easy deletion browsing
275  if ( $this->unhide ) {
276  $query['unhide'] = 1;
277  }
278 
279  # Check if one of the revisions is deleted/suppressed
280  $deleted = $suppressed = false;
281  $allowed = $this->mNewRev->userCan( Revision::DELETED_TEXT, $user );
282 
283  $revisionTools = [];
284 
285  # mOldRev is false if the difference engine is called with a "vague" query for
286  # a diff between a version V and its previous version V' AND the version V
287  # is the first version of that article. In that case, V' does not exist.
288  if ( $this->mOldRev === false ) {
289  $out->setPageTitle( $this->msg( 'difference-title', $this->mNewPage->getPrefixedText() ) );
290  $samePage = true;
291  $oldHeader = '';
292  // Allow extensions to change the $oldHeader variable
293  Hooks::run( 'DifferenceEngineOldHeaderNoOldRev', [ &$oldHeader ] );
294  } else {
295  Hooks::run( 'DiffViewHeader', [ $this, $this->mOldRev, $this->mNewRev ] );
296 
297  if ( $this->mNewPage->equals( $this->mOldPage ) ) {
298  $out->setPageTitle( $this->msg( 'difference-title', $this->mNewPage->getPrefixedText() ) );
299  $samePage = true;
300  } else {
301  $out->setPageTitle( $this->msg( 'difference-title-multipage',
302  $this->mOldPage->getPrefixedText(), $this->mNewPage->getPrefixedText() ) );
303  $out->addSubtitle( $this->msg( 'difference-multipage' ) );
304  $samePage = false;
305  }
306 
307  if ( $samePage && $this->mNewPage->quickUserCan( 'edit', $user ) ) {
308  if ( $this->mNewRev->isCurrent() && $this->mNewPage->userCan( 'rollback', $user ) ) {
309  $rollbackLink = Linker::generateRollback( $this->mNewRev, $this->getContext() );
310  if ( $rollbackLink ) {
311  $out->preventClickjacking();
312  $rollback = '&#160;&#160;&#160;' . $rollbackLink;
313  }
314  }
315 
316  if ( !$this->mOldRev->isDeleted( Revision::DELETED_TEXT ) &&
317  !$this->mNewRev->isDeleted( Revision::DELETED_TEXT )
318  ) {
319  $undoLink = Html::element( 'a', [
320  'href' => $this->mNewPage->getLocalURL( [
321  'action' => 'edit',
322  'undoafter' => $this->mOldid,
323  'undo' => $this->mNewid
324  ] ),
325  'title' => Linker::titleAttrib( 'undo' ),
326  ],
327  $this->msg( 'editundo' )->text()
328  );
329  $revisionTools['mw-diff-undo'] = $undoLink;
330  }
331  }
332 
333  # Make "previous revision link"
334  if ( $samePage && $this->mOldRev->getPrevious() ) {
335  $prevlink = Linker::linkKnown(
336  $this->mOldPage,
337  $this->msg( 'previousdiff' )->escaped(),
338  [ 'id' => 'differences-prevlink' ],
339  [ 'diff' => 'prev', 'oldid' => $this->mOldid ] + $query
340  );
341  } else {
342  $prevlink = '&#160;';
343  }
344 
345  if ( $this->mOldRev->isMinor() ) {
346  $oldminor = ChangesList::flag( 'minor' );
347  } else {
348  $oldminor = '';
349  }
350 
351  $ldel = $this->revisionDeleteLink( $this->mOldRev );
352  $oldRevisionHeader = $this->getRevisionHeader( $this->mOldRev, 'complete' );
353  $oldChangeTags = ChangeTags::formatSummaryRow( $this->mOldTags, 'diff', $this->getContext() );
354 
355  $oldHeader = '<div id="mw-diff-otitle1"><strong>' . $oldRevisionHeader . '</strong></div>' .
356  '<div id="mw-diff-otitle2">' .
357  Linker::revUserTools( $this->mOldRev, !$this->unhide ) . '</div>' .
358  '<div id="mw-diff-otitle3">' . $oldminor .
359  Linker::revComment( $this->mOldRev, !$diffOnly, !$this->unhide ) . $ldel . '</div>' .
360  '<div id="mw-diff-otitle5">' . $oldChangeTags[0] . '</div>' .
361  '<div id="mw-diff-otitle4">' . $prevlink . '</div>';
362 
363  // Allow extensions to change the $oldHeader variable
364  Hooks::run( 'DifferenceEngineOldHeader', [ $this, &$oldHeader, $prevlink, $oldminor,
365  $diffOnly, $ldel, $this->unhide ] );
366 
367  if ( $this->mOldRev->isDeleted( Revision::DELETED_TEXT ) ) {
368  $deleted = true; // old revisions text is hidden
369  if ( $this->mOldRev->isDeleted( Revision::DELETED_RESTRICTED ) ) {
370  $suppressed = true; // also suppressed
371  }
372  }
373 
374  # Check if this user can see the revisions
375  if ( !$this->mOldRev->userCan( Revision::DELETED_TEXT, $user ) ) {
376  $allowed = false;
377  }
378  }
379 
380  # Make "next revision link"
381  # Skip next link on the top revision
382  if ( $samePage && !$this->mNewRev->isCurrent() ) {
383  $nextlink = Linker::linkKnown(
384  $this->mNewPage,
385  $this->msg( 'nextdiff' )->escaped(),
386  [ 'id' => 'differences-nextlink' ],
387  [ 'diff' => 'next', 'oldid' => $this->mNewid ] + $query
388  );
389  } else {
390  $nextlink = '&#160;';
391  }
392 
393  if ( $this->mNewRev->isMinor() ) {
394  $newminor = ChangesList::flag( 'minor' );
395  } else {
396  $newminor = '';
397  }
398 
399  # Handle RevisionDelete links...
400  $rdel = $this->revisionDeleteLink( $this->mNewRev );
401 
402  # Allow extensions to define their own revision tools
403  Hooks::run( 'DiffRevisionTools',
404  [ $this->mNewRev, &$revisionTools, $this->mOldRev, $user ] );
405  $formattedRevisionTools = [];
406  // Put each one in parentheses (poor man's button)
407  foreach ( $revisionTools as $key => $tool ) {
408  $toolClass = is_string( $key ) ? $key : 'mw-diff-tool';
409  $element = Html::rawElement(
410  'span',
411  [ 'class' => $toolClass ],
412  $this->msg( 'parentheses' )->rawParams( $tool )->escaped()
413  );
414  $formattedRevisionTools[] = $element;
415  }
416  $newRevisionHeader = $this->getRevisionHeader( $this->mNewRev, 'complete' ) .
417  ' ' . implode( ' ', $formattedRevisionTools );
418  $newChangeTags = ChangeTags::formatSummaryRow( $this->mNewTags, 'diff', $this->getContext() );
419 
420  $newHeader = '<div id="mw-diff-ntitle1"><strong>' . $newRevisionHeader . '</strong></div>' .
421  '<div id="mw-diff-ntitle2">' . Linker::revUserTools( $this->mNewRev, !$this->unhide ) .
422  " $rollback</div>" .
423  '<div id="mw-diff-ntitle3">' . $newminor .
424  Linker::revComment( $this->mNewRev, !$diffOnly, !$this->unhide ) . $rdel . '</div>' .
425  '<div id="mw-diff-ntitle5">' . $newChangeTags[0] . '</div>' .
426  '<div id="mw-diff-ntitle4">' . $nextlink . $this->markPatrolledLink() . '</div>';
427 
428  // Allow extensions to change the $newHeader variable
429  Hooks::run( 'DifferenceEngineNewHeader', [ $this, &$newHeader, $formattedRevisionTools,
430  $nextlink, $rollback, $newminor, $diffOnly, $rdel, $this->unhide ] );
431 
432  if ( $this->mNewRev->isDeleted( Revision::DELETED_TEXT ) ) {
433  $deleted = true; // new revisions text is hidden
434  if ( $this->mNewRev->isDeleted( Revision::DELETED_RESTRICTED ) ) {
435  $suppressed = true; // also suppressed
436  }
437  }
438 
439  # If the diff cannot be shown due to a deleted revision, then output
440  # the diff header and links to unhide (if available)...
441  if ( $deleted && ( !$this->unhide || !$allowed ) ) {
442  $this->showDiffStyle();
443  $multi = $this->getMultiNotice();
444  $out->addHTML( $this->addHeader( '', $oldHeader, $newHeader, $multi ) );
445  if ( !$allowed ) {
446  $msg = $suppressed ? 'rev-suppressed-no-diff' : 'rev-deleted-no-diff';
447  # Give explanation for why revision is not visible
448  $out->wrapWikiMsg( "<div id='mw-$msg' class='mw-warning plainlinks'>\n$1\n</div>\n",
449  [ $msg ] );
450  } else {
451  # Give explanation and add a link to view the diff...
452  $query = $this->getRequest()->appendQueryValue( 'unhide', '1' );
453  $link = $this->getTitle()->getFullURL( $query );
454  $msg = $suppressed ? 'rev-suppressed-unhide-diff' : 'rev-deleted-unhide-diff';
455  $out->wrapWikiMsg(
456  "<div id='mw-$msg' class='mw-warning plainlinks'>\n$1\n</div>\n",
457  [ $msg, $link ]
458  );
459  }
460  # Otherwise, output a regular diff...
461  } else {
462  # Add deletion notice if the user is viewing deleted content
463  $notice = '';
464  if ( $deleted ) {
465  $msg = $suppressed ? 'rev-suppressed-diff-view' : 'rev-deleted-diff-view';
466  $notice = "<div id='mw-$msg' class='mw-warning plainlinks'>\n" .
467  $this->msg( $msg )->parse() .
468  "</div>\n";
469  }
470  $this->showDiff( $oldHeader, $newHeader, $notice );
471  if ( !$diffOnly ) {
472  $this->renderNewRevision();
473  }
474  }
475  }
476 
486  public function markPatrolledLink() {
487  if ( $this->mMarkPatrolledLink === null ) {
488  $linkInfo = $this->getMarkPatrolledLinkInfo();
489  // If false, there is no patrol link needed/allowed
490  if ( !$linkInfo ) {
491  $this->mMarkPatrolledLink = '';
492  } else {
493  $this->mMarkPatrolledLink = ' <span class="patrollink" data-mw="interface">[' .
495  $this->mNewPage,
496  $this->msg( 'markaspatrolleddiff' )->escaped(),
497  [],
498  [
499  'action' => 'markpatrolled',
500  'rcid' => $linkInfo['rcid'],
501  ]
502  ) . ']</span>';
503  // Allow extensions to change the markpatrolled link
504  Hooks::run( 'DifferenceEngineMarkPatrolledLink', [ $this,
505  &$this->mMarkPatrolledLink, $linkInfo['rcid'] ] );
506  }
507  }
509  }
510 
518  protected function getMarkPatrolledLinkInfo() {
519  global $wgUseRCPatrol, $wgEnableAPI, $wgEnableWriteAPI;
520 
521  $user = $this->getUser();
522 
523  // Prepare a change patrol link, if applicable
524  if (
525  // Is patrolling enabled and the user allowed to?
526  $wgUseRCPatrol && $this->mNewPage->quickUserCan( 'patrol', $user ) &&
527  // Only do this if the revision isn't more than 6 hours older
528  // than the Max RC age (6h because the RC might not be cleaned out regularly)
529  RecentChange::isInRCLifespan( $this->mNewRev->getTimestamp(), 21600 )
530  ) {
531  // Look for an unpatrolled change corresponding to this diff
532  $db = wfGetDB( DB_REPLICA );
533  $change = RecentChange::newFromConds(
534  [
535  'rc_timestamp' => $db->timestamp( $this->mNewRev->getTimestamp() ),
536  'rc_this_oldid' => $this->mNewid,
537  'rc_patrolled' => 0
538  ],
539  __METHOD__
540  );
541 
542  if ( $change && !$change->getPerformer()->equals( $user ) ) {
543  $rcid = $change->getAttribute( 'rc_id' );
544  } else {
545  // None found or the page has been created by the current user.
546  // If the user could patrol this it already would be patrolled
547  $rcid = 0;
548  }
549 
550  // Allow extensions to possibly change the rcid here
551  // For example the rcid might be set to zero due to the user
552  // being the same as the performer of the change but an extension
553  // might still want to show it under certain conditions
554  Hooks::run( 'DifferenceEngineMarkPatrolledRCID', [ &$rcid, $this, $change, $user ] );
555 
556  // Build the link
557  if ( $rcid ) {
558  $this->getOutput()->preventClickjacking();
559  if ( $wgEnableAPI && $wgEnableWriteAPI
560  && $user->isAllowed( 'writeapi' )
561  ) {
562  $this->getOutput()->addModules( 'mediawiki.page.patrol.ajax' );
563  }
564 
565  return [
566  'rcid' => $rcid,
567  ];
568  }
569  }
570 
571  // No mark as patrolled link applicable
572  return false;
573  }
574 
580  protected function revisionDeleteLink( $rev ) {
581  $link = Linker::getRevDeleteLink( $this->getUser(), $rev, $rev->getTitle() );
582  if ( $link !== '' ) {
583  $link = '&#160;&#160;&#160;' . $link . ' ';
584  }
585 
586  return $link;
587  }
588 
592  public function renderNewRevision() {
593  $out = $this->getOutput();
594  $revHeader = $this->getRevisionHeader( $this->mNewRev );
595  # Add "current version as of X" title
596  $out->addHTML( "<hr class='diff-hr' id='mw-oldid' />
597  <h2 class='diff-currentversion-title'>{$revHeader}</h2>\n" );
598  # Page content may be handled by a hooked call instead...
599  # @codingStandardsIgnoreStart Ignoring long lines.
600  if ( Hooks::run( 'ArticleContentOnDiff', [ $this, $out ] ) ) {
601  $this->loadNewText();
602  $out->setRevisionId( $this->mNewid );
603  $out->setRevisionTimestamp( $this->mNewRev->getTimestamp() );
604  $out->setArticleFlag( true );
605 
606  if ( !Hooks::run( 'ArticleContentViewCustom', [ $this->mNewContent, $this->mNewPage, $out ] ) ) {
607  // Handled by extension
608  } else {
609  // Normal page
610  if ( $this->getTitle()->equals( $this->mNewPage ) ) {
611  // If the Title stored in the context is the same as the one
612  // of the new revision, we can use its associated WikiPage
613  // object.
614  $wikiPage = $this->getWikiPage();
615  } else {
616  // Otherwise we need to create our own WikiPage object
617  $wikiPage = WikiPage::factory( $this->mNewPage );
618  }
619 
620  $parserOutput = $this->getParserOutput( $wikiPage, $this->mNewRev );
621 
622  # WikiPage::getParserOutput() should not return false, but just in case
623  if ( $parserOutput ) {
624  // Allow extensions to change parser output here
625  if ( Hooks::run( 'DifferenceEngineRenderRevisionAddParserOutput', [ $this, $out, $parserOutput, $wikiPage ] ) ) {
626  $out->addParserOutput( $parserOutput );
627  }
628  }
629  }
630  }
631  # @codingStandardsIgnoreEnd
632 
633  // Allow extensions to optionally not show the final patrolled link
634  if ( Hooks::run( 'DifferenceEngineRenderRevisionShowFinalPatrolLink' ) ) {
635  # Add redundant patrol link on bottom...
636  $out->addHTML( $this->markPatrolledLink() );
637  }
638  }
639 
640  protected function getParserOutput( WikiPage $page, Revision $rev ) {
641  $parserOptions = $page->makeParserOptions( $this->getContext() );
642 
643  if ( !$rev->isCurrent() || !$rev->getTitle()->quickUserCan( 'edit', $this->getUser() ) ) {
644  $parserOptions->setEditSection( false );
645  }
646 
647  $parserOutput = $page->getParserOutput( $parserOptions, $rev->getId() );
648 
649  return $parserOutput;
650  }
651 
662  public function showDiff( $otitle, $ntitle, $notice = '' ) {
663  // Allow extensions to affect the output here
664  Hooks::run( 'DifferenceEngineShowDiff', [ $this ] );
665 
666  $diff = $this->getDiff( $otitle, $ntitle, $notice );
667  if ( $diff === false ) {
668  $this->showMissingRevision();
669 
670  return false;
671  } else {
672  $this->showDiffStyle();
673  $this->getOutput()->addHTML( $diff );
674 
675  return true;
676  }
677  }
678 
682  public function showDiffStyle() {
683  $this->getOutput()->addModuleStyles( 'mediawiki.diff.styles' );
684  }
685 
695  public function getDiff( $otitle, $ntitle, $notice = '' ) {
696  $body = $this->getDiffBody();
697  if ( $body === false ) {
698  return false;
699  }
700 
701  $multi = $this->getMultiNotice();
702  // Display a message when the diff is empty
703  if ( $body === '' ) {
704  $notice .= '<div class="mw-diff-empty">' .
705  $this->msg( 'diff-empty' )->parse() .
706  "</div>\n";
707  }
708 
709  return $this->addHeader( $body, $otitle, $ntitle, $multi, $notice );
710  }
711 
717  public function getDiffBody() {
718  $this->mCacheHit = true;
719  // Check if the diff should be hidden from this user
720  if ( !$this->loadRevisionData() ) {
721  return false;
722  } elseif ( $this->mOldRev &&
723  !$this->mOldRev->userCan( Revision::DELETED_TEXT, $this->getUser() )
724  ) {
725  return false;
726  } elseif ( $this->mNewRev &&
727  !$this->mNewRev->userCan( Revision::DELETED_TEXT, $this->getUser() )
728  ) {
729  return false;
730  }
731  // Short-circuit
732  if ( $this->mOldRev === false || ( $this->mOldRev && $this->mNewRev
733  && $this->mOldRev->getId() == $this->mNewRev->getId() )
734  ) {
735  if ( Hooks::run( 'DifferenceEngineShowEmptyOldContent', [ $this ] ) ) {
736  return '';
737  }
738  }
739  // Cacheable?
740  $key = false;
742  if ( $this->mOldid && $this->mNewid ) {
743  $key = $this->getDiffBodyCacheKey();
744 
745  // Try cache
746  if ( !$this->mRefreshCache ) {
747  $difftext = $cache->get( $key );
748  if ( $difftext ) {
749  wfIncrStats( 'diff_cache.hit' );
750  $difftext = $this->localiseLineNumbers( $difftext );
751  $difftext .= "\n<!-- diff cache key $key -->\n";
752 
753  return $difftext;
754  }
755  } // don't try to load but save the result
756  }
757  $this->mCacheHit = false;
758 
759  // Loadtext is permission safe, this just clears out the diff
760  if ( !$this->loadText() ) {
761  return false;
762  }
763 
764  $difftext = $this->generateContentDiffBody( $this->mOldContent, $this->mNewContent );
765 
766  // Avoid PHP 7.1 warning from passing $this by reference
767  $diffEngine = $this;
768 
769  // Save to cache for 7 days
770  if ( !Hooks::run( 'AbortDiffCache', [ &$diffEngine ] ) ) {
771  wfIncrStats( 'diff_cache.uncacheable' );
772  } elseif ( $key !== false && $difftext !== false ) {
773  wfIncrStats( 'diff_cache.miss' );
774  $cache->set( $key, $difftext, 7 * 86400 );
775  } else {
776  wfIncrStats( 'diff_cache.uncacheable' );
777  }
778  // Replace line numbers with the text in the user's language
779  if ( $difftext !== false ) {
780  $difftext = $this->localiseLineNumbers( $difftext );
781  }
782 
783  return $difftext;
784  }
785 
794  protected function getDiffBodyCacheKey() {
795  if ( !$this->mOldid || !$this->mNewid ) {
796  throw new MWException( 'mOldid and mNewid must be set to get diff cache key.' );
797  }
798 
799  return wfMemcKey( 'diff', 'version', self::DIFF_VERSION,
800  'oldid', $this->mOldid, 'newid', $this->mNewid );
801  }
802 
822  public function generateContentDiffBody( Content $old, Content $new ) {
823  if ( !( $old instanceof TextContent ) ) {
824  throw new MWException( "Diff not implemented for " . get_class( $old ) . "; " .
825  "override generateContentDiffBody to fix this." );
826  }
827 
828  if ( !( $new instanceof TextContent ) ) {
829  throw new MWException( "Diff not implemented for " . get_class( $new ) . "; "
830  . "override generateContentDiffBody to fix this." );
831  }
832 
833  $otext = $old->serialize();
834  $ntext = $new->serialize();
835 
836  return $this->generateTextDiffBody( $otext, $ntext );
837  }
838 
849  public function generateTextDiffBody( $otext, $ntext ) {
850  $diff = function() use ( $otext, $ntext ) {
851  $time = microtime( true );
852 
853  $result = $this->textDiff( $otext, $ntext );
854 
855  $time = intval( ( microtime( true ) - $time ) * 1000 );
856  MediaWikiServices::getInstance()->getStatsdDataFactory()->timing( 'diff_time', $time );
857  // Log requests slower than 99th percentile
858  if ( $time > 100 && $this->mOldPage && $this->mNewPage ) {
859  wfDebugLog( 'diff',
860  "$time ms diff: {$this->mOldid} -> {$this->mNewid} {$this->mNewPage}" );
861  }
862 
863  return $result;
864  };
865 
870  $error = function( $status ) {
871  throw new FatalError( $status->getWikiText() );
872  };
873 
874  // Use PoolCounter if the diff looks like it can be expensive
875  if ( strlen( $otext ) + strlen( $ntext ) > 20000 ) {
876  $work = new PoolCounterWorkViaCallback( 'diff',
877  md5( $otext ) . md5( $ntext ),
878  [ 'doWork' => $diff, 'error' => $error ]
879  );
880  return $work->execute();
881  }
882 
883  return $diff();
884  }
885 
893  protected function textDiff( $otext, $ntext ) {
894  global $wgExternalDiffEngine, $wgContLang;
895 
896  $otext = str_replace( "\r\n", "\n", $otext );
897  $ntext = str_replace( "\r\n", "\n", $ntext );
898 
899  if ( $wgExternalDiffEngine == 'wikidiff' || $wgExternalDiffEngine == 'wikidiff3' ) {
900  wfDeprecated( "\$wgExternalDiffEngine = '{$wgExternalDiffEngine}'", '1.27' );
901  $wgExternalDiffEngine = false;
902  } elseif ( $wgExternalDiffEngine == 'wikidiff2' ) {
903  // Same as above, but with no deprecation warnings
904  $wgExternalDiffEngine = false;
905  } elseif ( !is_string( $wgExternalDiffEngine ) && $wgExternalDiffEngine !== false ) {
906  // And prevent people from shooting themselves in the foot...
907  wfWarn( '$wgExternalDiffEngine is set to a non-string value, forcing it to false' );
908  $wgExternalDiffEngine = false;
909  }
910 
911  if ( function_exists( 'wikidiff2_do_diff' ) && $wgExternalDiffEngine === false ) {
912  # Better external diff engine, the 2 may some day be dropped
913  # This one does the escaping and segmenting itself
914  $text = wikidiff2_do_diff( $otext, $ntext, 2 );
915  $text .= $this->debug( 'wikidiff2' );
916 
917  return $text;
918  } elseif ( $wgExternalDiffEngine !== false && is_executable( $wgExternalDiffEngine ) ) {
919  # Diff via the shell
920  $tmpDir = wfTempDir();
921  $tempName1 = tempnam( $tmpDir, 'diff_' );
922  $tempName2 = tempnam( $tmpDir, 'diff_' );
923 
924  $tempFile1 = fopen( $tempName1, "w" );
925  if ( !$tempFile1 ) {
926  return false;
927  }
928  $tempFile2 = fopen( $tempName2, "w" );
929  if ( !$tempFile2 ) {
930  return false;
931  }
932  fwrite( $tempFile1, $otext );
933  fwrite( $tempFile2, $ntext );
934  fclose( $tempFile1 );
935  fclose( $tempFile2 );
936  $cmd = wfEscapeShellArg( $wgExternalDiffEngine, $tempName1, $tempName2 );
937  $difftext = wfShellExec( $cmd );
938  $difftext .= $this->debug( "external $wgExternalDiffEngine" );
939  unlink( $tempName1 );
940  unlink( $tempName2 );
941 
942  return $difftext;
943  }
944 
945  # Native PHP diff
946  $ota = explode( "\n", $wgContLang->segmentForDiff( $otext ) );
947  $nta = explode( "\n", $wgContLang->segmentForDiff( $ntext ) );
948  $diffs = new Diff( $ota, $nta );
949  $formatter = new TableDiffFormatter();
950  $difftext = $wgContLang->unsegmentForDiff( $formatter->format( $diffs ) );
951 
952  return $difftext;
953  }
954 
963  protected function debug( $generator = "internal" ) {
964  global $wgShowHostnames;
965  if ( !$this->enableDebugComment ) {
966  return '';
967  }
968  $data = [ $generator ];
969  if ( $wgShowHostnames ) {
970  $data[] = wfHostname();
971  }
972  $data[] = wfTimestamp( TS_DB );
973 
974  return "<!-- diff generator: " .
975  implode( " ", array_map( "htmlspecialchars", $data ) ) .
976  " -->\n";
977  }
978 
986  public function localiseLineNumbers( $text ) {
987  return preg_replace_callback(
988  '/<!--LINE (\d+)-->/',
989  [ $this, 'localiseLineNumbersCb' ],
990  $text
991  );
992  }
993 
994  public function localiseLineNumbersCb( $matches ) {
995  if ( $matches[1] === '1' && $this->mReducedLineNumbers ) {
996  return '';
997  }
998 
999  return $this->msg( 'lineno' )->numParams( $matches[1] )->escaped();
1000  }
1001 
1007  public function getMultiNotice() {
1008  if ( !is_object( $this->mOldRev ) || !is_object( $this->mNewRev ) ) {
1009  return '';
1010  } elseif ( !$this->mOldPage->equals( $this->mNewPage ) ) {
1011  // Comparing two different pages? Count would be meaningless.
1012  return '';
1013  }
1014 
1015  if ( $this->mOldRev->getTimestamp() > $this->mNewRev->getTimestamp() ) {
1016  $oldRev = $this->mNewRev; // flip
1017  $newRev = $this->mOldRev; // flip
1018  } else { // normal case
1019  $oldRev = $this->mOldRev;
1020  $newRev = $this->mNewRev;
1021  }
1022 
1023  // Sanity: don't show the notice if too many rows must be scanned
1024  // @todo show some special message for that case
1025  $nEdits = $this->mNewPage->countRevisionsBetween( $oldRev, $newRev, 1000 );
1026  if ( $nEdits > 0 && $nEdits <= 1000 ) {
1027  $limit = 100; // use diff-multi-manyusers if too many users
1028  $users = $this->mNewPage->getAuthorsBetween( $oldRev, $newRev, $limit );
1029  $numUsers = count( $users );
1030 
1031  if ( $numUsers == 1 && $users[0] == $newRev->getUserText( Revision::RAW ) ) {
1032  $numUsers = 0; // special case to say "by the same user" instead of "by one other user"
1033  }
1034 
1035  return self::intermediateEditsMsg( $nEdits, $numUsers, $limit );
1036  }
1037 
1038  return ''; // nothing
1039  }
1040 
1050  public static function intermediateEditsMsg( $numEdits, $numUsers, $limit ) {
1051  if ( $numUsers === 0 ) {
1052  $msg = 'diff-multi-sameuser';
1053  } elseif ( $numUsers > $limit ) {
1054  $msg = 'diff-multi-manyusers';
1055  $numUsers = $limit;
1056  } else {
1057  $msg = 'diff-multi-otherusers';
1058  }
1059 
1060  return wfMessage( $msg )->numParams( $numEdits, $numUsers )->parse();
1061  }
1062 
1072  public function getRevisionHeader( Revision $rev, $complete = '' ) {
1073  $lang = $this->getLanguage();
1074  $user = $this->getUser();
1075  $revtimestamp = $rev->getTimestamp();
1076  $timestamp = $lang->userTimeAndDate( $revtimestamp, $user );
1077  $dateofrev = $lang->userDate( $revtimestamp, $user );
1078  $timeofrev = $lang->userTime( $revtimestamp, $user );
1079 
1080  $header = $this->msg(
1081  $rev->isCurrent() ? 'currentrev-asof' : 'revisionasof',
1082  $timestamp,
1083  $dateofrev,
1084  $timeofrev
1085  )->escaped();
1086 
1087  if ( $complete !== 'complete' ) {
1088  return $header;
1089  }
1090 
1091  $title = $rev->getTitle();
1092 
1094  [ 'oldid' => $rev->getId() ] );
1095 
1096  if ( $rev->userCan( Revision::DELETED_TEXT, $user ) ) {
1097  $editQuery = [ 'action' => 'edit' ];
1098  if ( !$rev->isCurrent() ) {
1099  $editQuery['oldid'] = $rev->getId();
1100  }
1101 
1102  $key = $title->quickUserCan( 'edit', $user ) ? 'editold' : 'viewsourceold';
1103  $msg = $this->msg( $key )->escaped();
1104  $editLink = $this->msg( 'parentheses' )->rawParams(
1105  Linker::linkKnown( $title, $msg, [], $editQuery ) )->escaped();
1106  $header .= ' ' . Html::rawElement(
1107  'span',
1108  [ 'class' => 'mw-diff-edit' ],
1109  $editLink
1110  );
1111  if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
1113  'span',
1114  [ 'class' => 'history-deleted' ],
1115  $header
1116  );
1117  }
1118  } else {
1119  $header = Html::rawElement( 'span', [ 'class' => 'history-deleted' ], $header );
1120  }
1121 
1122  return $header;
1123  }
1124 
1137  public function addHeader( $diff, $otitle, $ntitle, $multi = '', $notice = '' ) {
1138  // shared.css sets diff in interface language/dir, but the actual content
1139  // is often in a different language, mostly the page content language/dir
1140  $header = Html::openElement( 'table', [
1141  'class' => [ 'diff', 'diff-contentalign-' . $this->getDiffLang()->alignStart() ],
1142  'data-mw' => 'interface',
1143  ] );
1144  $userLang = htmlspecialchars( $this->getLanguage()->getHtmlCode() );
1145 
1146  if ( !$diff && !$otitle ) {
1147  $header .= "
1148  <tr style='vertical-align: top;' lang='{$userLang}'>
1149  <td class='diff-ntitle'>{$ntitle}</td>
1150  </tr>";
1151  $multiColspan = 1;
1152  } else {
1153  if ( $diff ) { // Safari/Chrome show broken output if cols not used
1154  $header .= "
1155  <col class='diff-marker' />
1156  <col class='diff-content' />
1157  <col class='diff-marker' />
1158  <col class='diff-content' />";
1159  $colspan = 2;
1160  $multiColspan = 4;
1161  } else {
1162  $colspan = 1;
1163  $multiColspan = 2;
1164  }
1165  if ( $otitle || $ntitle ) {
1166  $header .= "
1167  <tr style='vertical-align: top;' lang='{$userLang}'>
1168  <td colspan='$colspan' class='diff-otitle'>{$otitle}</td>
1169  <td colspan='$colspan' class='diff-ntitle'>{$ntitle}</td>
1170  </tr>";
1171  }
1172  }
1173 
1174  if ( $multi != '' ) {
1175  $header .= "<tr><td colspan='{$multiColspan}' style='text-align: center;' " .
1176  "class='diff-multi' lang='{$userLang}'>{$multi}</td></tr>";
1177  }
1178  if ( $notice != '' ) {
1179  $header .= "<tr><td colspan='{$multiColspan}' style='text-align: center;' " .
1180  "lang='{$userLang}'>{$notice}</td></tr>";
1181  }
1182 
1183  return $header . $diff . "</table>";
1184  }
1185 
1192  public function setContent( Content $oldContent, Content $newContent ) {
1193  $this->mOldContent = $oldContent;
1194  $this->mNewContent = $newContent;
1195 
1196  $this->mTextLoaded = 2;
1197  $this->mRevisionsLoaded = true;
1198  }
1199 
1206  public function setTextLanguage( $lang ) {
1207  $this->mDiffLang = wfGetLangObj( $lang );
1208  }
1209 
1221  public function mapDiffPrevNext( $old, $new ) {
1222  if ( $new === 'prev' ) {
1223  // Show diff between revision $old and the previous one. Get previous one from DB.
1224  $newid = intval( $old );
1225  $oldid = $this->getTitle()->getPreviousRevisionID( $newid );
1226  } elseif ( $new === 'next' ) {
1227  // Show diff between revision $old and the next one. Get next one from DB.
1228  $oldid = intval( $old );
1229  $newid = $this->getTitle()->getNextRevisionID( $oldid );
1230  } else {
1231  $oldid = intval( $old );
1232  $newid = intval( $new );
1233  }
1234 
1235  return [ $oldid, $newid ];
1236  }
1237 
1241  private function loadRevisionIds() {
1242  if ( $this->mRevisionsIdsLoaded ) {
1243  return;
1244  }
1245 
1246  $this->mRevisionsIdsLoaded = true;
1247 
1248  $old = $this->mOldid;
1249  $new = $this->mNewid;
1250 
1251  list( $this->mOldid, $this->mNewid ) = self::mapDiffPrevNext( $old, $new );
1252  if ( $new === 'next' && $this->mNewid === false ) {
1253  # if no result, NewId points to the newest old revision. The only newer
1254  # revision is cur, which is "0".
1255  $this->mNewid = 0;
1256  }
1257 
1258  Hooks::run(
1259  'NewDifferenceEngine',
1260  [ $this->getTitle(), &$this->mOldid, &$this->mNewid, $old, $new ]
1261  );
1262  }
1263 
1276  public function loadRevisionData() {
1277  if ( $this->mRevisionsLoaded ) {
1278  return true;
1279  }
1280 
1281  // Whether it succeeds or fails, we don't want to try again
1282  $this->mRevisionsLoaded = true;
1283 
1284  $this->loadRevisionIds();
1285 
1286  // Load the new revision object
1287  if ( $this->mNewid ) {
1288  $this->mNewRev = Revision::newFromId( $this->mNewid );
1289  } else {
1290  $this->mNewRev = Revision::newFromTitle(
1291  $this->getTitle(),
1292  false,
1293  Revision::READ_NORMAL
1294  );
1295  }
1296 
1297  if ( !$this->mNewRev instanceof Revision ) {
1298  return false;
1299  }
1300 
1301  // Update the new revision ID in case it was 0 (makes life easier doing UI stuff)
1302  $this->mNewid = $this->mNewRev->getId();
1303  $this->mNewPage = $this->mNewRev->getTitle();
1304 
1305  // Load the old revision object
1306  $this->mOldRev = false;
1307  if ( $this->mOldid ) {
1308  $this->mOldRev = Revision::newFromId( $this->mOldid );
1309  } elseif ( $this->mOldid === 0 ) {
1310  $rev = $this->mNewRev->getPrevious();
1311  if ( $rev ) {
1312  $this->mOldid = $rev->getId();
1313  $this->mOldRev = $rev;
1314  } else {
1315  // No previous revision; mark to show as first-version only.
1316  $this->mOldid = false;
1317  $this->mOldRev = false;
1318  }
1319  } /* elseif ( $this->mOldid === false ) leave mOldRev false; */
1320 
1321  if ( is_null( $this->mOldRev ) ) {
1322  return false;
1323  }
1324 
1325  if ( $this->mOldRev ) {
1326  $this->mOldPage = $this->mOldRev->getTitle();
1327  }
1328 
1329  // Load tags information for both revisions
1330  $dbr = wfGetDB( DB_REPLICA );
1331  if ( $this->mOldid !== false ) {
1332  $this->mOldTags = $dbr->selectField(
1333  'tag_summary',
1334  'ts_tags',
1335  [ 'ts_rev_id' => $this->mOldid ],
1336  __METHOD__
1337  );
1338  } else {
1339  $this->mOldTags = false;
1340  }
1341  $this->mNewTags = $dbr->selectField(
1342  'tag_summary',
1343  'ts_tags',
1344  [ 'ts_rev_id' => $this->mNewid ],
1345  __METHOD__
1346  );
1347 
1348  return true;
1349  }
1350 
1356  public function loadText() {
1357  if ( $this->mTextLoaded == 2 ) {
1358  return true;
1359  }
1360 
1361  // Whether it succeeds or fails, we don't want to try again
1362  $this->mTextLoaded = 2;
1363 
1364  if ( !$this->loadRevisionData() ) {
1365  return false;
1366  }
1367 
1368  if ( $this->mOldRev ) {
1369  $this->mOldContent = $this->mOldRev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
1370  if ( $this->mOldContent === null ) {
1371  return false;
1372  }
1373  }
1374 
1375  if ( $this->mNewRev ) {
1376  $this->mNewContent = $this->mNewRev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
1377  Hooks::run( 'DifferenceEngineLoadTextAfterNewContentIsLoaded', [ $this ] );
1378  if ( $this->mNewContent === null ) {
1379  return false;
1380  }
1381  }
1382 
1383  return true;
1384  }
1385 
1391  public function loadNewText() {
1392  if ( $this->mTextLoaded >= 1 ) {
1393  return true;
1394  }
1395 
1396  $this->mTextLoaded = 1;
1397 
1398  if ( !$this->loadRevisionData() ) {
1399  return false;
1400  }
1401 
1402  $this->mNewContent = $this->mNewRev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
1403 
1404  Hooks::run( 'DifferenceEngineAfterLoadNewText', [ $this ] );
1405 
1406  return true;
1407  }
1408 
1409 }
Revision\newFromArchiveRow
static newFromArchiveRow( $row, $overrides=[])
Make a fake revision object from an archive table row.
Definition: Revision.php:189
DifferenceEngine\$mRevisionsIdsLoaded
bool $mRevisionsIdsLoaded
Have the revisions IDs been loaded.
Definition: DifferenceEngine.php:72
DifferenceEngine\revisionDeleteLink
revisionDeleteLink( $rev)
Definition: DifferenceEngine.php:580
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:34
Revision\DELETED_RESTRICTED
const DELETED_RESTRICTED
Definition: Revision.php:93
DifferenceEngine\markPatrolledLink
markPatrolledLink()
Build a link to mark a change as patrolled.
Definition: DifferenceEngine.php:486
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:41
DifferenceEngine\$mTextLoaded
int $mTextLoaded
How many text blobs have been loaded, 0, 1 or 2?
Definition: DifferenceEngine.php:78
Content\serialize
serialize( $format=null)
Convenience method for serializing this Content object.
wfMergeErrorArrays
wfMergeErrorArrays()
Merge arrays in the style of getUserPermissionsErrors, with duplicate removal e.g.
Definition: GlobalFunctions.php:242
Revision\newFromId
static newFromId( $id, $flags=0)
Load a page revision from a given revision ID number.
Definition: Revision.php:116
DifferenceEngine\$mNewContent
Content $mNewContent
Definition: DifferenceEngine.php:54
ContextSource\msg
msg()
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:187
DifferenceEngine\$mNewRev
Revision $mNewRev
Definition: DifferenceEngine.php:69
DifferenceEngine\$mOldPage
Title $mOldPage
Definition: DifferenceEngine.php:60
DifferenceEngine\$unhide
bool $unhide
Show rev_deleted content if allowed.
Definition: DifferenceEngine.php:99
DifferenceEngine\$mOldTags
$mOldTags
Definition: DifferenceEngine.php:47
DifferenceEngine\setTextLanguage
setTextLanguage( $lang)
Set the language in which the diff text is written (Defaults to page content language).
Definition: DifferenceEngine.php:1206
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:33
RecentChange\newFromConds
static newFromConds( $conds, $fname=__METHOD__, $dbType=DB_REPLICA)
Find the first recent change matching some specific conditions.
Definition: RecentChange.php:185
DifferenceEngine\setReducedLineNumbers
setReducedLineNumbers( $value=true)
Definition: DifferenceEngine.php:133
captcha-old.count
count
Definition: captcha-old.py:225
DifferenceEngine\setContent
setContent(Content $oldContent, Content $newContent)
Use specified text instead of loading from the database.
Definition: DifferenceEngine.php:1192
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetMagic':DEPRECATED! Use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language & $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetSpecialPageAliases':DEPRECATED! Use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language & $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1954
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1994
DifferenceEngine\getNewid
getNewid()
Definition: DifferenceEngine.php:168
DifferenceEngine\getOldid
getOldid()
Definition: DifferenceEngine.php:159
$status
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set $status
Definition: hooks.txt:1049
DifferenceEngine\$mNewTags
$mNewTags
Definition: DifferenceEngine.php:48
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:246
WikiPage
Class representing a MediaWiki article and history.
Definition: WikiPage.php:36
DifferenceEngine\$mRevisionsLoaded
bool $mRevisionsLoaded
Have the revisions been loaded.
Definition: DifferenceEngine.php:75
DifferenceEngine\deletedIdMarker
deletedIdMarker( $id)
Build a wikitext link toward a deleted revision, if viewable.
Definition: DifferenceEngine.php:209
wfHostname
wfHostname()
Fetch server name for use in error reporting etc.
Definition: GlobalFunctions.php:1435
Linker\linkKnown
static linkKnown( $target, $html=null, $customAttribs=[], $query=[], $options=[ 'known'])
Identical to link(), except $options defaults to 'known'.
Definition: Linker.php:159
$rollback
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers please use GetContentModels hook to make them known to core if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok inclusive false for true for descending in case the handler function wants to provide a converted Content object Note that $result getContentModel() must return $toModel. 'CustomEditor' also included in $newHeader $rollback
Definition: hooks.txt:1167
SpecialPage\getTitleFor
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Definition: SpecialPage.php:82
DifferenceEngine\$mNewPage
Title $mNewPage
Definition: DifferenceEngine.php:63
Revision\isCurrent
isCurrent()
Definition: Revision.php:1185
TableDiffFormatter
MediaWiki default table style diff formatter.
Definition: TableDiffFormatter.php:33
ContextSource\getRequest
getRequest()
Get the WebRequest object.
Definition: ContextSource.php:78
PermissionsError
Show an error when a user tries to do something they do not have the necessary permissions for.
Definition: PermissionsError.php:28
PoolCounterWorkViaCallback
Convenience class for dealing with PoolCounters using callbacks.
Definition: PoolCounterWorkViaCallback.php:28
DifferenceEngine\showDiffStyle
showDiffStyle()
Add style sheets for diff display.
Definition: DifferenceEngine.php:682
DifferenceEngine\loadNewText
loadNewText()
Load the text of the new revision, not the old one.
Definition: DifferenceEngine.php:1391
ContextSource\getUser
getUser()
Get the User object.
Definition: ContextSource.php:133
ContextSource\getTitle
getTitle()
Get the Title object.
Definition: ContextSource.php:88
DifferenceEngine\showDiff
showDiff( $otitle, $ntitle, $notice='')
Get the diff text, send it to the OutputPage object Returns false if the diff could not be generated,...
Definition: DifferenceEngine.php:662
DifferenceEngine\getDiffBodyCacheKey
getDiffBodyCacheKey()
Returns the cache key for diff body text or content.
Definition: DifferenceEngine.php:794
wfDebugLog
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
Definition: GlobalFunctions.php:1092
DifferenceEngine\$mOldid
int $mOldid
Definition: DifferenceEngine.php:42
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
DifferenceEngine\$mNewid
int $mNewid
Definition: DifferenceEngine.php:45
DifferenceEngine\generateTextDiffBody
generateTextDiffBody( $otext, $ntext)
Generate a diff, no caching.
Definition: DifferenceEngine.php:849
ContextSource\getLanguage
getLanguage()
Get the Language object.
Definition: ContextSource.php:143
below
controlled by $wgMainCacheType controlled by $wgParserCacheType controlled by $wgMessageCacheType If you set CACHE_NONE to one of the three control default value for MediaWiki still create a but requests to it are no ops and we always fall through to the database If the cache daemon can t be it should also disable itself fairly smoothly By $wgMemc is used but when it is $parserMemc or $messageMemc this is mentioned below
Definition: memcached.txt:96
Revision\FOR_THIS_USER
const FOR_THIS_USER
Definition: Revision.php:99
Revision
Definition: Revision.php:33
DifferenceEngine\$mReducedLineNumbers
bool $mReducedLineNumbers
If true, line X is not displayed when X is 1, for example to increase readability and conserve space ...
Definition: DifferenceEngine.php:93
Revision\newFromTitle
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given link target.
Definition: Revision.php:134
$query
null for the wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1572
DifferenceEngine\loadRevisionData
loadRevisionData()
Load revision metadata for the specified articles.
Definition: DifferenceEngine.php:1276
DifferenceEngine\localiseLineNumbersCb
localiseLineNumbersCb( $matches)
Definition: DifferenceEngine.php:994
MWException
MediaWiki exception.
Definition: MWException.php:26
wfMemcKey
wfMemcKey()
Make a cache key for the local wiki.
Definition: GlobalFunctions.php:2961
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:934
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:120
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1128
Linker\generateRollback
static generateRollback( $rev, IContextSource $context=null, $options=[ 'verify'])
Generate a rollback link for a given revision.
Definition: Linker.php:1675
DifferenceEngine\wasCacheHit
wasCacheHit()
Definition: DifferenceEngine.php:152
wfIncrStats
wfIncrStats( $key, $count=1)
Increment a statistics counter.
Definition: GlobalFunctions.php:1267
DifferenceEngine\getDiffLang
getDiffLang()
Definition: DifferenceEngine.php:140
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3060
Linker\revUserTools
static revUserTools( $rev, $isPublic=false)
Generate a user tool link cluster if the current user is allowed to view it.
Definition: Linker.php:1055
$page
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached $page
Definition: hooks.txt:2536
ContextSource\getOutput
getOutput()
Get the OutputPage object.
Definition: ContextSource.php:123
$matches
$matches
Definition: NoLocalSettings.php:24
ContextSource
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
Definition: ContextSource.php:30
ContextSource\getWikiPage
getWikiPage()
Get the WikiPage object.
Definition: ContextSource.php:113
not
if not
Definition: COPYING.txt:307
DifferenceEngine\$mOldContent
Content $mOldContent
Definition: DifferenceEngine.php:51
$limit
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers please use GetContentModels hook to make them known to core if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok inclusive $limit
Definition: hooks.txt:1049
DifferenceEngine\deletedLink
deletedLink( $id)
Look up a special:Undelete link to the given deleted revision id, as a workaround for being unable to...
Definition: DifferenceEngine.php:182
wfGetLangObj
wfGetLangObj( $langcode=false)
Return a Language object from $langcode.
Definition: GlobalFunctions.php:1321
ChangesList\flag
static flag( $flag, IContextSource $context=null)
Make an "<abbr>" element for a given change flag.
Definition: ChangesList.php:221
DifferenceEngine\getDiffBody
getDiffBody()
Get the diff table body, without header.
Definition: DifferenceEngine.php:717
DifferenceEngine\getRevisionHeader
getRevisionHeader(Revision $rev, $complete='')
Get a header for a specified revision.
Definition: DifferenceEngine.php:1072
$generator
$generator
Definition: generateLocalAutoload.php:12
$time
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1769
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
DifferenceEngine\loadText
loadText()
Load the text of the revisions, as well as revision data.
Definition: DifferenceEngine.php:1356
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:999
ContextSource\setContext
setContext(IContextSource $context)
Set the IContextSource object.
Definition: ContextSource.php:58
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
DifferenceEngine\$mCacheHit
bool $mCacheHit
Was the diff fetched from cache?
Definition: DifferenceEngine.php:81
MW_DIFF_VERSION
const MW_DIFF_VERSION
Definition: DifferenceEngine.php:26
DifferenceEngine\$enableDebugComment
$enableDebugComment
Set this to true to add debug info to the HTML output.
Definition: DifferenceEngine.php:88
DifferenceEngine\__construct
__construct( $context=null, $old=0, $new=0, $rcid=0, $refreshCache=false, $unhide=false)
#-
Definition: DifferenceEngine.php:115
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:538
Linker\revComment
static revComment(Revision $rev, $local=false, $isPublic=false)
Wrap and format the given revision's comment block, if the current user is allowed to view it.
Definition: Linker.php:1464
see
Some information about database access in MediaWiki By Tim January Database layout For information about the MediaWiki database such as a description of the tables and their please see
Definition: database.txt:2
$value
$value
Definition: styleTest.css.php:45
$header
$header
Definition: updateCredits.php:35
Linker\getRevDeleteLink
static getRevDeleteLink(User $user, Revision $rev, Title $title)
Get a revision-deletion link, or disabled link, or nothing, depending on user permissions & the setti...
Definition: Linker.php:2015
$suppressed
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging a wrapping ErrorException $suppressed
Definition: hooks.txt:2122
wfEscapeShellArg
wfEscapeShellArg()
Version of escapeshellarg() that works better on Windows.
Definition: GlobalFunctions.php:2195
$refreshCache
null for the wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify as strings Extensions should add to this list prev or next $refreshCache
Definition: hooks.txt:1572
Revision\RAW
const RAW
Definition: Revision.php:100
DifferenceEngine\showDiffPage
showDiffPage( $diffOnly=false)
Definition: DifferenceEngine.php:241
TextContent
Content object implementation for representing flat text.
Definition: TextContent.php:35
Linker\titleAttrib
static titleAttrib( $name, $options=null, array $msgParams=[])
Given the id of an interface element, constructs the appropriate title attribute from the system mess...
Definition: Linker.php:1936
DifferenceEngine\DIFF_VERSION
const DIFF_VERSION
Constant to indicate diff cache compatibility.
Definition: DifferenceEngine.php:39
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:55
DifferenceEngine\intermediateEditsMsg
static intermediateEditsMsg( $numEdits, $numUsers, $limit)
Get a notice about how many intermediate edits and users there are.
Definition: DifferenceEngine.php:1050
$newminor
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers please use GetContentModels hook to make them known to core if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok inclusive false for true for descending in case the handler function wants to provide a converted Content object Note that $result getContentModel() must return $toModel. 'CustomEditor' also included in $newHeader if any $newminor
Definition: hooks.txt:1167
DifferenceEngine\showMissingRevision
showMissingRevision()
Definition: DifferenceEngine.php:218
Content
Base interface for content objects.
Definition: Content.php:34
DifferenceEngine\$mOldRev
Revision $mOldRev
Definition: DifferenceEngine.php:66
DifferenceEngine\loadRevisionIds
loadRevisionIds()
Load revision IDs.
Definition: DifferenceEngine.php:1241
DifferenceEngine\getParserOutput
getParserOutput(WikiPage $page, Revision $rev)
Definition: DifferenceEngine.php:640
Title
Represents a title within MediaWiki.
Definition: Title.php:39
wfTempDir
wfTempDir()
Tries to get the system directory for temporary files.
Definition: GlobalFunctions.php:2061
$dbr
if(! $regexes) $dbr
Definition: cleanup.php:94
$cache
$cache
Definition: mcc.php:33
DifferenceEngine\$mDiffLang
Language $mDiffLang
Definition: DifferenceEngine.php:57
ObjectCache\getMainWANInstance
static getMainWANInstance()
Get the main WAN cache object.
Definition: ObjectCache.php:370
DifferenceEngine\getMarkPatrolledLinkInfo
getMarkPatrolledLinkInfo()
Returns an array of meta data needed to build a "mark as patrolled" link and adds the mediawiki....
Definition: DifferenceEngine.php:518
FatalError
Exception class which takes an HTML error message, and does not produce a backtrace.
Definition: FatalError.php:28
$rev
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition: hooks.txt:1741
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
Html\openElement
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:251
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:209
DifferenceEngine
Definition: DifferenceEngine.php:32
RecentChange\isInRCLifespan
static isInRCLifespan( $timestamp, $tolerance=0)
Check whether the given timestamp is new enough to have a RC row with a given tolerance as the recent...
Definition: RecentChange.php:1003
$link
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition: hooks.txt:2929
wikidiff2_do_diff
wikidiff2_do_diff( $text1, $text2, $numContextLines)
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...
Definition: wikidiff.php:27
$oldminor
passed in as a query string parameter to the various URLs constructed here(i.e. $nextlink) $rdel also included in $oldHeader $oldminor
Definition: hooks.txt:1237
DifferenceEngine\$mMarkPatrolledLink
string $mMarkPatrolledLink
Link to action=markpatrolled.
Definition: DifferenceEngine.php:96
DifferenceEngine\localiseLineNumbers
localiseLineNumbers( $text)
Replace line numbers with the text in the user's language.
Definition: DifferenceEngine.php:986
wfMessage
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
wfWarn
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
Definition: GlobalFunctions.php:1142
DifferenceEngine\debug
debug( $generator="internal")
Generate a debug comment indicating diff generating time, server node, and generator backend.
Definition: DifferenceEngine.php:963
DifferenceEngine\renderNewRevision
renderNewRevision()
Show the new revision of the page.
Definition: DifferenceEngine.php:592
Html\element
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:231
MediaWikiServices
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 MediaWikiServices
Definition: injection.txt:23
DifferenceEngine\getDiff
getDiff( $otitle, $ntitle, $notice='')
Get complete diff table, including header.
Definition: DifferenceEngine.php:695
DifferenceEngine\generateContentDiffBody
generateContentDiffBody(Content $old, Content $new)
Generate a diff, no caching.
Definition: DifferenceEngine.php:822
DifferenceEngine\mapDiffPrevNext
mapDiffPrevNext( $old, $new)
Maps a revision pair definition as accepted by DifferenceEngine constructor to a pair of actual integ...
Definition: DifferenceEngine.php:1221
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
DifferenceEngine\addHeader
addHeader( $diff, $otitle, $ntitle, $multi='', $notice='')
Add the header to a diff body.
Definition: DifferenceEngine.php:1137
ChangeTags\formatSummaryRow
static formatSummaryRow( $tags, $page, IContextSource $context=null)
Creates HTML for the given tags.
Definition: ChangeTags.php:52
Revision\DELETED_TEXT
const DELETED_TEXT
Definition: Revision.php:90
Language
Internationalisation code.
Definition: Language.php:35
DifferenceEngine\textDiff
textDiff( $otext, $ntext)
Generates diff, to be wrapped internally in a logging/instrumentation.
Definition: DifferenceEngine.php:893
$parserOutput
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context $parserOutput
Definition: hooks.txt:1049
$wgContLang
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the content language as $wgContLang
Definition: design.txt:56
Diff
Class representing a 'diff' between two sequences of strings.
Definition: DairikiDiff.php:200
wfShellExec
wfShellExec( $cmd, &$retval=null, $environ=[], $limits=[], $options=[])
Execute a shell command, with time and memory limits mirrored from the PHP configuration if supported...
Definition: GlobalFunctions.php:2297
DifferenceEngine\$mRefreshCache
bool $mRefreshCache
Refresh the diff cache.
Definition: DifferenceEngine.php:102
$out
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:783
DifferenceEngine\getMultiNotice
getMultiNotice()
If there are revisions between the ones being compared, return a note saying so.
Definition: DifferenceEngine.php:1007