MediaWiki
REL1_24
|
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 $this->db = wfGetDB( DB_MASTER ); 00054 00055 $fix = $this->hasOption( 'fix' ); 00056 $suffix = $this->getOption( 'suffix', '' ); 00057 $prefix = $this->getOption( 'prefix', '' ); 00058 $key = intval( $this->getOption( 'key', 0 ) ); 00059 00060 if ( $prefix ) { 00061 $retval = $this->checkPrefix( $key, $prefix, $fix, $suffix ); 00062 } else { 00063 $retval = $this->checkAll( $fix, $suffix ); 00064 } 00065 00066 if ( $retval ) { 00067 $this->output( "\nLooks good!\n" ); 00068 } else { 00069 $this->output( "\nOh noeees\n" ); 00070 } 00071 } 00072 00080 private function checkAll( $fix, $suffix = '' ) { 00081 global $wgContLang, $wgNamespaceAliases, $wgCapitalLinks; 00082 00083 $spaces = array(); 00084 00085 // List interwikis first, so they'll be overridden 00086 // by any conflicting local namespaces. 00087 foreach ( $this->getInterwikiList() as $prefix ) { 00088 $name = $wgContLang->ucfirst( $prefix ); 00089 $spaces[$name] = 0; 00090 } 00091 00092 // Now pull in all canonical and alias namespaces... 00093 foreach ( MWNamespace::getCanonicalNamespaces() as $ns => $name ) { 00094 // This includes $wgExtraNamespaces 00095 if ( $name !== '' ) { 00096 $spaces[$name] = $ns; 00097 } 00098 } 00099 foreach ( $wgContLang->getNamespaces() as $ns => $name ) { 00100 if ( $name !== '' ) { 00101 $spaces[$name] = $ns; 00102 } 00103 } 00104 foreach ( $wgNamespaceAliases as $name => $ns ) { 00105 $spaces[$name] = $ns; 00106 } 00107 foreach ( $wgContLang->getNamespaceAliases() as $name => $ns ) { 00108 $spaces[$name] = $ns; 00109 } 00110 00111 // We'll need to check for lowercase keys as well, 00112 // since we're doing case-sensitive searches in the db. 00113 foreach ( $spaces as $name => $ns ) { 00114 $moreNames = array(); 00115 $moreNames[] = $wgContLang->uc( $name ); 00116 $moreNames[] = $wgContLang->ucfirst( $wgContLang->lc( $name ) ); 00117 $moreNames[] = $wgContLang->ucwords( $name ); 00118 $moreNames[] = $wgContLang->ucwords( $wgContLang->lc( $name ) ); 00119 $moreNames[] = $wgContLang->ucwordbreaks( $name ); 00120 $moreNames[] = $wgContLang->ucwordbreaks( $wgContLang->lc( $name ) ); 00121 if ( !$wgCapitalLinks ) { 00122 foreach ( $moreNames as $altName ) { 00123 $moreNames[] = $wgContLang->lcfirst( $altName ); 00124 } 00125 $moreNames[] = $wgContLang->lcfirst( $name ); 00126 } 00127 foreach ( array_unique( $moreNames ) as $altName ) { 00128 if ( $altName !== $name ) { 00129 $spaces[$altName] = $ns; 00130 } 00131 } 00132 } 00133 00134 ksort( $spaces ); 00135 asort( $spaces ); 00136 00137 $ok = true; 00138 foreach ( $spaces as $name => $ns ) { 00139 $ok = $this->checkNamespace( $ns, $name, $fix, $suffix ) && $ok; 00140 } 00141 00142 return $ok; 00143 } 00144 00150 private function getInterwikiList() { 00151 $result = Interwiki::getAllPrefixes(); 00152 $prefixes = array(); 00153 foreach ( $result as $row ) { 00154 $prefixes[] = $row['iw_prefix']; 00155 } 00156 00157 return $prefixes; 00158 } 00159 00168 private function checkNamespace( $ns, $name, $fix, $suffix = '' ) { 00169 $conflicts = $this->getConflicts( $ns, $name ); 00170 $count = count( $conflicts ); 00171 if ( $count == 0 ) { 00172 return true; 00173 } 00174 00175 $ok = true; 00176 foreach ( $conflicts as $row ) { 00177 $resolvable = $this->reportConflict( $row, $suffix ); 00178 $ok = $ok && $resolvable; 00179 if ( $fix && ( $resolvable || $suffix != '' ) ) { 00180 $ok = $this->resolveConflict( $row, $resolvable, $suffix ) && $ok; 00181 } 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 00198 return $this->checkNamespace( $key, $prefix, $fix, $suffix ); 00199 } 00200 00210 private function getConflicts( $ns, $name ) { 00211 $titleSql = "TRIM(LEADING {$this->db->addQuotes( "$name:" )} FROM page_title)"; 00212 if ( $ns == 0 ) { 00213 // An interwiki; try an alternate encoding with '-' for ':' 00214 $titleSql = $this->db->buildConcat( array( 00215 $this->db->addQuotes( "$name-" ), 00216 $titleSql, 00217 ) ); 00218 } 00219 00220 return iterator_to_array( $this->db->select( 'page', 00221 array( 00222 'id' => 'page_id', 00223 'oldtitle' => 'page_title', 00224 'namespace' => $this->db->addQuotes( $ns ) . ' + page_namespace', 00225 'title' => $titleSql, 00226 'oldnamespace' => 'page_namespace', 00227 ), 00228 array( 00229 'page_namespace' => array( 0, 1 ), 00230 'page_title' . $this->db->buildLike( "$name:", $this->db->anyString() ), 00231 ), 00232 __METHOD__ 00233 ) ); 00234 } 00235 00243 private function reportConflict( $row, $suffix ) { 00244 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title ); 00245 if ( is_null( $newTitle ) || !$newTitle->canExist() ) { 00246 // Title is also an illegal title... 00247 // For the moment we'll let these slide to cleanupTitles or whoever. 00248 $this->output( sprintf( "... %d (%d,\"%s\")\n", 00249 $row->id, 00250 $row->oldnamespace, 00251 $row->oldtitle ) ); 00252 $this->output( "... *** cannot resolve automatically; illegal title ***\n" ); 00253 00254 return false; 00255 } 00256 00257 $this->output( sprintf( "... %d (%d,\"%s\") -> (%d,\"%s\") [[%s]]\n", 00258 $row->id, 00259 $row->oldnamespace, 00260 $row->oldtitle, 00261 $newTitle->getNamespace(), 00262 $newTitle->getDBkey(), 00263 $newTitle->getPrefixedText() ) ); 00264 00265 $id = $newTitle->getArticleID(); 00266 if ( $id ) { 00267 $this->output( "... *** cannot resolve automatically; page exists with ID $id ***\n" ); 00268 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 00293 return false; 00294 } 00295 $id = $title->getArticleID(); 00296 if ( $id ) { 00297 $this->output( "... *** page exists with ID $id ***\n" ); 00298 } else { 00299 break; 00300 } 00301 } 00302 $this->output( "... *** using suffixed form [[" . $title->getPrefixedText() . "]] ***\n" ); 00303 } 00304 $this->resolveConflictOn( $row, 'page', 'page' ); 00305 00306 return true; 00307 } 00308 00317 private function resolveConflictOn( $row, $table, $prefix ) { 00318 $this->output( "... resolving on $table... " ); 00319 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title ); 00320 $this->db->update( $table, 00321 array( 00322 "{$prefix}_namespace" => $newTitle->getNamespace(), 00323 "{$prefix}_title" => $newTitle->getDBkey(), 00324 ), 00325 array( 00326 // "{$prefix}_namespace" => 0, 00327 // "{$prefix}_title" => $row->oldtitle, 00328 "{$prefix}_id" => $row->id, 00329 ), 00330 __METHOD__ ); 00331 $this->output( "ok.\n" ); 00332 00333 return true; 00334 } 00335 } 00336 00337 $maintClass = "NamespaceConflictChecker"; 00338 require_once RUN_MAINTENANCE_IF_MAIN;