MediaWiki REL1_29
SpecialUndelete.php
Go to the documentation of this file.
1<?php
26
34 private $mAction;
35 private $mTarget;
36 private $mTimestamp;
37 private $mRestore;
38 private $mRevdel;
39 private $mInvert;
40 private $mFilename;
42 private $mAllowed;
43 private $mCanView;
44 private $mComment;
45 private $mToken;
46
48 private $mTargetObj;
53
54 function __construct() {
55 parent::__construct( 'Undelete', 'deletedhistory' );
56 }
57
58 public function doesWrites() {
59 return true;
60 }
61
62 function loadRequest( $par ) {
63 $request = $this->getRequest();
64 $user = $this->getUser();
65
66 $this->mAction = $request->getVal( 'action' );
67 if ( $par !== null && $par !== '' ) {
68 $this->mTarget = $par;
69 } else {
70 $this->mTarget = $request->getVal( 'target' );
71 }
72
73 $this->mTargetObj = null;
74
75 if ( $this->mTarget !== null && $this->mTarget !== '' ) {
76 $this->mTargetObj = Title::newFromText( $this->mTarget );
77 }
78
79 $this->mSearchPrefix = $request->getText( 'prefix' );
80 $time = $request->getVal( 'timestamp' );
81 $this->mTimestamp = $time ? wfTimestamp( TS_MW, $time ) : '';
82 $this->mFilename = $request->getVal( 'file' );
83
84 $posted = $request->wasPosted() &&
85 $user->matchEditToken( $request->getVal( 'wpEditToken' ) );
86 $this->mRestore = $request->getCheck( 'restore' ) && $posted;
87 $this->mRevdel = $request->getCheck( 'revdel' ) && $posted;
88 $this->mInvert = $request->getCheck( 'invert' ) && $posted;
89 $this->mPreview = $request->getCheck( 'preview' ) && $posted;
90 $this->mDiff = $request->getCheck( 'diff' );
91 $this->mDiffOnly = $request->getBool( 'diffonly', $this->getUser()->getOption( 'diffonly' ) );
92 $this->mComment = $request->getText( 'wpComment' );
93 $this->mUnsuppress = $request->getVal( 'wpUnsuppress' ) && $user->isAllowed( 'suppressrevision' );
94 $this->mToken = $request->getVal( 'token' );
95
96 if ( $this->isAllowed( 'undelete' ) && !$user->isBlocked() ) {
97 $this->mAllowed = true; // user can restore
98 $this->mCanView = true; // user can view content
99 } elseif ( $this->isAllowed( 'deletedtext' ) ) {
100 $this->mAllowed = false; // user cannot restore
101 $this->mCanView = true; // user can view content
102 $this->mRestore = false;
103 } else { // user can only view the list of revisions
104 $this->mAllowed = false;
105 $this->mCanView = false;
106 $this->mTimestamp = '';
107 $this->mRestore = false;
108 }
109
110 if ( $this->mRestore || $this->mInvert ) {
111 $timestamps = [];
112 $this->mFileVersions = [];
113 foreach ( $request->getValues() as $key => $val ) {
114 $matches = [];
115 if ( preg_match( '/^ts(\d{14})$/', $key, $matches ) ) {
116 array_push( $timestamps, $matches[1] );
117 }
118
119 if ( preg_match( '/^fileid(\d+)$/', $key, $matches ) ) {
120 $this->mFileVersions[] = intval( $matches[1] );
121 }
122 }
123 rsort( $timestamps );
124 $this->mTargetTimestamp = $timestamps;
125 }
126 }
127
136 protected function isAllowed( $permission, User $user = null ) {
137 $user = $user ?: $this->getUser();
138 if ( $this->mTargetObj !== null ) {
139 return $this->mTargetObj->userCan( $permission, $user );
140 } else {
141 return $user->isAllowed( $permission );
142 }
143 }
144
145 function userCanExecute( User $user ) {
146 return $this->isAllowed( $this->mRestriction, $user );
147 }
148
149 function execute( $par ) {
151
152 $user = $this->getUser();
153
154 $this->setHeaders();
155 $this->outputHeader();
156
157 $this->loadRequest( $par );
158 $this->checkPermissions(); // Needs to be after mTargetObj is set
159
160 $out = $this->getOutput();
161
162 if ( is_null( $this->mTargetObj ) ) {
163 $out->addWikiMsg( 'undelete-header' );
164
165 # Not all users can just browse every deleted page from the list
166 if ( $user->isAllowed( 'browsearchive' ) ) {
167 $this->showSearchForm();
168 }
169
170 return;
171 }
172
173 $this->addHelpLink( 'Help:Undelete' );
174 if ( $this->mAllowed ) {
175 $out->setPageTitle( $this->msg( 'undeletepage' ) );
176 } else {
177 $out->setPageTitle( $this->msg( 'viewdeletedpage' ) );
178 }
179
180 $this->getSkin()->setRelevantTitle( $this->mTargetObj );
181
182 if ( $this->mTimestamp !== '' ) {
183 $this->showRevision( $this->mTimestamp );
184 } elseif ( $this->mFilename !== null && $this->mTargetObj->inNamespace( NS_FILE ) ) {
185 $file = new ArchivedFile( $this->mTargetObj, '', $this->mFilename );
186 // Check if user is allowed to see this file
187 if ( !$file->exists() ) {
188 $out->addWikiMsg( 'filedelete-nofile', $this->mFilename );
189 } elseif ( !$file->userCan( File::DELETED_FILE, $user ) ) {
190 if ( $file->isDeleted( File::DELETED_RESTRICTED ) ) {
191 throw new PermissionsError( 'suppressrevision' );
192 } else {
193 throw new PermissionsError( 'deletedtext' );
194 }
195 } elseif ( !$user->matchEditToken( $this->mToken, $this->mFilename ) ) {
196 $this->showFileConfirmationForm( $this->mFilename );
197 } else {
198 $this->showFile( $this->mFilename );
199 }
200 } elseif ( $this->mAction === "submit" ) {
201 if ( $this->mRestore ) {
202 $this->undelete();
203 } elseif ( $this->mRevdel ) {
204 $this->redirectToRevDel();
205 }
206
207 } else {
208 $this->showHistory();
209 }
210 }
211
216 private function redirectToRevDel() {
217 $archive = new PageArchive( $this->mTargetObj );
218
219 $revisions = [];
220
221 foreach ( $this->getRequest()->getValues() as $key => $val ) {
222 $matches = [];
223 if ( preg_match( "/^ts(\d{14})$/", $key, $matches ) ) {
224 $revisions[ $archive->getRevision( $matches[1] )->getId() ] = 1;
225 }
226 }
227 $query = [
228 "type" => "revision",
229 "ids" => $revisions,
230 "target" => $this->mTargetObj->getPrefixedText()
231 ];
232 $url = SpecialPage::getTitleFor( 'Revisiondelete' )->getFullURL( $query );
233 $this->getOutput()->redirect( $url );
234 }
235
236 function showSearchForm() {
237 $out = $this->getOutput();
238 $out->setPageTitle( $this->msg( 'undelete-search-title' ) );
239 $out->addHTML(
240 Xml::openElement( 'form', [ 'method' => 'get', 'action' => wfScript() ] ) .
241 Xml::fieldset( $this->msg( 'undelete-search-box' )->text() ) .
242 Html::hidden( 'title', $this->getPageTitle()->getPrefixedDBkey() ) .
243 Html::hidden( 'fuzzy', $this->getRequest()->getVal( 'fuzzy' ) ) .
244 Html::rawElement(
245 'label',
246 [ 'for' => 'prefix' ],
247 $this->msg( 'undelete-search-prefix' )->parse()
248 ) .
249 Xml::input(
250 'prefix',
251 20,
252 $this->mSearchPrefix,
253 [ 'id' => 'prefix', 'autofocus' => '' ]
254 ) .
255 ' ' .
256 Xml::submitButton(
257 $this->msg( 'undelete-search-submit' )->text(),
258 [ 'id' => 'searchUndelete' ]
259 ) .
260 Xml::closeElement( 'fieldset' ) .
261 Xml::closeElement( 'form' )
262 );
263
264 # List undeletable articles
265 if ( $this->mSearchPrefix ) {
266 // For now, we enable search engine match only when specifically asked to
267 // by using fuzzy=1 parameter.
268 if ( $this->getRequest()->getVal( "fuzzy", false ) ) {
269 $result = PageArchive::listPagesBySearch( $this->mSearchPrefix );
270 } else {
271 $result = PageArchive::listPagesByPrefix( $this->mSearchPrefix );
272 }
273 $this->showList( $result );
274 }
275 }
276
283 private function showList( $result ) {
284 $out = $this->getOutput();
285
286 if ( $result->numRows() == 0 ) {
287 $out->addWikiMsg( 'undelete-no-results' );
288
289 return false;
290 }
291
292 $out->addWikiMsg( 'undeletepagetext', $this->getLanguage()->formatNum( $result->numRows() ) );
293
295 $undelete = $this->getPageTitle();
296 $out->addHTML( "<ul id='undeleteResultsList'>\n" );
297 foreach ( $result as $row ) {
298 $title = Title::makeTitleSafe( $row->ar_namespace, $row->ar_title );
299 if ( $title !== null ) {
300 $item = $linkRenderer->makeKnownLink(
301 $undelete,
302 $title->getPrefixedText(),
303 [],
304 [ 'target' => $title->getPrefixedText() ]
305 );
306 } else {
307 // The title is no longer valid, show as text
308 $item = Html::element(
309 'span',
310 [ 'class' => 'mw-invalidtitle' ],
312 $this->getContext(),
313 $row->ar_namespace,
314 $row->ar_title
315 )
316 );
317 }
318 $revs = $this->msg( 'undeleterevisions' )->numParams( $row->count )->parse();
319 $out->addHTML( "<li class='undeleteResult'>{$item} ({$revs})</li>\n" );
320 }
321 $result->free();
322 $out->addHTML( "</ul>\n" );
323
324 return true;
325 }
326
327 private function showRevision( $timestamp ) {
328 if ( !preg_match( '/[0-9]{14}/', $timestamp ) ) {
329 return;
330 }
331
332 $archive = new PageArchive( $this->mTargetObj, $this->getConfig() );
333 if ( !Hooks::run( 'UndeleteForm::showRevision', [ &$archive, $this->mTargetObj ] ) ) {
334 return;
335 }
336 $rev = $archive->getRevision( $timestamp );
337
338 $out = $this->getOutput();
339 $user = $this->getUser();
340
341 if ( !$rev ) {
342 $out->addWikiMsg( 'undeleterevision-missing' );
343
344 return;
345 }
346
347 if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
348 if ( !$rev->userCan( Revision::DELETED_TEXT, $user ) ) {
349 $out->wrapWikiMsg(
350 "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
351 $rev->isDeleted( Revision::DELETED_RESTRICTED ) ?
352 'rev-suppressed-text-permission' : 'rev-deleted-text-permission'
353 );
354
355 return;
356 }
357
358 $out->wrapWikiMsg(
359 "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
360 $rev->isDeleted( Revision::DELETED_RESTRICTED ) ?
361 'rev-suppressed-text-view' : 'rev-deleted-text-view'
362 );
363 $out->addHTML( '<br />' );
364 // and we are allowed to see...
365 }
366
367 if ( $this->mDiff ) {
368 $previousRev = $archive->getPreviousRevision( $timestamp );
369 if ( $previousRev ) {
370 $this->showDiff( $previousRev, $rev );
371 if ( $this->mDiffOnly ) {
372 return;
373 }
374
375 $out->addHTML( '<hr />' );
376 } else {
377 $out->addWikiMsg( 'undelete-nodiff' );
378 }
379 }
380
381 $link = $this->getLinkRenderer()->makeKnownLink(
382 $this->getPageTitle( $this->mTargetObj->getPrefixedDBkey() ),
383 $this->mTargetObj->getPrefixedText()
384 );
385
386 $lang = $this->getLanguage();
387
388 // date and time are separate parameters to facilitate localisation.
389 // $time is kept for backward compat reasons.
390 $time = $lang->userTimeAndDate( $timestamp, $user );
391 $d = $lang->userDate( $timestamp, $user );
392 $t = $lang->userTime( $timestamp, $user );
393 $userLink = Linker::revUserTools( $rev );
394
395 $content = $rev->getContent( Revision::FOR_THIS_USER, $user );
396
397 $isText = ( $content instanceof TextContent );
398
399 if ( $this->mPreview || $isText ) {
400 $openDiv = '<div id="mw-undelete-revision" class="mw-warning">';
401 } else {
402 $openDiv = '<div id="mw-undelete-revision">';
403 }
404 $out->addHTML( $openDiv );
405
406 // Revision delete links
407 if ( !$this->mDiff ) {
408 $revdel = Linker::getRevDeleteLink( $user, $rev, $this->mTargetObj );
409 if ( $revdel ) {
410 $out->addHTML( "$revdel " );
411 }
412 }
413
414 $out->addHTML( $this->msg( 'undelete-revision' )->rawParams( $link )->params(
415 $time )->rawParams( $userLink )->params( $d, $t )->parse() . '</div>' );
416
417 if ( !Hooks::run( 'UndeleteShowRevision', [ $this->mTargetObj, $rev ] ) ) {
418 return;
419 }
420
421 if ( ( $this->mPreview || !$isText ) && $content ) {
422 // NOTE: non-text content has no source view, so always use rendered preview
423
424 // Hide [edit]s
425 $popts = $out->parserOptions();
426 $popts->setEditSection( false );
427
428 $pout = $content->getParserOutput( $this->mTargetObj, $rev->getId(), $popts, true );
429 $out->addParserOutput( $pout );
430 }
431
432 if ( $isText ) {
433 // source view for textual content
434 $sourceView = Xml::element(
435 'textarea',
436 [
437 'readonly' => 'readonly',
438 'cols' => 80,
439 'rows' => 25
440 ],
441 $content->getNativeData() . "\n"
442 );
443
444 $previewButton = Xml::element( 'input', [
445 'type' => 'submit',
446 'name' => 'preview',
447 'value' => $this->msg( 'showpreview' )->text()
448 ] );
449 } else {
450 $sourceView = '';
451 $previewButton = '';
452 }
453
454 $diffButton = Xml::element( 'input', [
455 'name' => 'diff',
456 'type' => 'submit',
457 'value' => $this->msg( 'showdiff' )->text() ] );
458
459 $out->addHTML(
460 $sourceView .
461 Xml::openElement( 'div', [
462 'style' => 'clear: both' ] ) .
463 Xml::openElement( 'form', [
464 'method' => 'post',
465 'action' => $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] ) ] ) .
466 Xml::element( 'input', [
467 'type' => 'hidden',
468 'name' => 'target',
469 'value' => $this->mTargetObj->getPrefixedDBkey() ] ) .
470 Xml::element( 'input', [
471 'type' => 'hidden',
472 'name' => 'timestamp',
473 'value' => $timestamp ] ) .
474 Xml::element( 'input', [
475 'type' => 'hidden',
476 'name' => 'wpEditToken',
477 'value' => $user->getEditToken() ] ) .
478 $previewButton .
479 $diffButton .
480 Xml::closeElement( 'form' ) .
481 Xml::closeElement( 'div' )
482 );
483 }
484
493 function showDiff( $previousRev, $currentRev ) {
494 $diffContext = clone $this->getContext();
495 $diffContext->setTitle( $currentRev->getTitle() );
496 $diffContext->setWikiPage( WikiPage::factory( $currentRev->getTitle() ) );
497
498 $diffEngine = $currentRev->getContentHandler()->createDifferenceEngine( $diffContext );
499 $diffEngine->showDiffStyle();
500
501 $formattedDiff = $diffEngine->generateContentDiffBody(
502 $previousRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ),
503 $currentRev->getContent( Revision::FOR_THIS_USER, $this->getUser() )
504 );
505
506 $formattedDiff = $diffEngine->addHeader(
507 $formattedDiff,
508 $this->diffHeader( $previousRev, 'o' ),
509 $this->diffHeader( $currentRev, 'n' )
510 );
511
512 $this->getOutput()->addHTML( "<div>$formattedDiff</div>\n" );
513 }
514
520 private function diffHeader( $rev, $prefix ) {
521 $isDeleted = !( $rev->getId() && $rev->getTitle() );
522 if ( $isDeleted ) {
524 $targetPage = $this->getPageTitle();
525 $targetQuery = [
526 'target' => $this->mTargetObj->getPrefixedText(),
527 'timestamp' => wfTimestamp( TS_MW, $rev->getTimestamp() )
528 ];
529 } else {
531 $targetPage = $rev->getTitle();
532 $targetQuery = [ 'oldid' => $rev->getId() ];
533 }
534
535 // Add show/hide deletion links if available
536 $user = $this->getUser();
537 $lang = $this->getLanguage();
538 $rdel = Linker::getRevDeleteLink( $user, $rev, $this->mTargetObj );
539
540 if ( $rdel ) {
541 $rdel = " $rdel";
542 }
543
544 $minor = $rev->isMinor() ? ChangesList::flag( 'minor' ) : '';
545
546 $tags = wfGetDB( DB_REPLICA )->selectField(
547 'tag_summary',
548 'ts_tags',
549 [ 'ts_rev_id' => $rev->getId() ],
550 __METHOD__
551 );
552 $tagSummary = ChangeTags::formatSummaryRow( $tags, 'deleteddiff', $this->getContext() );
553
554 // FIXME This is reimplementing DifferenceEngine#getRevisionHeader
555 // and partially #showDiffPage, but worse
556 return '<div id="mw-diff-' . $prefix . 'title1"><strong>' .
557 $this->getLinkRenderer()->makeLink(
558 $targetPage,
559 $this->msg(
560 'revisionasof',
561 $lang->userTimeAndDate( $rev->getTimestamp(), $user ),
562 $lang->userDate( $rev->getTimestamp(), $user ),
563 $lang->userTime( $rev->getTimestamp(), $user )
564 )->text(),
565 [],
566 $targetQuery
567 ) .
568 '</strong></div>' .
569 '<div id="mw-diff-' . $prefix . 'title2">' .
570 Linker::revUserTools( $rev ) . '<br />' .
571 '</div>' .
572 '<div id="mw-diff-' . $prefix . 'title3">' .
573 $minor . Linker::revComment( $rev ) . $rdel . '<br />' .
574 '</div>' .
575 '<div id="mw-diff-' . $prefix . 'title5">' .
576 $tagSummary[0] . '<br />' .
577 '</div>';
578 }
579
584 private function showFileConfirmationForm( $key ) {
585 $out = $this->getOutput();
586 $lang = $this->getLanguage();
587 $user = $this->getUser();
588 $file = new ArchivedFile( $this->mTargetObj, '', $this->mFilename );
589 $out->addWikiMsg( 'undelete-show-file-confirm',
590 $this->mTargetObj->getText(),
591 $lang->userDate( $file->getTimestamp(), $user ),
592 $lang->userTime( $file->getTimestamp(), $user ) );
593 $out->addHTML(
594 Xml::openElement( 'form', [
595 'method' => 'POST',
596 'action' => $this->getPageTitle()->getLocalURL( [
597 'target' => $this->mTarget,
598 'file' => $key,
599 'token' => $user->getEditToken( $key ),
600 ] ),
601 ]
602 ) .
603 Xml::submitButton( $this->msg( 'undelete-show-file-submit' )->text() ) .
604 '</form>'
605 );
606 }
607
612 private function showFile( $key ) {
613 $this->getOutput()->disable();
614
615 # We mustn't allow the output to be CDN cached, otherwise
616 # if an admin previews a deleted image, and it's cached, then
617 # a user without appropriate permissions can toddle off and
618 # nab the image, and CDN will serve it
619 $response = $this->getRequest()->response();
620 $response->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
621 $response->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
622 $response->header( 'Pragma: no-cache' );
623
624 $repo = RepoGroup::singleton()->getLocalRepo();
625 $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
626 $repo->streamFile( $path );
627 }
628
629 protected function showHistory() {
630 $this->checkReadOnly();
631
632 $out = $this->getOutput();
633 if ( $this->mAllowed ) {
634 $out->addModules( 'mediawiki.special.undelete' );
635 }
636 $out->wrapWikiMsg(
637 "<div class='mw-undelete-pagetitle'>\n$1\n</div>\n",
638 [ 'undeletepagetitle', wfEscapeWikiText( $this->mTargetObj->getPrefixedText() ) ]
639 );
640
641 $archive = new PageArchive( $this->mTargetObj, $this->getConfig() );
642 Hooks::run( 'UndeleteForm::showHistory', [ &$archive, $this->mTargetObj ] );
643 /*
644 $text = $archive->getLastRevisionText();
645 if( is_null( $text ) ) {
646 $out->addWikiMsg( 'nohistory' );
647 return;
648 }
649 */
650 $out->addHTML( '<div class="mw-undelete-history">' );
651 if ( $this->mAllowed ) {
652 $out->addWikiMsg( 'undeletehistory' );
653 $out->addWikiMsg( 'undeleterevdel' );
654 } else {
655 $out->addWikiMsg( 'undeletehistorynoadmin' );
656 }
657 $out->addHTML( '</div>' );
658
659 # List all stored revisions
660 $revisions = $archive->listRevisions();
661 $files = $archive->listFiles();
662
663 $haveRevisions = $revisions && $revisions->numRows() > 0;
664 $haveFiles = $files && $files->numRows() > 0;
665
666 # Batch existence check on user and talk pages
667 if ( $haveRevisions ) {
668 $batch = new LinkBatch();
669 foreach ( $revisions as $row ) {
670 $batch->addObj( Title::makeTitleSafe( NS_USER, $row->ar_user_text ) );
671 $batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->ar_user_text ) );
672 }
673 $batch->execute();
674 $revisions->seek( 0 );
675 }
676 if ( $haveFiles ) {
677 $batch = new LinkBatch();
678 foreach ( $files as $row ) {
679 $batch->addObj( Title::makeTitleSafe( NS_USER, $row->fa_user_text ) );
680 $batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->fa_user_text ) );
681 }
682 $batch->execute();
683 $files->seek( 0 );
684 }
685
686 if ( $this->mAllowed ) {
687 $action = $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] );
688 # Start the form here
689 $top = Xml::openElement(
690 'form',
691 [ 'method' => 'post', 'action' => $action, 'id' => 'undelete' ]
692 );
693 $out->addHTML( $top );
694 }
695
696 # Show relevant lines from the deletion log:
697 $deleteLogPage = new LogPage( 'delete' );
698 $out->addHTML( Xml::element( 'h2', null, $deleteLogPage->getName()->text() ) . "\n" );
699 LogEventsList::showLogExtract( $out, 'delete', $this->mTargetObj );
700 # Show relevant lines from the suppression log:
701 $suppressLogPage = new LogPage( 'suppress' );
702 if ( $this->getUser()->isAllowed( 'suppressionlog' ) ) {
703 $out->addHTML( Xml::element( 'h2', null, $suppressLogPage->getName()->text() ) . "\n" );
704 LogEventsList::showLogExtract( $out, 'suppress', $this->mTargetObj );
705 }
706
707 if ( $this->mAllowed && ( $haveRevisions || $haveFiles ) ) {
708 # Format the user-visible controls (comment field, submission button)
709 # in a nice little table
710 if ( $this->getUser()->isAllowed( 'suppressrevision' ) ) {
711 $unsuppressBox =
712 "<tr>
713 <td>&#160;</td>
714 <td class='mw-input'>" .
715 Xml::checkLabel( $this->msg( 'revdelete-unsuppress' )->text(),
716 'wpUnsuppress', 'mw-undelete-unsuppress', $this->mUnsuppress ) .
717 "</td>
718 </tr>";
719 } else {
720 $unsuppressBox = '';
721 }
722
723 $table = Xml::fieldset( $this->msg( 'undelete-fieldset-title' )->text() ) .
724 Xml::openElement( 'table', [ 'id' => 'mw-undelete-table' ] ) .
725 "<tr>
726 <td colspan='2' class='mw-undelete-extrahelp'>" .
727 $this->msg( 'undeleteextrahelp' )->parseAsBlock() .
728 "</td>
729 </tr>
730 <tr>
731 <td class='mw-label'>" .
732 Xml::label( $this->msg( 'undeletecomment' )->text(), 'wpComment' ) .
733 "</td>
734 <td class='mw-input'>" .
735 Xml::input(
736 'wpComment',
737 50,
738 $this->mComment,
739 [ 'id' => 'wpComment', 'autofocus' => '' ]
740 ) .
741 "</td>
742 </tr>
743 <tr>
744 <td>&#160;</td>
745 <td class='mw-submit'>" .
746 Xml::submitButton(
747 $this->msg( 'undeletebtn' )->text(),
748 [ 'name' => 'restore', 'id' => 'mw-undelete-submit' ]
749 ) . ' ' .
750 Xml::submitButton(
751 $this->msg( 'undeleteinvert' )->text(),
752 [ 'name' => 'invert', 'id' => 'mw-undelete-invert' ]
753 ) .
754 "</td>
755 </tr>" .
756 $unsuppressBox .
757 Xml::closeElement( 'table' ) .
758 Xml::closeElement( 'fieldset' );
759
760 $out->addHTML( $table );
761 }
762
763 $out->addHTML( Xml::element( 'h2', null, $this->msg( 'history' )->text() ) . "\n" );
764
765 if ( $haveRevisions ) {
766 # Show the page's stored (deleted) history
767
768 if ( $this->getUser()->isAllowed( 'deleterevision' ) ) {
769 $out->addHTML( Html::element(
770 'button',
771 [
772 'name' => 'revdel',
773 'type' => 'submit',
774 'class' => 'deleterevision-log-submit mw-log-deleterevision-button'
775 ],
776 $this->msg( 'showhideselectedversions' )->text()
777 ) . "\n" );
778 }
779
780 $out->addHTML( '<ul>' );
781 $remaining = $revisions->numRows();
782 $earliestLiveTime = $this->mTargetObj->getEarliestRevTime();
783
784 foreach ( $revisions as $row ) {
785 $remaining--;
786 $out->addHTML( $this->formatRevisionRow( $row, $earliestLiveTime, $remaining ) );
787 }
788 $revisions->free();
789 $out->addHTML( '</ul>' );
790 } else {
791 $out->addWikiMsg( 'nohistory' );
792 }
793
794 if ( $haveFiles ) {
795 $out->addHTML( Xml::element( 'h2', null, $this->msg( 'filehist' )->text() ) . "\n" );
796 $out->addHTML( '<ul>' );
797 foreach ( $files as $row ) {
798 $out->addHTML( $this->formatFileRow( $row ) );
799 }
800 $files->free();
801 $out->addHTML( '</ul>' );
802 }
803
804 if ( $this->mAllowed ) {
805 # Slip in the hidden controls here
806 $misc = Html::hidden( 'target', $this->mTarget );
807 $misc .= Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() );
808 $misc .= Xml::closeElement( 'form' );
809 $out->addHTML( $misc );
810 }
811
812 return true;
813 }
814
815 protected function formatRevisionRow( $row, $earliestLiveTime, $remaining ) {
817 [
818 'title' => $this->mTargetObj
819 ] );
820
821 $revTextSize = '';
822 $ts = wfTimestamp( TS_MW, $row->ar_timestamp );
823 // Build checkboxen...
824 if ( $this->mAllowed ) {
825 if ( $this->mInvert ) {
826 if ( in_array( $ts, $this->mTargetTimestamp ) ) {
827 $checkBox = Xml::check( "ts$ts" );
828 } else {
829 $checkBox = Xml::check( "ts$ts", true );
830 }
831 } else {
832 $checkBox = Xml::check( "ts$ts" );
833 }
834 } else {
835 $checkBox = '';
836 }
837
838 // Build page & diff links...
839 $user = $this->getUser();
840 if ( $this->mCanView ) {
841 $titleObj = $this->getPageTitle();
842 # Last link
843 if ( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
844 $pageLink = htmlspecialchars( $this->getLanguage()->userTimeAndDate( $ts, $user ) );
845 $last = $this->msg( 'diff' )->escaped();
846 } elseif ( $remaining > 0 || ( $earliestLiveTime && $ts > $earliestLiveTime ) ) {
847 $pageLink = $this->getPageLink( $rev, $titleObj, $ts );
848 $last = $this->getLinkRenderer()->makeKnownLink(
849 $titleObj,
850 $this->msg( 'diff' )->text(),
851 [],
852 [
853 'target' => $this->mTargetObj->getPrefixedText(),
854 'timestamp' => $ts,
855 'diff' => 'prev'
856 ]
857 );
858 } else {
859 $pageLink = $this->getPageLink( $rev, $titleObj, $ts );
860 $last = $this->msg( 'diff' )->escaped();
861 }
862 } else {
863 $pageLink = htmlspecialchars( $this->getLanguage()->userTimeAndDate( $ts, $user ) );
864 $last = $this->msg( 'diff' )->escaped();
865 }
866
867 // User links
868 $userLink = Linker::revUserTools( $rev );
869
870 // Minor edit
871 $minor = $rev->isMinor() ? ChangesList::flag( 'minor' ) : '';
872
873 // Revision text size
874 $size = $row->ar_len;
875 if ( !is_null( $size ) ) {
876 $revTextSize = Linker::formatRevisionSize( $size );
877 }
878
879 // Edit summary
880 $comment = Linker::revComment( $rev );
881
882 // Tags
883 $attribs = [];
884 list( $tagSummary, $classes ) = ChangeTags::formatSummaryRow(
885 $row->ts_tags,
886 'deletedhistory',
887 $this->getContext()
888 );
889 if ( $classes ) {
890 $attribs['class'] = implode( ' ', $classes );
891 }
892
893 $revisionRow = $this->msg( 'undelete-revision-row2' )
894 ->rawParams(
895 $checkBox,
896 $last,
897 $pageLink,
898 $userLink,
899 $minor,
900 $revTextSize,
901 $comment,
902 $tagSummary
903 )
904 ->escaped();
905
906 return Xml::tags( 'li', $attribs, $revisionRow ) . "\n";
907 }
908
909 private function formatFileRow( $row ) {
910 $file = ArchivedFile::newFromRow( $row );
911 $ts = wfTimestamp( TS_MW, $row->fa_timestamp );
912 $user = $this->getUser();
913
914 $checkBox = '';
915 if ( $this->mCanView && $row->fa_storage_key ) {
916 if ( $this->mAllowed ) {
917 $checkBox = Xml::check( 'fileid' . $row->fa_id );
918 }
919 $key = urlencode( $row->fa_storage_key );
920 $pageLink = $this->getFileLink( $file, $this->getPageTitle(), $ts, $key );
921 } else {
922 $pageLink = $this->getLanguage()->userTimeAndDate( $ts, $user );
923 }
924 $userLink = $this->getFileUser( $file );
925 $data = $this->msg( 'widthheight' )->numParams( $row->fa_width, $row->fa_height )->text();
926 $bytes = $this->msg( 'parentheses' )
927 ->rawParams( $this->msg( 'nbytes' )->numParams( $row->fa_size )->text() )
928 ->plain();
929 $data = htmlspecialchars( $data . ' ' . $bytes );
930 $comment = $this->getFileComment( $file );
931
932 // Add show/hide deletion links if available
933 $canHide = $this->isAllowed( 'deleterevision' );
934 if ( $canHide || ( $file->getVisibility() && $this->isAllowed( 'deletedhistory' ) ) ) {
935 if ( !$file->userCan( File::DELETED_RESTRICTED, $user ) ) {
936 // Revision was hidden from sysops
937 $revdlink = Linker::revDeleteLinkDisabled( $canHide );
938 } else {
939 $query = [
940 'type' => 'filearchive',
941 'target' => $this->mTargetObj->getPrefixedDBkey(),
942 'ids' => $row->fa_id
943 ];
944 $revdlink = Linker::revDeleteLink( $query,
945 $file->isDeleted( File::DELETED_RESTRICTED ), $canHide );
946 }
947 } else {
948 $revdlink = '';
949 }
950
951 return "<li>$checkBox $revdlink $pageLink . . $userLink $data $comment</li>\n";
952 }
953
962 function getPageLink( $rev, $titleObj, $ts ) {
963 $user = $this->getUser();
964 $time = $this->getLanguage()->userTimeAndDate( $ts, $user );
965
966 if ( !$rev->userCan( Revision::DELETED_TEXT, $user ) ) {
967 return '<span class="history-deleted">' . $time . '</span>';
968 }
969
970 $link = $this->getLinkRenderer()->makeKnownLink(
971 $titleObj,
972 $time,
973 [],
974 [
975 'target' => $this->mTargetObj->getPrefixedText(),
976 'timestamp' => $ts
977 ]
978 );
979
980 if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
981 $link = '<span class="history-deleted">' . $link . '</span>';
982 }
983
984 return $link;
985 }
986
997 function getFileLink( $file, $titleObj, $ts, $key ) {
998 $user = $this->getUser();
999 $time = $this->getLanguage()->userTimeAndDate( $ts, $user );
1000
1001 if ( !$file->userCan( File::DELETED_FILE, $user ) ) {
1002 return '<span class="history-deleted">' . $time . '</span>';
1003 }
1004
1005 $link = $this->getLinkRenderer()->makeKnownLink(
1006 $titleObj,
1007 $time,
1008 [],
1009 [
1010 'target' => $this->mTargetObj->getPrefixedText(),
1011 'file' => $key,
1012 'token' => $user->getEditToken( $key )
1013 ]
1014 );
1015
1016 if ( $file->isDeleted( File::DELETED_FILE ) ) {
1017 $link = '<span class="history-deleted">' . $link . '</span>';
1018 }
1019
1020 return $link;
1021 }
1022
1029 function getFileUser( $file ) {
1030 if ( !$file->userCan( File::DELETED_USER, $this->getUser() ) ) {
1031 return '<span class="history-deleted">' .
1032 $this->msg( 'rev-deleted-user' )->escaped() .
1033 '</span>';
1034 }
1035
1036 $link = Linker::userLink( $file->getRawUser(), $file->getRawUserText() ) .
1037 Linker::userToolLinks( $file->getRawUser(), $file->getRawUserText() );
1038
1039 if ( $file->isDeleted( File::DELETED_USER ) ) {
1040 $link = '<span class="history-deleted">' . $link . '</span>';
1041 }
1042
1043 return $link;
1044 }
1045
1052 function getFileComment( $file ) {
1053 if ( !$file->userCan( File::DELETED_COMMENT, $this->getUser() ) ) {
1054 return '<span class="history-deleted"><span class="comment">' .
1055 $this->msg( 'rev-deleted-comment' )->escaped() . '</span></span>';
1056 }
1057
1058 $link = Linker::commentBlock( $file->getRawDescription() );
1059
1060 if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
1061 $link = '<span class="history-deleted">' . $link . '</span>';
1062 }
1063
1064 return $link;
1065 }
1066
1067 function undelete() {
1068 if ( $this->getConfig()->get( 'UploadMaintenance' )
1069 && $this->mTargetObj->getNamespace() == NS_FILE
1070 ) {
1071 throw new ErrorPageError( 'undelete-error', 'filedelete-maintenance' );
1072 }
1073
1074 $this->checkReadOnly();
1075
1076 $out = $this->getOutput();
1077 $archive = new PageArchive( $this->mTargetObj, $this->getConfig() );
1078 Hooks::run( 'UndeleteForm::undelete', [ &$archive, $this->mTargetObj ] );
1079 $ok = $archive->undelete(
1080 $this->mTargetTimestamp,
1081 $this->mComment,
1082 $this->mFileVersions,
1083 $this->mUnsuppress,
1084 $this->getUser()
1085 );
1086
1087 if ( is_array( $ok ) ) {
1088 if ( $ok[1] ) { // Undeleted file count
1089 Hooks::run( 'FileUndeleteComplete', [
1090 $this->mTargetObj, $this->mFileVersions,
1091 $this->getUser(), $this->mComment ] );
1092 }
1093
1094 $link = $this->getLinkRenderer()->makeKnownLink( $this->mTargetObj );
1095 $out->addHTML( $this->msg( 'undeletedpage' )->rawParams( $link )->parse() );
1096 } else {
1097 $out->setPageTitle( $this->msg( 'undelete-error' ) );
1098 }
1099
1100 // Show revision undeletion warnings and errors
1101 $status = $archive->getRevisionStatus();
1102 if ( $status && !$status->isGood() ) {
1103 $out->wrapWikiMsg(
1104 "<div class=\"error\" id=\"mw-error-cannotundelete\">\n$1\n</div>",
1105 'cannotundelete'
1106 );
1107 }
1108
1109 // Show file undeletion warnings and errors
1110 $status = $archive->getFileStatus();
1111 if ( $status && !$status->isGood() ) {
1112 $out->addWikiText( '<div class="error">' .
1113 $status->getWikiText(
1114 'undelete-error-short',
1115 'undelete-error-long'
1116 ) . '</div>'
1117 );
1118 }
1119 }
1120
1129 public function prefixSearchSubpages( $search, $limit, $offset ) {
1130 return $this->prefixSearchString( $search, $limit, $offset );
1131 }
1132
1133 protected function getGroupName() {
1134 return 'pagetools';
1135 }
1136}
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Class representing a row of the 'filearchive' table.
static newFromRow( $row)
Loads a file object from the filearchive table.
static formatSummaryRow( $tags, $page, IContextSource $context=null)
Creates HTML for the given tags.
static flag( $flag, IContextSource $context=null)
Make an "<abbr>" element for a given change flag.
An error page which can definitely be safely rendered using the OutputPage.
const DELETED_COMMENT
Definition File.php:54
const DELETED_RESTRICTED
Definition File.php:56
const DELETED_FILE
Definition File.php:53
const DELETED_USER
Definition File.php:55
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition LinkBatch.php:34
static userLink( $userId, $userName, $altUserName=false)
Make user link (or user contributions for unregistered users)
Definition Linker.php:888
static revDeleteLinkDisabled( $delete=true)
Creates a dead (show/hide) link for deleting revisions/log entries.
Definition Linker.php:2080
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
static commentBlock( $comment, $title=null, $local=false, $wikiId=null)
Wrap a comment in standard punctuation and formatting if it's non-empty, otherwise return empty strin...
Definition Linker.php:1439
static getInvalidTitleDescription(IContextSource $context, $namespace, $title)
Get a message saying that an invalid title was encountered.
Definition Linker.php:204
static revUserTools( $rev, $isPublic=false)
Generate a user tool link cluster if the current user is allowed to view it.
Definition Linker.php:1055
static userToolLinks( $userId, $userText, $redContribsWhenNoEdits=false, $flags=0, $edits=null)
Generate standard user tool links (talk, contributions, block link, etc.)
Definition Linker.php:921
static formatRevisionSize( $size)
Definition Linker.php:1487
static revDeleteLink( $query=[], $restricted=false, $delete=true)
Creates a (show/hide) link for deleting revisions/log entries.
Definition Linker.php:2058
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:2017
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Class to simplify the use of log pages.
Definition LogPage.php:31
MediaWikiServices is the service locator for the application scope of MediaWiki.
Used to show archived pages and eventually restore them.
static listPagesBySearch( $term)
List deleted pages recorded in the archive matching the given term, using search engine archive.
static listPagesByPrefix( $prefix)
List deleted pages recorded in the archive table matching the given title prefix.
Show an error when a user tries to do something they do not have the necessary permissions for.
static singleton()
Get a RepoGroup instance.
Definition RepoGroup.php:59
static newFromArchiveRow( $row, $overrides=[])
Make a fake revision object from an archive table row.
Definition Revision.php:189
const DELETED_TEXT
Definition Revision.php:90
const DELETED_RESTRICTED
Definition Revision.php:93
const FOR_THIS_USER
Definition Revision.php:99
Parent class for all special pages.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getOutput()
Get the OutputPage being used for this instance.
getUser()
Shortcut to get the User executing this instance.
getSkin()
Shortcut to get the skin being used for this instance.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
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,...
getContext()
Gets the context this SpecialPage is executed in.
getConfig()
Shortcut to get main config object.
getRequest()
Get the WebRequest being used for this instance.
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
getPageTitle( $subpage=false)
Get a self-referential title object.
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
getLanguage()
Shortcut to get user's language.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
prefixSearchString( $search, $limit, $offset)
Perform a regular substring search for prefixSearchSubpages.
msg()
Wrapper around wfMessage that sets the current context.
MediaWiki Linker LinkRenderer null $linkRenderer
Special page allowing users with the appropriate permissions to view and restore deleted content.
redirectToRevDel()
Convert submitted form data to format expected by RevisionDelete and redirect the request.
showList( $result)
Generic list of deleted pages.
getFileComment( $file)
Fetch file upload comment if it's available to this user.
diffHeader( $rev, $prefix)
showFileConfirmationForm( $key)
Show a form confirming whether a tokenless user really wants to see a file.
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
showFile( $key)
Show a deleted file version requested by the visitor.
getPageLink( $rev, $titleObj, $ts)
Fetch revision text link if it's available to all users.
getFileUser( $file)
Fetch file's user id if it's available to this user.
string $mSearchPrefix
Search prefix.
execute( $par)
Default execute method Checks user permissions.
showRevision( $timestamp)
getFileLink( $file, $titleObj, $ts, $key)
Fetch image view link if it's available to all users.
doesWrites()
Indicates whether this special page may perform database writes.
isAllowed( $permission, User $user=null)
Checks whether a user is allowed the permission for the specific title if one is set.
userCanExecute(User $user)
Checks if the given user (identified by an object) can execute this special page (as defined by $mRes...
formatRevisionRow( $row, $earliestLiveTime, $remaining)
showDiff( $previousRev, $currentRev)
Build a diff display between this and the previous either deleted or non-deleted edit.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Content object implementation for representing flat text.
Represents a title within MediaWiki.
Definition Title.php:39
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:50
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition WikiPage.php:120
Result wrapper for grabbing data queried from an IDatabase object.
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
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition design.txt:18
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
const NS_USER
Definition Defines.php:64
const NS_FILE
Definition Defines.php:68
const NS_USER_TALK
Definition Defines.php:65
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 local account $user
Definition hooks.txt:249
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition hooks.txt:1769
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
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:1143
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 $content
Definition hooks.txt:1100
namespace and then decline to actually register it file or subcat img or subcat $title
Definition hooks.txt:964
error also a ContextSource you ll probably need to make sure the header is varied on $request
Definition hooks.txt:2723
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:864
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition hooks.txt:2937
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing & $attribs
Definition hooks.txt:1975
this hook is for auditing only $response
Definition hooks.txt:783
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
null for the local 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:1601
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:1751
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
$batch
Definition linkcache.txt:23
$last
const DB_REPLICA
Definition defines.php:25
if(!isset( $args[0])) $lang