Issues (4122)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/media/MediaHandler.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
 * Media-handling base classes and generic functionality.
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 Media
22
 */
23
use MediaWiki\MediaWikiServices;
24
25
/**
26
 * Base media handler class
27
 *
28
 * @ingroup Media
29
 */
30
abstract class MediaHandler {
31
	const TRANSFORM_LATER = 1;
32
	const METADATA_GOOD = true;
33
	const METADATA_BAD = false;
34
	const METADATA_COMPATIBLE = 2; // for old but backwards compatible.
35
	/**
36
	 * Max length of error logged by logErrorForExternalProcess()
37
	 */
38
	const MAX_ERR_LOG_SIZE = 65535;
39
40
	/**
41
	 * Get a MediaHandler for a given MIME type from the instance cache
42
	 *
43
	 * @param string $type
44
	 * @return MediaHandler|bool
45
	 */
46
	static function getHandler( $type ) {
47
		return MediaWikiServices::getInstance()
48
			->getMediaHandlerFactory()->getHandler( $type );
49
	}
50
51
	/**
52
	 * Get an associative array mapping magic word IDs to parameter names.
53
	 * Will be used by the parser to identify parameters.
54
	 */
55
	abstract public function getParamMap();
56
57
	/**
58
	 * Validate a thumbnail parameter at parse time.
59
	 * Return true to accept the parameter, and false to reject it.
60
	 * If you return false, the parser will do something quiet and forgiving.
61
	 *
62
	 * @param string $name
63
	 * @param mixed $value
64
	 */
65
	abstract public function validateParam( $name, $value );
66
67
	/**
68
	 * Merge a parameter array into a string appropriate for inclusion in filenames
69
	 *
70
	 * @param array $params Array of parameters that have been through normaliseParams.
71
	 * @return string
72
	 */
73
	abstract public function makeParamString( $params );
74
75
	/**
76
	 * Parse a param string made with makeParamString back into an array
77
	 *
78
	 * @param string $str The parameter string without file name (e.g. 122px)
79
	 * @return array|bool Array of parameters or false on failure.
80
	 */
81
	abstract public function parseParamString( $str );
82
83
	/**
84
	 * Changes the parameter array as necessary, ready for transformation.
85
	 * Should be idempotent.
86
	 * Returns false if the parameters are unacceptable and the transform should fail
87
	 * @param File $image
88
	 * @param array $params
89
	 */
90
	abstract function normaliseParams( $image, &$params );
91
92
	/**
93
	 * Get an image size array like that returned by getimagesize(), or false if it
94
	 * can't be determined.
95
	 *
96
	 * This function is used for determining the width, height and bitdepth directly
97
	 * from an image. The results are stored in the database in the img_width,
98
	 * img_height, img_bits fields.
99
	 *
100
	 * @note If this is a multipage file, return the width and height of the
101
	 *  first page.
102
	 *
103
	 * @param File|FSFile $image The image object, or false if there isn't one.
104
	 *   Warning, FSFile::getPropsFromPath might pass an FSFile instead of File (!)
105
	 * @param string $path The filename
106
	 * @return array|bool Follow the format of PHP getimagesize() internal function.
107
	 *   See https://secure.php.net/getimagesize. MediaWiki will only ever use the
108
	 *   first two array keys (the width and height), and the 'bits' associative
109
	 *   key. All other array keys are ignored. Returning a 'bits' key is optional
110
	 *   as not all formats have a notion of "bitdepth". Returns false on failure.
111
	 */
112
	abstract function getImageSize( $image, $path );
113
114
	/**
115
	 * Get handler-specific metadata which will be saved in the img_metadata field.
116
	 *
117
	 * @param File|FSFile $image The image object, or false if there isn't one.
118
	 *   Warning, FSFile::getPropsFromPath might pass an FSFile instead of File (!)
119
	 * @param string $path The filename
120
	 * @return string A string of metadata in php serialized form (Run through serialize())
121
	 */
122
	function getMetadata( $image, $path ) {
123
		return '';
124
	}
125
126
	/**
127
	 * Get metadata version.
128
	 *
129
	 * This is not used for validating metadata, this is used for the api when returning
130
	 * metadata, since api content formats should stay the same over time, and so things
131
	 * using ForeignApiRepo can keep backwards compatibility
132
	 *
133
	 * All core media handlers share a common version number, and extensions can
134
	 * use the GetMetadataVersion hook to append to the array (they should append a unique
135
	 * string so not to get confusing). If there was a media handler named 'foo' with metadata
136
	 * version 3 it might add to the end of the array the element 'foo=3'. if the core metadata
137
	 * version is 2, the end version string would look like '2;foo=3'.
138
	 *
139
	 * @return string Version string
140
	 */
141
	static function getMetadataVersion() {
142
		$version = [ '2' ]; // core metadata version
143
		Hooks::run( 'GetMetadataVersion', [ &$version ] );
144
145
		return implode( ';', $version );
146
	}
147
148
	/**
149
	 * Convert metadata version.
150
	 *
151
	 * By default just returns $metadata, but can be used to allow
152
	 * media handlers to convert between metadata versions.
153
	 *
154
	 * @param string|array $metadata Metadata array (serialized if string)
155
	 * @param int $version Target version
156
	 * @return array Serialized metadata in specified version, or $metadata on fail.
157
	 */
158
	function convertMetadataVersion( $metadata, $version = 1 ) {
159
		if ( !is_array( $metadata ) ) {
160
161
			// unserialize to keep return parameter consistent.
162
			MediaWiki\suppressWarnings();
163
			$ret = unserialize( $metadata );
164
			MediaWiki\restoreWarnings();
165
166
			return $ret;
167
		}
168
169
		return $metadata;
170
	}
171
172
	/**
173
	 * Get a string describing the type of metadata, for display purposes.
174
	 *
175
	 * @note This method is currently unused.
176
	 * @param File $image
177
	 * @return string
178
	 */
179
	function getMetadataType( $image ) {
180
		return false;
181
	}
182
183
	/**
184
	 * Check if the metadata string is valid for this handler.
185
	 * If it returns MediaHandler::METADATA_BAD (or false), Image
186
	 * will reload the metadata from the file and update the database.
187
	 * MediaHandler::METADATA_GOOD for if the metadata is a-ok,
188
	 * MediaHandler::METADATA_COMPATIBLE if metadata is old but backwards
189
	 * compatible (which may or may not trigger a metadata reload).
190
	 *
191
	 * @note Returning self::METADATA_BAD will trigger a metadata reload from
192
	 *  file on page view. Always returning this from a broken file, or suddenly
193
	 *  triggering as bad metadata for a large number of files can cause
194
	 *  performance problems.
195
	 * @param File $image
196
	 * @param string $metadata The metadata in serialized form
197
	 * @return bool
198
	 */
199
	function isMetadataValid( $image, $metadata ) {
200
		return self::METADATA_GOOD;
201
	}
202
203
	/**
204
	 * Get an array of standard (FormatMetadata type) metadata values.
205
	 *
206
	 * The returned data is largely the same as that from getMetadata(),
207
	 * but formatted in a standard, stable, handler-independent way.
208
	 * The idea being that some values like ImageDescription or Artist
209
	 * are universal and should be retrievable in a handler generic way.
210
	 *
211
	 * The specific properties are the type of properties that can be
212
	 * handled by the FormatMetadata class. These values are exposed to the
213
	 * user via the filemetadata parser function.
214
	 *
215
	 * Details of the response format of this function can be found at
216
	 * https://www.mediawiki.org/wiki/Manual:File_metadata_handling
217
	 * tl/dr: the response is an associative array of
218
	 * properties keyed by name, but the value can be complex. You probably
219
	 * want to call one of the FormatMetadata::flatten* functions on the
220
	 * property values before using them, or call
221
	 * FormatMetadata::getFormattedData() on the full response array, which
222
	 * transforms all values into prettified, human-readable text.
223
	 *
224
	 * Subclasses overriding this function must return a value which is a
225
	 * valid API response fragment (all associative array keys are valid
226
	 * XML tagnames).
227
	 *
228
	 * Note, if the file simply has no metadata, but the handler supports
229
	 * this interface, it should return an empty array, not false.
230
	 *
231
	 * @param File $file
232
	 * @return array|bool False if interface not supported
233
	 * @since 1.23
234
	 */
235
	public function getCommonMetaArray( File $file ) {
236
		return false;
237
	}
238
239
	/**
240
	 * Get a MediaTransformOutput object representing an alternate of the transformed
241
	 * output which will call an intermediary thumbnail assist script.
242
	 *
243
	 * Used when the repository has a thumbnailScriptUrl option configured.
244
	 *
245
	 * Return false to fall back to the regular getTransform().
246
	 * @param File $image
247
	 * @param string $script
248
	 * @param array $params
249
	 * @return bool|ThumbnailImage
250
	 */
251
	function getScriptedTransform( $image, $script, $params ) {
252
		return false;
253
	}
254
255
	/**
256
	 * Get a MediaTransformOutput object representing the transformed output. Does not
257
	 * actually do the transform.
258
	 *
259
	 * @param File $image The image object
260
	 * @param string $dstPath Filesystem destination path
261
	 * @param string $dstUrl Destination URL to use in output HTML
262
	 * @param array $params Arbitrary set of parameters validated by $this->validateParam()
263
	 * @return MediaTransformOutput
264
	 */
265
	final function getTransform( $image, $dstPath, $dstUrl, $params ) {
266
		return $this->doTransform( $image, $dstPath, $dstUrl, $params, self::TRANSFORM_LATER );
267
	}
268
269
	/**
270
	 * Get a MediaTransformOutput object representing the transformed output. Does the
271
	 * transform unless $flags contains self::TRANSFORM_LATER.
272
	 *
273
	 * @param File $image The image object
274
	 * @param string $dstPath Filesystem destination path
275
	 * @param string $dstUrl Destination URL to use in output HTML
276
	 * @param array $params Arbitrary set of parameters validated by $this->validateParam()
277
	 *   Note: These parameters have *not* gone through $this->normaliseParams()
278
	 * @param int $flags A bitfield, may contain self::TRANSFORM_LATER
279
	 * @return MediaTransformOutput
280
	 */
281
	abstract function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 );
