]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - maintenance/populateImageSha1.php
MediaWiki 1.30.2-scripts
[autoinstalls/mediawiki.git] / maintenance / populateImageSha1.php
1 <?php
2 /**
3  * Optional upgrade script to populate the img_sha1 field
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  * http://www.gnu.org/copyleft/gpl.html
19  *
20  * @file
21  * @ingroup Maintenance
22  */
23
24 require_once __DIR__ . '/Maintenance.php';
25
26 /**
27  * Maintenance script to populate the img_sha1 field.
28  *
29  * @ingroup Maintenance
30  */
31 class PopulateImageSha1 extends LoggedUpdateMaintenance {
32         public function __construct() {
33                 parent::__construct();
34                 $this->addDescription( 'Populate the img_sha1 field' );
35                 $this->addOption( 'force', "Recalculate sha1 for rows that already have a value" );
36                 $this->addOption( 'multiversiononly', "Calculate only for files with several versions" );
37                 $this->addOption( 'method', "Use 'pipe' to pipe to mysql command line,\n" .
38                         "\t\tdefault uses Database class", false, true );
39                 $this->addOption(
40                         'file',
41                         'Fix for a specific file, without File: namespace prefixed',
42                         false,
43                         true
44                 );
45         }
46
47         protected function getUpdateKey() {
48                 return 'populate img_sha1';
49         }
50
51         protected function updateSkippedMessage() {
52                 return 'img_sha1 column of image table already populated.';
53         }
54
55         public function execute() {
56                 if ( $this->getOption( 'file' ) || $this->hasOption( 'multiversiononly' ) ) {
57                         $this->doDBUpdates(); // skip update log checks/saves
58                 } else {
59                         parent::execute();
60                 }
61         }
62
63         public function doDBUpdates() {
64                 $method = $this->getOption( 'method', 'normal' );
65                 $file = $this->getOption( 'file', '' );
66                 $force = $this->getOption( 'force' );
67                 $isRegen = ( $force || $file != '' ); // forced recalculation?
68
69                 $t = -microtime( true );
70                 $dbw = $this->getDB( DB_MASTER );
71                 if ( $file != '' ) {
72                         $res = $dbw->select(
73                                 'image',
74                                 [ 'img_name' ],
75                                 [ 'img_name' => $file ],
76                                 __METHOD__
77                         );
78                         if ( !$res ) {
79                                 $this->error( "No such file: $file", true );
80
81                                 return false;
82                         }
83                         $this->output( "Populating img_sha1 field for specified files\n" );
84                 } else {
85                         if ( $this->hasOption( 'multiversiononly' ) ) {
86                                 $conds = [];
87                                 $this->output( "Populating and recalculating img_sha1 field for versioned files\n" );
88                         } elseif ( $force ) {
89                                 $conds = [];
90                                 $this->output( "Populating and recalculating img_sha1 field\n" );
91                         } else {
92                                 $conds = [ 'img_sha1' => '' ];
93                                 $this->output( "Populating img_sha1 field\n" );
94                         }
95                         if ( $this->hasOption( 'multiversiononly' ) ) {
96                                 $res = $dbw->select( 'oldimage',
97                                         [ 'img_name' => 'DISTINCT(oi_name)' ], $conds, __METHOD__ );
98                         } else {
99                                 $res = $dbw->select( 'image', [ 'img_name' ], $conds, __METHOD__ );
100                         }
101                 }
102
103                 $imageTable = $dbw->tableName( 'image' );
104                 $oldImageTable = $dbw->tableName( 'oldimage' );
105
106                 if ( $method == 'pipe' ) {
107                         // Opening a pipe allows the SHA-1 operation to be done in parallel
108                         // with the database write operation, because the writes are queued
109                         // in the pipe buffer. This can improve performance by up to a
110                         // factor of 2.
111                         global $wgDBuser, $wgDBserver, $wgDBpassword, $wgDBname;
112                         $cmd = 'mysql -u' . wfEscapeShellArg( $wgDBuser ) .
113                                 ' -h' . wfEscapeShellArg( $wgDBserver ) .
114                                 ' -p' . wfEscapeShellArg( $wgDBpassword, $wgDBname );
115                         $this->output( "Using pipe method\n" );
116                         $pipe = popen( $cmd, 'w' );
117                 }
118
119                 $numRows = $res->numRows();
120                 $i = 0;
121                 foreach ( $res as $row ) {
122                         if ( $i % $this->mBatchSize == 0 ) {
123                                 $this->output( sprintf(
124                                         "Done %d of %d, %5.3f%%  \r", $i, $numRows, $i / $numRows * 100 ) );
125                                 wfWaitForSlaves();
126                         }
127
128                         $file = wfLocalFile( $row->img_name );
129                         if ( !$file ) {
130                                 continue;
131                         }
132
133                         // Upgrade the current file version...
134                         $sha1 = $file->getRepo()->getFileSha1( $file->getPath() );
135                         if ( strval( $sha1 ) !== '' ) { // file on disk and hashed properly
136                                 if ( $isRegen && $file->getSha1() !== $sha1 ) {
137                                         // The population was probably done already. If the old SHA1
138                                         // does not match, then both fix the SHA1 and the metadata.
139                                         $file->upgradeRow();
140                                 } else {
141                                         $sql = "UPDATE $imageTable SET img_sha1=" . $dbw->addQuotes( $sha1 ) .
142                                                 " WHERE img_name=" . $dbw->addQuotes( $file->getName() );
143                                         if ( $method == 'pipe' ) {
144                                                 fwrite( $pipe, "$sql;\n" );
145                                         } else {
146                                                 $dbw->query( $sql, __METHOD__ );
147                                         }
148                                 }
149                         }
150                         // Upgrade the old file versions...
151                         foreach ( $file->getHistory() as $oldFile ) {
152                                 $sha1 = $oldFile->getRepo()->getFileSha1( $oldFile->getPath() );
153                                 if ( strval( $sha1 ) !== '' ) { // file on disk and hashed properly
154                                         if ( $isRegen && $oldFile->getSha1() !== $sha1 ) {
155                                                 // The population was probably done already. If the old SHA1
156                                                 // does not match, then both fix the SHA1 and the metadata.
157                                                 $oldFile->upgradeRow();
158                                         } else {
159                                                 $sql = "UPDATE $oldImageTable SET oi_sha1=" . $dbw->addQuotes( $sha1 ) .
160                                                         " WHERE (oi_name=" . $dbw->addQuotes( $oldFile->getName() ) . " AND" .
161                                                         " oi_archive_name=" . $dbw->addQuotes( $oldFile->getArchiveName() ) . ")";
162                                                 if ( $method == 'pipe' ) {
163                                                         fwrite( $pipe, "$sql;\n" );
164                                                 } else {
165                                                         $dbw->query( $sql, __METHOD__ );
166                                                 }
167                                         }
168                                 }
169                         }
170                         $i++;
171                 }
172                 if ( $method == 'pipe' ) {
173                         fflush( $pipe );
174                         pclose( $pipe );
175                 }
176                 $t += microtime( true );
177                 $this->output( sprintf( "\nDone %d files in %.1f seconds\n", $numRows, $t ) );
178
179                 return !$file; // we only updated *some* files, don't log
180         }
181 }
182
183 $maintClass = "PopulateImageSha1";
184 require_once RUN_MAINTENANCE_IF_MAIN;