Completed
Branch master (939199)
by
unknown
39:35
created

includes/filerepo/file/ArchivedFile.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 string 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;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type object<Title> of property $title.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
108
		$this->name = false;
0 ignored issues
show
Documentation Bug introduced by
The property $name was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
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
	 * @return array
219
	 */
220
	static function selectFields() {
221
		return [
222
			'fa_id',
223
			'fa_name',
224
			'fa_archive_name',
225
			'fa_storage_key',
226
			'fa_storage_group',
227
			'fa_size',
228
			'fa_bits',
229
			'fa_width',
230
			'fa_height',
231
			'fa_metadata',
232
			'fa_media_type',
233
			'fa_major_mime',
234
			'fa_minor_mime',
235
			'fa_description',
236
			'fa_user',
237
			'fa_user_text',
238
			'fa_timestamp',
239
			'fa_deleted',
240
			'fa_deleted_timestamp', /* Used by LocalFileRestoreBatch */
241
			'fa_sha1',
242
		];
243
	}
244
245
	/**
246
	 * Load ArchivedFile object fields from a DB row.
247
	 *
248
	 * @param stdClass $row Object database row
249
	 * @since 1.21
250
	 */
251
	public function loadFromRow( $row ) {
252
		$this->id = intval( $row->fa_id );
253
		$this->name = $row->fa_name;
254
		$this->archive_name = $row->fa_archive_name;
255
		$this->group = $row->fa_storage_group;
256
		$this->key = $row->fa_storage_key;
257
		$this->size = $row->fa_size;
258
		$this->bits = $row->fa_bits;
259
		$this->width = $row->fa_width;
260
		$this->height = $row->fa_height;
261
		$this->metadata = $row->fa_metadata;
262
		$this->mime = "$row->fa_major_mime/$row->fa_minor_mime";
263
		$this->media_type = $row->fa_media_type;
264
		$this->description = $row->fa_description;
265
		$this->user = $row->fa_user;
266
		$this->user_text = $row->fa_user_text;
267
		$this->timestamp = $row->fa_timestamp;
268
		$this->deleted = $row->fa_deleted;
269
		if ( isset( $row->fa_sha1 ) ) {
270
			$this->sha1 = $row->fa_sha1;
271
		} else {
272
			// old row, populate from key
273
			$this->sha1 = LocalRepo::getHashFromKey( $this->key );
274
		}
275
		if ( !$this->title ) {
276
			$this->title = Title::makeTitleSafe( NS_FILE, $row->fa_name );
277
		}
278
	}
279
280
	/**
281
	 * Return the associated title object
282
	 *
283
	 * @return Title
284
	 */
285
	public function getTitle() {
286
		if ( !$this->title ) {
287
			$this->load();
288
		}
289
		return $this->title;
290
	}
291
292
	/**
293
	 * Return the file name
294
	 *
295
	 * @return string
296
	 */
297
	public function getName() {
298
		if ( $this->name === false ) {
299
			$this->load();
300
		}
301
302
		return $this->name;
303
	}
304
305
	/**
306
	 * @return int
307
	 */
308
	public function getID() {
309
		$this->load();
310
311
		return $this->id;
312
	}
313
314
	/**
315
	 * @return bool
316
	 */
317
	public function exists() {
318
		$this->load();
319
320
		return $this->exists;
321
	}
322
323
	/**
324
	 * Return the FileStore key
325
	 * @return string
326
	 */
327
	public function getKey() {
328
		$this->load();
329
330
		return $this->key;
331
	}
332
333
	/**
334
	 * Return the FileStore key (overriding base File class)
335
	 * @return string
336
	 */
337
	public function getStorageKey() {
338
		return $this->getKey();
339
	}
340
341
	/**
342
	 * Return the FileStore storage group
343
	 * @return string
344
	 */
345
	public function getGroup() {
346
		return $this->group;
347
	}
348
349
	/**
350
	 * Return the width of the image
351
	 * @return int
352
	 */
353
	public function getWidth() {
354
		$this->load();
355
356
		return $this->width;
357
	}
358
359
	/**
360
	 * Return the height of the image
361
	 * @return int
362
	 */
363
	public function getHeight() {
364
		$this->load();
365
366
		return $this->height;
367
	}
368
369
	/**
370
	 * Get handler-specific metadata
371
	 * @return string
372
	 */
373
	public function getMetadata() {
374
		$this->load();
375
376
		return $this->metadata;
377
	}
378
379
	/**
380
	 * Return the size of the image file, in bytes
381
	 * @return int
382
	 */
383
	public function getSize() {
384
		$this->load();
385
386
		return $this->size;
387
	}
388
389
	/**
390
	 * Return the bits of the image file, in bytes
391
	 * @return int
392
	 */
393
	public function getBits() {
394
		$this->load();
395
396
		return $this->bits;
397
	}
398
399
	/**
400
	 * Returns the MIME type of the file.
401
	 * @return string
402
	 */
