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