282
283
	/**
284
	 * Get the thumbnail extension and MIME type for a given source MIME type
285
	 *
286
	 * @param string $ext Extension of original file
287
	 * @param string $mime MIME type of original file
288
	 * @param array $params Handler specific rendering parameters
289
	 * @return array Thumbnail extension and MIME type
290
	 */
291
	function getThumbType( $ext, $mime, $params = null ) {
292
		$magic = MimeMagic::singleton();
293
		if ( !$ext || $magic->isMatchingExtension( $ext, $mime ) === false ) {
294
			// The extension is not valid for this MIME type and we do
295
			// recognize the MIME type
296
			$extensions = $magic->getExtensionsForType( $mime );
297
			if ( $extensions ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extensions of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
298
				return [ strtok( $extensions, ' ' ), $mime ];
299
			}
300
		}
301
302
		// The extension is correct (true) or the MIME type is unknown to
303
		// MediaWiki (null)
304
		return [ $ext, $mime ];
305
	}
306
307
	/**
308
	 * Get useful response headers for GET/HEAD requests for a file with the given metadata
309
	 *
310
	 * @param mixed $metadata Result of the getMetadata() function of this handler for a file
311
	 * @return array
312
	 */
313
	public function getStreamHeaders( $metadata ) {
314
		return [];
315
	}
