MediaWiki  master
OldLocalFile.php
Go to the documentation of this file.
1 <?php
26 
33 class OldLocalFile extends LocalFile {
35  protected $requestedTime;
36 
38  protected $archive_name;
39 
40  public const CACHE_VERSION = 1;
41 
50  public static function newFromTitle( $title, $repo, $time = null ) {
51  # The null default value is only here to avoid an E_STRICT
52  if ( $time === null ) {
53  throw new MWException( __METHOD__ . ' got null for $time parameter' );
54  }
55 
56  return new static( $title, $repo, $time, null );
57  }
58 
67  public static function newFromArchiveName( $title, $repo, $archiveName ) {
68  return new static( $title, $repo, null, $archiveName );
69  }
70 
78  public static function newFromRow( $row, $repo ) {
79  $title = Title::makeTitle( NS_FILE, $row->oi_name );
80  $file = new static( $title, $repo, null, $row->oi_archive_name );
81  $file->loadFromRow( $row, 'oi_' );
82 
83  return $file;
84  }
85 
98  public static function newFromKey( $sha1, $repo, $timestamp = false ) {
99  $dbr = $repo->getReplicaDB();
100 
101  $conds = [ 'oi_sha1' => $sha1 ];
102  if ( $timestamp ) {
103  $conds['oi_timestamp'] = $dbr->timestamp( $timestamp );
104  }
105 
106  $fileQuery = static::getQueryInfo();
107  $row = $dbr->selectRow(
108  $fileQuery['tables'], $fileQuery['fields'], $conds, __METHOD__, [], $fileQuery['joins']
109  );
110  if ( $row ) {
111  return static::newFromRow( $row, $repo );
112  } else {
113  return false;
114  }
115  }
116 
136  public static function getQueryInfo( array $options = [] ) {
137  $commentQuery = MediaWikiServices::getInstance()->getCommentStore()->getJoin( 'oi_description' );
138  $ret = [
139  'tables' => [
140  'oldimage',
141  'oldimage_actor' => 'actor'
142  ] + $commentQuery['tables'],
143  'fields' => [
144  'oi_name',
145  'oi_archive_name',
146  'oi_size',
147  'oi_width',
148  'oi_height',
149  'oi_bits',
150  'oi_media_type',
151  'oi_major_mime',
152  'oi_minor_mime',
153  'oi_timestamp',
154  'oi_deleted',
155  'oi_sha1',
156  'oi_actor',
157  'oi_user' => 'oldimage_actor.actor_user',
158  'oi_user_text' => 'oldimage_actor.actor_name'
159  ] + $commentQuery['fields'],
160  'joins' => [
161  'oldimage_actor' => [ 'JOIN', 'actor_id=oi_actor' ]
162  ] + $commentQuery['joins'],
163  ];
164 
165  if ( in_array( 'omit-nonlazy', $options, true ) ) {
166  // Internal use only for getting only the lazy fields
167  $ret['fields'] = [];
168  }
169  if ( !in_array( 'omit-lazy', $options, true ) ) {
170  // Note: Keep this in sync with self::getLazyCacheFields()
171  $ret['fields'][] = 'oi_metadata';
172  }
173 
174  return $ret;
175  }
176 
186  public function __construct( $title, $repo, $time, $archiveName ) {
187  parent::__construct( $title, $repo );
188  $this->requestedTime = $time;
189  $this->archive_name = $archiveName;
190  if ( $time === null && $archiveName === null ) {
191  throw new MWException( __METHOD__ . ': must specify at least one of $time or $archiveName' );
192  }
193  }
194 
195  public function loadFromRow( $row, $prefix = 'img_' ) {
196  $this->archive_name = $row->{"{$prefix}archive_name"};
197  $this->deleted = $row->{"{$prefix}deleted"};
198  $row = clone $row;
199  unset( $row->{"{$prefix}archive_name"} );
200  unset( $row->{"{$prefix}deleted"} );
201  parent::loadFromRow( $row, $prefix );
202  }
203 
208  protected function getCacheKey() {
209  return false;
210  }
211 
216  public function getArchiveName() {
217  if ( !isset( $this->archive_name ) ) {
218  $this->load();
219  }
220 
221  return $this->archive_name;
222  }
223 
227  public function isOld() {
228  return true;
229  }
230 
234  public function isVisible() {
235  return $this->exists() && !$this->isDeleted( File::DELETED_FILE );
236  }
237 
242  protected function loadFromDB( $flags = 0 ) {
243  $this->dataLoaded = true;
244 
245  $dbr = ( $flags & self::READ_LATEST )
246  ? $this->repo->getPrimaryDB()
247  : $this->repo->getReplicaDB();
248 
249  $conds = [ 'oi_name' => $this->getName() ];
250  if ( $this->requestedTime === null ) {
251  $conds['oi_archive_name'] = $this->archive_name;
252  } else {
253  $conds['oi_timestamp'] = $dbr->timestamp( $this->requestedTime );
254  }
255  $fileQuery = static::getQueryInfo();
256  $row = $dbr->selectRow(
257  $fileQuery['tables'],
258  $fileQuery['fields'],
259  $conds,
260  __METHOD__,
261  [ 'ORDER BY' => 'oi_timestamp DESC' ],
262  $fileQuery['joins']
263  );
264  if ( $row ) {
265  $this->loadFromRow( $row, 'oi_' );
266  } else {
267  $this->fileExists = false;
268  }
269  }
270 
275  protected function loadExtraFromDB() {
276  $this->extraDataLoaded = true;
277  $dbr = $this->repo->getReplicaDB();
278  $conds = [ 'oi_name' => $this->getName() ];
279  if ( $this->requestedTime === null ) {
280  $conds['oi_archive_name'] = $this->archive_name;
281  } else {
282  $conds['oi_timestamp'] = $dbr->timestamp( $this->requestedTime );
283  }
284  $fileQuery = static::getQueryInfo( [ 'omit-nonlazy' ] );
285  // In theory the file could have just been renamed/deleted...oh well
286  $row = $dbr->selectRow(
287  $fileQuery['tables'],
288  $fileQuery['fields'],
289  $conds,
290  __METHOD__,
291  [ 'ORDER BY' => 'oi_timestamp DESC' ],
292  $fileQuery['joins']
293  );
294 
295  if ( !$row ) { // fallback to primary DB
296  $dbr = $this->repo->getPrimaryDB();
297  $row = $dbr->selectRow(
298  $fileQuery['tables'],
299  $fileQuery['fields'],
300  $conds,
301  __METHOD__,
302  [ 'ORDER BY' => 'oi_timestamp DESC' ],
303  $fileQuery['joins']
304  );
305  }
306 
307  if ( $row ) {
308  foreach ( $this->unprefixRow( $row, 'oi_' ) as $name => $value ) {
309  $this->$name = $value;
310  }
311  } else {
312  throw new MWException( "Could not find data for image '{$this->archive_name}'." );
313  }
314  }
315 
320  protected function getCacheFields( $prefix = 'img_' ) {
321  $fields = parent::getCacheFields( $prefix );
322  $fields[] = $prefix . 'archive_name';
323  $fields[] = $prefix . 'deleted';
324 
325  return $fields;
326  }
327 
332  public function getRel() {
333  return $this->getArchiveRel( $this->getArchiveName() );
334  }
335 
340  public function getUrlRel() {
341  return $this->getArchiveRel( rawurlencode( $this->getArchiveName() ) );
342  }
343 
347  public function upgradeRow() {
348  $this->loadFromFile();
349 
350  # Don't destroy file info of missing files
351  if ( !$this->fileExists ) {
352  wfDebug( __METHOD__ . ": file does not exist, aborting" );
353 
354  return;
355  }
356 
357  $dbw = $this->repo->getPrimaryDB();
358  [ $major, $minor ] = self::splitMime( $this->mime );
359 
360  wfDebug( __METHOD__ . ': upgrading ' . $this->archive_name . " to the current schema" );
361  $dbw->update( 'oldimage',
362  [
363  'oi_size' => $this->size,
364  'oi_width' => $this->width,
365  'oi_height' => $this->height,
366  'oi_bits' => $this->bits,
367  'oi_media_type' => $this->media_type,
368  'oi_major_mime' => $major,
369  'oi_minor_mime' => $minor,
370  'oi_metadata' => $this->getMetadataForDb( $dbw ),
371  'oi_sha1' => $this->sha1,
372  ], [
373  'oi_name' => $this->getName(),
374  'oi_archive_name' => $this->archive_name ],
375  __METHOD__
376  );
377  }
378 
379  protected function reserializeMetadata() {
380  // TODO: implement this and make it possible to hit it from refreshImageMetadata.php
381  // It can be hit from action=purge but that's not very useful if the
382  // goal is to reserialize the whole oldimage table.
383  }
384 
390  public function isDeleted( $field ) {
391  $this->load();
392 
393  return ( $this->deleted & $field ) == $field;
394  }
395 
400  public function getVisibility() {
401  $this->load();
402 
403  return (int)$this->deleted;
404  }
405 
414  public function userCan( $field, Authority $performer ) {
415  $this->load();
416 
417  return RevisionRecord::userCanBitfield(
418  $this->deleted,
419  $field,
420  $performer
421  );
422  }
423 
433  public function uploadOld( $srcPath, $timestamp, $comment, UserIdentity $user ) {
434  $archiveName = $this->getArchiveName();
435  $dstRel = $this->getArchiveRel( $archiveName );
436  $status = $this->publishTo( $srcPath, $dstRel );
437 
438  if ( $status->isGood() &&
439  !$this->recordOldUpload( $srcPath, $archiveName, $timestamp, $comment, $user )
440  ) {
441  $status->fatal( 'filenotfound', $srcPath );
442  }
443 
444  return $status;
445  }
446 
458  protected function recordOldUpload( $srcPath, $archiveName, $timestamp, $comment, $user ) {
459  $dbw = $this->repo->getPrimaryDB();
460 
461  $services = MediaWikiServices::getInstance();
462  $mwProps = new MWFileProps( $services->getMimeAnalyzer() );
463  $props = $mwProps->getPropsFromPath( $srcPath, true );
464  if ( !$props['fileExists'] ) {
465  return false;
466  }
467  $this->setProps( $props );
468 
469  $dbw->startAtomic( __METHOD__ );
470  $commentFields = $services->getCommentStore()
471  ->insert( $dbw, 'oi_description', $comment );
472  $actorId = $services->getActorNormalization()
473  ->acquireActorId( $user, $dbw );
474  $dbw->insert( 'oldimage',
475  [
476  'oi_name' => $this->getName(),
477  'oi_archive_name' => $archiveName,
478  'oi_size' => $props['size'],
479  'oi_width' => intval( $props['width'] ),
480  'oi_height' => intval( $props['height'] ),
481  'oi_bits' => $props['bits'],
482  'oi_actor' => $actorId,
483  'oi_timestamp' => $dbw->timestamp( $timestamp ),
484  'oi_metadata' => $this->getMetadataForDb( $dbw ),
485  'oi_media_type' => $props['media_type'],
486  'oi_major_mime' => $props['major_mime'],
487  'oi_minor_mime' => $props['minor_mime'],
488  'oi_sha1' => $props['sha1'],
489  ] + $commentFields, __METHOD__
490  );
491  $dbw->endAtomic( __METHOD__ );
492 
493  return true;
494  }
495 
503  public function exists() {
504  $archiveName = $this->getArchiveName();
505  if ( $archiveName === '' || !is_string( $archiveName ) ) {
506  return false;
507  }
508  return parent::exists();
509  }
510 }
const NS_FILE
Definition: Defines.php:70
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
FileRepo LocalRepo ForeignAPIRepo false $repo
Some member variables can be lazy-initialised using __get().
Definition: File.php:115
Title string false $title
Definition: File.php:118
const DELETED_FILE
Definition: File.php:72
Local file in the wiki's own database.
Definition: LocalFile.php:61
string $sha1
SHA-1 base 36 content hash.
Definition: LocalFile.php:125
MediaWiki exception.
Definition: MWException.php:32
MimeMagic helper wrapper.
Definition: MWFileProps.php:28
Service locator for MediaWiki core services.
Page revision base class.
Represents a title within MediaWiki.
Definition: Title.php:82
Old file in the oldimage table.
static newFromArchiveName( $title, $repo, $archiveName)
recordOldUpload( $srcPath, $archiveName, $timestamp, $comment, $user)
Record a file upload in the oldimage table, without adding log entries.
uploadOld( $srcPath, $timestamp, $comment, UserIdentity $user)
Upload a file directly into archive.
static newFromRow( $row, $repo)
static getQueryInfo(array $options=[])
Return the tables, fields, and join conditions to be selected to create a new oldlocalfile object.
const CACHE_VERSION
__construct( $title, $repo, $time, $archiveName)
loadFromDB( $flags=0)
reserializeMetadata()
Write the metadata back to the database with the current serialization format.
static newFromKey( $sha1, $repo, $timestamp=false)
Create a OldLocalFile from a SHA-1 key Do not call this except from inside a repo class.
loadFromRow( $row, $prefix='img_')
Load file metadata from a DB result row.
getVisibility()
Returns bitfield value.
static newFromTitle( $title, $repo, $time=null)
string $archive_name
Archive name.
exists()
If archive name is an empty string, then file does not "exist".
getCacheFields( $prefix='img_')
Returns the list of object properties that are included as-is in the cache.Stability: stableto overri...
userCan( $field, Authority $performer)
Determine if the current user is allowed to view a particular field of this image file,...
string int $requestedTime
Timestamp.
isDeleted( $field)
loadExtraFromDB()
Load lazy file metadata from the DB.
This interface represents the authority associated the current execution context, such as a web reque...
Definition: Authority.php:37
Interface for objects representing user identity.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42