00001 <?php
00026 require_once( dirname(__FILE__) . '/Maintenance.php' );
00027
00028 class NamespaceConflictChecker extends Maintenance {
00029 public function __construct() {
00030 parent::__construct();
00031 $this->mDescription = "";
00032 $this->addOption( 'fix', 'Attempt to automatically fix errors' );
00033 $this->addOption( 'suffix', "Dupes will be renamed with correct namespace with\n" .
00034 "\t\t<text> Appended after the article name", false, true );
00035 $this->addOption( 'prefix', "Do an explicit check for the given title prefix\n" .
00036 "\t\tappended after the article name", false, true );
00037 }
00038
00039 public function execute() {
00040 global $wgTitle;
00041
00042 $this->db = wfGetDB( DB_MASTER );
00043 $wgTitle = Title::newFromText( 'Namespace title conflict cleanup script' );
00044
00045 $fix = $this->hasOption( 'fix' );
00046 $suffix = $this->getOption( 'suffix', '' );
00047 $prefix = $this->getOption( 'prefix', '' );
00048 $key = intval( $this->getOption( 'key', 0 ) );
00049
00050 if( $prefix ) {
00051 $retval = $this->checkPrefix( $key, $prefix, $fix, $suffix );
00052 } else {
00053 $retval = $this->checkAll( $fix, $suffix );
00054 }
00055
00056 if( $retval ) {
00057 $this->output( "\nLooks good!\n" );
00058 } else {
00059 $this->output( "\nOh noeees\n" );
00060 }
00061 }
00062
00068 private function checkAll( $fix, $suffix = '' ) {
00069 global $wgContLang, $wgNamespaceAliases, $wgCanonicalNamespaceNames;
00070 global $wgCapitalLinks;
00071
00072 $spaces = array();
00073
00074
00075
00076 foreach( $this->getInterwikiList() as $prefix ) {
00077 $name = $wgContLang->ucfirst( $prefix );
00078 $spaces[$name] = 0;
00079 }
00080
00081
00082 foreach( $wgCanonicalNamespaceNames as $ns => $name ) {
00083
00084 if( $name !== '' ) {
00085 $spaces[$name] = $ns;
00086 }
00087 }
00088 foreach( $wgContLang->getNamespaces() as $ns => $name ) {
00089 if( $name !== '' ) {
00090 $spaces[$name] = $ns;
00091 }
00092 }
00093 foreach( $wgNamespaceAliases as $name => $ns ) {
00094 $spaces[$name] = $ns;
00095 }
00096 foreach( $wgContLang->getNamespaceAliases() as $name => $ns ) {
00097 $spaces[$name] = $ns;
00098 }
00099
00100
00101
00102 foreach( $spaces as $name => $ns ) {
00103 $moreNames = array();
00104 $moreNames[] = $wgContLang->uc( $name );
00105 $moreNames[] = $wgContLang->ucfirst( $wgContLang->lc( $name ) );
00106 $moreNames[] = $wgContLang->ucwords( $name );
00107 $moreNames[] = $wgContLang->ucwords( $wgContLang->lc( $name ) );
00108 $moreNames[] = $wgContLang->ucwordbreaks( $name );
00109 $moreNames[] = $wgContLang->ucwordbreaks( $wgContLang->lc( $name ) );
00110 if( !$wgCapitalLinks ) {
00111 foreach( $moreNames as $altName ) {
00112 $moreNames[] = $wgContLang->lcfirst( $altName );
00113 }
00114 $moreNames[] = $wgContLang->lcfirst( $name );
00115 }
00116 foreach( array_unique( $moreNames ) as $altName ) {
00117 if( $altName !== $name ) {
00118 $spaces[$altName] = $ns;
00119 }
00120 }
00121 }
00122
00123 ksort( $spaces );
00124 asort( $spaces );
00125
00126 $ok = true;
00127 foreach( $spaces as $name => $ns ) {
00128 $ok = $this->checkNamespace( $ns, $name, $fix, $suffix ) && $ok;
00129 }
00130 return $ok;
00131 }
00132
00138 private function getInterwikiList() {
00139 $result = $this->db->select( 'interwiki', array( 'iw_prefix' ) );
00140 $prefixes = array();
00141 foreach( $result as $row ) {
00142 $prefixes[] = $row->iw_prefix;
00143 }
00144 $this->db->freeResult( $result );
00145 return $prefixes;
00146 }
00147
00155 private function checkNamespace( $ns, $name, $fix, $suffix = '' ) {
00156 $conflicts = $this->getConflicts( $ns, $name );
00157 $count = count( $conflicts );
00158 if( $count == 0 ) {
00159 return true;
00160 }
00161
00162 $ok = true;
00163 foreach( $conflicts as $row ) {
00164 $resolvable = $this->reportConflict( $row, $suffix );
00165 $ok = $ok && $resolvable;
00166 if( $fix && ( $resolvable || $suffix != '' ) ) {
00167 $ok = $this->resolveConflict( $row, $resolvable, $suffix ) && $ok;
00168 }
00169 }
00170 return $ok;
00171 }
00172
00176 private function checkPrefix( $key, $prefix, $fix, $suffix = '' ) {
00177 $this->output( "Checking prefix \"$prefix\" vs namespace $key\n" );
00178 return $this->checkNamespace( $key, $prefix, $fix, $suffix );
00179 }
00180
00187 private function getConflicts( $ns, $name ) {
00188 $page = 'page';
00189 $table = $this->db->tableName( $page );
00190
00191 $prefix = $this->db->strencode( $name );
00192 $encNamespace = $this->db->addQuotes( $ns );
00193
00194 $titleSql = "TRIM(LEADING '$prefix:' FROM {$page}_title)";
00195 if( $ns == 0 ) {
00196
00197 $titleSql = $this->db->buildConcat( array( "'$prefix-'", $titleSql ) );
00198 }
00199
00200 $sql = "SELECT {$page}_id AS id,
00201 {$page}_title AS oldtitle,
00202 $encNamespace AS namespace,
00203 $titleSql AS title
00204 FROM {$table}
00205 WHERE {$page}_namespace=0
00206 AND {$page}_title " . $this->db->buildLike( $name . ':', $this->db->anyString() );
00207
00208 $result = $this->db->query( $sql, __METHOD__ );
00209
00210 $set = array();
00211 foreach( $result as $row ) {
00212 $set[] = $row;
00213 }
00214 $this->db->freeResult( $result );
00215
00216 return $set;
00217 }
00218
00222 private function reportConflict( $row, $suffix ) {
00223 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title );
00224 if( is_null($newTitle) || !$newTitle->canExist() ) {
00225
00226
00227 $this->output( sprintf( "... %d (0,\"%s\")\n",
00228 $row->id,
00229 $row->oldtitle ) );
00230 $this->output( "... *** cannot resolve automatically; illegal title ***\n" );
00231 return false;
00232 }
00233
00234 $this->output( sprintf( "... %d (0,\"%s\") -> (%d,\"%s\") [[%s]]\n",
00235 $row->id,
00236 $row->oldtitle,
00237 $newTitle->getNamespace(),
00238 $newTitle->getDBkey(),
00239 $newTitle->getPrefixedText() ) );
00240
00241 $id = $newTitle->getArticleId();
00242 if( $id ) {
00243 $this->output( "... *** cannot resolve automatically; page exists with ID $id ***\n" );
00244 return false;
00245 } else {
00246 return true;
00247 }
00248 }
00249
00256 private function resolveConflict( $row, $resolvable, $suffix ) {
00257 if( !$resolvable ) {
00258 $this->output( "... *** old title {$row->title}\n" );
00259 while( true ) {
00260 $row->title .= $suffix;
00261 $this->output( "... *** new title {$row->title}\n" );
00262 $title = Title::makeTitleSafe( $row->namespace, $row->title );
00263 if ( ! $title ) {
00264 $this->output( "... !!! invalid title\n" );
00265 return false;
00266 }
00267 if ( $id = $title->getArticleId() ) {
00268 $this->output( "... *** page exists with ID $id ***\n" );
00269 } else {
00270 break;
00271 }
00272 }
00273 $this->output( "... *** using suffixed form [[" . $title->getPrefixedText() . "]] ***\n" );
00274 }
00275 $this->resolveConflictOn( $row, 'page', 'page' );
00276 return true;
00277 }
00278
00285 private function resolveConflictOn( $row, $table, $prefix ) {
00286 $this->output( "... resolving on $table... " );
00287 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title );
00288 $this->db->update( $table,
00289 array(
00290 "{$prefix}_namespace" => $newTitle->getNamespace(),
00291 "{$prefix}_title" => $newTitle->getDBkey(),
00292 ),
00293 array(
00294 "{$prefix}_namespace" => 0,
00295 "{$prefix}_title" => $row->oldtitle,
00296 ),
00297 __METHOD__ );
00298 $this->output( "ok.\n" );
00299 return true;
00300 }
00301 }
00302
00303 $maintClass = "NamespaceConflictChecker";
00304 require_once( DO_MAINTENANCE );