45 private const MDS_EMPTY =
'empty';
48 private const MDS_LEGACY =
'legacy';
51 private const MDS_PHP =
'php';
54 private const MDS_JSON =
'json';
81 protected $metadataArray = [];
84 protected $extraDataLoaded =
false;
95 protected $metadataBlobs = [];
103 protected $unloadedMetadataBlobs = [];
112 private $description;
135 private $archive_name;
150 private $metadataStorageHelper;
159 public function __construct( $title, $id = 0, $key =
'', $sha1 =
'' ) {
163 $this->group =
'deleted';
169 $this->mime =
"unknown/unknown";
170 $this->media_type =
'';
171 $this->description =
'';
173 $this->timestamp =
null;
175 $this->dataLoaded =
false;
180 $this->title = File::normalizeTitle(
$title,
'exception' );
196 if ( !$id && !$key && !(
$title instanceof
Title ) && !$sha1 ) {
197 throw new BadMethodCallException(
"No specifications provided to ArchivedFile constructor." );
200 $this->repo = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo();
210 if ( $this->dataLoaded ) {
215 if ( $this->
id > 0 ) {
216 $conds[
'fa_id'] = $this->id;
219 $conds[
'fa_storage_group'] = $this->group;
220 $conds[
'fa_storage_key'] = $this->key;
222 if ( $this->title ) {
223 $conds[
'fa_name'] = $this->title->getDBkey();
226 $conds[
'fa_sha1'] = $this->sha1;
229 if ( $conds === [] ) {
230 throw new RuntimeException(
"No specific information for retrieving archived file" );
233 if ( !$this->title || $this->title->getNamespace() ===
NS_FILE ) {
234 $this->dataLoaded =
true;
235 $dbr = $this->repo->getReplicaDB();
236 $queryBuilder = FileSelectQueryBuilder::newForArchivedFile( $dbr );
237 $row = $queryBuilder->where( $conds )
238 ->orderBy(
'fa_timestamp', SelectQueryBuilder::SORT_DESC )
239 ->caller( __METHOD__ )->fetchRow();
248 throw new UnexpectedValueException(
'This title does not correspond to an image page.' );
263 $file->loadFromRow( $row );
286 $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
287 $queryInfo = ( FileSelectQueryBuilder::newForArchivedFile( $dbr ) )->
getQueryInfo();
289 'tables' => $queryInfo[
'tables'],
290 'fields' => $queryInfo[
'fields'],
291 'joins' => $queryInfo[
'join_conds'],
303 $this->
id = intval( $row->fa_id );
304 $this->name = $row->fa_name;
305 $this->archive_name = $row->fa_archive_name;
306 $this->group = $row->fa_storage_group;
307 $this->key = $row->fa_storage_key;
308 $this->size = $row->fa_size;
309 $this->bits = $row->fa_bits;
310 $this->width = $row->fa_width;
311 $this->height = $row->fa_height;
313 $this->repo->getReplicaDB(), $row->fa_metadata );
314 $this->mime =
"$row->fa_major_mime/$row->fa_minor_mime";
315 $this->media_type = $row->fa_media_type;
316 $services = MediaWikiServices::getInstance();
317 $this->description = $services->getCommentStore()
319 ->getCommentLegacy( $this->repo->getReplicaDB(),
'fa_description', $row )->text;
320 $this->user = $services->getUserFactory()
321 ->newFromAnyId( $row->fa_user, $row->fa_user_text, $row->fa_actor );
322 $this->timestamp = $row->fa_timestamp;
323 $this->deleted = $row->fa_deleted;
324 if ( isset( $row->fa_sha1 ) ) {
325 $this->sha1 = $row->fa_sha1;
328 $this->sha1 = LocalRepo::getHashFromKey( $this->key );
330 if ( !$this->title ) {
331 $this->title = Title::makeTitleSafe(
NS_FILE, $row->fa_name );
333 $this->
exists = $row->fa_archive_name !==
'';
342 if ( !$this->title ) {
354 if ( $this->name ===
false ) {
376 return $this->exists;
422 return $this->height;
435 } elseif ( array_keys( $data ) === [
'_error' ] ) {
437 return $data[
'_error'];
451 if ( $this->unloadedMetadataBlobs ) {
453 array_unique( array_merge(
454 array_keys( $this->metadataArray ),
455 array_keys( $this->unloadedMetadataBlobs )
459 return $this->metadataArray;
466 foreach ( $itemNames as $itemName ) {
467 if ( array_key_exists( $itemName, $this->metadataArray ) ) {
468 $result[$itemName] = $this->metadataArray[$itemName];
469 } elseif ( isset( $this->unloadedMetadataBlobs[$itemName] ) ) {
470 $addresses[$itemName] = $this->unloadedMetadataBlobs[$itemName];
475 $resultFromBlob = $this->metadataStorageHelper->getMetadataFromBlobStore( $addresses );
476 foreach ( $addresses as $itemName => $address ) {
477 unset( $this->unloadedMetadataBlobs[$itemName] );
478 $value = $resultFromBlob[$itemName] ??
null;
479 if ( $value !==
null ) {
480 $result[$itemName] = $value;
481 $this->metadataArray[$itemName] = $value;
501 if ( !$this->metadataArray && !$this->metadataBlobs ) {
503 } elseif ( $this->repo->isJsonMetadataEnabled() ) {
504 $s = $this->getJsonMetadata();
506 $s = serialize( $this->getMetadataArray() );
508 if ( !is_string( $s ) ) {
509 throw new RuntimeException(
'Could not serialize image metadata value for DB' );
520 private function getJsonMetadata() {
523 'data' => array_diff_key( $this->metadataArray, $this->metadataBlobs )
527 if ( $this->metadataBlobs ) {
528 $envelope[
'blobs'] = $this->metadataBlobs;
531 [ $s, $blobAddresses ] = $this->metadataStorageHelper->getJsonMetadata( $this, $envelope );
534 $this->metadataBlobs += $blobAddresses;
548 $this->loadMetadataFromString( $db->
decodeBlob( $metadataBlob ) );
559 $this->extraDataLoaded =
true;
560 $this->metadataArray = [];
561 $this->metadataBlobs = [];
562 $this->unloadedMetadataBlobs = [];
563 $metadataString = (string)$metadataString;
564 if ( $metadataString ===
'' ) {
565 $this->metadataSerializationFormat = self::MDS_EMPTY;
568 if ( $metadataString[0] ===
'{' ) {
569 $envelope = $this->metadataStorageHelper->jsonDecode( $metadataString );
572 $this->metadataArray = [
'_error' => $metadataString ];
573 $this->metadataSerializationFormat = self::MDS_LEGACY;
575 $this->metadataSerializationFormat = self::MDS_JSON;
576 if ( isset( $envelope[
'data'] ) ) {
577 $this->metadataArray = $envelope[
'data'];
579 if ( isset( $envelope[
'blobs'] ) ) {
580 $this->metadataBlobs = $this->unloadedMetadataBlobs = $envelope[
'blobs'];
585 $data = @unserialize( $metadataString );
586 if ( !is_array( $data ) ) {
588 $data = [
'_error' => $metadataString ];
589 $this->metadataSerializationFormat = self::MDS_LEGACY;
591 $this->metadataSerializationFormat = self::MDS_PHP;
593 $this->metadataArray = $data;
630 private function getHandler() {
631 if ( !$this->handler ) {
632 $this->handler = MediaHandler::getHandler( $this->getMimeType() );
635 return $this->handler;
645 if ( $this->pageCount ===
null ) {
648 if ( $this->getHandler() && $this->handler->isMultiPage( $this ) ) {
650 $this->pageCount = $this->handler->pageCount( $this );
652 $this->pageCount =
false;
656 return $this->pageCount;
667 return $this->media_type;
706 if ( $audience === self::FOR_PUBLIC && $this->isDeleted( File::DELETED_USER ) ) {
708 } elseif ( $audience === self::FOR_THIS_USER && !$this->userCan( File::DELETED_USER, $performer ) ) {
729 if ( $audience === self::FOR_PUBLIC && $this->isDeleted( File::DELETED_COMMENT ) ) {
731 } elseif ( $audience === self::FOR_THIS_USER && !$this->userCan( File::DELETED_COMMENT, $performer ) ) {
734 return $this->description;
745 return $this->deleted;
757 return ( $this->deleted & $field ) == $field;
771 return RevisionRecord::userCanBitfield(
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Deleted file in the 'filearchive' table.
getTimestamp()
Return upload timestamp.
getSize()
Return the size of the image file, in bytes.
isDeleted( $field)
for file or revision rows
getHeight()
Return the height of the image.
string[] $metadataBlobs
Map of metadata item name to blob address.
loadMetadataFromDbFieldValue(IReadableDatabase $db, $metadataBlob)
Unserialize a metadata blob which came from the database and store it in $this.
array $metadataArray
Unserialized metadata.
string[] $unloadedMetadataBlobs
Map of metadata item name to blob address for items that exist but have not yet been loaded into $thi...
getSha1()
Get the SHA-1 base 36 hash of the file.
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new archivedfile object.
loadFromRow( $row)
Load ArchivedFile object fields from a DB row.
string null $metadataSerializationFormat
One of the MDS_* constants, giving the format of the metadata as stored in the DB,...
getDescription(int $audience=self::FOR_PUBLIC, ?Authority $performer=null)
Return upload description.
getMetadataItems(array $itemNames)
__construct( $title, $id=0, $key='', $sha1='')
load()
Loads a file object from the filearchive table.
pageCount()
Returns the number of pages of a multipage document, or false for documents which aren't multipage do...
getGroup()
Return the FileStore storage group.
static newFromRow( $row)
Loads a file object from the filearchive table.
getTitle()
Return the associated title object.
getWidth()
Return the width of the image.
getStorageKey()
Return the FileStore key (overriding base File class)
getMimeType()
Returns the MIME type of the file.
getKey()
Return the FileStore key.
userCan( $field, Authority $performer)
Determine if the current user is allowed to view a particular field of this FileStore image file,...
getMetadataArray()
Get unserialized handler-specific metadata.
loadMetadataFromString( $metadataString)
Unserialize a metadata string which came from some non-DB source, or is the return value of IReadable...
getName()
Return the file name.
getUploader(int $audience=self::FOR_PUBLIC, ?Authority $performer=null)
getMediaType()
Return the type of the media in the file.
getMetadataForDb(IReadableDatabase $db)
Serialize the metadata array for insertion into img_metadata, oi_metadata or fa_metadata.
getVisibility()
Returns the deletion bitfield.
getMetadata()
Get handler-specific metadata as a serialized string.
bool $extraDataLoaded
Whether or not lazy-loaded data has been loaded from the database.
Local repository that stores files in the local filesystem and registers them in the wiki's own datab...