MediaWiki  REL1_19
fixTimestamps.php
Go to the documentation of this file.
00001 <?php
00027 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
00028 
00029 class FixTimestamps extends Maintenance {
00030         public function __construct() {
00031                 parent::__construct();
00032                 $this->mDescription = "";
00033                 $this->addArg( 'offset', '' );
00034                 $this->addArg( 'start', 'Starting timestamp' );
00035                 $this->addArg( 'end', 'Ending timestamp' );
00036         }
00037 
00038         public function execute() {
00039                 $offset = $this->getArg( 0 ) * 3600;
00040                 $start = $this->getArg( 1 );
00041                 $end = $this->getArg( 2 );
00042                 $grace = 60; // maximum normal clock offset
00043 
00044                 # Find bounding revision IDs
00045                 $dbw = wfGetDB( DB_MASTER );
00046                 $revisionTable = $dbw->tableName( 'revision' );
00047                 $res = $dbw->query( "SELECT MIN(rev_id) as minrev, MAX(rev_id) as maxrev FROM $revisionTable " .
00048                         "WHERE rev_timestamp BETWEEN '{$start}' AND '{$end}'", __METHOD__ );
00049                 $row = $dbw->fetchObject( $res );
00050 
00051                 if ( is_null( $row->minrev ) ) {
00052                         $this->error( "No revisions in search period.", true );
00053                 }
00054 
00055                 $minRev = $row->minrev;
00056                 $maxRev = $row->maxrev;
00057 
00058                 # Select all timestamps and IDs
00059                 $sql = "SELECT rev_id, rev_timestamp FROM $revisionTable " .
00060                         "WHERE rev_id BETWEEN $minRev AND $maxRev";
00061                 if ( $offset > 0 ) {
00062                         $sql .= " ORDER BY rev_id DESC";
00063                         $expectedSign = -1;
00064                 } else {
00065                         $expectedSign = 1;
00066                 }
00067 
00068                 $res = $dbw->query( $sql, __METHOD__ );
00069 
00070                 $lastNormal = 0;
00071                 $badRevs = array();
00072                 $numGoodRevs = 0;
00073 
00074                 foreach ( $res as $row ) {
00075                         $timestamp = wfTimestamp( TS_UNIX, $row->rev_timestamp );
00076                         $delta = $timestamp - $lastNormal;
00077                         $sign = $delta == 0 ? 0 : $delta / abs( $delta );
00078                         if ( $sign == 0 || $sign == $expectedSign ) {
00079                                 // Monotonic change
00080                                 $lastNormal = $timestamp;
00081                                 ++ $numGoodRevs;
00082                                 continue;
00083                         } elseif ( abs( $delta ) <= $grace ) {
00084                                 // Non-monotonic change within grace interval
00085                                 ++ $numGoodRevs;
00086                                 continue;
00087                         } else {
00088                                 // Non-monotonic change larger than grace interval
00089                                 $badRevs[] = $row->rev_id;
00090                         }
00091                 }
00092 
00093                 $numBadRevs = count( $badRevs );
00094                 if ( $numBadRevs > $numGoodRevs ) {
00095                         $this->error(
00096                 "The majority of revisions in the search interval are marked as bad.
00097 
00098                 Are you sure the offset ($offset) has the right sign? Positive means the clock
00099                 was incorrectly set forward, negative means the clock was incorrectly set back.
00100 
00101                 If the offset is right, then increase the search interval until there are enough
00102                 good revisions to provide a majority reference.", true );
00103                 } elseif ( $numBadRevs == 0 ) {
00104                         $this->output( "No bad revisions found.\n" );
00105                         exit( 0 );
00106                 }
00107 
00108                 $this->output( sprintf( "Fixing %d revisions (%.2f%% of revisions in search interval)\n",
00109                         $numBadRevs, $numBadRevs / ( $numGoodRevs + $numBadRevs ) * 100 ) );
00110 
00111                 $fixup = -$offset;
00112                 $sql = "UPDATE $revisionTable " .
00113                         "SET rev_timestamp=DATE_FORMAT(DATE_ADD(rev_timestamp, INTERVAL $fixup SECOND), '%Y%m%d%H%i%s') " .
00114                         "WHERE rev_id IN (" . $dbw->makeList( $badRevs ) . ')';
00115                 $dbw->query( $sql, __METHOD__ );
00116                 $this->output( "Done\n" );
00117         }
00118 }
00119 
00120 $maintClass = "FixTimestamps";
00121 require_once( RUN_MAINTENANCE_IF_MAIN );