Index: trunk/phase3/maintenance/refreshCategoryCounts.inc
===================================================================
--- trunk/phase3/maintenance/refreshCategoryCounts.inc	(revision 0)
+++ trunk/phase3/maintenance/refreshCategoryCounts.inc	(revision 0)
@@ -0,0 +1,67 @@
+<?php
+/**
+ * @file
+ * @ingroup Maintenance
+ * @author Happy-melon
+ */
+
+define( 'REPORTING_INTERVAL', 1000 );
+
+function refreshCategoryCounts( $begin, $maxlag, $throttle ) {
+    $dbw = wfGetDB( DB_MASTER );
+
+    $maxlag   = intval( $maxlag );
+    $throttle = intval( $throttle );
+    if( $begin !== '' ) {
+        $where = 'cat_id > '.$dbw->addQuotes( $begin );
+    } else {
+        $where = null;
+    }
+
+    $i = 0;
+    while( true ) {
+        # Find which category to update
+        $row = $dbw->selectRow(
+            'category',
+            array( 'cat_id', 'cat_title' ),
+            $where,
+            __FUNCTION__
+        );
+        if( !$row ) {
+            # Done, hopefully.
+            break;
+        }
+        $id    = $row->cat_id;
+        $name  = $row->cat_title;
+        $where = 'cat_id > '.$dbw->addQuotes( $id );
+
+        # Use the row to update the category count
+        $cat = Category::newFromName( $name );
+        if( !is_object( $cat ) ) {
+            wfOut( "The category named $name is not valid?!\n" );
+        } else {
+            $cat->refreshCounts();
+        }
+
+        ++$i;
+        if( !($i % REPORTING_INTERVAL) ) {
+            wfOut( "$id\n" );
+            wfWaitForSlaves( $maxlag );
+        }
+        usleep( $throttle*1000 );
+    }
+
+    if( $dbw->insert(
+            'updatelog',
+            array( 'ul_key' => 'refresh catgory counts' ),
+            __FUNCTION__,
+            'IGNORE'
+        )
+    ) {
+        wfOut( "Category count refresh complete.\n" );
+        return true;
+    } else {
+        wfOut( "Could not insert category population row.\n" );
+        return false;
+    }
+}
Index: trunk/phase3/maintenance/refreshCategoryCounts.php
===================================================================
--- trunk/phase3/maintenance/refreshCategoryCounts.php	(revision 0)
+++ trunk/phase3/maintenance/refreshCategoryCounts.php	(revision 0)
@@ -0,0 +1,51 @@
+<?php
+/**
+ * @file 
+ * @ingroup Maintenance
+ * @author Happy-melon
+ */
+
+$optionsWithArgs = array( 'begin', 'max-slave-lag', 'throttle' );
+
+require_once "commandLine.inc";
+require_once "refreshCategoryCounts.inc";
+
+if( isset( $options['help'] ) ) {
+    echo <<<TEXT
+This script will refresh the cat_pages, cat_subcats and cat_files fields of
+the category table, which may be incorrect if the wiki ran the corrupted
+version of Article::doDeleteArticle (r40912 --> r47326); see explanation at
+[https://bugzilla.wikimedia.org/show_bug.cgi?id=17155].  It will print out 
+progressindicators every 1000 categories it updates. You may want to use the 
+throttling options if it's causing too much load; they will not affect correctness.
+
+If the script is stopped and later resumed, you can use the --begin option with
+the last printed progress indicator to pick up where you left off.  This is
+safe, because any newly-added categories will  be added at the end of the table.
+
+Based on /maintenance/populateCategory.php by Simetrical.
+
+Usage:
+    php refreshCategoryCounts.php [--max-slave-lag <seconds>] [--begin <name>]
+[--throttle <seconds>]
+
+    --begin: Only do categories with ids greater than the pro-vided id.
+      Default: empty (start from beginning).
+    --max-slave-lag: If slave lag exceeds this many seconds, wait until it
+drops before continuing.  Default: 10.
+    --throttle: Wait this many milliseconds after each category.  Default: 0.
+
+TEXT;
+    exit( 0 );
+}
+
+$defaults = array(
+    'begin' => '',
+    'max-slave-lag' => 10,
+    'throttle' => 0,
+);
+$options = array_merge( $defaults, $options );
+
+refreshCategoryCounts( $options['begin'], $options['max-slave-lag'],
+    $options['throttle'] );
+
