MediaWiki REL1_32
rebuildImages.php
Go to the documentation of this file.
1<?php
33require_once __DIR__ . '/Maintenance.php';
34
37
44
48 protected $dbw;
49
50 function __construct() {
51 parent::__construct();
52
54 // make sure to update old, but compatible img_metadata fields.
56
57 $this->addDescription( 'Script to update image metadata records' );
58
59 $this->addOption( 'missing', 'Check for files without associated database record' );
60 $this->addOption( 'dry-run', 'Only report, don\'t update the database' );
61 }
62
63 public function execute() {
64 $this->dbw = $this->getDB( DB_MASTER );
65 $this->dryrun = $this->hasOption( 'dry-run' );
66 if ( $this->dryrun ) {
67 MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode()
68 ->setReason( 'Dry run mode, image upgrades are suppressed' );
69 }
70
71 if ( $this->hasOption( 'missing' ) ) {
72 $this->crawlMissing();
73 } else {
74 $this->build();
75 }
76 }
77
81 function getRepo() {
82 if ( !isset( $this->repo ) ) {
83 $this->repo = RepoGroup::singleton()->getLocalRepo();
84 }
85
86 return $this->repo;
87 }
88
89 function build() {
90 $this->buildImage();
91 $this->buildOldImage();
92 }
93
94 function init( $count, $table ) {
95 $this->processed = 0;
96 $this->updated = 0;
97 $this->count = $count;
98 $this->startTime = microtime( true );
99 $this->table = $table;
100 }
101
102 function progress( $updated ) {
103 $this->updated += $updated;
104 $this->processed++;
105 if ( $this->processed % 100 != 0 ) {
106 return;
107 }
108 $portion = $this->processed / $this->count;
109 $updateRate = $this->updated / $this->processed;
110
111 $now = microtime( true );
112 $delta = $now - $this->startTime;
113 $estimatedTotalTime = $delta / $portion;
114 $eta = $this->startTime + $estimatedTotalTime;
115 $rate = $this->processed / $delta;
116
117 $this->output( sprintf( "%s: %6.2f%% done on %s; ETA %s [%d/%d] %.2f/sec <%.2f%% updated>\n",
118 wfTimestamp( TS_DB, intval( $now ) ),
119 $portion * 100.0,
120 $this->table,
121 wfTimestamp( TS_DB, intval( $eta ) ),
122 $this->processed,
123 $this->count,
124 $rate,
125 $updateRate * 100.0 ) );
126 flush();
127 }
128
129 function buildTable( $table, $key, $queryInfo, $callback ) {
130 $count = $this->dbw->selectField( $table, 'count(*)', '', __METHOD__ );
131 $this->init( $count, $table );
132 $this->output( "Processing $table...\n" );
133
134 $result = $this->getDB( DB_REPLICA )->select(
135 $queryInfo['tables'], $queryInfo['fields'], [], __METHOD__, [], $queryInfo['joins']
136 );
137
138 foreach ( $result as $row ) {
139 $update = call_user_func( $callback, $row, null );
140 if ( $update ) {
141 $this->progress( 1 );
142 } else {
143 $this->progress( 0 );
144 }
145 }
146 $this->output( "Finished $table... $this->updated of $this->processed rows updated\n" );
147 }
148
149 function buildImage() {
150 $callback = [ $this, 'imageCallback' ];
151 $this->buildTable( 'image', 'img_name', LocalFile::getQueryInfo(), $callback );
152 }
153
154 function imageCallback( $row, $copy ) {
155 // Create a File object from the row
156 // This will also upgrade it
157 $file = $this->getRepo()->newFileFromRow( $row );
158
159 return $file->getUpgraded();
160 }
161
162 function buildOldImage() {
163 $this->buildTable( 'oldimage', 'oi_archive_name', OldLocalFile::getQueryInfo(),
164 [ $this, 'oldimageCallback' ] );
165 }
166
167 function oldimageCallback( $row, $copy ) {
168 // Create a File object from the row
169 // This will also upgrade it
170 if ( $row->oi_archive_name == '' ) {
171 $this->output( "Empty oi_archive_name for oi_name={$row->oi_name}\n" );
172
173 return false;
174 }
175 $file = $this->getRepo()->newFileFromRow( $row );
176
177 return $file->getUpgraded();
178 }
179
180 function crawlMissing() {
181 $this->getRepo()->enumFiles( [ $this, 'checkMissingImage' ] );
182 }
183
184 function checkMissingImage( $fullpath ) {
185 $filename = wfBaseName( $fullpath );
186 $row = $this->dbw->selectRow( 'image',
187 [ 'img_name' ],
188 [ 'img_name' => $filename ],
189 __METHOD__ );
190
191 if ( !$row ) { // file not registered
192 $this->addMissingImage( $filename, $fullpath );
193 }
194 }
195
196 function addMissingImage( $filename, $fullpath ) {
197 $timestamp = $this->dbw->timestamp( $this->getRepo()->getFileTimestamp( $fullpath ) );
198
199 $altname = MediaWikiServices::getInstance()->getContentLanguage()->
200 checkTitleEncoding( $filename );
201 if ( $altname != $filename ) {
202 if ( $this->dryrun ) {
203 $filename = $altname;
204 $this->output( "Estimating transcoding... $altname\n" );
205 } else {
206 # @todo FIXME: create renameFile()
207 $filename = $this->renameFile( $filename );
208 }
209 }
210
211 if ( $filename == '' ) {
212 $this->output( "Empty filename for $fullpath\n" );
213
214 return;
215 }
216 if ( !$this->dryrun ) {
217 $file = wfLocalFile( $filename );
218 if ( !$file->recordUpload(
219 '',
220 '(recovered file, missing upload log entry)',
221 '',
222 '',
223 '',
224 false,
225 $timestamp
226 ) ) {
227 $this->output( "Error uploading file $fullpath\n" );
228
229 return;
230 }
231 }
232 $this->output( $fullpath . "\n" );
233 }
234}
235
236$maintClass = ImageBuilder::class;
237require_once RUN_MAINTENANCE_IF_MAIN;
$wgUpdateCompatibleMetadata
If to automatically update the img_metadata field if the metadata field is outdated but compatible wi...
wfBaseName( $path, $suffix='')
Return the final portion of a pathname.
wfLocalFile( $title)
Get an object referring to a locally registered file.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Maintenance script to update image metadata records.
__construct()
Default constructor.
buildTable( $table, $key, $queryInfo, $callback)
oldimageCallback( $row, $copy)
checkMissingImage( $fullpath)
IMaintainableDatabase $dbw
imageCallback( $row, $copy)
progress( $updated)
execute()
Do the actual work.
init( $count, $table)
addMissingImage( $filename, $fullpath)
static getQueryInfo(array $options=[])
Return the tables, fields, and join conditions to be selected to create a new localfile object.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
output( $out, $channel=null)
Throw some output to the user.
getDB( $db, $groups=[], $wiki=false)
Returns a database to be used by current maintenance script.
hasOption( $name)
Checks to see if a particular option exists.
addDescription( $text)
Set the description text.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
MediaWikiServices is the service locator for the application scope of MediaWiki.
static getQueryInfo(array $options=[])
Return the tables, fields, and join conditions to be selected to create a new oldlocalfile object.
static singleton()
Get a RepoGroup instance.
Definition RepoGroup.php:59
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global then executing the whole list after the page is displayed We don t do anything smart like collating updates to the same table or such because the list is almost always going to have just one item on if so it s not worth the trouble Since there is a job queue in the jobs table
Definition deferred.txt:16
Advanced database interface for IDatabase handles that include maintenance methods.
require_once RUN_MAINTENANCE_IF_MAIN
const DB_REPLICA
Definition defines.php:25
const DB_MASTER
Definition defines.php:26
$maintClass