316
317
	/**
318
	 * True if the handled types can be transformed
319
	 *
320
	 * @param File $file
321
	 * @return bool
322
	 */
323
	public function canRender( $file ) {
324
		return true;
325
	}
326
327
	/**
328
	 * True if handled types cannot be displayed directly in a browser
329
	 * but can be rendered
330
	 *
331
	 * @param File $file
332
	 * @return bool
333
	 */
334
	public function mustRender( $file ) {
335
		return false;
336
	}
337
338
	/**
339
	 * True if the type has multi-page capabilities
340
	 *
341
	 * @param File $file
342
	 * @return bool
343
	 */
344
	public function isMultiPage( $file ) {
345
		return false;
346
	}
347
348
	/**
349
	 * Page count for a multi-page document, false if unsupported or unknown
350
	 *
351
	 * @param File $file
352
	 * @return bool
353
	 */
354
	function pageCount( File $file ) {
355
		return false;
356
	}
357
358
	/**
359
	 * The material is vectorized and thus scaling is lossless
360
	 *
361
	 * @param File $file
362
	 * @return bool
363
	 */
364
	function isVectorized( $file ) {
365
		return false;
366
	}
367
368
	/**
369
	 * The material is an image, and is animated.
370
	 * In particular, video material need not return true.
371
	 * @note Before 1.20, this was a method of ImageHandler only
372
	 *
373
	 * @param File $file
374
	 * @return bool
375
	 */
