FileRevertForm.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <?php
  2. /**
  3. * File reversion user interface
  4. *
  5. * @ingroup Media
  6. * @author Rob Church <robchur@gmail.com>
  7. */
  8. class FileRevertForm {
  9. protected $title = null;
  10. protected $file = null;
  11. protected $archiveName = '';
  12. protected $timestamp = false;
  13. protected $oldFile;
  14. /**
  15. * Constructor
  16. *
  17. * @param File $file File we're reverting
  18. */
  19. public function __construct( $file ) {
  20. $this->title = $file->getTitle();
  21. $this->file = $file;
  22. }
  23. /**
  24. * Fulfil the request; shows the form or reverts the file,
  25. * pending authentication, confirmation, etc.
  26. */
  27. public function execute() {
  28. global $wgOut, $wgRequest, $wgUser, $wgLang;
  29. $this->setHeaders();
  30. if( wfReadOnly() ) {
  31. $wgOut->readOnlyPage();
  32. return;
  33. } elseif( !$wgUser->isLoggedIn() ) {
  34. $wgOut->showErrorPage( 'uploadnologin', 'uploadnologintext' );
  35. return;
  36. } elseif( !$this->title->userCan( 'edit' ) || !$this->title->userCan( 'upload' ) ) {
  37. // The standard read-only thing doesn't make a whole lot of sense
  38. // here; surely it should show the image or something? -- RC
  39. $article = new Article( $this->title );
  40. $wgOut->readOnlyPage( $article->getContent(), true );
  41. return;
  42. } elseif( $wgUser->isBlocked() ) {
  43. $wgOut->blockedPage();
  44. return;
  45. }
  46. $this->archiveName = $wgRequest->getText( 'oldimage' );
  47. $token = $wgRequest->getText( 'wpEditToken' );
  48. if( !$this->isValidOldSpec() ) {
  49. $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars( $this->archiveName ) );
  50. return;
  51. }
  52. if( !$this->haveOldVersion() ) {
  53. $wgOut->addHTML( wfMsgExt( 'filerevert-badversion', 'parse' ) );
  54. $wgOut->returnToMain( false, $this->title );
  55. return;
  56. }
  57. // Perform the reversion if appropriate
  58. if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $token, $this->archiveName ) ) {
  59. $source = $this->file->getArchiveVirtualUrl( $this->archiveName );
  60. $comment = $wgRequest->getText( 'wpComment' );
  61. // TODO: Preserve file properties from database instead of reloading from file
  62. $status = $this->file->upload( $source, $comment, $comment );
  63. if( $status->isGood() ) {
  64. $wgOut->addHTML( wfMsgExt( 'filerevert-success', 'parse', $this->title->getText(),
  65. $wgLang->date( $this->getTimestamp(), true ),
  66. $wgLang->time( $this->getTimestamp(), true ),
  67. wfExpandUrl( $this->file->getArchiveUrl( $this->archiveName ) ) ) );
  68. $wgOut->returnToMain( false, $this->title );
  69. } else {
  70. $wgOut->addWikiText( $status->getWikiText() );
  71. }
  72. return;
  73. }
  74. // Show the form
  75. $this->showForm();
  76. }
  77. /**
  78. * Show the confirmation form
  79. */
  80. protected function showForm() {
  81. global $wgOut, $wgUser, $wgRequest, $wgLang, $wgContLang;
  82. $timestamp = $this->getTimestamp();
  83. $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getAction() ) );
  84. $form .= Xml::hidden( 'wpEditToken', $wgUser->editToken( $this->archiveName ) );
  85. $form .= '<fieldset><legend>' . wfMsgHtml( 'filerevert-legend' ) . '</legend>';
  86. $form .= wfMsgExt( 'filerevert-intro', 'parse', $this->title->getText(),
  87. $wgLang->date( $timestamp, true ), $wgLang->time( $timestamp, true ),
  88. wfExpandUrl( $this->file->getArchiveUrl( $this->archiveName ) ) );
  89. $form .= '<p>' . Xml::inputLabel( wfMsg( 'filerevert-comment' ), 'wpComment', 'wpComment',
  90. 60, wfMsgForContent( 'filerevert-defaultcomment',
  91. $wgContLang->date( $timestamp, false, false ), $wgContLang->time( $timestamp, false, false ) ) ) . '</p>';
  92. $form .= '<p>' . Xml::submitButton( wfMsg( 'filerevert-submit' ) ) . '</p>';
  93. $form .= '</fieldset>';
  94. $form .= '</form>';
  95. $wgOut->addHTML( $form );
  96. }
  97. /**
  98. * Set headers, titles and other bits
  99. */
  100. protected function setHeaders() {
  101. global $wgOut, $wgUser;
  102. $wgOut->setPageTitle( wfMsg( 'filerevert', $this->title->getText() ) );
  103. $wgOut->setRobotPolicy( 'noindex,nofollow' );
  104. $wgOut->setSubtitle( wfMsg( 'filerevert-backlink', $wgUser->getSkin()->makeKnownLinkObj( $this->title ) ) );
  105. }
  106. /**
  107. * Is the provided `oldimage` value valid?
  108. *
  109. * @return bool
  110. */
  111. protected function isValidOldSpec() {
  112. return strlen( $this->archiveName ) >= 16
  113. && strpos( $this->archiveName, '/' ) === false
  114. && strpos( $this->archiveName, '\\' ) === false;
  115. }
  116. /**
  117. * Does the provided `oldimage` value correspond
  118. * to an existing, local, old version of this file?
  119. *
  120. * @return bool
  121. */
  122. protected function haveOldVersion() {
  123. return $this->getOldFile()->exists();
  124. }
  125. /**
  126. * Prepare the form action
  127. *
  128. * @return string
  129. */
  130. protected function getAction() {
  131. $q = array();
  132. $q[] = 'action=revert';
  133. $q[] = 'oldimage=' . urlencode( $this->archiveName );
  134. return $this->title->getLocalUrl( implode( '&', $q ) );
  135. }
  136. /**
  137. * Extract the timestamp of the old version
  138. *
  139. * @return string
  140. */
  141. protected function getTimestamp() {
  142. if( $this->timestamp === false ) {
  143. $this->timestamp = $this->getOldFile()->getTimestamp();
  144. }
  145. return $this->timestamp;
  146. }
  147. protected function getOldFile() {
  148. if ( !isset( $this->oldFile ) ) {
  149. $this->oldFile = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $this->title, $this->archiveName );
  150. }
  151. return $this->oldFile;
  152. }
  153. }