MediaWiki
REL1_22
|
00001 <?php 00027 require_once __DIR__ . '/Maintenance.php'; 00028 00035 class NamespaceConflictChecker extends Maintenance { 00036 00040 protected $db; 00041 00042 public function __construct() { 00043 parent::__construct(); 00044 $this->mDescription = ""; 00045 $this->addOption( 'fix', 'Attempt to automatically fix errors' ); 00046 $this->addOption( 'suffix', "Dupes will be renamed with correct namespace with " . 00047 "<text> appended after the article name", false, true ); 00048 $this->addOption( 'prefix', "Do an explicit check for the given title prefix " . 00049 "appended after the article name", false, true ); 00050 } 00051 00052 public function execute() { 00053 global $wgTitle; 00054 00055 $this->db = wfGetDB( DB_MASTER ); 00056 $wgTitle = Title::newFromText( 'Namespace title conflict cleanup script' ); 00057 00058 $fix = $this->hasOption( 'fix' ); 00059 $suffix = $this->getOption( 'suffix', '' ); 00060 $prefix = $this->getOption( 'prefix', '' ); 00061 $key = intval( $this->getOption( 'key', 0 ) ); 00062 00063 if ( $prefix ) { 00064 $retval = $this->checkPrefix( $key, $prefix, $fix, $suffix ); 00065 } else { 00066 $retval = $this->checkAll( $fix, $suffix ); 00067 } 00068 00069 if ( $retval ) { 00070 $this->output( "\nLooks good!\n" ); 00071 } else { 00072 $this->output( "\nOh noeees\n" ); 00073 } 00074 } 00075 00083 private function checkAll( $fix, $suffix = '' ) { 00084 global $wgContLang, $wgNamespaceAliases, $wgCapitalLinks; 00085 00086 $spaces = array(); 00087 00088 // List interwikis first, so they'll be overridden 00089 // by any conflicting local namespaces. 00090 foreach ( $this->getInterwikiList() as $prefix ) { 00091 $name = $wgContLang->ucfirst( $prefix ); 00092 $spaces[$name] = 0; 00093 } 00094 00095 // Now pull in all canonical and alias namespaces... 00096 foreach ( MWNamespace::getCanonicalNamespaces() as $ns => $name ) { 00097 // This includes $wgExtraNamespaces 00098 if ( $name !== '' ) { 00099 $spaces[$name] = $ns; 00100 } 00101 } 00102 foreach ( $wgContLang->getNamespaces() as $ns => $name ) { 00103 if ( $name !== '' ) { 00104 $spaces[$name] = $ns; 00105 } 00106 } 00107 foreach ( $wgNamespaceAliases as $name => $ns ) { 00108 $spaces[$name] = $ns; 00109 } 00110 foreach ( $wgContLang->getNamespaceAliases() as $name => $ns ) { 00111 $spaces[$name] = $ns; 00112 } 00113 00114 // We'll need to check for lowercase keys as well, 00115 // since we're doing case-sensitive searches in the db. 00116 foreach ( $spaces as $name => $ns ) { 00117 $moreNames = array(); 00118 $moreNames[] = $wgContLang->uc( $name ); 00119 $moreNames[] = $wgContLang->ucfirst( $wgContLang->lc( $name ) ); 00120 $moreNames[] = $wgContLang->ucwords( $name ); 00121 $moreNames[] = $wgContLang->ucwords( $wgContLang->lc( $name ) ); 00122 $moreNames[] = $wgContLang->ucwordbreaks( $name ); 00123 $moreNames[] = $wgContLang->ucwordbreaks( $wgContLang->lc( $name ) ); 00124 if ( !$wgCapitalLinks ) { 00125 foreach ( $moreNames as $altName ) { 00126 $moreNames[] = $wgContLang->lcfirst( $altName ); 00127 } 00128 $moreNames[] = $wgContLang->lcfirst( $name ); 00129 } 00130 foreach ( array_unique( $moreNames ) as $altName ) { 00131 if ( $altName !== $name ) { 00132 $spaces[$altName] = $ns; 00133 } 00134 } 00135 } 00136 00137 ksort( $spaces ); 00138 asort( $spaces ); 00139 00140 $ok = true; 00141 foreach ( $spaces as $name => $ns ) { 00142 $ok = $this->checkNamespace( $ns, $name, $fix, $suffix ) && $ok; 00143 } 00144 return $ok; 00145 } 00146 00152 private function getInterwikiList() { 00153 $result = Interwiki::getAllPrefixes(); 00154 $prefixes = array(); 00155 foreach ( $result as $row ) { 00156 $prefixes[] = $row['iw_prefix']; 00157 } 00158 return $prefixes; 00159 } 00160 00169 private function checkNamespace( $ns, $name, $fix, $suffix = '' ) { 00170 $conflicts = $this->getConflicts( $ns, $name ); 00171 $count = count( $conflicts ); 00172 if ( $count == 0 ) { 00173 return true; 00174 } 00175 00176 $ok = true; 00177 foreach ( $conflicts as $row ) { 00178 $resolvable = $this->reportConflict( $row, $suffix ); 00179 $ok = $ok && $resolvable; 00180 if ( $fix && ( $resolvable || $suffix != '' ) ) { 00181 $ok = $this->resolveConflict( $row, $resolvable, $suffix ) && $ok; 00182 } 00183 } 00184 return $ok; 00185 } 00186 00195 private function checkPrefix( $key, $prefix, $fix, $suffix = '' ) { 00196 $this->output( "Checking prefix \"$prefix\" vs namespace $key\n" ); 00197 return $this->checkNamespace( $key, $prefix, $fix, $suffix ); 00198 } 00199 00209 private function getConflicts( $ns, $name ) { 00210 $page = 'page'; 00211 $table = $this->db->tableName( $page ); 00212 00213 $prefix = $this->db->strencode( $name ); 00214 $encNamespace = $this->db->addQuotes( $ns ); 00215 00216 $titleSql = "TRIM(LEADING '$prefix:' FROM {$page}_title)"; 00217 if ( $ns == 0 ) { 00218 // An interwiki; try an alternate encoding with '-' for ':' 00219 $titleSql = $this->db->buildConcat( array( "'$prefix-'", $titleSql ) ); 00220 } 00221 00222 $sql = "SELECT {$page}_id AS id, 00223 {$page}_title AS oldtitle, 00224 $encNamespace + {$page}_namespace AS namespace, 00225 $titleSql AS title, 00226 {$page}_namespace AS oldnamespace 00227 FROM {$table} 00228 WHERE ( {$page}_namespace=0 OR {$page}_namespace=1 ) 00229 AND {$page}_title " . $this->db->buildLike( $name . ':', $this->db->anyString() ); 00230 00231 $result = $this->db->query( $sql, __METHOD__ ); 00232 00233 $set = array(); 00234 foreach ( $result as $row ) { 00235 $set[] = $row; 00236 } 00237 return $set; 00238 } 00239 00245 private function reportConflict( $row, $suffix ) { 00246 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title ); 00247 if ( is_null( $newTitle ) || !$newTitle->canExist() ) { 00248 // Title is also an illegal title... 00249 // For the moment we'll let these slide to cleanupTitles or whoever. 00250 $this->output( sprintf( "... %d (%d,\"%s\")\n", 00251 $row->id, 00252 $row->oldnamespace, 00253 $row->oldtitle ) ); 00254 $this->output( "... *** cannot resolve automatically; illegal title ***\n" ); 00255 return false; 00256 } 00257 00258 $this->output( sprintf( "... %d (%d,\"%s\") -> (%d,\"%s\") [[%s]]\n", 00259 $row->id, 00260 $row->oldnamespace, 00261 $row->oldtitle, 00262 $newTitle->getNamespace(), 00263 $newTitle->getDBkey(), 00264 $newTitle->getPrefixedText() ) ); 00265 00266 $id = $newTitle->getArticleID(); 00267 if ( $id ) { 00268 $this->output( "... *** cannot resolve automatically; page exists with ID $id ***\n" ); 00269 return false; 00270 } else { 00271 return true; 00272 } 00273 } 00274 00283 private function resolveConflict( $row, $resolvable, $suffix ) { 00284 if ( !$resolvable ) { 00285 $this->output( "... *** old title {$row->title}\n" ); 00286 while ( true ) { 00287 $row->title .= $suffix; 00288 $this->output( "... *** new title {$row->title}\n" ); 00289 $title = Title::makeTitleSafe( $row->namespace, $row->title ); 00290 if ( !$title ) { 00291 $this->output( "... !!! invalid title\n" ); 00292 return false; 00293 } 00294 $id = $title->getArticleID(); 00295 if ( $id ) { 00296 $this->output( "... *** page exists with ID $id ***\n" ); 00297 } else { 00298 break; 00299 } 00300 } 00301 $this->output( "... *** using suffixed form [[" . $title->getPrefixedText() . "]] ***\n" ); 00302 } 00303 $this->resolveConflictOn( $row, 'page', 'page' ); 00304 return true; 00305 } 00306 00315 private function resolveConflictOn( $row, $table, $prefix ) { 00316 $this->output( "... resolving on $table... " ); 00317 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title ); 00318 $this->db->update( $table, 00319 array( 00320 "{$prefix}_namespace" => $newTitle->getNamespace(), 00321 "{$prefix}_title" => $newTitle->getDBkey(), 00322 ), 00323 array( 00324 // "{$prefix}_namespace" => 0, 00325 // "{$prefix}_title" => $row->oldtitle, 00326 "{$prefix}_id" => $row->id, 00327 ), 00328 __METHOD__ ); 00329 $this->output( "ok.\n" ); 00330 return true; 00331 } 00332 } 00333 00334 $maintClass = "NamespaceConflictChecker"; 00335 require_once RUN_MAINTENANCE_IF_MAIN;