[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/maintenance/ -> namespaceDupes.php (source)

   1  <?php
   2  /**
   3   * Check for articles to fix after adding/deleting namespaces
   4   *
   5   * Copyright © 2005-2007 Brion Vibber <[email protected]>
   6   * https://www.mediawiki.org/
   7   *
   8   * This program is free software; you can redistribute it and/or modify
   9   * it under the terms of the GNU General Public License as published by
  10   * the Free Software Foundation; either version 2 of the License, or
  11   * (at your option) any later version.
  12   *
  13   * This program is distributed in the hope that it will be useful,
  14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16   * GNU General Public License for more details.
  17   *
  18   * You should have received a copy of the GNU General Public License along
  19   * with this program; if not, write to the Free Software Foundation, Inc.,
  20   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21   * http://www.gnu.org/copyleft/gpl.html
  22   *
  23   * @file
  24   * @ingroup Maintenance
  25   */
  26  
  27  require_once  __DIR__ . '/Maintenance.php';
  28  
  29  /**
  30   * Maintenance script that checks for articles to fix after
  31   * adding/deleting namespaces.
  32   *
  33   * @ingroup Maintenance
  34   */
  35  class NamespaceConflictChecker extends Maintenance {
  36  
  37      /**
  38       * @var DatabaseBase
  39       */
  40      protected $db;
  41  
  42  	public function __construct() {
  43          parent::__construct();
  44          $this->mDescription = "";
  45          $this->addOption( 'fix', 'Attempt to automatically fix errors' );
  46          $this->addOption( 'suffix', "Dupes will be renamed with correct namespace with " .
  47              "<text> appended after the article name", false, true );
  48          $this->addOption( 'prefix', "Do an explicit check for the given title prefix " .
  49              "appended after the article name", false, true );
  50      }
  51  
  52  	public function execute() {
  53          $this->db = wfGetDB( DB_MASTER );
  54  
  55          $fix = $this->hasOption( 'fix' );
  56          $suffix = $this->getOption( 'suffix', '' );
  57          $prefix = $this->getOption( 'prefix', '' );
  58          $key = intval( $this->getOption( 'key', 0 ) );
  59  
  60          if ( $prefix ) {
  61              $retval = $this->checkPrefix( $key, $prefix, $fix, $suffix );
  62          } else {
  63              $retval = $this->checkAll( $fix, $suffix );
  64          }
  65  
  66          if ( $retval ) {
  67              $this->output( "\nLooks good!\n" );
  68          } else {
  69              $this->output( "\nOh noeees\n" );
  70          }
  71      }
  72  
  73      /**
  74       * @todo Document
  75       * @param bool $fix Whether or not to fix broken entries
  76       * @param string $suffix Suffix to append to renamed articles
  77       *
  78       * @return bool
  79       */
  80  	private function checkAll( $fix, $suffix = '' ) {
  81          global $wgContLang, $wgNamespaceAliases, $wgCapitalLinks;
  82  
  83          $spaces = array();
  84  
  85          // List interwikis first, so they'll be overridden
  86          // by any conflicting local namespaces.
  87          foreach ( $this->getInterwikiList() as $prefix ) {
  88              $name = $wgContLang->ucfirst( $prefix );
  89              $spaces[$name] = 0;
  90          }
  91  
  92          // Now pull in all canonical and alias namespaces...
  93          foreach ( MWNamespace::getCanonicalNamespaces() as $ns => $name ) {
  94              // This includes $wgExtraNamespaces
  95              if ( $name !== '' ) {
  96                  $spaces[$name] = $ns;
  97              }
  98          }
  99          foreach ( $wgContLang->getNamespaces() as $ns => $name ) {
 100              if ( $name !== '' ) {
 101                  $spaces[$name] = $ns;
 102              }
 103          }
 104          foreach ( $wgNamespaceAliases as $name => $ns ) {
 105              $spaces[$name] = $ns;
 106          }
 107          foreach ( $wgContLang->getNamespaceAliases() as $name => $ns ) {
 108              $spaces[$name] = $ns;
 109          }
 110  
 111          // We'll need to check for lowercase keys as well,
 112          // since we're doing case-sensitive searches in the db.
 113          foreach ( $spaces as $name => $ns ) {
 114              $moreNames = array();
 115              $moreNames[] = $wgContLang->uc( $name );
 116              $moreNames[] = $wgContLang->ucfirst( $wgContLang->lc( $name ) );
 117              $moreNames[] = $wgContLang->ucwords( $name );
 118              $moreNames[] = $wgContLang->ucwords( $wgContLang->lc( $name ) );
 119              $moreNames[] = $wgContLang->ucwordbreaks( $name );
 120              $moreNames[] = $wgContLang->ucwordbreaks( $wgContLang->lc( $name ) );
 121              if ( !$wgCapitalLinks ) {
 122                  foreach ( $moreNames as $altName ) {
 123                      $moreNames[] = $wgContLang->lcfirst( $altName );
 124                  }
 125                  $moreNames[] = $wgContLang->lcfirst( $name );
 126              }
 127              foreach ( array_unique( $moreNames ) as $altName ) {
 128                  if ( $altName !== $name ) {
 129                      $spaces[$altName] = $ns;
 130                  }
 131              }
 132          }
 133  
 134          ksort( $spaces );
 135          asort( $spaces );
 136  
 137          $ok = true;
 138          foreach ( $spaces as $name => $ns ) {
 139              $ok = $this->checkNamespace( $ns, $name, $fix, $suffix ) && $ok;
 140          }
 141  
 142          return $ok;
 143      }
 144  
 145      /**
 146       * Get the interwiki list
 147       *
 148       * @return array
 149       */
 150  	private function getInterwikiList() {
 151          $result = Interwiki::getAllPrefixes();
 152          $prefixes = array();
 153          foreach ( $result as $row ) {
 154              $prefixes[] = $row['iw_prefix'];
 155          }
 156  
 157          return $prefixes;
 158      }
 159  
 160      /**
 161       * @todo Document
 162       * @param int $ns A namespace id
 163       * @param string $name
 164       * @param bool $fix Whether to fix broken entries
 165       * @param string $suffix Suffix to append to renamed articles
 166       * @return bool
 167       */
 168  	private function checkNamespace( $ns, $name, $fix, $suffix = '' ) {
 169          $conflicts = $this->getConflicts( $ns, $name );
 170          $count = count( $conflicts );
 171          if ( $count == 0 ) {
 172              return true;
 173          }
 174  
 175          $ok = true;
 176          foreach ( $conflicts as $row ) {
 177              $resolvable = $this->reportConflict( $row, $suffix );
 178              $ok = $ok && $resolvable;
 179              if ( $fix && ( $resolvable || $suffix != '' ) ) {
 180                  $ok = $this->resolveConflict( $row, $resolvable, $suffix ) && $ok;
 181              }
 182          }
 183  
 184          return $ok;
 185      }
 186  
 187      /**
 188       * @todo Do this for real
 189       * @param int $key
 190       * @param string $prefix
 191       * @param bool $fix
 192       * @param string $suffix
 193       * @return bool
 194       */
 195  	private function checkPrefix( $key, $prefix, $fix, $suffix = '' ) {
 196          $this->output( "Checking prefix \"$prefix\" vs namespace $key\n" );
 197  
 198          return $this->checkNamespace( $key, $prefix, $fix, $suffix );
 199      }
 200  
 201      /**
 202       * Find pages in mainspace that have a prefix of the new namespace
 203       * so we know titles that will need migrating
 204       *
 205       * @param int $ns Namespace id (id for new namespace?)
 206       * @param string $name Prefix that is being made a namespace
 207       *
 208       * @return array
 209       */
 210  	private function getConflicts( $ns, $name ) {
 211          $titleSql = "TRIM(LEADING {$this->db->addQuotes( "$name:" )} FROM page_title)";
 212          if ( $ns == 0 ) {
 213              // An interwiki; try an alternate encoding with '-' for ':'
 214              $titleSql = $this->db->buildConcat( array(
 215                  $this->db->addQuotes( "$name-" ),
 216                  $titleSql,
 217              ) );
 218          }
 219  
 220          return iterator_to_array( $this->db->select( 'page',
 221              array(
 222                  'id' => 'page_id',
 223                  'oldtitle' => 'page_title',
 224                  'namespace' => $this->db->addQuotes( $ns ) . ' + page_namespace',
 225                  'title' => $titleSql,
 226                  'oldnamespace' => 'page_namespace',
 227              ),
 228              array(
 229                  'page_namespace' => array( 0, 1 ),
 230                  'page_title' . $this->db->buildLike( "$name:", $this->db->anyString() ),
 231              ),
 232              __METHOD__
 233          ) );
 234      }
 235  
 236      /**
 237       * Report any conflicts we find
 238       *
 239       * @param stdClass $row
 240       * @param string $suffix
 241       * @return bool
 242       */
 243  	private function reportConflict( $row, $suffix ) {
 244          $newTitle = Title::makeTitleSafe( $row->namespace, $row->title );
 245          if ( is_null( $newTitle ) || !$newTitle->canExist() ) {
 246              // Title is also an illegal title...
 247              // For the moment we'll let these slide to cleanupTitles or whoever.
 248              $this->output( sprintf( "... %d (%d,\"%s\")\n",
 249                  $row->id,
 250                  $row->oldnamespace,
 251                  $row->oldtitle ) );
 252              $this->output( "...  *** cannot resolve automatically; illegal title ***\n" );
 253  
 254              return false;
 255          }
 256  
 257          $this->output( sprintf( "... %d (%d,\"%s\") -> (%d,\"%s\") [[%s]]\n",
 258              $row->id,
 259              $row->oldnamespace,
 260              $row->oldtitle,
 261              $newTitle->getNamespace(),
 262              $newTitle->getDBkey(),
 263              $newTitle->getPrefixedText() ) );
 264  
 265          $id = $newTitle->getArticleID();
 266          if ( $id ) {
 267              $this->output( "...  *** cannot resolve automatically; page exists with ID $id ***\n" );
 268  
 269              return false;
 270          } else {
 271              return true;
 272          }
 273      }
 274  
 275      /**
 276       * Resolve any conflicts
 277       *
 278       * @param stClass $row Row from the page table to fix
 279       * @param bool $resolvable
 280       * @param string $suffix Suffix to append to the fixed page
 281       * @return bool
 282       */
 283  	private function resolveConflict( $row, $resolvable, $suffix ) {
 284          if ( !$resolvable ) {
 285              $this->output( "...  *** old title {$row->title}\n" );
 286              while ( true ) {
 287                  $row->title .= $suffix;
 288                  $this->output( "...  *** new title {$row->title}\n" );
 289                  $title = Title::makeTitleSafe( $row->namespace, $row->title );
 290                  if ( !$title ) {
 291                      $this->output( "... !!! invalid title\n" );
 292  
 293                      return false;
 294                  }
 295                  $id = $title->getArticleID();
 296                  if ( $id ) {
 297                      $this->output( "...  *** page exists with ID $id ***\n" );
 298                  } else {
 299                      break;
 300                  }
 301              }
 302              $this->output( "...  *** using suffixed form [[" . $title->getPrefixedText() . "]] ***\n" );
 303          }
 304          $this->resolveConflictOn( $row, 'page', 'page' );
 305  
 306          return true;
 307      }
 308  
 309      /**
 310       * Resolve a given conflict
 311       *
 312       * @param stdClass $row Row from the old broken entry
 313       * @param string $table Table to update
 314       * @param string $prefix Prefix for column name, like page or ar
 315       * @return bool
 316       */
 317  	private function resolveConflictOn( $row, $table, $prefix ) {
 318          $this->output( "... resolving on $table... " );
 319          $newTitle = Title::makeTitleSafe( $row->namespace, $row->title );
 320          $this->db->update( $table,
 321              array(
 322                  "{$prefix}_namespace" => $newTitle->getNamespace(),
 323                  "{$prefix}_title" => $newTitle->getDBkey(),
 324              ),
 325              array(
 326                  // "{$prefix}_namespace" => 0,
 327                  // "{$prefix}_title" => $row->oldtitle,
 328                  "{$prefix}_id" => $row->id,
 329              ),
 330              __METHOD__ );
 331          $this->output( "ok.\n" );
 332  
 333          return true;
 334      }
 335  }
 336  
 337  $maintClass = "NamespaceConflictChecker";
 338  require_once RUN_MAINTENANCE_IF_MAIN;


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1