MediaWiki  1.23.8
SpecialUndelete.php
Go to the documentation of this file.
1 <?php
29 class PageArchive {
31  protected $title;
32 
34  protected $fileStatus;
35 
37  protected $revisionStatus;
38 
39  function __construct( $title ) {
40  if ( is_null( $title ) ) {
41  throw new MWException( __METHOD__ . ' given a null title.' );
42  }
43  $this->title = $title;
44  }
45 
53  public static function listAllPages() {
54  $dbr = wfGetDB( DB_SLAVE );
55 
56  return self::listPages( $dbr, '' );
57  }
58 
67  public static function listPagesByPrefix( $prefix ) {
68  $dbr = wfGetDB( DB_SLAVE );
69 
70  $title = Title::newFromText( $prefix );
71  if ( $title ) {
72  $ns = $title->getNamespace();
73  $prefix = $title->getDBkey();
74  } else {
75  // Prolly won't work too good
76  // @todo handle bare namespace names cleanly?
77  $ns = 0;
78  }
79 
80  $conds = array(
81  'ar_namespace' => $ns,
82  'ar_title' . $dbr->buildLike( $prefix, $dbr->anyString() ),
83  );
84 
85  return self::listPages( $dbr, $conds );
86  }
87 
93  protected static function listPages( $dbr, $condition ) {
94  return $dbr->resultObject( $dbr->select(
95  array( 'archive' ),
96  array(
97  'ar_namespace',
98  'ar_title',
99  'count' => 'COUNT(*)'
100  ),
101  $condition,
102  __METHOD__,
103  array(
104  'GROUP BY' => array( 'ar_namespace', 'ar_title' ),
105  'ORDER BY' => array( 'ar_namespace', 'ar_title' ),
106  'LIMIT' => 100,
107  )
108  ) );
109  }
110 
117  function listRevisions() {
118  global $wgContentHandlerUseDB;
119 
120  $dbr = wfGetDB( DB_SLAVE );
121 
122  $tables = array( 'archive' );
123 
124  $fields = array(
125  'ar_minor_edit', 'ar_timestamp', 'ar_user', 'ar_user_text',
126  'ar_comment', 'ar_len', 'ar_deleted', 'ar_rev_id', 'ar_sha1',
127  );
128 
129  if ( $wgContentHandlerUseDB ) {
130  $fields[] = 'ar_content_format';
131  $fields[] = 'ar_content_model';
132  }
133 
134  $conds = array( 'ar_namespace' => $this->title->getNamespace(),
135  'ar_title' => $this->title->getDBkey() );
136 
137  $options = array( 'ORDER BY' => 'ar_timestamp DESC' );
138 
139  $join_conds = array();
140 
142  $tables,
143  $fields,
144  $conds,
145  $join_conds,
146  $options
147  );
148 
149  $res = $dbr->select( $tables,
150  $fields,
151  $conds,
152  __METHOD__,
153  $options,
154  $join_conds
155  );
156 
157  return $dbr->resultObject( $res );
158  }
159 
168  function listFiles() {
169  if ( $this->title->getNamespace() != NS_FILE ) {
170  return null;
171  }
172 
173  $dbr = wfGetDB( DB_SLAVE );
174  $res = $dbr->select(
175  'filearchive',
177  array( 'fa_name' => $this->title->getDBkey() ),
178  __METHOD__,
179  array( 'ORDER BY' => 'fa_timestamp DESC' )
180  );
181 
182  return $dbr->resultObject( $res );
183  }
184 
192  function getRevision( $timestamp ) {
193  global $wgContentHandlerUseDB;
194 
195  $dbr = wfGetDB( DB_SLAVE );
196 
197  $fields = array(
198  'ar_rev_id',
199  'ar_text',
200  'ar_comment',
201  'ar_user',
202  'ar_user_text',
203  'ar_timestamp',
204  'ar_minor_edit',
205  'ar_flags',
206  'ar_text_id',
207  'ar_deleted',
208  'ar_len',
209  'ar_sha1',
210  );
211 
212  if ( $wgContentHandlerUseDB ) {
213  $fields[] = 'ar_content_format';
214  $fields[] = 'ar_content_model';
215  }
216 
217  $row = $dbr->selectRow( 'archive',
218  $fields,
219  array( 'ar_namespace' => $this->title->getNamespace(),
220  'ar_title' => $this->title->getDBkey(),
221  'ar_timestamp' => $dbr->timestamp( $timestamp ) ),
222  __METHOD__ );
223 
224  if ( $row ) {
225  return Revision::newFromArchiveRow( $row, array( 'title' => $this->title ) );
226  }
227 
228  return null;
229  }
230 
241  function getPreviousRevision( $timestamp ) {
242  $dbr = wfGetDB( DB_SLAVE );
243 
244  // Check the previous deleted revision...
245  $row = $dbr->selectRow( 'archive',
246  'ar_timestamp',
247  array( 'ar_namespace' => $this->title->getNamespace(),
248  'ar_title' => $this->title->getDBkey(),
249  'ar_timestamp < ' .
250  $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ),
251  __METHOD__,
252  array(
253  'ORDER BY' => 'ar_timestamp DESC',
254  'LIMIT' => 1 ) );
255  $prevDeleted = $row ? wfTimestamp( TS_MW, $row->ar_timestamp ) : false;
256 
257  $row = $dbr->selectRow( array( 'page', 'revision' ),
258  array( 'rev_id', 'rev_timestamp' ),
259  array(
260  'page_namespace' => $this->title->getNamespace(),
261  'page_title' => $this->title->getDBkey(),
262  'page_id = rev_page',
263  'rev_timestamp < ' .
264  $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ),
265  __METHOD__,
266  array(
267  'ORDER BY' => 'rev_timestamp DESC',
268  'LIMIT' => 1 ) );
269  $prevLive = $row ? wfTimestamp( TS_MW, $row->rev_timestamp ) : false;
270  $prevLiveId = $row ? intval( $row->rev_id ) : null;
271 
272  if ( $prevLive && $prevLive > $prevDeleted ) {
273  // Most prior revision was live
274  return Revision::newFromId( $prevLiveId );
275  } elseif ( $prevDeleted ) {
276  // Most prior revision was deleted
277  return $this->getRevision( $prevDeleted );
278  }
279 
280  // No prior revision on this page.
281  return null;
282  }
283 
290  function getTextFromRow( $row ) {
291  if ( is_null( $row->ar_text_id ) ) {
292  // An old row from MediaWiki 1.4 or previous.
293  // Text is embedded in this row in classic compression format.
294  return Revision::getRevisionText( $row, 'ar_' );
295  }
296 
297  // New-style: keyed to the text storage backend.
298  $dbr = wfGetDB( DB_SLAVE );
299  $text = $dbr->selectRow( 'text',
300  array( 'old_text', 'old_flags' ),
301  array( 'old_id' => $row->ar_text_id ),
302  __METHOD__ );
303 
304  return Revision::getRevisionText( $text );
305  }
306 
315  function getLastRevisionText() {
316  $dbr = wfGetDB( DB_SLAVE );
317  $row = $dbr->selectRow( 'archive',
318  array( 'ar_text', 'ar_flags', 'ar_text_id' ),
319  array( 'ar_namespace' => $this->title->getNamespace(),
320  'ar_title' => $this->title->getDBkey() ),
321  __METHOD__,
322  array( 'ORDER BY' => 'ar_timestamp DESC' ) );
323 
324  if ( $row ) {
325  return $this->getTextFromRow( $row );
326  }
327 
328  return null;
329  }
330 
336  function isDeleted() {
337  $dbr = wfGetDB( DB_SLAVE );
338  $n = $dbr->selectField( 'archive', 'COUNT(ar_title)',
339  array( 'ar_namespace' => $this->title->getNamespace(),
340  'ar_title' => $this->title->getDBkey() ),
341  __METHOD__
342  );
343 
344  return ( $n > 0 );
345  }
346 
361  function undelete( $timestamps, $comment = '', $fileVersions = array(),
362  $unsuppress = false, User $user = null
363  ) {
364  // If both the set of text revisions and file revisions are empty,
365  // restore everything. Otherwise, just restore the requested items.
366  $restoreAll = empty( $timestamps ) && empty( $fileVersions );
367 
368  $restoreText = $restoreAll || !empty( $timestamps );
369  $restoreFiles = $restoreAll || !empty( $fileVersions );
370 
371  if ( $restoreFiles && $this->title->getNamespace() == NS_FILE ) {
372  $img = wfLocalFile( $this->title );
373  $this->fileStatus = $img->restore( $fileVersions, $unsuppress );
374  if ( !$this->fileStatus->isOK() ) {
375  return false;
376  }
377  $filesRestored = $this->fileStatus->successCount;
378  } else {
379  $filesRestored = 0;
380  }
381 
382  if ( $restoreText ) {
383  $this->revisionStatus = $this->undeleteRevisions( $timestamps, $unsuppress, $comment );
384  if ( !$this->revisionStatus->isOK() ) {
385  return false;
386  }
387 
388  $textRestored = $this->revisionStatus->getValue();
389  } else {
390  $textRestored = 0;
391  }
392 
393  // Touch the log!
394 
395  if ( $textRestored && $filesRestored ) {
396  $reason = wfMessage( 'undeletedrevisions-files' )
397  ->numParams( $textRestored, $filesRestored )->inContentLanguage()->text();
398  } elseif ( $textRestored ) {
399  $reason = wfMessage( 'undeletedrevisions' )->numParams( $textRestored )
400  ->inContentLanguage()->text();
401  } elseif ( $filesRestored ) {
402  $reason = wfMessage( 'undeletedfiles' )->numParams( $filesRestored )
403  ->inContentLanguage()->text();
404  } else {
405  wfDebug( "Undelete: nothing undeleted...\n" );
406 
407  return false;
408  }
409 
410  if ( trim( $comment ) != '' ) {
411  $reason .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $comment;
412  }
413 
414  if ( $user === null ) {
415  global $wgUser;
416  $user = $wgUser;
417  }
418 
419  $logEntry = new ManualLogEntry( 'delete', 'restore' );
420  $logEntry->setPerformer( $user );
421  $logEntry->setTarget( $this->title );
422  $logEntry->setComment( $reason );
423 
424  wfRunHooks( 'ArticleUndeleteLogEntry', array( $this, &$logEntry, $user ) );
425 
426  $logid = $logEntry->insert();
427  $logEntry->publish( $logid );
428 
429  return array( $textRestored, $filesRestored, $reason );
430  }
431 
444  private function undeleteRevisions( $timestamps, $unsuppress = false, $comment = '' ) {
445  global $wgContentHandlerUseDB;
446 
447  if ( wfReadOnly() ) {
448  throw new ReadOnlyError();
449  }
450 
451  $restoreAll = empty( $timestamps );
452  $dbw = wfGetDB( DB_MASTER );
453 
454  # Does this page already exist? We'll have to update it...
455  $article = WikiPage::factory( $this->title );
456  # Load latest data for the current page (bug 31179)
457  $article->loadPageData( 'fromdbmaster' );
458  $oldcountable = $article->isCountable();
459 
460  $page = $dbw->selectRow( 'page',
461  array( 'page_id', 'page_latest' ),
462  array( 'page_namespace' => $this->title->getNamespace(),
463  'page_title' => $this->title->getDBkey() ),
464  __METHOD__,
465  array( 'FOR UPDATE' ) // lock page
466  );
467 
468  if ( $page ) {
469  $makepage = false;
470  # Page already exists. Import the history, and if necessary
471  # we'll update the latest revision field in the record.
472 
473  $previousRevId = $page->page_latest;
474 
475  # Get the time span of this page
476  $previousTimestamp = $dbw->selectField( 'revision', 'rev_timestamp',
477  array( 'rev_id' => $previousRevId ),
478  __METHOD__ );
479 
480  if ( $previousTimestamp === false ) {
481  wfDebug( __METHOD__ . ": existing page refers to a page_latest that does not exist\n" );
482 
483  $status = Status::newGood( 0 );
484  $status->warning( 'undeleterevision-missing' );
485 
486  return $status;
487  }
488  } else {
489  # Have to create a new article...
490  $makepage = true;
491  $previousRevId = 0;
492  $previousTimestamp = 0;
493  }
494 
495  if ( $restoreAll ) {
496  $oldones = '1 = 1'; # All revisions...
497  } else {
498  $oldts = implode( ',',
499  array_map( array( &$dbw, 'addQuotes' ),
500  array_map( array( &$dbw, 'timestamp' ),
501  $timestamps ) ) );
502 
503  $oldones = "ar_timestamp IN ( {$oldts} )";
504  }
505 
506  $fields = array(
507  'ar_rev_id',
508  'ar_text',
509  'ar_comment',
510  'ar_user',
511  'ar_user_text',
512  'ar_timestamp',
513  'ar_minor_edit',
514  'ar_flags',
515  'ar_text_id',
516  'ar_deleted',
517  'ar_page_id',
518  'ar_len',
519  'ar_sha1'
520  );
521 
522  if ( $wgContentHandlerUseDB ) {
523  $fields[] = 'ar_content_format';
524  $fields[] = 'ar_content_model';
525  }
526 
530  $result = $dbw->select( 'archive',
531  $fields,
532  /* WHERE */ array(
533  'ar_namespace' => $this->title->getNamespace(),
534  'ar_title' => $this->title->getDBkey(),
535  $oldones ),
536  __METHOD__,
537  /* options */ array( 'ORDER BY' => 'ar_timestamp' )
538  );
539  $ret = $dbw->resultObject( $result );
540  $rev_count = $dbw->numRows( $result );
541 
542  if ( !$rev_count ) {
543  wfDebug( __METHOD__ . ": no revisions to restore\n" );
544 
545  $status = Status::newGood( 0 );
546  $status->warning( "undelete-no-results" );
547 
548  return $status;
549  }
550 
551  $ret->seek( $rev_count - 1 ); // move to last
552  $row = $ret->fetchObject(); // get newest archived rev
553  $ret->seek( 0 ); // move back
554 
555  // grab the content to check consistency with global state before restoring the page.
556  $revision = Revision::newFromArchiveRow( $row,
557  array(
558  'title' => $article->getTitle(), // used to derive default content model
559  )
560  );
561  $user = User::newFromName( $revision->getRawUserText(), false );
562  $content = $revision->getContent( Revision::RAW );
563 
564  //NOTE: article ID may not be known yet. prepareSave() should not modify the database.
565  $status = $content->prepareSave( $article, 0, -1, $user );
566 
567  if ( !$status->isOK() ) {
568  return $status;
569  }
570 
571  if ( $makepage ) {
572  // Check the state of the newest to-be version...
573  if ( !$unsuppress && ( $row->ar_deleted & Revision::DELETED_TEXT ) ) {
574  return Status::newFatal( "undeleterevdel" );
575  }
576  // Safe to insert now...
577  $newid = $article->insertOn( $dbw );
578  $pageId = $newid;
579  } else {
580  // Check if a deleted revision will become the current revision...
581  if ( $row->ar_timestamp > $previousTimestamp ) {
582  // Check the state of the newest to-be version...
583  if ( !$unsuppress && ( $row->ar_deleted & Revision::DELETED_TEXT ) ) {
584  return Status::newFatal( "undeleterevdel" );
585  }
586  }
587 
588  $newid = false;
589  $pageId = $article->getId();
590  }
591 
592  $revision = null;
593  $restored = 0;
594 
595  foreach ( $ret as $row ) {
596  // Check for key dupes due to shitty archive integrity.
597  if ( $row->ar_rev_id ) {
598  $exists = $dbw->selectField( 'revision', '1',
599  array( 'rev_id' => $row->ar_rev_id ), __METHOD__ );
600  if ( $exists ) {
601  continue; // don't throw DB errors
602  }
603  }
604  // Insert one revision at a time...maintaining deletion status
605  // unless we are specifically removing all restrictions...
606  $revision = Revision::newFromArchiveRow( $row,
607  array(
608  'page' => $pageId,
609  'title' => $this->title,
610  'deleted' => $unsuppress ? 0 : $row->ar_deleted
611  ) );
612 
613  $revision->insertOn( $dbw );
614  $restored++;
615 
616  wfRunHooks( 'ArticleRevisionUndeleted', array( &$this->title, $revision, $row->ar_page_id ) );
617  }
618  # Now that it's safely stored, take it out of the archive
619  $dbw->delete( 'archive',
620  /* WHERE */ array(
621  'ar_namespace' => $this->title->getNamespace(),
622  'ar_title' => $this->title->getDBkey(),
623  $oldones ),
624  __METHOD__ );
625 
626  // Was anything restored at all?
627  if ( $restored == 0 ) {
628  return Status::newGood( 0 );
629  }
630 
631  $created = (bool)$newid;
632 
633  // Attach the latest revision to the page...
634  $wasnew = $article->updateIfNewerOn( $dbw, $revision, $previousRevId );
635  if ( $created || $wasnew ) {
636  // Update site stats, link tables, etc
637  $user = User::newFromName( $revision->getRawUserText(), false );
638  $article->doEditUpdates(
639  $revision,
640  $user,
641  array( 'created' => $created, 'oldcountable' => $oldcountable )
642  );
643  }
644 
645  wfRunHooks( 'ArticleUndelete', array( &$this->title, $created, $comment ) );
646 
647  if ( $this->title->getNamespace() == NS_FILE ) {
648  $update = new HTMLCacheUpdate( $this->title, 'imagelinks' );
649  $update->doUpdate();
650  }
651 
652  return Status::newGood( $restored );
653  }
654 
658  function getFileStatus() {
659  return $this->fileStatus;
660  }
661 
665  function getRevisionStatus() {
666  return $this->revisionStatus;
667  }
668 }
669 
677  private $mAction;
678  private $mTarget;
679  private $mTimestamp;
680  private $mRestore;
681  private $mInvert;
682  private $mFilename;
684  private $mAllowed;
685  private $mCanView;
686  private $mComment;
687  private $mToken;
688 
690  private $mTargetObj;
691 
692  function __construct() {
693  parent::__construct( 'Undelete', 'deletedhistory' );
694  }
695 
696  function loadRequest( $par ) {
697  $request = $this->getRequest();
698  $user = $this->getUser();
699 
700  $this->mAction = $request->getVal( 'action' );
701  if ( $par !== null && $par !== '' ) {
702  $this->mTarget = $par;
703  } else {
704  $this->mTarget = $request->getVal( 'target' );
705  }
706 
707  $this->mTargetObj = null;
708 
709  if ( $this->mTarget !== null && $this->mTarget !== '' ) {
710  $this->mTargetObj = Title::newFromURL( $this->mTarget );
711  }
712 
713  $this->mSearchPrefix = $request->getText( 'prefix' );
714  $time = $request->getVal( 'timestamp' );
715  $this->mTimestamp = $time ? wfTimestamp( TS_MW, $time ) : '';
716  $this->mFilename = $request->getVal( 'file' );
717 
718  $posted = $request->wasPosted() &&
719  $user->matchEditToken( $request->getVal( 'wpEditToken' ) );
720  $this->mRestore = $request->getCheck( 'restore' ) && $posted;
721  $this->mInvert = $request->getCheck( 'invert' ) && $posted;
722  $this->mPreview = $request->getCheck( 'preview' ) && $posted;
723  $this->mDiff = $request->getCheck( 'diff' );
724  $this->mDiffOnly = $request->getBool( 'diffonly', $this->getUser()->getOption( 'diffonly' ) );
725  $this->mComment = $request->getText( 'wpComment' );
726  $this->mUnsuppress = $request->getVal( 'wpUnsuppress' ) && $user->isAllowed( 'suppressrevision' );
727  $this->mToken = $request->getVal( 'token' );
728 
729  if ( $user->isAllowed( 'undelete' ) && !$user->isBlocked() ) {
730  $this->mAllowed = true; // user can restore
731  $this->mCanView = true; // user can view content
732  } elseif ( $user->isAllowed( 'deletedtext' ) ) {
733  $this->mAllowed = false; // user cannot restore
734  $this->mCanView = true; // user can view content
735  $this->mRestore = false;
736  } else { // user can only view the list of revisions
737  $this->mAllowed = false;
738  $this->mCanView = false;
739  $this->mTimestamp = '';
740  $this->mRestore = false;
741  }
742 
743  if ( $this->mRestore || $this->mInvert ) {
744  $timestamps = array();
745  $this->mFileVersions = array();
746  foreach ( $request->getValues() as $key => $val ) {
747  $matches = array();
748  if ( preg_match( '/^ts(\d{14})$/', $key, $matches ) ) {
749  array_push( $timestamps, $matches[1] );
750  }
751 
752  if ( preg_match( '/^fileid(\d+)$/', $key, $matches ) ) {
753  $this->mFileVersions[] = intval( $matches[1] );
754  }
755  }
756  rsort( $timestamps );
757  $this->mTargetTimestamp = $timestamps;
758  }
759  }
760 
761  function execute( $par ) {
762  $this->checkPermissions();
763  $user = $this->getUser();
764 
765  $this->setHeaders();
766  $this->outputHeader();
767 
768  $this->loadRequest( $par );
769 
770  $out = $this->getOutput();
771 
772  if ( is_null( $this->mTargetObj ) ) {
773  $out->addWikiMsg( 'undelete-header' );
774 
775  # Not all users can just browse every deleted page from the list
776  if ( $user->isAllowed( 'browsearchive' ) ) {
777  $this->showSearchForm();
778  }
779 
780  return;
781  }
782 
783  if ( $this->mAllowed ) {
784  $out->setPageTitle( $this->msg( 'undeletepage' ) );
785  } else {
786  $out->setPageTitle( $this->msg( 'viewdeletedpage' ) );
787  }
788 
789  $this->getSkin()->setRelevantTitle( $this->mTargetObj );
790 
791  if ( $this->mTimestamp !== '' ) {
792  $this->showRevision( $this->mTimestamp );
793  } elseif ( $this->mFilename !== null && $this->mTargetObj->inNamespace( NS_FILE ) ) {
794  $file = new ArchivedFile( $this->mTargetObj, '', $this->mFilename );
795  // Check if user is allowed to see this file
796  if ( !$file->exists() ) {
797  $out->addWikiMsg( 'filedelete-nofile', $this->mFilename );
798  } elseif ( !$file->userCan( File::DELETED_FILE, $user ) ) {
799  if ( $file->isDeleted( File::DELETED_RESTRICTED ) ) {
800  throw new PermissionsError( 'suppressrevision' );
801  } else {
802  throw new PermissionsError( 'deletedtext' );
803  }
804  } elseif ( !$user->matchEditToken( $this->mToken, $this->mFilename ) ) {
805  $this->showFileConfirmationForm( $this->mFilename );
806  } else {
807  $this->showFile( $this->mFilename );
808  }
809  } elseif ( $this->mRestore && $this->mAction == 'submit' ) {
810  $this->undelete();
811  } else {
812  $this->showHistory();
813  }
814  }
815 
816  function showSearchForm() {
817  global $wgScript;
818 
819  $out = $this->getOutput();
820  $out->setPageTitle( $this->msg( 'undelete-search-title' ) );
821  $out->addHTML(
822  Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) .
823  Xml::fieldset( $this->msg( 'undelete-search-box' )->text() ) .
824  Html::hidden( 'title', $this->getPageTitle()->getPrefixedDBkey() ) .
826  'label',
827  array( 'for' => 'prefix' ),
828  $this->msg( 'undelete-search-prefix' )->parse()
829  ) .
830  Xml::input(
831  'prefix',
832  20,
833  $this->mSearchPrefix,
834  array( 'id' => 'prefix', 'autofocus' => true )
835  ) . ' ' .
836  Xml::submitButton( $this->msg( 'undelete-search-submit' )->text() ) .
837  Xml::closeElement( 'fieldset' ) .
838  Xml::closeElement( 'form' )
839  );
840 
841  # List undeletable articles
842  if ( $this->mSearchPrefix ) {
843  $result = PageArchive::listPagesByPrefix( $this->mSearchPrefix );
844  $this->showList( $result );
845  }
846  }
847 
854  private function showList( $result ) {
855  $out = $this->getOutput();
856 
857  if ( $result->numRows() == 0 ) {
858  $out->addWikiMsg( 'undelete-no-results' );
859 
860  return false;
861  }
862 
863  $out->addWikiMsg( 'undeletepagetext', $this->getLanguage()->formatNum( $result->numRows() ) );
864 
865  $undelete = $this->getPageTitle();
866  $out->addHTML( "<ul>\n" );
867  foreach ( $result as $row ) {
868  $title = Title::makeTitleSafe( $row->ar_namespace, $row->ar_title );
869  if ( $title !== null ) {
870  $item = Linker::linkKnown(
871  $undelete,
872  htmlspecialchars( $title->getPrefixedText() ),
873  array(),
874  array( 'target' => $title->getPrefixedText() )
875  );
876  } else {
877  // The title is no longer valid, show as text
878  $item = Html::element(
879  'span',
880  array( 'class' => 'mw-invalidtitle' ),
882  $this->getContext(),
883  $row->ar_namespace,
884  $row->ar_title
885  )
886  );
887  }
888  $revs = $this->msg( 'undeleterevisions' )->numParams( $row->count )->parse();
889  $out->addHTML( "<li>{$item} ({$revs})</li>\n" );
890  }
891  $result->free();
892  $out->addHTML( "</ul>\n" );
893 
894  return true;
895  }
896 
897  private function showRevision( $timestamp ) {
898  if ( !preg_match( '/[0-9]{14}/', $timestamp ) ) {
899  return;
900  }
901 
902  $archive = new PageArchive( $this->mTargetObj );
903  if ( !wfRunHooks( 'UndeleteForm::showRevision', array( &$archive, $this->mTargetObj ) ) ) {
904  return;
905  }
906  $rev = $archive->getRevision( $timestamp );
907 
908  $out = $this->getOutput();
909  $user = $this->getUser();
910 
911  if ( !$rev ) {
912  $out->addWikiMsg( 'undeleterevision-missing' );
913 
914  return;
915  }
916 
917  if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
918  if ( !$rev->userCan( Revision::DELETED_TEXT, $user ) ) {
919  $out->wrapWikiMsg(
920  "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
921  'rev-deleted-text-permission'
922  );
923 
924  return;
925  }
926 
927  $out->wrapWikiMsg(
928  "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
929  'rev-deleted-text-view'
930  );
931  $out->addHTML( '<br />' );
932  // and we are allowed to see...
933  }
934 
935  if ( $this->mDiff ) {
936  $previousRev = $archive->getPreviousRevision( $timestamp );
937  if ( $previousRev ) {
938  $this->showDiff( $previousRev, $rev );
939  if ( $this->mDiffOnly ) {
940  return;
941  }
942 
943  $out->addHTML( '<hr />' );
944  } else {
945  $out->addWikiMsg( 'undelete-nodiff' );
946  }
947  }
948 
950  $this->getPageTitle( $this->mTargetObj->getPrefixedDBkey() ),
951  htmlspecialchars( $this->mTargetObj->getPrefixedText() )
952  );
953 
954  $lang = $this->getLanguage();
955 
956  // date and time are separate parameters to facilitate localisation.
957  // $time is kept for backward compat reasons.
958  $time = $lang->userTimeAndDate( $timestamp, $user );
959  $d = $lang->userDate( $timestamp, $user );
960  $t = $lang->userTime( $timestamp, $user );
961  $userLink = Linker::revUserTools( $rev );
962 
963  $content = $rev->getContent( Revision::FOR_THIS_USER, $user );
964 
965  $isText = ( $content instanceof TextContent );
966 
967  if ( $this->mPreview || $isText ) {
968  $openDiv = '<div id="mw-undelete-revision" class="mw-warning">';
969  } else {
970  $openDiv = '<div id="mw-undelete-revision">';
971  }
972  $out->addHTML( $openDiv );
973 
974  // Revision delete links
975  if ( !$this->mDiff ) {
976  $revdel = Linker::getRevDeleteLink( $user, $rev, $this->mTargetObj );
977  if ( $revdel ) {
978  $out->addHTML( "$revdel " );
979  }
980  }
981 
982  $out->addHTML( $this->msg( 'undelete-revision' )->rawParams( $link )->params(
983  $time )->rawParams( $userLink )->params( $d, $t )->parse() . '</div>' );
984 
985  if ( !wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) ) ) {
986  return;
987  }
988 
989  if ( $this->mPreview || !$isText ) {
990  // NOTE: non-text content has no source view, so always use rendered preview
991 
992  // Hide [edit]s
993  $popts = $out->parserOptions();
994  $popts->setEditSection( false );
995 
996  $pout = $content->getParserOutput( $this->mTargetObj, $rev->getId(), $popts, true );
997  $out->addParserOutput( $pout );
998  }
999 
1000  if ( $isText ) {
1001  // source view for textual content
1002  $sourceView = Xml::element(
1003  'textarea',
1004  array(
1005  'readonly' => 'readonly',
1006  'cols' => $user->getIntOption( 'cols' ),
1007  'rows' => $user->getIntOption( 'rows' )
1008  ),
1009  $content->getNativeData() . "\n"
1010  );
1011 
1012  $previewButton = Xml::element( 'input', array(
1013  'type' => 'submit',
1014  'name' => 'preview',
1015  'value' => $this->msg( 'showpreview' )->text()
1016  ) );
1017  } else {
1018  $sourceView = '';
1019  $previewButton = '';
1020  }
1021 
1022  $diffButton = Xml::element( 'input', array(
1023  'name' => 'diff',
1024  'type' => 'submit',
1025  'value' => $this->msg( 'showdiff' )->text() ) );
1026 
1027  $out->addHTML(
1028  $sourceView .
1029  Xml::openElement( 'div', array(
1030  'style' => 'clear: both' ) ) .
1031  Xml::openElement( 'form', array(
1032  'method' => 'post',
1033  'action' => $this->getPageTitle()->getLocalURL( array( 'action' => 'submit' ) ) ) ) .
1034  Xml::element( 'input', array(
1035  'type' => 'hidden',
1036  'name' => 'target',
1037  'value' => $this->mTargetObj->getPrefixedDBkey() ) ) .
1038  Xml::element( 'input', array(
1039  'type' => 'hidden',
1040  'name' => 'timestamp',
1041  'value' => $timestamp ) ) .
1042  Xml::element( 'input', array(
1043  'type' => 'hidden',
1044  'name' => 'wpEditToken',
1045  'value' => $user->getEditToken() ) ) .
1046  $previewButton .
1047  $diffButton .
1048  Xml::closeElement( 'form' ) .
1049  Xml::closeElement( 'div' )
1050  );
1051  }
1052 
1061  function showDiff( $previousRev, $currentRev ) {
1062  $diffContext = clone $this->getContext();
1063  $diffContext->setTitle( $currentRev->getTitle() );
1064  $diffContext->setWikiPage( WikiPage::factory( $currentRev->getTitle() ) );
1065 
1066  $diffEngine = $currentRev->getContentHandler()->createDifferenceEngine( $diffContext );
1067  $diffEngine->showDiffStyle();
1068 
1069  $formattedDiff = $diffEngine->generateContentDiffBody(
1070  $previousRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ),
1071  $currentRev->getContent( Revision::FOR_THIS_USER, $this->getUser() )
1072  );
1073 
1074  $formattedDiff = $diffEngine->addHeader(
1075  $formattedDiff,
1076  $this->diffHeader( $previousRev, 'o' ),
1077  $this->diffHeader( $currentRev, 'n' )
1078  );
1079 
1080  $this->getOutput()->addHTML( "<div>$formattedDiff</div>\n" );
1081  }
1082 
1088  private function diffHeader( $rev, $prefix ) {
1089  $isDeleted = !( $rev->getId() && $rev->getTitle() );
1090  if ( $isDeleted ) {
1092  $targetPage = $this->getPageTitle();
1093  $targetQuery = array(
1094  'target' => $this->mTargetObj->getPrefixedText(),
1095  'timestamp' => wfTimestamp( TS_MW, $rev->getTimestamp() )
1096  );
1097  } else {
1099  $targetPage = $rev->getTitle();
1100  $targetQuery = array( 'oldid' => $rev->getId() );
1101  }
1102 
1103  // Add show/hide deletion links if available
1104  $user = $this->getUser();
1105  $lang = $this->getLanguage();
1106  $rdel = Linker::getRevDeleteLink( $user, $rev, $this->mTargetObj );
1107 
1108  if ( $rdel ) {
1109  $rdel = " $rdel";
1110  }
1111 
1112  $minor = $rev->isMinor() ? ChangesList::flag( 'minor' ) : '';
1113 
1114  $tags = wfGetDB( DB_SLAVE )->selectField(
1115  'tag_summary',
1116  'ts_tags',
1117  array( 'ts_rev_id' => $rev->getId() ),
1118  __METHOD__
1119  );
1120  $tagSummary = ChangeTags::formatSummaryRow( $tags, 'deleteddiff' );
1121 
1122  // FIXME This is reimplementing DifferenceEngine#getRevisionHeader
1123  // and partially #showDiffPage, but worse
1124  return '<div id="mw-diff-' . $prefix . 'title1"><strong>' .
1125  Linker::link(
1126  $targetPage,
1127  $this->msg(
1128  'revisionasof',
1129  $lang->userTimeAndDate( $rev->getTimestamp(), $user ),
1130  $lang->userDate( $rev->getTimestamp(), $user ),
1131  $lang->userTime( $rev->getTimestamp(), $user )
1132  )->escaped(),
1133  array(),
1134  $targetQuery
1135  ) .
1136  '</strong></div>' .
1137  '<div id="mw-diff-' . $prefix . 'title2">' .
1138  Linker::revUserTools( $rev ) . '<br />' .
1139  '</div>' .
1140  '<div id="mw-diff-' . $prefix . 'title3">' .
1141  $minor . Linker::revComment( $rev ) . $rdel . '<br />' .
1142  '</div>' .
1143  '<div id="mw-diff-' . $prefix . 'title5">' .
1144  $tagSummary[0] . '<br />' .
1145  '</div>';
1146  }
1151  private function showFileConfirmationForm( $key ) {
1152  $out = $this->getOutput();
1153  $lang = $this->getLanguage();
1154  $user = $this->getUser();
1155  $file = new ArchivedFile( $this->mTargetObj, '', $this->mFilename );
1156  $out->addWikiMsg( 'undelete-show-file-confirm',
1157  $this->mTargetObj->getText(),
1158  $lang->userDate( $file->getTimestamp(), $user ),
1159  $lang->userTime( $file->getTimestamp(), $user ) );
1160  $out->addHTML(
1161  Xml::openElement( 'form', array(
1162  'method' => 'POST',
1163  'action' => $this->getPageTitle()->getLocalURL( array(
1164  'target' => $this->mTarget,
1165  'file' => $key,
1166  'token' => $user->getEditToken( $key ),
1167  ) ),
1168  )
1169  ) .
1170  Xml::submitButton( $this->msg( 'undelete-show-file-submit' )->text() ) .
1171  '</form>'
1172  );
1173  }
1178  private function showFile( $key ) {
1179  $this->getOutput()->disable();
1180 
1181  # We mustn't allow the output to be Squid cached, otherwise
1182  # if an admin previews a deleted image, and it's cached, then
1183  # a user without appropriate permissions can toddle off and
1184  # nab the image, and Squid will serve it
1185  $response = $this->getRequest()->response();
1186  $response->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
1187  $response->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
1188  $response->header( 'Pragma: no-cache' );
1189 
1190  $repo = RepoGroup::singleton()->getLocalRepo();
1191  $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
1192  $repo->streamFile( $path );
1193  }
1194 
1195  private function showHistory() {
1196  $out = $this->getOutput();
1197  if ( $this->mAllowed ) {
1198  $out->addModules( 'mediawiki.special.undelete' );
1199  }
1200  $out->wrapWikiMsg(
1201  "<div class='mw-undelete-pagetitle'>\n$1\n</div>\n",
1202  array( 'undeletepagetitle', wfEscapeWikiText( $this->mTargetObj->getPrefixedText() ) )
1203  );
1204 
1205  $archive = new PageArchive( $this->mTargetObj );
1206  wfRunHooks( 'UndeleteForm::showHistory', array( &$archive, $this->mTargetObj ) );
1207  /*
1208  $text = $archive->getLastRevisionText();
1209  if( is_null( $text ) ) {
1210  $out->addWikiMsg( 'nohistory' );
1211  return;
1212  }
1213  */
1214  $out->addHTML( '<div class="mw-undelete-history">' );
1215  if ( $this->mAllowed ) {
1216  $out->addWikiMsg( 'undeletehistory' );
1217  $out->addWikiMsg( 'undeleterevdel' );
1218  } else {
1219  $out->addWikiMsg( 'undeletehistorynoadmin' );
1220  }
1221  $out->addHTML( '</div>' );
1222 
1223  # List all stored revisions
1224  $revisions = $archive->listRevisions();
1225  $files = $archive->listFiles();
1226 
1227  $haveRevisions = $revisions && $revisions->numRows() > 0;
1228  $haveFiles = $files && $files->numRows() > 0;
1229 
1230  # Batch existence check on user and talk pages
1231  if ( $haveRevisions ) {
1232  $batch = new LinkBatch();
1233  foreach ( $revisions as $row ) {
1234  $batch->addObj( Title::makeTitleSafe( NS_USER, $row->ar_user_text ) );
1235  $batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->ar_user_text ) );
1236  }
1237  $batch->execute();
1238  $revisions->seek( 0 );
1239  }
1240  if ( $haveFiles ) {
1241  $batch = new LinkBatch();
1242  foreach ( $files as $row ) {
1243  $batch->addObj( Title::makeTitleSafe( NS_USER, $row->fa_user_text ) );
1244  $batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->fa_user_text ) );
1245  }
1246  $batch->execute();
1247  $files->seek( 0 );
1248  }
1249 
1250  if ( $this->mAllowed ) {
1251  $action = $this->getPageTitle()->getLocalURL( array( 'action' => 'submit' ) );
1252  # Start the form here
1253  $top = Xml::openElement(
1254  'form',
1255  array( 'method' => 'post', 'action' => $action, 'id' => 'undelete' )
1256  );
1257  $out->addHTML( $top );
1258  }
1259 
1260  # Show relevant lines from the deletion log:
1261  $deleteLogPage = new LogPage( 'delete' );
1262  $out->addHTML( Xml::element( 'h2', null, $deleteLogPage->getName()->text() ) . "\n" );
1263  LogEventsList::showLogExtract( $out, 'delete', $this->mTargetObj );
1264  # Show relevant lines from the suppression log:
1265  $suppressLogPage = new LogPage( 'suppress' );
1266  if ( $this->getUser()->isAllowed( 'suppressionlog' ) ) {
1267  $out->addHTML( Xml::element( 'h2', null, $suppressLogPage->getName()->text() ) . "\n" );
1268  LogEventsList::showLogExtract( $out, 'suppress', $this->mTargetObj );
1269  }
1270 
1271  if ( $this->mAllowed && ( $haveRevisions || $haveFiles ) ) {
1272  # Format the user-visible controls (comment field, submission button)
1273  # in a nice little table
1274  if ( $this->getUser()->isAllowed( 'suppressrevision' ) ) {
1275  $unsuppressBox =
1276  "<tr>
1277  <td>&#160;</td>
1278  <td class='mw-input'>" .
1279  Xml::checkLabel( $this->msg( 'revdelete-unsuppress' )->text(),
1280  'wpUnsuppress', 'mw-undelete-unsuppress', $this->mUnsuppress ) .
1281  "</td>
1282  </tr>";
1283  } else {
1284  $unsuppressBox = '';
1285  }
1286 
1287  $table = Xml::fieldset( $this->msg( 'undelete-fieldset-title' )->text() ) .
1288  Xml::openElement( 'table', array( 'id' => 'mw-undelete-table' ) ) .
1289  "<tr>
1290  <td colspan='2' class='mw-undelete-extrahelp'>" .
1291  $this->msg( 'undeleteextrahelp' )->parseAsBlock() .
1292  "</td>
1293  </tr>
1294  <tr>
1295  <td class='mw-label'>" .
1296  Xml::label( $this->msg( 'undeletecomment' )->text(), 'wpComment' ) .
1297  "</td>
1298  <td class='mw-input'>" .
1299  Xml::input(
1300  'wpComment',
1301  50,
1302  $this->mComment,
1303  array( 'id' => 'wpComment', 'autofocus' => true )
1304  ) .
1305  "</td>
1306  </tr>
1307  <tr>
1308  <td>&#160;</td>
1309  <td class='mw-submit'>" .
1311  $this->msg( 'undeletebtn' )->text(),
1312  array( 'name' => 'restore', 'id' => 'mw-undelete-submit' )
1313  ) . ' ' .
1315  $this->msg( 'undeleteinvert' )->text(),
1316  array( 'name' => 'invert', 'id' => 'mw-undelete-invert' )
1317  ) .
1318  "</td>
1319  </tr>" .
1320  $unsuppressBox .
1321  Xml::closeElement( 'table' ) .
1322  Xml::closeElement( 'fieldset' );
1323 
1324  $out->addHTML( $table );
1325  }
1326 
1327  $out->addHTML( Xml::element( 'h2', null, $this->msg( 'history' )->text() ) . "\n" );
1328 
1329  if ( $haveRevisions ) {
1330  # The page's stored (deleted) history:
1331  $out->addHTML( '<ul>' );
1332  $remaining = $revisions->numRows();
1333  $earliestLiveTime = $this->mTargetObj->getEarliestRevTime();
1334 
1335  foreach ( $revisions as $row ) {
1336  $remaining--;
1337  $out->addHTML( $this->formatRevisionRow( $row, $earliestLiveTime, $remaining ) );
1338  }
1339  $revisions->free();
1340  $out->addHTML( '</ul>' );
1341  } else {
1342  $out->addWikiMsg( 'nohistory' );
1343  }
1344 
1345  if ( $haveFiles ) {
1346  $out->addHTML( Xml::element( 'h2', null, $this->msg( 'filehist' )->text() ) . "\n" );
1347  $out->addHTML( '<ul>' );
1348  foreach ( $files as $row ) {
1349  $out->addHTML( $this->formatFileRow( $row ) );
1350  }
1351  $files->free();
1352  $out->addHTML( '</ul>' );
1353  }
1354 
1355  if ( $this->mAllowed ) {
1356  # Slip in the hidden controls here
1357  $misc = Html::hidden( 'target', $this->mTarget );
1358  $misc .= Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() );
1359  $misc .= Xml::closeElement( 'form' );
1360  $out->addHTML( $misc );
1361  }
1363  return true;
1364  }
1365 
1366  private function formatRevisionRow( $row, $earliestLiveTime, $remaining ) {
1368  array(
1369  'title' => $this->mTargetObj
1370  ) );
1371 
1372  $revTextSize = '';
1373  $ts = wfTimestamp( TS_MW, $row->ar_timestamp );
1374  // Build checkboxen...
1375  if ( $this->mAllowed ) {
1376  if ( $this->mInvert ) {
1377  if ( in_array( $ts, $this->mTargetTimestamp ) ) {
1378  $checkBox = Xml::check( "ts$ts" );
1379  } else {
1380  $checkBox = Xml::check( "ts$ts", true );
1381  }
1382  } else {
1383  $checkBox = Xml::check( "ts$ts" );
1384  }
1385  } else {
1386  $checkBox = '';
1387  }
1388 
1389  // Build page & diff links...
1390  $user = $this->getUser();
1391  if ( $this->mCanView ) {
1392  $titleObj = $this->getPageTitle();
1393  # Last link
1394  if ( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
1395  $pageLink = htmlspecialchars( $this->getLanguage()->userTimeAndDate( $ts, $user ) );
1396  $last = $this->msg( 'diff' )->escaped();
1397  } elseif ( $remaining > 0 || ( $earliestLiveTime && $ts > $earliestLiveTime ) ) {
1398  $pageLink = $this->getPageLink( $rev, $titleObj, $ts );
1400  $titleObj,
1401  $this->msg( 'diff' )->escaped(),
1402  array(),
1403  array(
1404  'target' => $this->mTargetObj->getPrefixedText(),
1405  'timestamp' => $ts,
1406  'diff' => 'prev'
1407  )
1408  );
1409  } else {
1410  $pageLink = $this->getPageLink( $rev, $titleObj, $ts );
1411  $last = $this->msg( 'diff' )->escaped();
1412  }
1413  } else {
1414  $pageLink = htmlspecialchars( $this->getLanguage()->userTimeAndDate( $ts, $user ) );
1415  $last = $this->msg( 'diff' )->escaped();
1416  }
1417 
1418  // User links
1419  $userLink = Linker::revUserTools( $rev );
1420 
1421  // Minor edit
1422  $minor = $rev->isMinor() ? ChangesList::flag( 'minor' ) : '';
1423 
1424  // Revision text size
1425  $size = $row->ar_len;
1426  if ( !is_null( $size ) ) {
1427  $revTextSize = Linker::formatRevisionSize( $size );
1428  }
1429 
1430  // Edit summary
1432 
1433  // Tags
1434  $attribs = array();
1435  list( $tagSummary, $classes ) = ChangeTags::formatSummaryRow( $row->ts_tags, 'deletedhistory' );
1436  if ( $classes ) {
1437  $attribs['class'] = implode( ' ', $classes );
1438  }
1439 
1440  // Revision delete links
1441  $revdlink = Linker::getRevDeleteLink( $user, $rev, $this->mTargetObj );
1442 
1443  $revisionRow = $this->msg( 'undelete-revision-row' )
1444  ->rawParams(
1445  $checkBox,
1446  $revdlink,
1447  $last,
1448  $pageLink,
1449  $userLink,
1450  $minor,
1451  $revTextSize,
1452  $comment,
1453  $tagSummary
1454  )
1455  ->escaped();
1457  return Xml::tags( 'li', $attribs, $revisionRow ) . "\n";
1458  }
1459 
1460  private function formatFileRow( $row ) {
1461  $file = ArchivedFile::newFromRow( $row );
1462  $ts = wfTimestamp( TS_MW, $row->fa_timestamp );
1463  $user = $this->getUser();
1464 
1465  if ( $this->mAllowed && $row->fa_storage_key ) {
1466  $checkBox = Xml::check( 'fileid' . $row->fa_id );
1467  $key = urlencode( $row->fa_storage_key );
1468  $pageLink = $this->getFileLink( $file, $this->getPageTitle(), $ts, $key );
1469  } else {
1470  $checkBox = '';
1471  $pageLink = $this->getLanguage()->userTimeAndDate( $ts, $user );
1472  }
1473  $userLink = $this->getFileUser( $file );
1474  $data = $this->msg( 'widthheight' )->numParams( $row->fa_width, $row->fa_height )->text();
1475  $bytes = $this->msg( 'parentheses' )
1476  ->rawParams( $this->msg( 'nbytes' )->numParams( $row->fa_size )->text() )
1477  ->plain();
1478  $data = htmlspecialchars( $data . ' ' . $bytes );
1479  $comment = $this->getFileComment( $file );
1480 
1481  // Add show/hide deletion links if available
1482  $canHide = $user->isAllowed( 'deleterevision' );
1483  if ( $canHide || ( $file->getVisibility() && $user->isAllowed( 'deletedhistory' ) ) ) {
1484  if ( !$file->userCan( File::DELETED_RESTRICTED, $user ) ) {
1485  // Revision was hidden from sysops
1486  $revdlink = Linker::revDeleteLinkDisabled( $canHide );
1487  } else {
1488  $query = array(
1489  'type' => 'filearchive',
1490  'target' => $this->mTargetObj->getPrefixedDBkey(),
1491  'ids' => $row->fa_id
1492  );
1493  $revdlink = Linker::revDeleteLink( $query,
1494  $file->isDeleted( File::DELETED_RESTRICTED ), $canHide );
1495  }
1496  } else {
1497  $revdlink = '';
1498  }
1499 
1500  return "<li>$checkBox $revdlink $pageLink . . $userLink $data $comment</li>\n";
1501  }
1502 
1511  function getPageLink( $rev, $titleObj, $ts ) {
1512  $user = $this->getUser();
1513  $time = $this->getLanguage()->userTimeAndDate( $ts, $user );
1514 
1515  if ( !$rev->userCan( Revision::DELETED_TEXT, $user ) ) {
1516  return '<span class="history-deleted">' . $time . '</span>';
1517  }
1518 
1520  $titleObj,
1521  htmlspecialchars( $time ),
1522  array(),
1523  array(
1524  'target' => $this->mTargetObj->getPrefixedText(),
1525  'timestamp' => $ts
1526  )
1527  );
1528 
1529  if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
1530  $link = '<span class="history-deleted">' . $link . '</span>';
1531  }
1532 
1533  return $link;
1534  }
1535 
1546  function getFileLink( $file, $titleObj, $ts, $key ) {
1547  $user = $this->getUser();
1548  $time = $this->getLanguage()->userTimeAndDate( $ts, $user );
1549 
1550  if ( !$file->userCan( File::DELETED_FILE, $user ) ) {
1551  return '<span class="history-deleted">' . $time . '</span>';
1552  }
1553 
1555  $titleObj,
1556  htmlspecialchars( $time ),
1557  array(),
1558  array(
1559  'target' => $this->mTargetObj->getPrefixedText(),
1560  'file' => $key,
1561  'token' => $user->getEditToken( $key )
1562  )
1563  );
1564 
1565  if ( $file->isDeleted( File::DELETED_FILE ) ) {
1566  $link = '<span class="history-deleted">' . $link . '</span>';
1567  }
1568 
1569  return $link;
1570  }
1571 
1578  function getFileUser( $file ) {
1579  if ( !$file->userCan( File::DELETED_USER, $this->getUser() ) ) {
1580  return '<span class="history-deleted">' .
1581  $this->msg( 'rev-deleted-user' )->escaped() .
1582  '</span>';
1583  }
1584 
1585  $link = Linker::userLink( $file->getRawUser(), $file->getRawUserText() ) .
1586  Linker::userToolLinks( $file->getRawUser(), $file->getRawUserText() );
1587 
1588  if ( $file->isDeleted( File::DELETED_USER ) ) {
1589  $link = '<span class="history-deleted">' . $link . '</span>';
1590  }
1591 
1592  return $link;
1593  }
1594 
1601  function getFileComment( $file ) {
1602  if ( !$file->userCan( File::DELETED_COMMENT, $this->getUser() ) ) {
1603  return '<span class="history-deleted"><span class="comment">' .
1604  $this->msg( 'rev-deleted-comment' )->escaped() . '</span></span>';
1605  }
1606 
1607  $link = Linker::commentBlock( $file->getRawDescription() );
1608 
1609  if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
1610  $link = '<span class="history-deleted">' . $link . '</span>';
1611  }
1613  return $link;
1614  }
1615 
1616  function undelete() {
1617  global $wgUploadMaintenance;
1618 
1619  if ( $wgUploadMaintenance && $this->mTargetObj->getNamespace() == NS_FILE ) {
1620  throw new ErrorPageError( 'undelete-error', 'filedelete-maintenance' );
1621  }
1622 
1623  if ( wfReadOnly() ) {
1624  throw new ReadOnlyError;
1625  }
1626 
1627  $out = $this->getOutput();
1628  $archive = new PageArchive( $this->mTargetObj );
1629  wfRunHooks( 'UndeleteForm::undelete', array( &$archive, $this->mTargetObj ) );
1630  $ok = $archive->undelete(
1631  $this->mTargetTimestamp,
1632  $this->mComment,
1633  $this->mFileVersions,
1634  $this->mUnsuppress,
1635  $this->getUser()
1636  );
1637 
1638  if ( is_array( $ok ) ) {
1639  if ( $ok[1] ) { // Undeleted file count
1640  wfRunHooks( 'FileUndeleteComplete', array(
1641  $this->mTargetObj, $this->mFileVersions,
1642  $this->getUser(), $this->mComment ) );
1643  }
1644 
1645  $link = Linker::linkKnown( $this->mTargetObj );
1646  $out->addHTML( $this->msg( 'undeletedpage' )->rawParams( $link )->parse() );
1647  } else {
1648  $out->setPageTitle( $this->msg( 'undelete-error' ) );
1649  }
1650 
1651  // Show revision undeletion warnings and errors
1652  $status = $archive->getRevisionStatus();
1653  if ( $status && !$status->isGood() ) {
1654  $out->addWikiText( '<div class="error">' .
1655  $status->getWikiText(
1656  'cannotundelete',
1657  'cannotundelete'
1658  ) . '</div>'
1659  );
1660  }
1661 
1662  // Show file undeletion warnings and errors
1663  $status = $archive->getFileStatus();
1664  if ( $status && !$status->isGood() ) {
1665  $out->addWikiText( '<div class="error">' .
1666  $status->getWikiText(
1667  'undelete-error-short',
1668  'undelete-error-long'
1669  ) . '</div>'
1670  );
1671  }
1672  }
1673 
1674  protected function getGroupName() {
1675  return 'pagetools';
1676  }
1677 }
ReadOnlyError
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
Definition: ReadOnlyError.php:28
Xml\checkLabel
static checkLabel( $label, $name, $id, $checked=false, $attribs=array())
Convenience function to build an HTML checkbox with a label.
Definition: Xml.php:433
SpecialPage\getPageTitle
getPageTitle( $subpage=false)
Get a self-referential title object.
Definition: SpecialPage.php:488
$wgUser
$wgUser
Definition: Setup.php:552
SpecialUndelete\formatRevisionRow
formatRevisionRow( $row, $earliestLiveTime, $remaining)
Definition: SpecialUndelete.php:1362
$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. $reader:XMLReader object $logInfo:Array of information Return false to stop further processing of the tag 'ImportHandlePageXMLTag':When parsing a XML tag in a page. $reader:XMLReader object $pageInfo:Array of information Return false to stop further processing of the tag 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information Return false to stop further processing of the tag 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. $reader:XMLReader object Return false to stop further processing of the tag 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. $reader:XMLReader object $revisionInfo:Array of information Return false to stop further processing of the tag '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 '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. '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 '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 '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 wfIsTrustedProxy() $ip:IP being check $result:Change this value to override the result of wfIsTrustedProxy() '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 User::isValidEmailAddr(), 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. '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 '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) '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:Associative array mapping language codes to prefixed links of the form "language:title". & $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. 'LinkBegin':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:1528
$time
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1358
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:189
SpecialUndelete\diffHeader
diffHeader( $rev, $prefix)
Definition: SpecialUndelete.php:1084
Linker\commentBlock
static commentBlock( $comment, $title=null, $local=false)
Wrap a comment in standard punctuation and formatting if it's non-empty, otherwise return empty strin...
Definition: Linker.php:1556
DB_MASTER
const DB_MASTER
Definition: Defines.php:56
SpecialUndelete\showDiff
showDiff( $previousRev, $currentRev)
Build a diff display between this and the previous either deleted or non-deleted edit.
Definition: SpecialUndelete.php:1057
PageArchive\getFileStatus
getFileStatus()
Definition: SpecialUndelete.php:655
RepoGroup\singleton
static singleton()
Get a RepoGroup instance.
Definition: RepoGroup.php:53
Linker\revDeleteLink
static revDeleteLink( $query=array(), $restricted=false, $delete=true)
Creates a (show/hide) link for deleting revisions/log entries.
Definition: Linker.php:2196
SpecialUndelete\$mAllowed
$mAllowed
Definition: SpecialUndelete.php:681
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
File\DELETED_USER
const DELETED_USER
Definition: File.php:54
Revision\newFromId
static newFromId( $id, $flags=0)
Load a page revision from a given revision ID number.
Definition: Revision.php:88
$files
$files
Definition: importImages.php:67
LinkBatch
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition: LinkBatch.php:30
Xml\tags
static tags( $element, $attribs=null, $contents)
Same as Xml::element(), but does not escape contents.
Definition: Xml.php:131
$tables
namespace and then decline to actually register it RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist & $tables
Definition: hooks.txt:815
PageArchive
Used to show archived pages and eventually restore them.
Definition: SpecialUndelete.php:29
$response
$response
Definition: opensearch_desc.php:32
Linker\userLink
static userLink( $userId, $userName, $altUserName=false)
Make user link (or user contributions for unregistered users)
Definition: Linker.php:1072
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:535
File\DELETED_RESTRICTED
const DELETED_RESTRICTED
Definition: File.php:55
SpecialUndelete\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialUndelete.php:1670
PageArchive\undelete
undelete( $timestamps, $comment='', $fileVersions=array(), $unsuppress=false, User $user=null)
Restore the given (or all) text and file revisions for the page.
Definition: SpecialUndelete.php:358
SpecialUndelete
Special page allowing users with the appropriate permissions to view and restore deleted content.
Definition: SpecialUndelete.php:673
$last
$last
Definition: profileinfo.php:365
wfGetDB
& wfGetDB( $db, $groups=array(), $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3659
text
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:12
$timestamp
if( $limit) $timestamp
Definition: importImages.php:104
PageArchive\listPages
static listPages( $dbr, $condition)
Definition: SpecialUndelete.php:90
SpecialUndelete\getPageLink
getPageLink( $rev, $titleObj, $ts)
Fetch revision text link if it's available to all users.
Definition: SpecialUndelete.php:1507
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:2483
SpecialUndelete\execute
execute( $par)
Default execute method Checks user permissions, calls the function given in mFunction.
Definition: SpecialUndelete.php:757
SpecialUndelete\$mAction
$mAction
Definition: SpecialUndelete.php:674
SpecialUndelete\showRevision
showRevision( $timestamp)
Definition: SpecialUndelete.php:893
$n
$n
Definition: RandomTest.php:76
$ret
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 & $ret
Definition: hooks.txt:1530
SpecialUndelete\showHistory
showHistory()
Definition: SpecialUndelete.php:1191
SpecialUndelete\showList
showList( $result)
Generic list of deleted pages.
Definition: SpecialUndelete.php:850
SpecialPage\checkPermissions
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
Definition: SpecialPage.php:287
SpecialUndelete\showSearchForm
showSearchForm()
Definition: SpecialUndelete.php:812
Status\newGood
static newGood( $value=null)
Factory function for good results.
Definition: Status.php:77
PageArchive\listPagesByPrefix
static listPagesByPrefix( $prefix)
List deleted pages recorded in the archive table matching the given title prefix.
Definition: SpecialUndelete.php:64
NS_FILE
const NS_FILE
Definition: Defines.php:85
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1313
Revision\getRevisionText
static getRevisionText( $row, $prefix='old_', $wiki=false)
Get revision text associated with an old or archive row $row is usually an object from wfFetchRow(),...
Definition: Revision.php:1212
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:389
PageArchive\listFiles
listFiles()
List the deleted file revisions for this page, if it's a file page.
Definition: SpecialUndelete.php:165
SpecialPage\getSkin
getSkin()
Shortcut to get the skin being used for this instance.
Definition: SpecialPage.php:555
SpecialUndelete\$mTargetTimestamp
$mTargetTimestamp
Definition: SpecialUndelete.php:680
Html\hidden
static hidden( $name, $value, $attribs=array())
Convenience function to produce an input element with type=hidden.
Definition: Html.php:662
PermissionsError
Show an error when a user tries to do something they do not have the necessary permissions for.
Definition: PermissionsError.php:28
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:578
Linker\getInvalidTitleDescription
static getInvalidTitleDescription(IContextSource $context, $namespace, $title)
Get a message saying that an invalid title was encountered.
Definition: Linker.php:427
PageArchive\$revisionStatus
Status $revisionStatus
Definition: SpecialUndelete.php:34
$link
set to $title object and return false for a match for latest after cache objects are set use the ContentHandler facility to handle CSS and JavaScript for highlighting & $link
Definition: hooks.txt:2149
SpecialUndelete\getFileUser
getFileUser( $file)
Fetch file's user id if it's available to this user.
Definition: SpecialUndelete.php:1574
Xml\openElement
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:109
SpecialUndelete\$mFilename
$mFilename
Definition: SpecialUndelete.php:679
Linker\linkKnown
static linkKnown( $target, $html=null, $customAttribs=array(), $query=array(), $options=array( 'known', 'noclasses'))
Identical to link(), except $options defaults to 'known'.
Definition: Linker.php:264
true
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 true
Definition: hooks.txt:1530
SpecialUndelete\$mRestore
$mRestore
Definition: SpecialUndelete.php:677
PageArchive\isDeleted
isDeleted()
Quick check if any archived revisions are present for the page.
Definition: SpecialUndelete.php:333
ChangesList\flag
static flag( $flag)
Provide the "<abbr>" element appropriate to a given abbreviated flag, namely the flag indicating a ne...
Definition: ChangesList.php:132
$dbr
$dbr
Definition: testCompression.php:48
Linker\link
static link( $target, $html=null, $customAttribs=array(), $query=array(), $options=array())
This function returns an HTML link to the given target.
Definition: Linker.php:192
Status
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:40
Revision\FOR_THIS_USER
const FOR_THIS_USER
Definition: Revision.php:73
SpecialUndelete\$mTargetObj
Title $mTargetObj
Definition: SpecialUndelete.php:686
title
to move a page</td >< td > &*You are moving the page across *A non empty talk page already exists under the new or *You uncheck the box below In those you will have to move or merge the page manually if desired</td >< td > be sure to &You are responsible for making sure that links continue to point where they are supposed to go Note that the page will &a page at the new title
Definition: All_system_messages.txt:2703
Title\getDBkey
getDBkey()
Get the main part with underscores.
Definition: Title.php:857
SpecialUndelete\$mTimestamp
$mTimestamp
Definition: SpecialUndelete.php:676
MWException
MediaWiki exception.
Definition: MWException.php:26
SpecialUndelete\$mCanView
$mCanView
Definition: SpecialUndelete.php:682
$out
$out
Definition: UtfNormalGenerate.php:167
File\DELETED_COMMENT
const DELETED_COMMENT
Definition: File.php:53
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:103
ChangeTags\modifyDisplayQuery
static modifyDisplayQuery(&$tables, &$fields, &$conds, &$join_conds, &$options, $filter_tag=false)
Applies all tags-related changes to a query.
Definition: ChangeTags.php:202
PageArchive\listAllPages
static listAllPages()
List all deleted pages recorded in the archive table.
Definition: SpecialUndelete.php:50
Title\getNamespace
getNamespace()
Get the namespace index, i.e.
Definition: Title.php:880
Html\element
static element( $element, $attribs=array(), $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:148
PageArchive\undeleteRevisions
undeleteRevisions( $timestamps, $unsuppress=false, $comment='')
This is the meaty bit – restores archived revisions of the given page to the cur/old tables.
Definition: SpecialUndelete.php:441
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:1219
PageArchive\listRevisions
listRevisions()
List the revisions of the given page.
Definition: SpecialUndelete.php:114
LogPage
Class to simplify the use of log pages.
Definition: LogPage.php:32
wfMessage
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 after in associative array form externallinks including delete and has completed for all link tables 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
Xml\element
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:39
wfRunHooks
wfRunHooks( $event, array $args=array(), $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
Definition: GlobalFunctions.php:4010
PageArchive\getRevisionStatus
getRevisionStatus()
Definition: SpecialUndelete.php:662
Linker\revDeleteLinkDisabled
static revDeleteLinkDisabled( $delete=true)
Creates a dead (show/hide) link for deleting revisions/log entries.
Definition: Linker.php:2213
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
SpecialUndelete\$mToken
$mToken
Definition: SpecialUndelete.php:684
SpecialPage\setHeaders
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
Definition: SpecialPage.php:352
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:545
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
$comment
$comment
Definition: importImages.php:107
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
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:188
SpecialPage\getContext
getContext()
Gets the context this SpecialPage is executed in.
Definition: SpecialPage.php:508
$options
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 & $options
Definition: hooks.txt:1530
PageArchive\$fileStatus
Status $fileStatus
Definition: SpecialUndelete.php:32
$ok
$ok
Definition: UtfNormalTest.php:71
TS_MW
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
Definition: GlobalFunctions.php:2431
wfDebug
wfDebug( $text, $dest='all')
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:933
HTMLCacheUpdate
Class to invalidate the HTML cache of all the pages linking to a given title.
Definition: HTMLCacheUpdate.php:29
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:422
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:1578
SpecialUndelete\formatFileRow
formatFileRow( $row)
Definition: SpecialUndelete.php:1456
$title
presenting them properly to the user as errors is done by the caller $title
Definition: hooks.txt:1324
NS_USER_TALK
const NS_USER_TALK
Definition: Defines.php:82
PageArchive\getRevision
getRevision( $timestamp)
Return a Revision object containing data for the deleted revision.
Definition: SpecialUndelete.php:189
$matches
if(!defined( 'MEDIAWIKI')) if(!isset( $wgVersion)) $matches
Definition: NoLocalSettings.php:33
$size
$size
Definition: RandomTest.php:75
Linker\userToolLinks
static userToolLinks( $userId, $userText, $redContribsWhenNoEdits=false, $flags=0, $edits=null)
Generate standard user tool links (talk, contributions, block link, etc.)
Definition: Linker.php:1100
SpecialPage\msg
msg()
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:609
Xml\check
static check( $name, $checked=false, $attribs=array())
Convenience function to build an HTML checkbox.
Definition: Xml.php:339
ArchivedFile
Class representing a row of the 'filearchive' table.
Definition: ArchivedFile.php:29
SpecialPage
Parent class for all special pages.
Definition: SpecialPage.php:33
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:2155
PageArchive\__construct
__construct( $title)
Definition: SpecialUndelete.php:36
SpecialUndelete\$mComment
$mComment
Definition: SpecialUndelete.php:683
SpecialUndelete\$mInvert
$mInvert
Definition: SpecialUndelete.php:678
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:525
Title\newFromURL
static newFromURL( $url)
THIS IS NOT THE FUNCTION YOU WANT.
Definition: Title.php:241
Revision\newFromArchiveRow
static newFromArchiveRow( $row, $overrides=array())
Make a fake revision object from an archive table row.
Definition: Revision.php:159
Linker\formatRevisionSize
static formatRevisionSize( $size)
Definition: Linker.php:1600
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:2077
Revision\RAW
const RAW
Definition: Revision.php:74
SpecialUndelete\getFileComment
getFileComment( $file)
Fetch file upload comment if it's available to this user.
Definition: SpecialUndelete.php:1597
$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:237
TextContent
Content object implementation for representing flat text.
Definition: TextContent.php:35
$file
if(PHP_SAPI !='cli') $file
Definition: UtfNormalTest2.php:30
$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:1337
SpecialUndelete\getFileLink
getFileLink( $file, $titleObj, $ts, $key)
Fetch image view link if it's available to all users.
Definition: SpecialUndelete.php:1542
DB_SLAVE
const DB_SLAVE
Definition: Defines.php:55
Title
Represents a title within MediaWiki.
Definition: Title.php:35
Xml\closeElement
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:118
PageArchive\getLastRevisionText
getLastRevisionText()
Fetch (and decompress if necessary) the stored text of the most recently edited deleted revision of t...
Definition: SpecialUndelete.php:312
SpecialUndelete\showFile
showFile( $key)
Show a deleted file version requested by the visitor.
Definition: SpecialUndelete.php:1174
$path
$path
Definition: NoLocalSettings.php:35
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
SpecialUndelete\__construct
__construct()
Definition: SpecialUndelete.php:688
NS_USER
const NS_USER
Definition: Defines.php:81
$batch
$batch
Definition: linkcache.txt:23
ManualLogEntry
Class for creating log entries manually, for example to inject them into the database.
Definition: LogEntry.php:339
PageArchive\getTextFromRow
getTextFromRow( $row)
Get the text from an archive row containing ar_text, ar_flags and ar_text_id.
Definition: SpecialUndelete.php:287
Xml\submitButton
static submitButton( $value, $attribs=array())
Convenience function to build an HTML submit button.
Definition: Xml.php:463
File\DELETED_FILE
const DELETED_FILE
Definition: File.php:52
$t
$t
Definition: testCompression.php:65
SpecialUndelete\$mTarget
$mTarget
Definition: SpecialUndelete.php:675
SpecialUndelete\undelete
undelete()
Definition: SpecialUndelete.php:1612
ArchivedFile\selectFields
static selectFields()
Fields in the filearchive table.
Definition: ArchivedFile.php:190
Xml\input
static input( $name, $size=false, $value=false, $attribs=array())
Convenience function to build an HTML text input field.
Definition: Xml.php:294
SpecialUndelete\showFileConfirmationForm
showFileConfirmationForm( $key)
Show a form confirming whether a tokenless user really wants to see a file.
Definition: SpecialUndelete.php:1147
Html\rawElement
static rawElement( $element, $attribs=array(), $contents='')
Returns an HTML element in a string.
Definition: Html.php:124
Xml\label
static label( $label, $id, $attribs=array())
Convenience function to build an HTML form label.
Definition: Xml.php:374
ErrorPageError
An error page which can definitely be safely rendered using the OutputPage.
Definition: ErrorPageError.php:27
$query
return true to allow those checks to and false if checking is done use this to change the tables headers temp or archived zone change it to an object instance and return false override the list derivative used the name of the old file when set the default code will be skipped add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1105
$attribs
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:1530
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:59
wfLocalFile
wfLocalFile( $title)
Get an object referring to a locally registered file.
Definition: GlobalFunctions.php:3713
$article
Using a hook running we can avoid having all this option specific stuff in our mainline code Using the function array $article
Definition: hooks.txt:78
$res
$res
Definition: database.txt:21
PageArchive\$title
Title $title
Definition: SpecialUndelete.php:30
SpecialPage\outputHeader
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
Definition: SpecialPage.php:443
Revision\DELETED_TEXT
const DELETED_TEXT
Definition: Revision.php:65
Xml\fieldset
static fieldset( $legend=false, $content=false, $attribs=array())
Shortcut for creating fieldsets.
Definition: Xml.php:563
ArchivedFile\newFromRow
static newFromRow( $row)
Loads a file object from the filearchive table.
Definition: ArchivedFile.php:179
ChangeTags\formatSummaryRow
static formatSummaryRow( $tags, $page)
Creates HTML for the given tags.
Definition: ChangeTags.php:34
SpecialUndelete\loadRequest
loadRequest( $par)
Definition: SpecialUndelete.php:692
LogEventsList\showLogExtract
static showLogExtract(&$out, $types=array(), $page='', $user='', $param=array())
Show log extract.
Definition: LogEventsList.php:507
Status\newFatal
static newFatal( $message)
Factory function for fatal errors.
Definition: Status.php:63
PageArchive\getPreviousRevision
getPreviousRevision( $timestamp)
Return the most-previous revision, either live or deleted, against the deleted revision given by time...
Definition: SpecialUndelete.php:238