PageRenderTime 25ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/mediawiki-integration/source/php/mediawiki/maintenance/rebuildImages.php

https://code.google.com/
PHP | 275 lines | 218 code | 24 blank | 33 comment | 15 complexity | 19150aeb7bfa1be6a8b4ff238ed48fd9 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-3.0
  1. <?php
  2. /*
  3. * Script to update image metadata records
  4. *
  5. * Usage: php rebuildImages.php [--missing] [--dry-run]
  6. * Options:
  7. * --missing Crawl the uploads dir for images without records, and
  8. * add them only.
  9. *
  10. * Copyright (C) 2005 Brion Vibber <brion@pobox.com>
  11. * http://www.mediawiki.org/
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License as published by
  15. * the Free Software Foundation; either version 2 of the License, or
  16. * (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License along
  24. * with this program; if not, write to the Free Software Foundation, Inc.,
  25. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  26. * http://www.gnu.org/copyleft/gpl.html
  27. *
  28. * @author Brion Vibber <brion at pobox.com>
  29. * @package MediaWiki
  30. * @subpackage maintenance
  31. */
  32. $options = array( 'missing', 'dry-run' );
  33. require_once( 'commandLine.inc' );
  34. require_once( 'FiveUpgrade.inc' );
  35. class ImageBuilder extends FiveUpgrade {
  36. function ImageBuilder( $dryrun = false ) {
  37. parent::FiveUpgrade();
  38. $this->maxLag = 10; # if slaves are lagged more than 10 secs, wait
  39. $this->dryrun = $dryrun;
  40. }
  41. function build() {
  42. $this->buildImage();
  43. $this->buildOldImage();
  44. }
  45. function init( $count, $table ) {
  46. $this->processed = 0;
  47. $this->updated = 0;
  48. $this->count = $count;
  49. $this->startTime = wfTime();
  50. $this->table = $table;
  51. }
  52. function progress( $updated ) {
  53. $this->updated += $updated;
  54. $this->processed++;
  55. if( $this->processed % 100 != 0 ) {
  56. return;
  57. }
  58. $portion = $this->processed / $this->count;
  59. $updateRate = $this->updated / $this->processed;
  60. $now = wfTime();
  61. $delta = $now - $this->startTime;
  62. $estimatedTotalTime = $delta / $portion;
  63. $eta = $this->startTime + $estimatedTotalTime;
  64. printf( "%s: %6.2f%% done on %s; ETA %s [%d/%d] %.2f/sec <%.2f%% updated>\n",
  65. wfTimestamp( TS_DB, intval( $now ) ),
  66. $portion * 100.0,
  67. $this->table,
  68. wfTimestamp( TS_DB, intval( $eta ) ),
  69. $completed,
  70. $this->count,
  71. $rate,
  72. $updateRate * 100.0 );
  73. flush();
  74. }
  75. function buildTable( $table, $key, $callback ) {
  76. $fname = 'ImageBuilder::buildTable';
  77. $count = $this->dbw->selectField( $table, 'count(*)', '', $fname );
  78. $this->init( $count, $table );
  79. $this->log( "Processing $table..." );
  80. $tableName = $this->dbr->tableName( $table );
  81. $sql = "SELECT * FROM $tableName";
  82. $result = $this->dbr->query( $sql, $fname );
  83. while( $row = $this->dbr->fetchObject( $result ) ) {
  84. $update = call_user_func( $callback, $row );
  85. if( is_array( $update ) ) {
  86. if( !$this->dryrun ) {
  87. $this->dbw->update( $table,
  88. $update,
  89. array( $key => $row->$key ),
  90. $fname );
  91. }
  92. $this->progress( 1 );
  93. } else {
  94. $this->progress( 0 );
  95. }
  96. }
  97. $this->log( "Finished $table... $this->updated of $this->processed rows updated" );
  98. $this->dbr->freeResult( $result );
  99. }
  100. function buildImage() {
  101. $callback = array( &$this, 'imageCallback' );
  102. $this->buildTable( 'image', 'img_name', $callback );
  103. }
  104. function imageCallback( $row ) {
  105. if( $row->img_width ) {
  106. // Already processed
  107. return null;
  108. }
  109. // Fill in the new image info fields
  110. $info = $this->imageInfo( $row->img_name );
  111. global $wgMemc;
  112. $key = wfMemcKey( "Image", md5( $row->img_name ) );
  113. $wgMemc->delete( $key );
  114. return array(
  115. 'img_width' => $info['width'],
  116. 'img_height' => $info['height'],
  117. 'img_bits' => $info['bits'],
  118. 'img_media_type' => $info['media'],
  119. 'img_major_mime' => $info['major'],
  120. 'img_minor_mime' => $info['minor'] );
  121. }
  122. function buildOldImage() {
  123. $this->buildTable( 'oldimage', 'oi_archive_name',
  124. array( &$this, 'oldimageCallback' ) );
  125. }
  126. function oldimageCallback( $row ) {
  127. if( $row->oi_width ) {
  128. return null;
  129. }
  130. // Fill in the new image info fields
  131. $info = $this->imageInfo( $row->oi_archive_name, 'wfImageArchiveDir', $row->oi_name );
  132. return array(
  133. 'oi_width' => $info['width' ],
  134. 'oi_height' => $info['height'],
  135. 'oi_bits' => $info['bits' ] );
  136. }
  137. function crawlMissing() {
  138. global $wgUploadDirectory, $wgHashedUploadDirectory;
  139. if( $wgHashedUploadDirectory ) {
  140. for( $i = 0; $i < 16; $i++ ) {
  141. for( $j = 0; $j < 16; $j++ ) {
  142. $dir = sprintf( '%s%s%01x%s%02x',
  143. $wgUploadDirectory,
  144. DIRECTORY_SEPARATOR,
  145. $i,
  146. DIRECTORY_SEPARATOR,
  147. $i * 16 + $j );
  148. $this->crawlDirectory( $dir );
  149. }
  150. }
  151. } else {
  152. $this->crawlDirectory( $wgUploadDirectory );
  153. }
  154. }
  155. function crawlDirectory( $dir ) {
  156. if( !file_exists( $dir ) ) {
  157. return $this->log( "no directory, skipping $dir" );
  158. }
  159. if( !is_dir( $dir ) ) {
  160. return $this->log( "not a directory?! skipping $dir" );
  161. }
  162. if( !is_readable( $dir ) ) {
  163. return $this->log( "dir not readable, skipping $dir" );
  164. }
  165. $source = opendir( $dir );
  166. if( $source === false ) {
  167. return $this->log( "couldn't open dir, skipping $dir" );
  168. }
  169. $this->log( "crawling $dir" );
  170. while( false !== ( $filename = readdir( $source ) ) ) {
  171. $fullpath = $dir . DIRECTORY_SEPARATOR . $filename;
  172. if( is_dir( $fullpath ) ) {
  173. continue;
  174. }
  175. if( is_link( $fullpath ) ) {
  176. $this->log( "skipping symlink at $fullpath" );
  177. continue;
  178. }
  179. $this->checkMissingImage( $filename, $fullpath );
  180. }
  181. closedir( $source );
  182. }
  183. function checkMissingImage( $filename, $fullpath ) {
  184. $fname = 'ImageBuilder::checkMissingImage';
  185. $row = $this->dbw->selectRow( 'image',
  186. array( 'img_name' ),
  187. array( 'img_name' => $filename ),
  188. $fname );
  189. if( $row ) {
  190. // already known, move on
  191. return;
  192. } else {
  193. $this->addMissingImage( $filename, $fullpath );
  194. }
  195. }
  196. function addMissingImage( $filename, $fullpath ) {
  197. $fname = 'ImageBuilder::addMissingImage';
  198. $size = filesize( $fullpath );
  199. $info = $this->imageInfo( $filename );
  200. $timestamp = $this->dbw->timestamp( filemtime( $fullpath ) );
  201. global $wgContLang;
  202. $altname = $wgContLang->checkTitleEncoding( $filename );
  203. if( $altname != $filename ) {
  204. if( $this->dryrun ) {
  205. $filename = $altname;
  206. $this->log( "Estimating transcoding... $altname" );
  207. } else {
  208. $filename = $this->renameFile( $filename );
  209. }
  210. }
  211. if( $filename == '' ) {
  212. $this->log( "Empty filename for $fullpath" );
  213. return;
  214. }
  215. $fields = array(
  216. 'img_name' => $filename,
  217. 'img_size' => $size,
  218. 'img_width' => $info['width'],
  219. 'img_height' => $info['height'],
  220. 'img_metadata' => '', // filled in on-demand
  221. 'img_bits' => $info['bits'],
  222. 'img_media_type' => $info['media'],
  223. 'img_major_mime' => $info['major'],
  224. 'img_minor_mime' => $info['minor'],
  225. 'img_description' => '(recovered file, missing upload log entry)',
  226. 'img_user' => 0,
  227. 'img_user_text' => 'Conversion script',
  228. 'img_timestamp' => $timestamp );
  229. if( !$this->dryrun ) {
  230. $this->dbw->insert( 'image', $fields, $fname );
  231. }
  232. $this->log( $fullpath );
  233. }
  234. }
  235. $builder = new ImageBuilder( isset( $options['dry-run'] ) );
  236. if( isset( $options['missing'] ) ) {
  237. $builder->crawlMissing();
  238. } else {
  239. $builder->build();
  240. }
  241. ?>