]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/filerepo/file/ArchivedFile.php
MediaWiki 1.30.2
[autoinstalls/mediawiki.git] / includes / filerepo / file / ArchivedFile.php
1 <?php
2 /**
3  * Deleted file in the 'filearchive' table.
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 FileAbstraction
22  */
23
24 /**
25  * Class representing a row of the 'filearchive' table
26  *
27  * @ingroup FileAbstraction
28  */
29 class ArchivedFile {
30         /** @var int Filearchive row ID */
31         private $id;
32
33         /** @var string File name */
34         private $name;
35
36         /** @var string FileStore storage group */
37         private $group;
38
39         /** @var string FileStore SHA-1 key */
40         private $key;
41
42         /** @var int File size in bytes */
43         private $size;
44
45         /** @var int Size in bytes */
46         private $bits;
47
48         /** @var int Width */
49         private $width;
50
51         /** @var int Height */
52         private $height;
53
54         /** @var string Metadata string */
55         private $metadata;
56
57         /** @var string MIME type */
58         private $mime;
59
60         /** @var string Media type */
61         private $media_type;
62
63         /** @var string Upload description */
64         private $description;
65
66         /** @var int User ID of uploader */
67         private $user;
68
69         /** @var string User name of uploader */
70         private $user_text;
71
72         /** @var string Time of upload */
73         private $timestamp;
74
75         /** @var bool Whether or not all this has been loaded from the database (loadFromXxx) */
76         private $dataLoaded;
77
78         /** @var int Bitfield akin to rev_deleted */
79         private $deleted;
80
81         /** @var string SHA-1 hash of file content */
82         private $sha1;
83
84         /** @var int|false Number of pages of a multipage document, or false for
85          * documents which aren't multipage documents
86          */
87         private $pageCount;
88
89         /** @var string Original base filename */
90         private $archive_name;
91
92         /** @var MediaHandler */
93         protected $handler;
94
95         /** @var Title */
96         protected $title; # image title
97
98         /**
99          * @throws MWException
100          * @param Title $title
101          * @param int $id
102          * @param string $key
103          * @param string $sha1
104          */
105         function __construct( $title, $id = 0, $key = '', $sha1 = '' ) {
106                 $this->id = -1;
107                 $this->title = false;
108                 $this->name = false;
109                 $this->group = 'deleted'; // needed for direct use of constructor
110                 $this->key = '';
111                 $this->size = 0;
112                 $this->bits = 0;
113                 $this->width = 0;
114                 $this->height = 0;
115                 $this->metadata = '';
116                 $this->mime = "unknown/unknown";
117                 $this->media_type = '';
118                 $this->description = '';
119                 $this->user = 0;
120                 $this->user_text = '';
121                 $this->timestamp = null;
122                 $this->deleted = 0;
123                 $this->dataLoaded = false;
124                 $this->exists = false;
125                 $this->sha1 = '';
126
127                 if ( $title instanceof Title ) {
128                         $this->title = File::normalizeTitle( $title, 'exception' );
129                         $this->name = $title->getDBkey();
130                 }
131
132                 if ( $id ) {
133                         $this->id = $id;
134                 }
135
136                 if ( $key ) {
137                         $this->key = $key;
138                 }
139
140                 if ( $sha1 ) {
141                         $this->sha1 = $sha1;
142                 }
143
144                 if ( !$id && !$key && !( $title instanceof Title ) && !$sha1 ) {
145                         throw new MWException( "No specifications provided to ArchivedFile constructor." );
146                 }
147         }
148
149         /**
150          * Loads a file object from the filearchive table
151          * @throws MWException
152          * @return bool|null True on success or null
153          */
154         public function load() {
155                 if ( $this->dataLoaded ) {
156                         return true;
157                 }
158                 $conds = [];
159
160                 if ( $this->id > 0 ) {
161                         $conds['fa_id'] = $this->id;
162                 }
163                 if ( $this->key ) {
164                         $conds['fa_storage_group'] = $this->group;
165                         $conds['fa_storage_key'] = $this->key;
166                 }
167                 if ( $this->title ) {
168                         $conds['fa_name'] = $this->title->getDBkey();
169                 }
170                 if ( $this->sha1 ) {
171                         $conds['fa_sha1'] = $this->sha1;
172                 }
173
174                 if ( !count( $conds ) ) {
175                         throw new MWException( "No specific information for retrieving archived file" );
176                 }
177
178                 if ( !$this->title || $this->title->getNamespace() == NS_FILE ) {
179                         $this->dataLoaded = true; // set it here, to have also true on miss
180                         $dbr = wfGetDB( DB_REPLICA );
181                         $row = $dbr->selectRow(
182                                 'filearchive',
183                                 self::selectFields(),
184                                 $conds,
185                                 __METHOD__,
186                                 [ 'ORDER BY' => 'fa_timestamp DESC' ]
187                         );
188                         if ( !$row ) {
189                                 // this revision does not exist?
190                                 return null;
191                         }
192
193                         // initialize fields for filestore image object
194                         $this->loadFromRow( $row );
195                 } else {
196                         throw new MWException( 'This title does not correspond to an image page.' );
197                 }
198                 $this->exists = true;
199
200                 return true;
201         }
202
203         /**
204          * Loads a file object from the filearchive table
205          *
206          * @param stdClass $row
207          * @return ArchivedFile
208          */
209         public static function newFromRow( $row ) {
210                 $file = new ArchivedFile( Title::makeTitle( NS_FILE, $row->fa_name ) );
211                 $file->loadFromRow( $row );
212
213                 return $file;
214         }
215
216         /**
217          * Fields in the filearchive table
218          * @todo Deprecate this in favor of a method that returns tables and joins
219          *  as well, and use CommentStore::getJoin().
220          * @return array
221          */
222         static function selectFields() {
223                 return [
224                         'fa_id',
225                         'fa_name',
226                         'fa_archive_name',
227                         'fa_storage_key',
228                         'fa_storage_group',
229                         'fa_size',
230                         'fa_bits',
231                         'fa_width',
232                         'fa_height',
233                         'fa_metadata',
234                         'fa_media_type',
235                         'fa_major_mime',
236                         'fa_minor_mime',
237                         'fa_user',
238                         'fa_user_text',
239                         'fa_timestamp',
240                         'fa_deleted',
241                         'fa_deleted_timestamp', /* Used by LocalFileRestoreBatch */
242                         'fa_sha1',
243                 ] + CommentStore::newKey( 'fa_description' )->getFields();
244         }
245
246         /**
247          * Load ArchivedFile object fields from a DB row.
248          *
249          * @param stdClass $row Object database row
250          * @since 1.21
251          */
252         public function loadFromRow( $row ) {
253                 $this->id = intval( $row->fa_id );
254                 $this->name = $row->fa_name;
255                 $this->archive_name = $row->fa_archive_name;
256                 $this->group = $row->fa_storage_group;
257                 $this->key = $row->fa_storage_key;
258                 $this->size = $row->fa_size;
259                 $this->bits = $row->fa_bits;
260                 $this->width = $row->fa_width;
261                 $this->height = $row->fa_height;
262                 $this->metadata = $row->fa_metadata;
263                 $this->mime = "$row->fa_major_mime/$row->fa_minor_mime";
264                 $this->media_type = $row->fa_media_type;
265                 $this->description = CommentStore::newKey( 'fa_description' )
266                         // Legacy because $row probably came from self::selectFields()
267                         ->getCommentLegacy( wfGetDB( DB_REPLICA ), $row )->text;
268                 $this->user = $row->fa_user;
269                 $this->user_text = $row->fa_user_text;
270                 $this->timestamp = $row->fa_timestamp;
271                 $this->deleted = $row->fa_deleted;
272                 if ( isset( $row->fa_sha1 ) ) {
273                         $this->sha1 = $row->fa_sha1;
274                 } else {
275                         // old row, populate from key
276                         $this->sha1 = LocalRepo::getHashFromKey( $this->key );
277                 }
278                 if ( !$this->title ) {
279                         $this->title = Title::makeTitleSafe( NS_FILE, $row->fa_name );
280                 }
281         }
282
283         /**
284          * Return the associated title object
285          *
286          * @return Title
287          */
288         public function getTitle() {
289                 if ( !$this->title ) {
290                         $this->load();
291                 }
292                 return $this->title;
293         }
294
295         /**
296          * Return the file name
297          *
298          * @return string
299          */
300         public function getName() {
301                 if ( $this->name === false ) {
302                         $this->load();
303                 }
304
305                 return $this->name;
306         }
307
308         /**
309          * @return int
310          */
311         public function getID() {
312                 $this->load();
313
314                 return $this->id;
315         }
316
317         /**
318          * @return bool
319          */
320         public function exists() {
321                 $this->load();
322
323                 return $this->exists;
324         }
325
326         /**
327          * Return the FileStore key
328          * @return string
329          */
330         public function getKey() {
331                 $this->load();
332
333                 return $this->key;
334         }
335
336         /**
337          * Return the FileStore key (overriding base File class)
338          * @return string
339          */
340         public function getStorageKey() {
341                 return $this->getKey();
342         }
343
344         /**
345          * Return the FileStore storage group
346          * @return string
347          */
348         public function getGroup() {
349                 return $this->group;
350         }
351
352         /**
353          * Return the width of the image
354          * @return int
355          */
356         public function getWidth() {
357                 $this->load();
358
359                 return $this->width;
360         }
361
362         /**
363          * Return the height of the image
364          * @return int
365          */
366         public function getHeight() {
367                 $this->load();
368
369                 return $this->height;
370         }
371
372         /**
373          * Get handler-specific metadata
374          * @return string
375          */
376         public function getMetadata() {
377                 $this->load();
378
379                 return $this->metadata;
380         }
381
382         /**
383          * Return the size of the image file, in bytes
384          * @return int
385          */
386         public function getSize() {
387                 $this->load();
388
389                 return $this->size;
390         }
391
392         /**
393          * Return the bits of the image file, in bytes
394          * @return int
395          */
396         public function getBits() {
397                 $this->load();
398
399                 return $this->bits;
400         }
401
402         /**
403          * Returns the MIME type of the file.
404          * @return string
405          */
406         public function getMimeType() {
407                 $this->load();
408
409                 return $this->mime;
410         }
411
412         /**
413          * Get a MediaHandler instance for this file
414          * @return MediaHandler
415          */
416         function getHandler() {
417                 if ( !isset( $this->handler ) ) {
418                         $this->handler = MediaHandler::getHandler( $this->getMimeType() );
419                 }
420
421                 return $this->handler;
422         }
423
424         /**
425          * Returns the number of pages of a multipage document, or false for
426          * documents which aren't multipage documents
427          * @return bool|int
428          */
429         function pageCount() {
430                 if ( !isset( $this->pageCount ) ) {
431                         // @FIXME: callers expect File objects
432                         if ( $this->getHandler() && $this->handler->isMultiPage( $this ) ) {
433                                 $this->pageCount = $this->handler->pageCount( $this );
434                         } else {
435                                 $this->pageCount = false;
436                         }
437                 }
438
439                 return $this->pageCount;
440         }
441
442         /**
443          * Return the type of the media in the file.
444          * Use the value returned by this function with the MEDIATYPE_xxx constants.
445          * @return string
446          */
447         public function getMediaType() {
448                 $this->load();
449
450                 return $this->media_type;
451         }
452
453         /**
454          * Return upload timestamp.
455          *
456          * @return string
457          */
458         public function getTimestamp() {
459                 $this->load();
460
461                 return wfTimestamp( TS_MW, $this->timestamp );
462         }
463
464         /**
465          * Get the SHA-1 base 36 hash of the file
466          *
467          * @return string
468          * @since 1.21
469          */
470         function getSha1() {
471                 $this->load();
472
473                 return $this->sha1;
474         }
475
476         /**
477          * Returns ID or name of user who uploaded the file
478          *
479          * @note Prior to MediaWiki 1.23, this method always
480          *   returned the user id, and was inconsistent with
481          *   the rest of the file classes.
482          * @param string $type 'text' or 'id'
483          * @return int|string
484          * @throws MWException
485          */
486         public function getUser( $type = 'text' ) {
487                 $this->load();
488
489                 if ( $type == 'text' ) {
490                         return $this->user_text;
491                 } elseif ( $type == 'id' ) {
492                         return (int)$this->user;
493                 }
494
495                 throw new MWException( "Unknown type '$type'." );
496         }
497
498         /**
499          * Return upload description.
500          *
501          * @return string|int
502          */
503         public function getDescription() {
504                 $this->load();
505                 if ( $this->isDeleted( File::DELETED_COMMENT ) ) {
506                         return 0;
507                 } else {
508                         return $this->description;
509                 }
510         }
511
512         /**
513          * Return the user ID of the uploader.
514          *
515          * @return int
516          */
517         public function getRawUser() {
518                 $this->load();
519
520                 return $this->user;
521         }
522
523         /**
524          * Return the user name of the uploader.
525          *
526          * @return string
527          */
528         public function getRawUserText() {
529                 $this->load();
530
531                 return $this->user_text;
532         }
533
534         /**
535          * Return upload description.
536          *
537          * @return string
538          */
539         public function getRawDescription() {
540                 $this->load();
541
542                 return $this->description;
543         }
544
545         /**
546          * Returns the deletion bitfield
547          * @return int
548          */
549         public function getVisibility() {
550                 $this->load();
551
552                 return $this->deleted;
553         }
554
555         /**
556          * for file or revision rows
557          *
558          * @param int $field One of DELETED_* bitfield constants
559          * @return bool
560          */
561         public function isDeleted( $field ) {
562                 $this->load();
563
564                 return ( $this->deleted & $field ) == $field;
565         }
566
567         /**
568          * Determine if the current user is allowed to view a particular
569          * field of this FileStore image file, if it's marked as deleted.
570          * @param int $field
571          * @param null|User $user User object to check, or null to use $wgUser
572          * @return bool
573          */
574         public function userCan( $field, User $user = null ) {
575                 $this->load();
576
577                 $title = $this->getTitle();
578                 return Revision::userCanBitfield( $this->deleted, $field, $user, $title ?: null );
579         }
580 }