MediaWiki
REL1_23
|
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 return $ok; 00142 } 00143 00149 private function getInterwikiList() { 00150 $result = Interwiki::getAllPrefixes(); 00151 $prefixes = array(); 00152 foreach ( $result as $row ) { 00153 $prefixes[] = $row['iw_prefix']; 00154 } 00155 return $prefixes; 00156 } 00157 00166 private function checkNamespace( $ns, $name, $fix, $suffix = '' ) { 00167 $conflicts = $this->getConflicts( $ns, $name ); 00168 $count = count( $conflicts ); 00169 if ( $count == 0 ) { 00170 return true; 00171 } 00172 00173 $ok = true; 00174 foreach ( $conflicts as $row ) { 00175 $resolvable = $this->reportConflict( $row, $suffix ); 00176 $ok = $ok && $resolvable; 00177 if ( $fix && ( $resolvable || $suffix != '' ) ) { 00178 $ok = $this->resolveConflict( $row, $resolvable, $suffix ) && $ok; 00179 } 00180 } 00181 return $ok; 00182 } 00183 00192 private function checkPrefix( $key, $prefix, $fix, $suffix = '' ) { 00193 $this->output( "Checking prefix \"$prefix\" vs namespace $key\n" ); 00194 return $this->checkNamespace( $key, $prefix, $fix, $suffix ); 00195 } 00196 00206 private function getConflicts( $ns, $name ) { 00207 $page = 'page'; 00208 $table = $this->db->tableName( $page ); 00209 00210 $prefix = $this->db->strencode( $name ); 00211 $encNamespace = $this->db->addQuotes( $ns ); 00212 00213 $titleSql = "TRIM(LEADING '$prefix:' FROM {$page}_title)"; 00214 if ( $ns == 0 ) { 00215 // An interwiki; try an alternate encoding with '-' for ':' 00216 $titleSql = $this->db->buildConcat( array( "'$prefix-'", $titleSql ) ); 00217 } 00218 00219 $sql = "SELECT {$page}_id AS id, 00220 {$page}_title AS oldtitle, 00221 $encNamespace + {$page}_namespace AS namespace, 00222 $titleSql AS title, 00223 {$page}_namespace AS oldnamespace 00224 FROM {$table} 00225 WHERE ( {$page}_namespace=0 OR {$page}_namespace=1 ) 00226 AND {$page}_title " . $this->db->buildLike( $name . ':', $this->db->anyString() ); 00227 00228 $result = $this->db->query( $sql, __METHOD__ ); 00229 00230 $set = array(); 00231 foreach ( $result as $row ) { 00232 $set[] = $row; 00233 } 00234 return $set; 00235 } 00236 00242 private function reportConflict( $row, $suffix ) { 00243 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title ); 00244 if ( is_null( $newTitle ) || !$newTitle->canExist() ) { 00245 // Title is also an illegal title... 00246 // For the moment we'll let these slide to cleanupTitles or whoever. 00247 $this->output( sprintf( "... %d (%d,\"%s\")\n", 00248 $row->id, 00249 $row->oldnamespace, 00250 $row->oldtitle ) ); 00251 $this->output( "... *** cannot resolve automatically; illegal title ***\n" ); 00252 return false; 00253 } 00254 00255 $this->output( sprintf( "... %d (%d,\"%s\") -> (%d,\"%s\") [[%s]]\n", 00256 $row->id, 00257 $row->oldnamespace, 00258 $row->oldtitle, 00259 $newTitle->getNamespace(), 00260 $newTitle->getDBkey(), 00261 $newTitle->getPrefixedText() ) ); 00262 00263 $id = $newTitle->getArticleID(); 00264 if ( $id ) { 00265 $this->output( "... *** cannot resolve automatically; page exists with ID $id ***\n" ); 00266 return false; 00267 } else { 00268 return true; 00269 } 00270 } 00271 00280 private function resolveConflict( $row, $resolvable, $suffix ) { 00281 if ( !$resolvable ) { 00282 $this->output( "... *** old title {$row->title}\n" ); 00283 while ( true ) { 00284 $row->title .= $suffix; 00285 $this->output( "... *** new title {$row->title}\n" ); 00286 $title = Title::makeTitleSafe( $row->namespace, $row->title ); 00287 if ( !$title ) { 00288 $this->output( "... !!! invalid title\n" ); 00289 return false; 00290 } 00291 $id = $title->getArticleID(); 00292 if ( $id ) { 00293 $this->output( "... *** page exists with ID $id ***\n" ); 00294 } else { 00295 break; 00296 } 00297 } 00298 $this->output( "... *** using suffixed form [[" . $title->getPrefixedText() . "]] ***\n" ); 00299 } 00300 $this->resolveConflictOn( $row, 'page', 'page' ); 00301 return true; 00302 } 00303 00312 private function resolveConflictOn( $row, $table, $prefix ) { 00313 $this->output( "... resolving on $table... " ); 00314 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title ); 00315 $this->db->update( $table, 00316 array( 00317 "{$prefix}_namespace" => $newTitle->getNamespace(), 00318 "{$prefix}_title" => $newTitle->getDBkey(), 00319 ), 00320 array( 00321 // "{$prefix}_namespace" => 0, 00322 // "{$prefix}_title" => $row->oldtitle, 00323 "{$prefix}_id" => $row->id, 00324 ), 00325 __METHOD__ ); 00326 $this->output( "ok.\n" ); 00327 return true; 00328 } 00329 } 00330 00331 $maintClass = "NamespaceConflictChecker"; 00332 require_once RUN_MAINTENANCE_IF_MAIN;