376
	function isAnimatedImage( $file ) {
377
		return false;
378
	}
379
380
	/**
381
	 * If the material is animated, we can animate the thumbnail
382
	 * @since 1.20
383
	 *
384
	 * @param File $file
385
	 * @return bool If material is not animated, handler may return any value.
386
	 */
387
	function canAnimateThumbnail( $file ) {
388
		return true;
389
	}
390
391
	/**
392
	 * False if the handler is disabled for all files
393
	 * @return bool
394
	 */
395
	function isEnabled() {
396
		return true;
397
	}
398
399
	/**
400
	 * Get an associative array of page dimensions
401
	 * Currently "width" and "height" are understood, but this might be
402
	 * expanded in the future.
403
	 * Returns false if unknown.
404
	 *
405
	 * It is expected that handlers for paged media (e.g. DjVuHandler)
406
	 * will override this method so that it gives the correct results
407
	 * for each specific page of the file, using the $page argument.
408
	 *
409
	 * @note For non-paged media, use getImageSize.
410
	 *
411
	 * @param File $image
412
	 * @param int $page What page to get dimensions of
413
	 * @return array|bool
414
	 */
415
	function getPageDimensions( File $image, $page ) {
416
		$gis = $this->getImageSize( $image, $image->getLocalRefPath() );
0 ignored issues
show
It seems like $image->getLocalRefPath() targeting File::getLocalRefPath() can also be of type boolean; however, MediaHandler::getImageSize() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
417
		if ( $gis ) {
418
			return [
419
				'width' => $gis[0],
420
				'height' => $gis[1]
421
			];
422
		} else {
423
			return false;
424
		}
425
	}
426
427
	/**
428
	 * Generic getter for text layer.
429
	 * Currently overloaded by PDF and DjVu handlers
430
	 * @param File $image
431
	 * @param int $page Page number to get information for
432
	 * @return bool|string Page text or false when no text found or if
433
	 *   unsupported.
434
	 */
435
	function getPageText( File $image, $page ) {
436
		return false;
437
	}
438
439
	/**
440
	 * Get the text of the entire document.
441
	 * @param File $file
442
	 * @return bool|string The text of the document or false if unsupported.
443
	 */
444
	public function getEntireText( File $file ) {
445
		$numPages = $file->pageCount();
446
		if ( !$numPages ) {
447
			// Not a multipage document
448
			return $this->getPageText( $file, 1 );
449
		}
450
		$document = '';
451
		for ( $i = 1; $i <= $numPages; $i++ ) {
452
			$curPage = $this->getPageText( $file, $i );
453
			if ( is_string( $curPage ) ) {
454
				$document .= $curPage . "\n";
455
			}
456
		}
457
		if ( $document !== '' ) {
458
			return $document;
459
		}
460
		return false;
461
	}
462
463
	/**
464
	 * Get an array structure that looks like this:
465
	 *
466
	 * [
467
	 *    'visible' => [
468
	 *       'Human-readable name' => 'Human readable value',
469
	 *       ...
470
	 *    ],
471
	 *    'collapsed' => [
472
	 *       'Human-readable name' => 'Human readable value',
473
	 *       ...
474
	 *    ]
475
	 * ]
476
	 * The UI will format this into a table where the visible fields are always
477
	 * visible, and the collapsed fields are optionally visible.
478
	 *
479
	 * The function should return false if there is no metadata to display.
480
	 */
481
482
	/**
483
	 * @todo FIXME: This interface is not very flexible. The media handler
484
	 * should generate HTML instead. It can do all the formatting according
485
	 * to some standard. That makes it possible to do things like visual
486
	 * indication of grouped and chained streams in ogg container files.
487
	 * @param File $image
488
	 * @param bool|IContextSource $context Context to use (optional)
489
	 * @return array|bool
490
	 */
491
	function formatMetadata( $image, $context = false ) {
492
		return false;
493
	}
