[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Job to fix double redirects after moving a page. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @ingroup JobQueue 22 */ 23 24 /** 25 * Job to fix double redirects after moving a page 26 * 27 * @ingroup JobQueue 28 */ 29 class DoubleRedirectJob extends Job { 30 /** @var string Reason for the change, 'maintenance' or 'move'. Suffix fo 31 * message key 'double-redirect-fixed-'. 32 */ 33 private $reason; 34 35 /** @var Title The title which has changed, redirects pointing to this 36 * title are fixed 37 */ 38 private $redirTitle; 39 40 /** @var User */ 41 private static $user; 42 43 /** 44 * Insert jobs into the job queue to fix redirects to the given title 45 * @param string $reason The reason for the fix, see message 46 * "double-redirect-fixed-<reason>" 47 * @param Title $redirTitle The title which has changed, redirects 48 * pointing to this title are fixed 49 * @param bool $destTitle Not used 50 */ 51 public static function fixRedirects( $reason, $redirTitle, $destTitle = false ) { 52 # Need to use the master to get the redirect table updated in the same transaction 53 $dbw = wfGetDB( DB_MASTER ); 54 $res = $dbw->select( 55 array( 'redirect', 'page' ), 56 array( 'page_namespace', 'page_title' ), 57 array( 58 'page_id = rd_from', 59 'rd_namespace' => $redirTitle->getNamespace(), 60 'rd_title' => $redirTitle->getDBkey() 61 ), __METHOD__ ); 62 if ( !$res->numRows() ) { 63 return; 64 } 65 $jobs = array(); 66 foreach ( $res as $row ) { 67 $title = Title::makeTitle( $row->page_namespace, $row->page_title ); 68 if ( !$title ) { 69 continue; 70 } 71 72 $jobs[] = new self( $title, array( 73 'reason' => $reason, 74 'redirTitle' => $redirTitle->getPrefixedDBkey() ) ); 75 # Avoid excessive memory usage 76 if ( count( $jobs ) > 10000 ) { 77 JobQueueGroup::singleton()->push( $jobs ); 78 $jobs = array(); 79 } 80 } 81 JobQueueGroup::singleton()->push( $jobs ); 82 } 83 84 /** 85 * @param Title $title 86 * @param array|bool $params 87 */ 88 function __construct( $title, $params = false ) { 89 parent::__construct( 'fixDoubleRedirect', $title, $params ); 90 $this->reason = $params['reason']; 91 $this->redirTitle = Title::newFromText( $params['redirTitle'] ); 92 } 93 94 /** 95 * @return bool 96 */ 97 function run() { 98 if ( !$this->redirTitle ) { 99 $this->setLastError( 'Invalid title' ); 100 101 return false; 102 } 103 104 $targetRev = Revision::newFromTitle( $this->title, false, Revision::READ_LATEST ); 105 if ( !$targetRev ) { 106 wfDebug( __METHOD__ . ": target redirect already deleted, ignoring\n" ); 107 108 return true; 109 } 110 $content = $targetRev->getContent(); 111 $currentDest = $content ? $content->getRedirectTarget() : null; 112 if ( !$currentDest || !$currentDest->equals( $this->redirTitle ) ) { 113 wfDebug( __METHOD__ . ": Redirect has changed since the job was queued\n" ); 114 115 return true; 116 } 117 118 // Check for a suppression tag (used e.g. in periodically archived discussions) 119 $mw = MagicWord::get( 'staticredirect' ); 120 if ( $content->matchMagicWord( $mw ) ) { 121 wfDebug( __METHOD__ . ": skipping: suppressed with __STATICREDIRECT__\n" ); 122 123 return true; 124 } 125 126 // Find the current final destination 127 $newTitle = self::getFinalDestination( $this->redirTitle ); 128 if ( !$newTitle ) { 129 wfDebug( __METHOD__ . 130 ": skipping: single redirect, circular redirect or invalid redirect destination\n" ); 131 132 return true; 133 } 134 if ( $newTitle->equals( $this->redirTitle ) ) { 135 // The redirect is already right, no need to change it 136 // This can happen if the page was moved back (say after vandalism) 137 wfDebug( __METHOD__ . " : skipping, already good\n" ); 138 } 139 140 // Preserve fragment (bug 14904) 141 $newTitle = Title::makeTitle( $newTitle->getNamespace(), $newTitle->getDBkey(), 142 $currentDest->getFragment(), $newTitle->getInterwiki() ); 143 144 // Fix the text 145 $newContent = $content->updateRedirect( $newTitle ); 146 147 if ( $newContent->equals( $content ) ) { 148 $this->setLastError( 'Content unchanged???' ); 149 150 return false; 151 } 152 153 $user = $this->getUser(); 154 if ( !$user ) { 155 $this->setLastError( 'Invalid user' ); 156 157 return false; 158 } 159 160 // Save it 161 global $wgUser; 162 $oldUser = $wgUser; 163 $wgUser = $user; 164 $article = WikiPage::factory( $this->title ); 165 166 // Messages: double-redirect-fixed-move, double-redirect-fixed-maintenance 167 $reason = wfMessage( 'double-redirect-fixed-' . $this->reason, 168 $this->redirTitle->getPrefixedText(), $newTitle->getPrefixedText() 169 )->inContentLanguage()->text(); 170 $article->doEditContent( $newContent, $reason, EDIT_UPDATE | EDIT_SUPPRESS_RC, false, $user ); 171 $wgUser = $oldUser; 172 173 return true; 174 } 175 176 /** 177 * Get the final destination of a redirect 178 * 179 * @param Title $title 180 * 181 * @return bool If the specified title is not a redirect, or if it is a circular redirect 182 */ 183 public static function getFinalDestination( $title ) { 184 $dbw = wfGetDB( DB_MASTER ); 185 186 // Circular redirect check 187 $seenTitles = array(); 188 $dest = false; 189 190 while ( true ) { 191 $titleText = $title->getPrefixedDBkey(); 192 if ( isset( $seenTitles[$titleText] ) ) { 193 wfDebug( __METHOD__, "Circular redirect detected, aborting\n" ); 194 195 return false; 196 } 197 $seenTitles[$titleText] = true; 198 199 if ( $title->isExternal() ) { 200 // If the target is interwiki, we have to break early (bug 40352). 201 // Otherwise it will look up a row in the local page table 202 // with the namespace/page of the interwiki target which can cause 203 // unexpected results (e.g. X -> foo:Bar -> Bar -> .. ) 204 break; 205 } 206 207 $row = $dbw->selectRow( 208 array( 'redirect', 'page' ), 209 array( 'rd_namespace', 'rd_title', 'rd_interwiki' ), 210 array( 211 'rd_from=page_id', 212 'page_namespace' => $title->getNamespace(), 213 'page_title' => $title->getDBkey() 214 ), __METHOD__ ); 215 if ( !$row ) { 216 # No redirect from here, chain terminates 217 break; 218 } else { 219 $dest = $title = Title::makeTitle( 220 $row->rd_namespace, 221 $row->rd_title, 222 '', 223 $row->rd_interwiki 224 ); 225 } 226 } 227 228 return $dest; 229 } 230 231 /** 232 * Get a user object for doing edits, from a request-lifetime cache 233 * False will be returned if the user name specified in the 234 * 'double-redirect-fixer' message is invalid. 235 * 236 * @return User|bool 237 */ 238 function getUser() { 239 if ( !self::$user ) { 240 $username = wfMessage( 'double-redirect-fixer' )->inContentLanguage()->text(); 241 self::$user = User::newFromName( $username ); 242 # User::newFromName() can return false on a badly configured wiki. 243 if ( self::$user && !self::$user->isLoggedIn() ) { 244 self::$user->addToDatabase(); 245 } 246 } 247 248 return self::$user; 249 } 250 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |