MediaWiki REL1_30
orphans.php
Go to the documentation of this file.
1<?php
31require_once __DIR__ . '/Maintenance.php';
32
34
41class Orphans extends Maintenance {
42 public function __construct() {
43 parent::__construct();
44 $this->addDescription( "Look for 'orphan' revisions hooked to pages which don't exist\n" .
45 "and 'childless' pages with no revisions\n" .
46 "Then, kill the poor widows and orphans\n" .
47 "Man this is depressing"
48 );
49 $this->addOption( 'fix', 'Actually fix broken entries' );
50 }
51
52 public function execute() {
53 $this->checkOrphans( $this->hasOption( 'fix' ) );
54 $this->checkSeparation( $this->hasOption( 'fix' ) );
55 # Does not work yet, do not use
56 # $this->checkWidows( $this->hasOption( 'fix' ) );
57 }
58
64 private function lockTables( $db, $extraTable = [] ) {
65 $tbls = [ 'page', 'revision', 'redirect' ];
66 if ( $extraTable ) {
67 $tbls = array_merge( $tbls, $extraTable );
68 }
69 $db->lockTables( [], $tbls, __METHOD__, false );
70 }
71
76 private function checkOrphans( $fix ) {
77 $dbw = $this->getDB( DB_MASTER );
78 $commentStore = new CommentStore( 'rev_comment' );
79
80 if ( $fix ) {
81 $this->lockTables( $dbw );
82 }
83
84 $commentQuery = $commentStore->getJoin();
85
86 $this->output( "Checking for orphan revision table entries... "
87 . "(this may take a while on a large wiki)\n" );
88 $result = $dbw->select(
89 [ 'revision', 'page' ] + $commentQuery['tables'],
90 [ 'rev_id', 'rev_page', 'rev_timestamp', 'rev_user_text' ] + $commentQuery['fields'],
91 [ 'page_id' => null ],
92 __METHOD__,
93 [],
94 [ 'page' => [ 'LEFT JOIN', [ 'rev_page=page_id' ] ] ] + $commentQuery['joins']
95 );
96 $orphans = $result->numRows();
97 if ( $orphans > 0 ) {
98 global $wgContLang;
99
100 $this->output( "$orphans orphan revisions...\n" );
101 $this->output( sprintf(
102 "%10s %10s %14s %20s %s\n",
103 'rev_id', 'rev_page', 'rev_timestamp', 'rev_user_text', 'rev_comment'
104 ) );
105
106 foreach ( $result as $row ) {
107 $comment = $commentStore->getComment( $row )->text;
108 if ( $comment !== '' ) {
109 $comment = '(' . $wgContLang->truncate( $comment, 40 ) . ')';
110 }
111 $this->output( sprintf( "%10d %10d %14s %20s %s\n",
112 $row->rev_id,
113 $row->rev_page,
114 $row->rev_timestamp,
115 $wgContLang->truncate( $row->rev_user_text, 17 ),
116 $comment ) );
117 if ( $fix ) {
118 $dbw->delete( 'revision', [ 'rev_id' => $row->rev_id ] );
119 }
120 }
121 if ( !$fix ) {
122 $this->output( "Run again with --fix to remove these entries automatically.\n" );
123 }
124 } else {
125 $this->output( "No orphans! Yay!\n" );
126 }
127
128 if ( $fix ) {
129 $dbw->unlockTables( __METHOD__ );
130 }
131 }
132
139 private function checkWidows( $fix ) {
140 $dbw = $this->getDB( DB_MASTER );
141 $page = $dbw->tableName( 'page' );
142 $revision = $dbw->tableName( 'revision' );
143
144 if ( $fix ) {
145 $this->lockTables( $dbw );
146 }
147
148 $this->output( "\nChecking for childless page table entries... "
149 . "(this may take a while on a large wiki)\n" );
150 $result = $dbw->query( "
151 SELECT *
152 FROM $page LEFT OUTER JOIN $revision ON page_latest=rev_id
153 WHERE rev_id IS NULL
154 " );
155 $widows = $result->numRows();
156 if ( $widows > 0 ) {
157 $this->output( "$widows childless pages...\n" );
158 $this->output( sprintf( "%10s %11s %2s %s\n", 'page_id', 'page_latest', 'ns', 'page_title' ) );
159 foreach ( $result as $row ) {
160 printf( "%10d %11d %2d %s\n",
161 $row->page_id,
162 $row->page_latest,
163 $row->page_namespace,
164 $row->page_title );
165 if ( $fix ) {
166 $dbw->delete( 'page', [ 'page_id' => $row->page_id ] );
167 }
168 }
169 if ( !$fix ) {
170 $this->output( "Run again with --fix to remove these entries automatically.\n" );
171 }
172 } else {
173 $this->output( "No childless pages! Yay!\n" );
174 }
175
176 if ( $fix ) {
177 $dbw->unlockTables( __METHOD__ );
178 }
179 }
180
185 private function checkSeparation( $fix ) {
186 $dbw = $this->getDB( DB_MASTER );
187 $page = $dbw->tableName( 'page' );
188 $revision = $dbw->tableName( 'revision' );
189
190 if ( $fix ) {
191 $this->lockTables( $dbw, [ 'user', 'text' ] );
192 }
193
194 $this->output( "\nChecking for pages whose page_latest links are incorrect... "
195 . "(this may take a while on a large wiki)\n" );
196 $result = $dbw->query( "
197 SELECT *
198 FROM $page LEFT OUTER JOIN $revision ON page_latest=rev_id
199 " );
200 $found = 0;
201 foreach ( $result as $row ) {
202 $result2 = $dbw->query( "
203 SELECT MAX(rev_timestamp) as max_timestamp
204 FROM $revision
205 WHERE rev_page=$row->page_id
206 " );
207 $row2 = $dbw->fetchObject( $result2 );
208 if ( $row2 ) {
209 if ( $row->rev_timestamp != $row2->max_timestamp ) {
210 if ( $found == 0 ) {
211 $this->output( sprintf( "%10s %10s %14s %14s\n",
212 'page_id', 'rev_id', 'timestamp', 'max timestamp' ) );
213 }
214 ++$found;
215 $this->output( sprintf( "%10d %10d %14s %14s\n",
216 $row->page_id,
217 $row->page_latest,
218 $row->rev_timestamp,
219 $row2->max_timestamp ) );
220 if ( $fix ) {
221 # ...
222 $maxId = $dbw->selectField(
223 'revision',
224 'rev_id',
225 [
226 'rev_page' => $row->page_id,
227 'rev_timestamp' => $row2->max_timestamp ] );
228 $this->output( "... updating to revision $maxId\n" );
229 $maxRev = Revision::newFromId( $maxId );
230 $title = Title::makeTitle( $row->page_namespace, $row->page_title );
231 $article = WikiPage::factory( $title );
232 $article->updateRevisionOn( $dbw, $maxRev );
233 }
234 }
235 } else {
236 $this->output( "wtf\n" );
237 }
238 }
239
240 if ( $found ) {
241 $this->output( "Found $found pages with incorrect latest revision.\n" );
242 } else {
243 $this->output( "No pages with incorrect latest revision. Yay!\n" );
244 }
245 if ( !$fix && $found > 0 ) {
246 $this->output( "Run again with --fix to remove these entries automatically.\n" );
247 }
248
249 if ( $fix ) {
250 $dbw->unlockTables( __METHOD__ );
251 }
252 }
253}
254
255$maintClass = "Orphans";
256require_once RUN_MAINTENANCE_IF_MAIN;
CommentStore handles storage of comments (edit summaries, log reasons, etc) in the database.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
getDB( $db, $groups=[], $wiki=false)
Returns a database to be used by current maintenance script.
hasOption( $name)
Checks to see if a particular param exists.
addDescription( $text)
Set the description text.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
Maintenance script that looks for 'orphan' revisions hooked to pages which don't exist and 'childless...
Definition orphans.php:41
lockTables( $db, $extraTable=[])
Lock the appropriate tables for the script.
Definition orphans.php:64
checkSeparation( $fix)
Check for pages where page_latest is wrong.
Definition orphans.php:185
checkWidows( $fix)
Definition orphans.php:139
execute()
Do the actual work.
Definition orphans.php:52
__construct()
Default constructor.
Definition orphans.php:42
checkOrphans( $fix)
Check for orphan revisions.
Definition orphans.php:76
static newFromId( $id, $flags=0)
Load a page revision from a given revision ID number.
Definition Revision.php:116
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition WikiPage.php:121
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the local content language as $wgContLang
Definition design.txt:57
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add in any and then calling output() to send it all. It could be easily changed to send incrementally if that becomes useful
Advanced database interface for IDatabase handles that include maintenance methods.
require_once RUN_MAINTENANCE_IF_MAIN
$maintClass
Definition orphans.php:255
const DB_MASTER
Definition defines.php:26