494
495
	/** sorts the visible/invisible field.
496
	 * Split off from ImageHandler::formatMetadata, as used by more than
497
	 * one type of handler.
498
	 *
499
	 * This is used by the media handlers that use the FormatMetadata class
500
	 *
501
	 * @param array $metadataArray Metadata array
502
	 * @param bool|IContextSource $context Context to use (optional)
503
	 * @return array Array for use displaying metadata.
504
	 */
505
	function formatMetadataHelper( $metadataArray, $context = false ) {
506
		$result = [
507
			'visible' => [],
508
			'collapsed' => []
509
		];
510
511
		$formatted = FormatMetadata::getFormattedData( $metadataArray, $context );
512
		// Sort fields into visible and collapsed
513
		$visibleFields = $this->visibleMetadataFields();
514
		foreach ( $formatted as $name => $value ) {
515
			$tag = strtolower( $name );
516
			self::addMeta( $result,
517
				in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed',
518
				'exif',
519
				$tag,
520
				$value
521
			);
522
		}
523
524
		return $result;
525
	}
526
527
	/**
528
	 * Get a list of metadata items which should be displayed when
529
	 * the metadata table is collapsed.
530
	 *
531
	 * @return array Array of strings
532
	 */
533
	protected function visibleMetadataFields() {
534
		return FormatMetadata::getVisibleFields();
535
	}
536
537
	/**
538
	 * This is used to generate an array element for each metadata value
539
	 * That array is then used to generate the table of metadata values
540
	 * on the image page
541
	 *
542
	 * @param array &$array An array containing elements for each type of visibility
543
	 *   and each of those elements being an array of metadata items. This function adds
544
	 *   a value to that array.
545
	 * @param string $visibility ('visible' or 'collapsed') if this value is hidden
546
	 *   by default.
547
	 * @param string $type Type of metadata tag (currently always 'exif')
548
	 * @param string $id The name of the metadata tag (like 'artist' for example).
549
	 *   its name in the table displayed is the message "$type-$id" (Ex exif-artist ).
550
	 * @param string $value Thingy goes into a wikitext table; it used to be escaped but
551
	 *   that was incompatible with previous practise of customized display
552
	 *   with wikitext formatting via messages such as 'exif-model-value'.
553
	 *   So the escaping is taken back out, but generally this seems a confusing
554
	 *   interface.
555
	 * @param bool|string $param Value to pass to the message for the name of the field
556
	 *   as $1. Currently this parameter doesn't seem to ever be used.
557
	 *
558
	 * Note, everything here is passed through the parser later on (!)
559
	 */
560
	protected static function addMeta( &$array, $visibility, $type, $id, $value, $param = false ) {
561
		$msg = wfMessage( "$type-$id", $param );
562
		if ( $msg->exists() ) {
563
			$name = $msg->text();
564
		} else {
565
			// This is for future compatibility when using instant commons.
566
			// So as to not display as ugly a name if a new metadata
567
			// property is defined that we don't know about
568
			// (not a major issue since such a property would be collapsed
569
			// by default).
570
			wfDebug( __METHOD__ . ' Unknown metadata name: ' . $id . "\n" );
571
			$name = wfEscapeWikiText( $id );
572
		}
573
		$array[$visibility][] = [
574
			'id' => "$type-$id",
575
			'name' => $name,
576
			'value' => $value
577
		];
578
	}
579
580
	/**
581
	 * Short description. Shown on Special:Search results.
582
	 *
583
	 * @param File $file
584
	 * @return string
585
	 */
586
	function getShortDesc( $file ) {
587
		return self::getGeneralShortDesc( $file );
588
	}
589
590
	/**
591
	 * Long description. Shown under image on image description page surounded by ().
592
	 *
593
	 * @param File $file
594
	 * @return string
595
	 */
596
	function getLongDesc( $file ) {
597
		return self::getGeneralLongDesc( $file );
598
	}
599
600
	/**
601
	 * Used instead of getShortDesc if there is no handler registered for file.
602
	 *
603
	 * @param File $file
604
	 * @return string
605
	 */
606
	static function getGeneralShortDesc( $file ) {
607
		global $wgLang;
608
609
		return htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
610
	}
611
612
	/**
613
	 * Used instead of getLongDesc if there is no handler registered for file.
614
	 *
615
	 * @param File $file
616
	 * @return string
617
	 */
