[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Check for articles to fix after adding/deleting namespaces 4 * 5 * Copyright © 2005-2007 Brion Vibber <[email protected]> 6 * https://www.mediawiki.org/ 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License along 19 * with this program; if not, write to the Free Software Foundation, Inc., 20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 * http://www.gnu.org/copyleft/gpl.html 22 * 23 * @file 24 * @ingroup Maintenance 25 */ 26 27 require_once __DIR__ . '/Maintenance.php'; 28 29 /** 30 * Maintenance script that checks for articles to fix after 31 * adding/deleting namespaces. 32 * 33 * @ingroup Maintenance 34 */ 35 class NamespaceConflictChecker extends Maintenance { 36 37 /** 38 * @var DatabaseBase 39 */ 40 protected $db; 41 42 public function __construct() { 43 parent::__construct(); 44 $this->mDescription = ""; 45 $this->addOption( 'fix', 'Attempt to automatically fix errors' ); 46 $this->addOption( 'suffix', "Dupes will be renamed with correct namespace with " . 47 "<text> appended after the article name", false, true ); 48 $this->addOption( 'prefix', "Do an explicit check for the given title prefix " . 49 "appended after the article name", false, true ); 50 } 51 52 public function execute() { 53 $this->db = wfGetDB( DB_MASTER ); 54 55 $fix = $this->hasOption( 'fix' ); 56 $suffix = $this->getOption( 'suffix', '' ); 57 $prefix = $this->getOption( 'prefix', '' ); 58 $key = intval( $this->getOption( 'key', 0 ) ); 59 60 if ( $prefix ) { 61 $retval = $this->checkPrefix( $key, $prefix, $fix, $suffix ); 62 } else { 63 $retval = $this->checkAll( $fix, $suffix ); 64 } 65 66 if ( $retval ) { 67 $this->output( "\nLooks good!\n" ); 68 } else { 69 $this->output( "\nOh noeees\n" ); 70 } 71 } 72 73 /** 74 * @todo Document 75 * @param bool $fix Whether or not to fix broken entries 76 * @param string $suffix Suffix to append to renamed articles 77 * 78 * @return bool 79 */ 80 private function checkAll( $fix, $suffix = '' ) { 81 global $wgContLang, $wgNamespaceAliases, $wgCapitalLinks; 82 83 $spaces = array(); 84 85 // List interwikis first, so they'll be overridden 86 // by any conflicting local namespaces. 87 foreach ( $this->getInterwikiList() as $prefix ) { 88 $name = $wgContLang->ucfirst( $prefix ); 89 $spaces[$name] = 0; 90 } 91 92 // Now pull in all canonical and alias namespaces... 93 foreach ( MWNamespace::getCanonicalNamespaces() as $ns => $name ) { 94 // This includes $wgExtraNamespaces 95 if ( $name !== '' ) { 96 $spaces[$name] = $ns; 97 } 98 } 99 foreach ( $wgContLang->getNamespaces() as $ns => $name ) { 100 if ( $name !== '' ) { 101 $spaces[$name] = $ns; 102 } 103 } 104 foreach ( $wgNamespaceAliases as $name => $ns ) { 105 $spaces[$name] = $ns; 106 } 107 foreach ( $wgContLang->getNamespaceAliases() as $name => $ns ) { 108 $spaces[$name] = $ns; 109 } 110 111 // We'll need to check for lowercase keys as well, 112 // since we're doing case-sensitive searches in the db. 113 foreach ( $spaces as $name => $ns ) { 114 $moreNames = array(); 115 $moreNames[] = $wgContLang->uc( $name ); 116 $moreNames[] = $wgContLang->ucfirst( $wgContLang->lc( $name ) ); 117 $moreNames[] = $wgContLang->ucwords( $name ); 118 $moreNames[] = $wgContLang->ucwords( $wgContLang->lc( $name ) ); 119 $moreNames[] = $wgContLang->ucwordbreaks( $name ); 120 $moreNames[] = $wgContLang->ucwordbreaks( $wgContLang->lc( $name ) ); 121 if ( !$wgCapitalLinks ) { 122 foreach ( $moreNames as $altName ) { 123 $moreNames[] = $wgContLang->lcfirst( $altName ); 124 } 125 $moreNames[] = $wgContLang->lcfirst( $name ); 126 } 127 foreach ( array_unique( $moreNames ) as $altName ) { 128 if ( $altName !== $name ) { 129 $spaces[$altName] = $ns; 130 } 131 } 132 } 133 134 ksort( $spaces ); 135 asort( $spaces ); 136 137 $ok = true; 138 foreach ( $spaces as $name => $ns ) { 139 $ok = $this->checkNamespace( $ns, $name, $fix, $suffix ) && $ok; 140 } 141 142 return $ok; 143 } 144 145 /** 146 * Get the interwiki list 147 * 148 * @return array 149 */ 150 private function getInterwikiList() { 151 $result = Interwiki::getAllPrefixes(); 152 $prefixes = array(); 153 foreach ( $result as $row ) { 154 $prefixes[] = $row['iw_prefix']; 155 } 156 157 return $prefixes; 158 } 159 160 /** 161 * @todo Document 162 * @param int $ns A namespace id 163 * @param string $name 164 * @param bool $fix Whether to fix broken entries 165 * @param string $suffix Suffix to append to renamed articles 166 * @return bool 167 */ 168 private function checkNamespace( $ns, $name, $fix, $suffix = '' ) { 169 $conflicts = $this->getConflicts( $ns, $name ); 170 $count = count( $conflicts ); 171 if ( $count == 0 ) { 172 return true; 173 } 174 175 $ok = true; 176 foreach ( $conflicts as $row ) { 177 $resolvable = $this->reportConflict( $row, $suffix ); 178 $ok = $ok && $resolvable; 179 if ( $fix && ( $resolvable || $suffix != '' ) ) { 180 $ok = $this->resolveConflict( $row, $resolvable, $suffix ) && $ok; 181 } 182 } 183 184 return $ok; 185 } 186 187 /** 188 * @todo Do this for real 189 * @param int $key 190 * @param string $prefix 191 * @param bool $fix 192 * @param string $suffix 193 * @return bool 194 */ 195 private function checkPrefix( $key, $prefix, $fix, $suffix = '' ) { 196 $this->output( "Checking prefix \"$prefix\" vs namespace $key\n" ); 197 198 return $this->checkNamespace( $key, $prefix, $fix, $suffix ); 199 } 200 201 /** 202 * Find pages in mainspace that have a prefix of the new namespace 203 * so we know titles that will need migrating 204 * 205 * @param int $ns Namespace id (id for new namespace?) 206 * @param string $name Prefix that is being made a namespace 207 * 208 * @return array 209 */ 210 private function getConflicts( $ns, $name ) { 211 $titleSql = "TRIM(LEADING {$this->db->addQuotes( "$name:" )} FROM page_title)"; 212 if ( $ns == 0 ) { 213 // An interwiki; try an alternate encoding with '-' for ':' 214 $titleSql = $this->db->buildConcat( array( 215 $this->db->addQuotes( "$name-" ), 216 $titleSql, 217 ) ); 218 } 219 220 return iterator_to_array( $this->db->select( 'page', 221 array( 222 'id' => 'page_id', 223 'oldtitle' => 'page_title', 224 'namespace' => $this->db->addQuotes( $ns ) . ' + page_namespace', 225 'title' => $titleSql, 226 'oldnamespace' => 'page_namespace', 227 ), 228 array( 229 'page_namespace' => array( 0, 1 ), 230 'page_title' . $this->db->buildLike( "$name:", $this->db->anyString() ), 231 ), 232 __METHOD__ 233 ) ); 234 } 235 236 /** 237 * Report any conflicts we find 238 * 239 * @param stdClass $row 240 * @param string $suffix 241 * @return bool 242 */ 243 private function reportConflict( $row, $suffix ) { 244 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title ); 245 if ( is_null( $newTitle ) || !$newTitle->canExist() ) { 246 // Title is also an illegal title... 247 // For the moment we'll let these slide to cleanupTitles or whoever. 248 $this->output( sprintf( "... %d (%d,\"%s\")\n", 249 $row->id, 250 $row->oldnamespace, 251 $row->oldtitle ) ); 252 $this->output( "... *** cannot resolve automatically; illegal title ***\n" ); 253 254 return false; 255 } 256 257 $this->output( sprintf( "... %d (%d,\"%s\") -> (%d,\"%s\") [[%s]]\n", 258 $row->id, 259 $row->oldnamespace, 260 $row->oldtitle, 261 $newTitle->getNamespace(), 262 $newTitle->getDBkey(), 263 $newTitle->getPrefixedText() ) ); 264 265 $id = $newTitle->getArticleID(); 266 if ( $id ) { 267 $this->output( "... *** cannot resolve automatically; page exists with ID $id ***\n" ); 268 269 return false; 270 } else { 271 return true; 272 } 273 } 274 275 /** 276 * Resolve any conflicts 277 * 278 * @param stClass $row Row from the page table to fix 279 * @param bool $resolvable 280 * @param string $suffix Suffix to append to the fixed page 281 * @return bool 282 */ 283 private function resolveConflict( $row, $resolvable, $suffix ) { 284 if ( !$resolvable ) { 285 $this->output( "... *** old title {$row->title}\n" ); 286 while ( true ) { 287 $row->title .= $suffix; 288 $this->output( "... *** new title {$row->title}\n" ); 289 $title = Title::makeTitleSafe( $row->namespace, $row->title ); 290 if ( !$title ) { 291 $this->output( "... !!! invalid title\n" ); 292 293 return false; 294 } 295 $id = $title->getArticleID(); 296 if ( $id ) { 297 $this->output( "... *** page exists with ID $id ***\n" ); 298 } else { 299 break; 300 } 301 } 302 $this->output( "... *** using suffixed form [[" . $title->getPrefixedText() . "]] ***\n" ); 303 } 304 $this->resolveConflictOn( $row, 'page', 'page' ); 305 306 return true; 307 } 308 309 /** 310 * Resolve a given conflict 311 * 312 * @param stdClass $row Row from the old broken entry 313 * @param string $table Table to update 314 * @param string $prefix Prefix for column name, like page or ar 315 * @return bool 316 */ 317 private function resolveConflictOn( $row, $table, $prefix ) { 318 $this->output( "... resolving on $table... " ); 319 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title ); 320 $this->db->update( $table, 321 array( 322 "{$prefix}_namespace" => $newTitle->getNamespace(), 323 "{$prefix}_title" => $newTitle->getDBkey(), 324 ), 325 array( 326 // "{$prefix}_namespace" => 0, 327 // "{$prefix}_title" => $row->oldtitle, 328 "{$prefix}_id" => $row->id, 329 ), 330 __METHOD__ ); 331 $this->output( "ok.\n" ); 332 333 return true; 334 } 335 } 336 337 $maintClass = "NamespaceConflictChecker"; 338 require_once RUN_MAINTENANCE_IF_MAIN;
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 |