403
	public function getMimeType() {
404
		$this->load();
405
406
		return $this->mime;
407
	}
408
409
	/**
410
	 * Get a MediaHandler instance for this file
411
	 * @return MediaHandler
412
	 */
413
	function getHandler() {
414
		if ( !isset( $this->handler ) ) {
415
			$this->handler = MediaHandler::getHandler( $this->getMimeType() );
416
		}
417
418
		return $this->handler;
419
	}
420
421
	/**
422
	 * Returns the number of pages of a multipage document, or false for
423
	 * documents which aren't multipage documents
424
	 * @return bool|int
425
	 */
426 View Code Duplication
	function pageCount() {
427
		if ( !isset( $this->pageCount ) ) {
428
			// @FIXME: callers expect File objects
429
			if ( $this->getHandler() && $this->handler->isMultiPage( $this ) ) {
430
				$this->pageCount = $this->handler->pageCount( $this );
431
			} else {
432
				$this->pageCount = false;
433
			}
434
		}
435
436
		return $this->pageCount;
437
	}
438
439
	/**
440
	 * Return the type of the media in the file.
441
	 * Use the value returned by this function with the MEDIATYPE_xxx constants.
442
	 * @return string
443
	 */
444
	public function getMediaType() {
445
		$this->load();
446
447
		return $this->media_type;
448
	}
449
450
	/**
451
	 * Return upload timestamp.
452
	 *
453
	 * @return string
454
	 */
455
	public function getTimestamp() {
456
		$this->load();
457
458
		return wfTimestamp( TS_MW, $this->timestamp );
459
	}
460
461
	/**
462
	 * Get the SHA-1 base 36 hash of the file
463
	 *
464
	 * @return string
465
	 * @since 1.21
466
	 */
467
	function getSha1() {
468
		$this->load();
469
470
		return $this->sha1;
471
	}
472
473
	/**
474
	 * Returns ID or name of user who uploaded the file
475
	 *
476
	 * @note Prior to MediaWiki 1.23, this method always
477
	 *   returned the user id, and was inconsistent with
478
	 *   the rest of the file classes.
479
	 * @param string $type 'text' or 'id'
480
	 * @return int|string
481
	 * @throws MWException
482
	 */
483
	public function getUser( $type = 'text' ) {
484
		$this->load();
485
486
		if ( $type == 'text' ) {
487
			return $this->user_text;
488
		} elseif ( $type == 'id' ) {
489
			return (int)$this->user;
490
		}
491
492
		throw new MWException( "Unknown type '$type'." );
493
	}
494
495
	/**
496
	 * Return the user name of the uploader.
497
	 *
498
	 * @deprecated since 1.23 Use getUser( 'text' ) instead.
499
	 * @return string
500
	 */
501
	public function getUserText() {
502
		wfDeprecated( __METHOD__, '1.23' );
503
		$this->load();
504
		if ( $this->isDeleted( File::DELETED_USER ) ) {
505
			return 0;
506
		} else {
507
			return $this->user_text;
508
		}
509
	}
510
511
	/**
512
	 * Return upload description.
513
	 *
514
	 * @return string
515
	 */
516
	public function getDescription() {
517
		$this->load();
518
		if ( $this->isDeleted( File::DELETED_COMMENT ) ) {
519
			return 0;
520
		} else {
521
			return $this->description;
522
		}
523
	}
524
525
	/**
526
	 * Return the user ID of the uploader.
527
	 *
528
	 * @return int
529
	 */
530
	public function getRawUser() {
531
		$this->load();
532
533
		return $this->user;
534
	}
535
536
	/**
537
	 * Return the user name of the uploader.
538
	 *
539
	 * @return string
540
	 */
541
	public function getRawUserText() {
542
		$this->load();
543
544
		return $this->user_text;
545
	}
546
547
	/**
548
	 * Return upload description.
549
	 *
550
	 * @return string
551
	 */
552
	public function getRawDescription() {
553
		$this->load();
554
555
		return $this->description;
556
	}
557
558
	/**
559
	 * Returns the deletion bitfield
560
	 * @return int
561
	 */
562
	public function getVisibility() {
563
		$this->load();
564
565
		return $this->deleted;
566
	}
567
568
	/**
569
	 * for file or revision rows
570
	 *
571
	 * @param int $field One of DELETED_* bitfield constants
572
	 * @return bool
573
	 */
574
	public function isDeleted( $field ) {
575
		$this->load();
576
577
		return ( $this->deleted & $field ) == $field;
578
	}
579
580
	/**
581
	 * Determine if the current user is allowed to view a particular
582
	 * field of this FileStore image file, if it's marked as deleted.
583
	 * @param int $field
584
	 * @param null|User $user User object to check, or null to use $wgUser
585
	 * @return bool
586
	 */
587
	public function userCan( $field, User $user = null ) {
588
		$this->load();
589
590
		$title = $this->getTitle();
591
		return Revision::userCanBitfield( $this->deleted, $field, $user, $title ?: null );
592
	}
593
}
594