618
	static function getGeneralLongDesc( $file ) {
619
		return wfMessage( 'file-info' )->sizeParams( $file->getSize() )
620
			->params( '<span class="mime-type">' . $file->getMimeType() . '</span>' )->parse();
621
	}
622
623
	/**
624
	 * Calculate the largest thumbnail width for a given original file size
625
	 * such that the thumbnail's height is at most $maxHeight.
626
	 * @param int $boxWidth Width of the thumbnail box.
627
	 * @param int $boxHeight Height of the thumbnail box.
628
	 * @param int $maxHeight Maximum height expected for the thumbnail.
629
	 * @return int
630
	 */
631
	public static function fitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {
632
		$idealWidth = $boxWidth * $maxHeight / $boxHeight;
633
		$roundedUp = ceil( $idealWidth );
634
		if ( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight ) {
635
			return floor( $idealWidth );
636
		} else {
637
			return $roundedUp;
638
		}
639
	}
640
641
	/**
642
	 * Shown in file history box on image description page.
643
	 *
644
	 * @param File $file
645
	 * @return string Dimensions
646
	 */
647
	function getDimensionsString( $file ) {
648
		return '';
649
	}
650
651
	/**
652
	 * Modify the parser object post-transform.
653
	 *
654
	 * This is often used to do $parser->addOutputHook(),
655
	 * in order to add some javascript to render a viewer.
656
	 * See TimedMediaHandler or OggHandler for an example.
657
	 *
658
	 * @param Parser $parser
659
	 * @param File $file
660
	 */
661
	function parserTransformHook( $parser, $file ) {
662
	}
663
664
	/**
665
	 * File validation hook called on upload.
666
	 *
667
	 * If the file at the given local path is not valid, or its MIME type does not
668
	 * match the handler class, a Status object should be returned containing
669
	 * relevant errors.
670
	 *
671
	 * @param string $fileName The local path to the file.
672
	 * @return Status
673
	 */
674
	function verifyUpload( $fileName ) {
675
		return Status::newGood();
676
	}
677
678
	/**
679
	 * Check for zero-sized thumbnails. These can be generated when
680
	 * no disk space is available or some other error occurs
681
	 *
682
	 * @param string $dstPath The location of the suspect file
683
	 * @param int $retval Return value of some shell process, file will be deleted if this is non-zero
684
	 * @return bool True if removed, false otherwise
685
	 */
686
	function removeBadFile( $dstPath, $retval = 0 ) {
687
		if ( file_exists( $dstPath ) ) {
688
			$thumbstat = stat( $dstPath );
689
			if ( $thumbstat['size'] == 0 || $retval != 0 ) {
690
				$result = unlink( $dstPath );
691
692
				if ( $result ) {
693
					wfDebugLog( 'thumbnail',
694
						sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() succeeded',
695
							$thumbstat['size'], $dstPath ) );
696
				} else {
697
					wfDebugLog( 'thumbnail',
698
						sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() failed',
699
							$thumbstat['size'], $dstPath ) );
700
				}
701
702
				return true;
703
			}
704
		}
705
706
		return false;
707
	}
708
709
	/**
710
	 * Remove files from the purge list.
711
	 *
712
	 * This is used by some video handlers to prevent ?action=purge
713
	 * from removing a transcoded video, which is expensive to
714
	 * regenerate.
715
	 *
716
	 * @see LocalFile::purgeThumbnails
717
	 *
718
	 * @param array $files
719
	 * @param array $options Purge options. Currently will always be
720
	 *  an array with a single key 'forThumbRefresh' set to true.
721
	 */
722
	public function filterThumbnailPurgeList( &$files, $options ) {
723
		// Do nothing
724
	}
725
726
	/**
727
	 * True if the handler can rotate the media
728
	 * @since 1.24 non-static. From 1.21-1.23 was static
729
	 * @return bool
730
	 */
731
	public function canRotate() {
732
		return false;
733
	}
734
735
	/**
736
	 * On supporting image formats, try to read out the low-level orientation
737
	 * of the file and return the angle that the file needs to be rotated to
738
	 * be viewed.
739
	 *
740
	 * This information is only useful when manipulating the original file;
741
	 * the width and height we normally work with is logical, and will match
742
	 * any produced output views.
743
	 *
744
	 * For files we don't know, we return 0.
745
	 *
746
	 * @param File $file
747
	 * @return int 0, 90, 180 or 270
748
	 */
