]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - maintenance/namespaceDupes.php
MediaWiki 1.14.0-scripts
[autoinstallsdev/mediawiki.git] / maintenance / namespaceDupes.php
1 <?php
2 # Copyright (C) 2005-2007 Brion Vibber <brion@pobox.com>
3 # http://www.mediawiki.org/
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # http://www.gnu.org/copyleft/gpl.html
19
20 /**
21  * @file
22  * @ingroup Maintenance
23  */
24
25 $options = array( 'fix', 'suffix', 'help' );
26
27 /** */
28 require_once( 'commandLine.inc' );
29
30 if(isset( $options['help'] ) ) {
31 print <<<ENDS
32 usage: namespaceDupes.php [--fix] [--suffix=<text>] [--help]
33     --help          : this help message
34     --fix           : attempt to automatically fix errors
35     --suffix=<text> : dupes will be renamed with correct namespace with <text>
36                       appended after the article name.
37     --prefix=<text> : Do an explicit check for the given title prefix
38                       in place of the standard namespace list.
39     --verbose       : Display output for checked namespaces without conflicts
40
41 ENDS;
42 die;
43 }
44
45 class NamespaceConflictChecker {
46         function NamespaceConflictChecker( $db, $verbose=false ) {
47                 $this->db = $db;
48                 $this->verbose = $verbose;
49         }
50
51         function checkAll( $fix, $suffix = '' ) {
52                 global $wgContLang, $wgNamespaceAliases, $wgCanonicalNamespaceNames;
53                 global $wgCapitalLinks;
54                 
55                 $spaces = array();
56                 
57                 // List interwikis first, so they'll be overridden
58                 // by any conflicting local namespaces.
59                 foreach( $this->getInterwikiList() as $prefix ) {
60                         $name = $wgContLang->ucfirst( $prefix );
61                         $spaces[$name] = 0;
62                 }
63
64                 // Now pull in all canonical and alias namespaces...
65                 foreach( $wgCanonicalNamespaceNames as $ns => $name ) {
66                         // This includes $wgExtraNamespaces
67                         if( $name !== '' ) {
68                                 $spaces[$name] = $ns;
69                         }
70                 }
71                 foreach( $wgContLang->getNamespaces() as $ns => $name ) {
72                         if( $name !== '' ) {
73                                 $spaces[$name] = $ns;
74                         }
75                 }
76                 foreach( $wgNamespaceAliases as $name => $ns ) {
77                         $spaces[$name] = $ns;
78                 }
79                 foreach( $wgContLang->namespaceAliases as $name => $ns ) {
80                         $spaces[$name] = $ns;
81                 }
82                 
83                 // We'll need to check for lowercase keys as well,
84                 // since we're doing case-sensitive searches in the db.
85                 foreach( $spaces as $name => $ns ) {
86                         $moreNames = array();
87                         $moreNames[] = $wgContLang->uc( $name );
88                         $moreNames[] = $wgContLang->ucfirst( $wgContLang->lc( $name ) );
89                         $moreNames[] = $wgContLang->ucwords( $name );
90                         $moreNames[] = $wgContLang->ucwords( $wgContLang->lc( $name ) );
91                         $moreNames[] = $wgContLang->ucwordbreaks( $name );
92                         $moreNames[] = $wgContLang->ucwordbreaks( $wgContLang->lc( $name ) );
93                         if( !$wgCapitalLinks ) {
94                                 foreach( $moreNames as $altName ) {
95                                         $moreNames[] = $wgContLang->lcfirst( $altName );
96                                 }
97                                 $moreNames[] = $wgContLang->lcfirst( $name );
98                         }
99                         foreach( array_unique( $moreNames ) as $altName ) {
100                                 if( $altName !== $name ) {
101                                         $spaces[$altName] = $ns;
102                                 }
103                         }
104                 }
105                 
106                 ksort( $spaces );
107                 asort( $spaces );
108                 
109                 $ok = true;
110                 foreach( $spaces as $name => $ns ) {
111                         $ok = $this->checkNamespace( $ns, $name, $fix, $suffix ) && $ok;
112                 }
113                 return $ok;
114         }
115         
116         private function getInterwikiList() {
117                 $result = $this->db->select( 'interwiki', array( 'iw_prefix' ) );
118                 while( $row = $this->db->fetchObject( $result ) ) {
119                         $prefixes[] = $row->iw_prefix;
120                 }
121                 $this->db->freeResult( $result );
122                 return $prefixes;
123         }
124
125         function checkNamespace( $ns, $name, $fix, $suffix = '' ) {
126                 if( $ns == 0 ) {
127                         $header = "Checking interwiki prefix: \"$name\"\n";
128                 } else {
129                         $header = "Checking namespace $ns: \"$name\"\n";
130                 }
131
132                 $conflicts = $this->getConflicts( $ns, $name );
133                 $count = count( $conflicts );
134                 if( $count == 0 ) {
135                         if( $this->verbose ) {
136                                 echo $header;
137                                 echo "... no conflicts detected!\n";
138                         }
139                         return true;
140                 }
141
142                 echo $header;
143                 echo "... $count conflicts detected:\n";
144                 $ok = true;
145                 foreach( $conflicts as $row ) {
146                         $resolvable = $this->reportConflict( $row, $suffix );
147                         $ok = $ok && $resolvable;
148                         if( $fix && ( $resolvable || $suffix != '' ) ) {
149                                 $ok = $this->resolveConflict( $row, $resolvable, $suffix ) && $ok;
150                         }
151                 }
152                 return $ok;
153         }
154         
155         /**
156          * @todo: do this for reals
157          */
158         function checkPrefix( $key, $prefix, $fix, $suffix = '' ) {
159                 echo "Checking prefix \"$prefix\" vs namespace $key\n";
160                 return $this->checkNamespace( $key, $prefix, $fix, $suffix );
161         }
162
163         function getConflicts( $ns, $name ) {
164                 $page  = 'page';
165                 $table = $this->db->tableName( $page );
166
167                 $prefix     = $this->db->strencode( $name );
168                 $likeprefix = str_replace( '_', '\\_', $prefix);
169                 $encNamespace = $this->db->addQuotes( $ns );
170
171                 $titleSql = "TRIM(LEADING '$prefix:' FROM {$page}_title)";
172                 if( $ns == 0 ) {
173                         // An interwiki; try an alternate encoding with '-' for ':'
174                         $titleSql = "CONCAT('$prefix-',$titleSql)";
175                 }
176                                      
177                 $sql = "SELECT {$page}_id    AS id,
178                                {$page}_title AS oldtitle,
179                                $encNamespace AS namespace,
180                                $titleSql     AS title
181                           FROM {$table}
182                          WHERE {$page}_namespace=0
183                            AND {$page}_title LIKE '$likeprefix:%'";
184
185                 $result = $this->db->query( $sql, 'NamespaceConflictChecker::getConflicts' );
186
187                 $set = array();
188                 while( $row = $this->db->fetchObject( $result ) ) {
189                         $set[] = $row;
190                 }
191                 $this->db->freeResult( $result );
192
193                 return $set;
194         }
195
196         function reportConflict( $row, $suffix ) {
197                 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title );
198                 if( is_null($newTitle) || !$newTitle->canExist() ) {
199                         // Title is also an illegal title...
200                         // For the moment we'll let these slide to cleanupTitles or whoever.
201                         printf( "... %d (0,\"%s\")\n",
202                                 $row->id,
203                                 $row->oldtitle );
204                         echo "...  *** cannot resolve automatically; illegal title ***\n";
205                         return false;
206                 }
207                 
208                 printf( "... %d (0,\"%s\") -> (%d,\"%s\") [[%s]]\n",
209                         $row->id,
210                         $row->oldtitle,
211                         $newTitle->getNamespace(),
212                         $newTitle->getDBkey(),
213                         $newTitle->getPrefixedText() );
214
215                 $id = $newTitle->getArticleId();
216                 if( $id ) {
217                         echo "...  *** cannot resolve automatically; page exists with ID $id ***\n";
218                         return false;
219                 } else {
220                         return true;
221                 }
222         }
223
224         function resolveConflict( $row, $resolvable, $suffix ) {
225                 if( !$resolvable ) {
226                         echo "...  *** old title {$row->title}\n";
227                         $row->title .= $suffix;
228                         echo "...  *** new title {$row->title}\n";
229                         $title = Title::makeTitleSafe( $row->namespace, $row->title );
230                         if ( ! $title ) {
231                                 echo "... !!! invalid title\n";
232                                 return false;
233                         }
234                         echo "...  *** using suffixed form [[" . $title->getPrefixedText() . "]] ***\n";
235                 }
236                 $tables = array( 'page' );
237                 foreach( $tables as $table ) {
238                         $this->resolveConflictOn( $row, $table );
239                 }
240                 return true;
241         }
242
243         function resolveConflictOn( $row, $table ) {
244                 echo "... resolving on $table... ";
245                 $newTitle = Title::makeTitleSafe( $row->namespace, $row->title );
246                 $this->db->update( $table,
247                         array(
248                                 "{$table}_namespace" => $newTitle->getNamespace(),
249                                 "{$table}_title"     => $newTitle->getDBkey(),
250                         ),
251                         array(
252                                 "{$table}_namespace" => 0,
253                                 "{$table}_title"     => $row->oldtitle,
254                         ),
255                         __METHOD__ );
256                 echo "ok.\n";
257                 return true;
258         }
259 }
260
261
262
263
264 $wgTitle = Title::newFromText( 'Namespace title conflict cleanup script' );
265
266 $verbose = isset( $options['verbose'] );
267 $fix = isset( $options['fix'] );
268 $suffix = isset( $options['suffix'] ) ? $options['suffix'] : '';
269 $prefix = isset( $options['prefix'] ) ? $options['prefix'] : '';
270 $key = isset( $options['key'] ) ? intval( $options['key'] ) : 0;
271
272 $dbw = wfGetDB( DB_MASTER );
273 $duper = new NamespaceConflictChecker( $dbw, $verbose );
274
275 if( $prefix ) {
276         $retval = $duper->checkPrefix( $key, $prefix, $fix, $suffix );
277 } else {
278         $retval = $duper->checkAll( $fix, $suffix );
279 }
280
281 if( $retval ) {
282         echo "\nLooks good!\n";
283         exit( 0 );
284 } else {
285         echo "\nOh noeees\n";
286         exit( -1 );
287 }
288
289