MediaWiki
REL1_19
|
00001 <?php 00026 require_once( dirname( __FILE__ ) . '/Maintenance.php' ); 00027 00028 class NamespaceConflictChecker extends Maintenance { 00029 00033 protected $db; 00034 00035 public function __construct() { 00036 parent::__construct(); 00037 $this->mDescription = ""; 00038 $this->addOption( 'fix', 'Attempt to automatically fix errors' ); 00039 $this->addOption( 'suffix', "Dupes will be renamed with correct namespace with " . 00040 "<text> appended after the article name", false, true ); 00041 $this->addOption( 'prefix', "Do an explicit check for the given title prefix " . 00042 "appended after the article name", false, true ); 00043 } 00044 00045 public function execute() { 00046 global $wgTitle; 00047 00048 $this->db = wfGetDB( DB_MASTER ); 00049 $wgTitle = Title::newFromText( 'Namespace title conflict cleanup script' ); 00050 00051 $fix = $this->hasOption( 'fix' ); 00052 $suffix = $this->getOption( 'suffix', '' ); 00053 $prefix = $this->getOption( 'prefix', '' ); 00054 $key = intval( $this->getOption( 'key', 0 ) ); 00055 00056 if ( $prefix ) { 00057 $retval = $this->checkPrefix( $key, $prefix, $fix, $suffix ); 00058 } else { 00059 $retval = $this->checkAll( $fix, $suffix ); 00060 } 00061 00062 if ( $retval ) { 00063 $this->output( "\nLooks good!\n" ); 00064 } else { 00065 $this->output( "\nOh noeees\n" ); 00066 } 00067 } 00068 00076 private function checkAll( $fix, $suffix = '' ) { 00077 global $wgContLang, $wgNamespaceAliases, $wgCapitalLinks; 00078 00079 $spaces = array(); 00080 00081 // List interwikis first, so they'll be overridden 00082 // by any conflicting local namespaces. 00083 foreach ( $this->getInterwikiList() as $prefix ) { 00084 $name = $wgContLang->ucfirst( $prefix ); 00085 $spaces[$name] = 0; 00086 } 00087 00088 // Now pull in all canonical and alias namespaces... 00089 foreach ( MWNamespace::getCanonicalNamespaces() as $ns => $name ) { 00090 // This includes $wgExtraNamespaces 00091 if ( $name !== '' ) { 00092 $spaces[$name] = $ns; 00093 } 00094 } 00095 foreach ( $wgContLang->getNamespaces() as $ns => $name ) { 00096 if ( $name !== '' ) { 00097 $spaces[$name] = $ns; 00098 } 00099 } 00100 foreach ( $wgNamespaceAliases as $name => $ns ) { 00101 $spaces[$name] = $ns; 00102 } 00103 foreach ( $wgContLang->getNamespaceAliases() as $name => $ns ) { 00104 $spaces[$name] = $ns; 00105 } 00106 00107 // We'll need to check for lowercase keys as well, 00108 // since we're doing case-sensitive searches in the db. 00109 foreach ( $spaces as $name => $ns ) { 00110 $moreNames = array(); 00111 $moreNames[] = $wgContLang->uc( $name ); 00112 $moreNames[] = $wgContLang->ucfirst( $wgContLang->lc( $name ) ); 00113 $moreNames[] = $wgContLang->ucwords( $name ); 00114 $moreNames[] = $wgContLang->ucwords( $wgContLang->lc( $name ) ); 00115 $moreNames[] = $wgContLang->ucwordbreaks( $name ); 00116 $moreNames[] = $wgContLang->ucwordbreaks( $wgContLang->lc( $name ) ); 00117 if ( !$wgCapitalLinks ) { 00118 foreach ( $moreNames as $altName ) { 00119 $moreNames[] = $wgContLang->lcfirst( $altName ); 00120 } 00121 $moreNames[] = $wgContLang->lcfirst( $name ); 00122 } 00123 foreach ( array_unique( $moreNames ) as $altName ) { 00124 if ( $altName !== $name ) { 00125 $spaces[$altName] = $ns; 00126 } 00127 } 00128 } 00129 00130 ksort( $spaces ); 00131 asort( $spaces ); 00132 00133 $ok = true; 00134 foreach ( $spaces as $name => $ns ) { 00135 $ok = $this->checkNamespace( $ns, $name, $fix, $suffix ) && $ok; 00136 } 00137 return $ok; 00138 } 00139 00146 private function getInterwikiList() { 00147 $result = $this->db->select( 'interwiki', array( 'iw_prefix' ) ); 00148 $prefixes = array(); 00149 foreach ( $result as $row ) { 00150 $prefixes[] = $row->iw_prefix; 00151 } 00152 return $prefixes; 00153 } 00154 00163 private function checkNamespace( $ns, $name, $fix, $suffix = '' ) { 00164 $conflicts = $this->getConflicts( $ns, $name ); 00165 $count = count( $conflicts ); 00166 if ( $count == 0 ) { 00167 return true; 00168 } 00169 00170 $ok = true; 00171 foreach ( $conflicts as $row ) { 00172 $resolvable = $this->reportConflict( $row, $suffix ); 00173 $ok = $ok && $resolvable; 00174 if ( $fix && ( $resolvable || $suffix != '' ) ) { 00175 $ok = $this->resolveConflict( $row, $resolvable, $suffix ) && $ok; 00176 } 00177 } 00178 return $ok; 00179 } 00180 00189 private function checkPrefix( $key, $prefix, $fix, $suffix = '' ) { 00190 $this->output( "Checking prefix \"$prefix\" vs namespace $key\n" ); 00191 return $this->checkNamespace( $key, $prefix, $fix, $suffix ); 00192 } 00193 00203 private function getConflicts( $ns, $name ) { 00204 $page = 'page'; 00205 $table = $this->db->tableName( $page ); 00206 00207 $prefix = $this->db->strencode( $name ); 00208 $encNamespace = $this->db->addQuotes( $ns ); 00209 00210 $titleSql = "TRIM(LEADING '$prefix:' FROM {$page}_title)"; 00211 if ( $ns == 0 ) { 00212 // An interwiki; try an alternate encoding with '-' for ':' 00213 $titleSql = $this->db->buildConcat( array( "'$prefix-'", $titleSql ) ); 00214 } 00215 00216 $sql = "SELECT {$page}_id AS id, 00217 {$page}_title AS oldtitle, 00218 $encNamespace + {$page}_namespace AS namespace, 00219 $titleSql AS title, 00220 {$page}_namespace AS oldnamespace 00221 FROM {$table} 00222 WHERE ( {$page}_namespace=0 OR {$page}_namespace=1 ) 00223 AND {$page}_title " . $this->db->buildLike( $name . ':', $this->db->anyString() ); 00224 00225 $result = $this->db->query( $sql, __METHOD__ ); 00226 00227 $set = array(); 00228 foreach ( $result as $row ) { 00229 $set[] = $row; 00230 } 00231 return $set; 00232 } 00233 00239 private function reportConflict( $row, $suffix ) { 00240 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title ); 00241 if ( is_null( $newTitle ) || !$newTitle->canExist() ) { 00242 // Title is also an illegal title... 00243 // For the moment we'll let these slide to cleanupTitles or whoever. 00244 $this->output( sprintf( "... %d (%d,\"%s\")\n", 00245 $row->id, 00246 $row->oldnamespace, 00247 $row->oldtitle ) ); 00248 $this->output( "... *** cannot resolve automatically; illegal title ***\n" ); 00249 return false; 00250 } 00251 00252 $this->output( sprintf( "... %d (%d,\"%s\") -> (%d,\"%s\") [[%s]]\n", 00253 $row->id, 00254 $row->oldnamespace, 00255 $row->oldtitle, 00256 $newTitle->getNamespace(), 00257 $newTitle->getDBkey(), 00258 $newTitle->getPrefixedText() ) ); 00259 00260 $id = $newTitle->getArticleId(); 00261 if ( $id ) { 00262 $this->output( "... *** cannot resolve automatically; page exists with ID $id ***\n" ); 00263 return false; 00264 } else { 00265 return true; 00266 } 00267 } 00268 00277 private function resolveConflict( $row, $resolvable, $suffix ) { 00278 if ( !$resolvable ) { 00279 $this->output( "... *** old title {$row->title}\n" ); 00280 while ( true ) { 00281 $row->title .= $suffix; 00282 $this->output( "... *** new title {$row->title}\n" ); 00283 $title = Title::makeTitleSafe( $row->namespace, $row->title ); 00284 if ( !$title ) { 00285 $this->output( "... !!! invalid title\n" ); 00286 return false; 00287 } 00288 $id = $title->getArticleId(); 00289 if ( $id ) { 00290 $this->output( "... *** page exists with ID $id ***\n" ); 00291 } else { 00292 break; 00293 } 00294 } 00295 $this->output( "... *** using suffixed form [[" . $title->getPrefixedText() . "]] ***\n" ); 00296 } 00297 $this->resolveConflictOn( $row, 'page', 'page' ); 00298 return true; 00299 } 00300 00309 private function resolveConflictOn( $row, $table, $prefix ) { 00310 $this->output( "... resolving on $table... " ); 00311 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title ); 00312 $this->db->update( $table, 00313 array( 00314 "{$prefix}_namespace" => $newTitle->getNamespace(), 00315 "{$prefix}_title" => $newTitle->getDBkey(), 00316 ), 00317 array( 00318 // "{$prefix}_namespace" => 0, 00319 // "{$prefix}_title" => $row->oldtitle, 00320 "{$prefix}_id" => $row->id, 00321 ), 00322 __METHOD__ ); 00323 $this->output( "ok.\n" ); 00324 return true; 00325 } 00326 } 00327 00328 $maintClass = "NamespaceConflictChecker"; 00329 require_once( RUN_MAINTENANCE_IF_MAIN );