749
	public function getRotation( $file ) {
750
		return 0;
751
	}
752
753
	/**
754
	 * Log an error that occurred in an external process
755
	 *
756
	 * Moved from BitmapHandler to MediaHandler with MediaWiki 1.23
757
	 *
758
	 * @since 1.23
759
	 * @param int $retval
760
	 * @param string $err Error reported by command. Anything longer than
761
	 * MediaHandler::MAX_ERR_LOG_SIZE is stripped off.
762
	 * @param string $cmd
763
	 */
764
	protected function logErrorForExternalProcess( $retval, $err, $cmd ) {
765
		# Keep error output limited (bug 57985)
766
		$errMessage = trim( substr( $err, 0, self::MAX_ERR_LOG_SIZE ) );
767
768
		wfDebugLog( 'thumbnail',
769
			sprintf( 'thumbnail failed on %s: error %d "%s" from "%s"',
770
					wfHostname(), $retval, $errMessage, $cmd ) );
771
	}
772
773
	/**
774
	 * Get list of languages file can be viewed in.
775
	 *
776
	 * @param File $file
777
	 * @return string[] Array of language codes, or empty array if unsupported.
778
	 * @since 1.23
779
	 */
780
	public function getAvailableLanguages( File $file ) {
781
		return [];
782
	}
783
784
	/**
785
	 * On file types that support renderings in multiple languages,
786
	 * which language is used by default if unspecified.
787
	 *
788
	 * If getAvailableLanguages returns a non-empty array, this must return
789
	 * a valid language code. Otherwise can return null if files of this
790
	 * type do not support alternative language renderings.
791
	 *
792
	 * @param File $file
793
	 * @return string|null Language code or null if multi-language not supported for filetype.
794
	 * @since 1.23
795
	 */
796
	public function getDefaultRenderLanguage( File $file ) {
797
		return null;
798
	}
799
800
	/**
801
	 * If its an audio file, return the length of the file. Otherwise 0.
802
	 *
803
	 * File::getLength() existed for a long time, but was calling a method
804
	 * that only existed in some subclasses of this class (The TMH ones).
805
	 *
806
	 * @param File $file
807
	 * @return float Length in seconds
808
	 * @since 1.23
809
	 */
810
	public function getLength( $file ) {
811
		return 0.0;
812
	}
813
814
	/**
815
	 * True if creating thumbnails from the file is large or otherwise resource-intensive.
816
	 * @param File $file
817
	 * @return bool
818
	 */
819
	public function isExpensiveToThumbnail( $file ) {
820
		return false;
821
	}
822
823
	/**
824
	 * Returns whether or not this handler supports the chained generation of thumbnails according
825
	 * to buckets
826
	 * @return bool
827
	 * @since 1.24
828
	 */
829
	public function supportsBucketing() {
830
		return false;
831
	}
832
833
	/**
834
	 * Returns a normalised params array for which parameters have been cleaned up for bucketing
835
	 * purposes
836
	 * @param array $params
837
	 * @return array
838
	 */
839
	public function sanitizeParamsForBucketing( $params ) {
840
		return $params;
841
	}
842
843
	/**
844
	 * Gets configuration for the file warning message. Return value of
845
	 * the following structure:
846
	 *   [
847
	 *     // Required, module with messages loaded for the client
848
	 *     'module' => 'example.filewarning.messages',
849
	 *     // Required, array of names of messages
850
	 *     'messages' => [
851
	 *       // Required, main warning message
852
	 *       'main' => 'example-filewarning-main',
853
	 *       // Optional, header for warning dialog
854
	 *       'header' => 'example-filewarning-header',
855
	 *       // Optional, footer for warning dialog
856
	 *       'footer' => 'example-filewarning-footer',
857
	 *       // Optional, text for more-information link (see below)
858
	 *       'info' => 'example-filewarning-info',
859
	 *     ],
860
	 *     // Optional, link for more information
861
	 *     'link' => 'http://example.com',
862
	 *   ]
863
	 *
864
	 * Returns null if no warning is necessary.
865
	 * @param File $file
866
	 * @return array|null
867
	 */
868
	public function getWarningConfig( $file ) {
869
		return null;
870
	}
871
}
872