MediaWiki REL1_40
MediaHandler.php
Go to the documentation of this file.
1<?php
23
38abstract class MediaHandler {
39 public const TRANSFORM_LATER = 1;
40 public const METADATA_GOOD = true;
41 public const METADATA_BAD = false;
42 public const METADATA_COMPATIBLE = 2; // for old but backwards compatible.
46 private const MAX_ERR_LOG_SIZE = 65535;
47
54 public static function getHandler( $type ) {
55 return MediaWikiServices::getInstance()
56 ->getMediaHandlerFactory()->getHandler( $type );
57 }
58
64 abstract public function getParamMap();
65
75 abstract public function validateParam( $name, $value );
76
83 abstract public function makeParamString( $params );
84
91 abstract public function parseParamString( $str );
92
101 abstract public function normaliseParams( $image, &$params );
102
125 public function getImageSize( $image, $path ) {
126 return false;
127 }
128
154 public function getSizeAndMetadata( $state, $path ) {
155 return null;
156 }
157
167 public function getMetadata( $image, $path ) {
168 return '';
169 }
170
180 protected function useLegacyMetadata() {
181 return $this->hasMostDerivedMethod( 'getMetadata' )
182 || $this->hasMostDerivedMethod( 'getImageSize' );
183 }
184
192 protected function hasMostDerivedMethod( $name ) {
193 $rc = new ReflectionClass( $this );
194 $rm = new ReflectionMethod( $this, $name );
195 return $rm->getDeclaringClass()->getName() === $rc->getName();
196 }
197
218 final public function getSizeAndMetadataWithFallback( $file, $path ) {
219 if ( !$this->useLegacyMetadata() ) {
220 if ( $file instanceof MediaHandlerState ) {
221 $state = $file;
222 } else {
223 $state = new TrivialMediaHandlerState;
224 }
225 $info = $this->getSizeAndMetadata( $state, $path );
226 if ( $info === false ) {
227 return false;
228 }
229 if ( $info !== null ) {
230 $info += [ 'width' => 0, 'height' => 0, 'metadata' => [] ];
231 if ( !is_array( $info['metadata'] ) ) {
232 throw new InvalidArgumentException( 'Media handler ' .
233 static::class . ' returned ' . gettype( $info['metadata'] ) .
234 ' for metadata, should be array' );
235 }
236 return $info;
237 }
238 }
239
240 $blob = $this->getMetadata( $file, $path );
241 // @phan-suppress-next-line PhanParamTooMany
242 $size = $this->getImageSize(
243 $file,
244 $path,
245 $blob // Secret TimedMediaHandler parameter
246 );
247 if ( $blob === false && $size === false ) {
248 return false;
249 }
250 if ( $size ) {
251 $info = [
252 'width' => $size[0] ?? 0,
253 'height' => $size[1] ?? 0
254 ];
255 if ( isset( $size['bits'] ) ) {
256 $info['bits'] = $size['bits'];
257 }
258 } else {
259 $info = [ 'width' => 0, 'height' => 0 ];
260 }
261 if ( $blob !== false ) {
262 // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
263 $metadata = @unserialize( $blob );
264 if ( $metadata === false ) {
265 // Unserialize error
266 $metadata = [ '_error' => $blob ];
267 } elseif ( !is_array( $metadata ) ) {
268 $metadata = [];
269 }
270 $info['metadata'] = $metadata;
271 } else {
272 $info['metadata'] = [];
273 }
274 return $info;
275 }
276
294 public static function getMetadataVersion() {
295 $version = [ '2' ]; // core metadata version
296 Hooks::runner()->onGetMetadataVersion( $version );
297
298 return implode( ';', $version );
299 }
300
312 public function convertMetadataVersion( $metadata, $version = 1 ) {
313 return $metadata;
314 }
315
324 public function getMetadataType( $image ) {
325 return false;
326 }
327
346 public function isMetadataValid( $image, $metadata ) {
347 return self::METADATA_GOOD;
348 }
349
375 public function isFileMetadataValid( $image ) {
376 return self::METADATA_GOOD;
377 }
378
413 public function getCommonMetaArray( File $file ) {
414 return false;
415 }
416
432 public function getScriptedTransform( $image, $script, $params ) {
433 return false;
434 }
435
448 final public function getTransform( $image, $dstPath, $dstUrl, $params ) {
449 return $this->doTransform( $image, $dstPath, $dstUrl, $params, self::TRANSFORM_LATER );
450 }
451
466 abstract public function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 );
467
478 public function getThumbType( $ext, $mime, $params = null ) {
479 $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
480 if ( !$ext || $magic->isMatchingExtension( $ext, $mime ) === false ) {
481 // The extension is not valid for this MIME type and we do
482 // recognize the MIME type
483 $knownExt = $magic->getExtensionFromMimeTypeOrNull( $mime );
484 if ( $knownExt !== null ) {
485 return [ $knownExt, $mime ];
486 }
487 }
488
489 // The extension is correct (true) or the MIME type is unknown to
490 // MediaWiki (null)
491 return [ $ext, $mime ];
492 }
493
502 public function canRender( $file ) {
503 return true;
504 }
505
515 public function mustRender( $file ) {
516 return false;
517 }
518
527 public function isMultiPage( $file ) {
528 return false;
529 }
530
539 public function pageCount( File $file ) {
540 return false;
541 }
542
551 public function isVectorized( $file ) {
552 return false;
553 }
554
565 public function isAnimatedImage( $file ) {
566 return false;
567 }
568
578 public function canAnimateThumbnail( $file ) {
579 return true;
580 }
581
588 public function isEnabled() {
589 return true;
590 }
591
609 public function getPageDimensions( File $image, $page ) {
610 return false;
611 }
612
623 public function getPageText( File $image, $page ) {
624 return false;
625 }
626
632 public function getEntireText( File $file ) {
633 $numPages = $file->pageCount();
634 if ( !$numPages ) {
635 // Not a multipage document
636 return $this->getPageText( $file, 1 );
637 }
638 $document = '';
639 for ( $i = 1; $i <= $numPages; $i++ ) {
640 $curPage = $this->getPageText( $file, $i );
641 if ( is_string( $curPage ) ) {
642 $document .= $curPage . "\n";
643 }
644 }
645 if ( $document !== '' ) {
646 return $document;
647 }
648 return false;
649 }
650
681 public function formatMetadata( $image, $context = false ) {
682 return false;
683 }
684
697 protected function formatMetadataHelper( $metadataArray, $context = false ) {
698 $result = [
699 'visible' => [],
700 'collapsed' => []
701 ];
702
703 // Allow this MediaHandler to override formatting on certain values
704 foreach ( $metadataArray as $tag => $vals ) {
705 $v = $this->formatTag( $tag, $vals, $context );
706 if ( $v === false ) {
707 // Use default formatting
708 continue;
709 }
710 if ( $v === null ) {
711 // Remove this tag, don't format it for display
712 unset( $metadataArray[$tag] );
713 } else {
714 // Allow subclass to override default formatting.
715 $metadataArray[$tag] = [ '_formatted' => $v ];
716 if ( isset( $v['_type'] ) ) {
717 $metadataArray[$tag]['_type'] = $v['_type'];
718 unset( $metadataArray[$tag]['_formatted']['_type'] );
719 }
720 }
721 }
722
723 $formatted = FormatMetadata::getFormattedData( $metadataArray, $context );
724 // Sort fields into visible and collapsed
725 $visibleFields = $this->visibleMetadataFields();
726 foreach ( $formatted as $name => $value ) {
727 $tag = strtolower( $name );
728 self::addMeta( $result,
729 in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed',
730 'exif',
731 $tag,
732 $value
733 );
734 }
735
736 return $result;
737 }
738
751 protected function formatTag( string $key, $vals, $context = false ) {
752 return false; // Use default formatting
753 }
754
763 protected function visibleMetadataFields() {
765 }
766
790 protected static function addMeta( &$array, $visibility, $type, $id, $value, $param = false ) {
791 $msg = wfMessage( "$type-$id", $param );
792 if ( $msg->exists() ) {
793 $name = $msg->text();
794 } else {
795 // This is for future compatibility when using instant commons.
796 // So as to not display as ugly a name if a new metadata
797 // property is defined that we don't know about
798 // (not a major issue since such a property would be collapsed
799 // by default).
800 wfDebug( __METHOD__ . ' Unknown metadata name: ' . $id );
801 $name = wfEscapeWikiText( $id );
802 }
803 $array[$visibility][] = [
804 'id' => "$type-$id",
805 'name' => $name,
806 'value' => $value
807 ];
808 }
809
818 public function getShortDesc( $file ) {
820 }
821
830 public function getLongDesc( $file ) {
832 }
833
840 public static function getGeneralShortDesc( $file ) {
841 global $wgLang;
842
843 return htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
844 }
845
852 public static function getGeneralLongDesc( $file ) {
853 return wfMessage( 'file-info' )->sizeParams( $file->getSize() )
854 ->params( '<span class="mime-type">' . $file->getMimeType() . '</span>' )->parse();
855 }
856
865 public static function fitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {
866 $idealWidth = $boxWidth * $maxHeight / $boxHeight;
867 $roundedUp = ceil( $idealWidth );
868 if ( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight ) {
869 return (int)floor( $idealWidth );
870 }
871 return $roundedUp;
872 }
873
882 public function getDimensionsString( $file ) {
883 return '';
884 }
885
898 public function parserTransformHook( $parser, $file ) {
899 }
900
913 public function verifyUpload( $fileName ) {
914 return Status::newGood();
915 }
916
927 public function removeBadFile( $dstPath, $retval = 0 ) {
928 if ( file_exists( $dstPath ) ) {
929 $thumbstat = stat( $dstPath );
930 if ( $thumbstat['size'] == 0 || $retval != 0 ) {
931 $result = unlink( $dstPath );
932
933 if ( $result ) {
934 wfDebugLog( 'thumbnail',
935 sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() succeeded',
936 $thumbstat['size'], $dstPath ) );
937 } else {
938 wfDebugLog( 'thumbnail',
939 sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() failed',
940 $thumbstat['size'], $dstPath ) );
941 }
942
943 return true;
944 }
945 }
946
947 return false;
948 }
949
964 public function filterThumbnailPurgeList( &$files, $options ) {
965 // Do nothing
966 }
967
975 public function canRotate() {
976 return false;
977 }
978
995 public function getRotation( $file ) {
996 return 0;
997 }
998
1010 protected function logErrorForExternalProcess( $retval, $err, $cmd ) {
1011 # Keep error output limited (T59985)
1012 $errMessage = trim( substr( $err, 0, self::MAX_ERR_LOG_SIZE ) );
1013
1014 wfDebugLog( 'thumbnail',
1015 sprintf( 'thumbnail failed on %s: error %d "%s" from "%s"',
1016 wfHostname(), $retval, $errMessage, $cmd ) );
1017 }
1018
1028 public function getAvailableLanguages( File $file ) {
1029 return [];
1030 }
1031
1043 public function getMatchedLanguage( $userPreferredLanguage, array $availableLanguages ) {
1044 return null;
1045 }
1046
1063 return null;
1064 }
1065
1078 public function getLength( $file ) {
1079 return 0.0;
1080 }
1081
1089 public function isExpensiveToThumbnail( $file ) {
1090 return false;
1091 }
1092
1101 public function supportsBucketing() {
1102 return false;
1103 }
1104
1113 public function sanitizeParamsForBucketing( $params ) {
1114 return $params;
1115 }
1116
1143 public function getWarningConfig( $file ) {
1144 return null;
1145 }
1146
1154 public static function getPageRangesByDimensions( $pagesByDimensions ) {
1155 $pageRangesByDimensions = [];
1156
1157 foreach ( $pagesByDimensions as $dimensions => $pageList ) {
1158 $ranges = [];
1159 $firstPage = $pageList[0];
1160 $lastPage = $firstPage - 1;
1161
1162 foreach ( $pageList as $page ) {
1163 if ( $page > $lastPage + 1 ) {
1164 if ( $firstPage !== $lastPage ) {
1165 $ranges[] = "$firstPage-$lastPage";
1166 } else {
1167 $ranges[] = "$firstPage";
1168 }
1169
1170 $firstPage = $page;
1171 }
1172
1173 $lastPage = $page;
1174 }
1175
1176 if ( $firstPage != $lastPage ) {
1177 $ranges[] = "$firstPage-$lastPage";
1178 } else {
1179 $ranges[] = "$firstPage";
1180 }
1181
1182 $pageRangesByDimensions[ $dimensions ] = $ranges;
1183 }
1184
1185 $dimensionsString = [];
1186 foreach ( $pageRangesByDimensions as $dimensions => $pageRanges ) {
1187 $dimensionsString[] = "$dimensions:" . implode( ',', $pageRanges );
1188 }
1189
1190 return implode( '/', $dimensionsString );
1191 }
1192
1201 public function getContentHeaders( $metadata ) {
1202 return [ 'X-Content-Dimensions' => '' ]; // T175689
1203 }
1204
1213 public function useSplitMetadata() {
1214 return false;
1215 }
1216}
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfHostname()
Get host name of the current machine, for use in error reporting.
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
if(!defined( 'MW_NO_SESSION') &&! $wgCommandLineMode $wgLang
Definition Setup.php:527
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition File.php:68
static getVisibleFields()
Get a list of fields that are visible by default.
static getFormattedData( $tags, $context=false)
Numbers given by Exif user agents are often magical, that is they should be replaced by a detailed ex...
Base media handler class.
normaliseParams( $image, &$params)
Changes the parameter array as necessary, ready for transformation.
getRotation( $file)
On supporting image formats, try to read out the low-level orientation of the file and return the ang...
const METADATA_COMPATIBLE
canRender( $file)
True if the handled types can be transformed.
getSizeAndMetadata( $state, $path)
Get image size information and metadata array.
canAnimateThumbnail( $file)
If the material is animated, we can animate the thumbnail.
useLegacyMetadata()
If this returns true, the new method getSizeAndMetadata() will not be called.
verifyUpload( $fileName)
File validation hook called on upload.
visibleMetadataFields()
Get a list of metadata items which should be displayed when the metadata table is collapsed.
static addMeta(&$array, $visibility, $type, $id, $value, $param=false)
This is used to generate an array element for each metadata value That array is then used to generate...
supportsBucketing()
Returns whether or not this handler supports the chained generation of thumbnails according to bucket...
useSplitMetadata()
If this returns true, LocalFile may split metadata up and store its constituent items separately.
parserTransformHook( $parser, $file)
Modify the parser object post-transform.
static getGeneralLongDesc( $file)
Used instead of getLongDesc if there is no handler registered for file.
formatTag(string $key, $vals, $context=false)
Override default formatting for the given metadata field.
canRotate()
True if the handler can rotate the media.
sanitizeParamsForBucketing( $params)
Returns a normalised params array for which parameters have been cleaned up for bucketing purposes.
getDefaultRenderLanguage(File $file)
On file types that support renderings in multiple languages, which language is used by default if uns...
getLength( $file)
If it's an audio file, return the length of the file.
getTransform( $image, $dstPath, $dstUrl, $params)
Get a MediaTransformOutput object representing the transformed output.
getDimensionsString( $file)
Shown in file history box on image description page.
static getHandler( $type)
Get a MediaHandler for a given MIME type from the instance cache.
isFileMetadataValid( $image)
Check if the metadata is valid for this handler.
getCommonMetaArray(File $file)
Get an array of standard (FormatMetadata type) metadata values.
doTransform( $image, $dstPath, $dstUrl, $params, $flags=0)
Get a MediaTransformOutput object representing the transformed output.
getMetadata( $image, $path)
Get handler-specific metadata which will be saved in the img_metadata field.
getPageText(File $image, $page)
Generic getter for text layer.
getSizeAndMetadataWithFallback( $file, $path)
Get the metadata array and the image size, with b/c fallback.
isAnimatedImage( $file)
The material is an image, and is animated.
isVectorized( $file)
The material is vectorized and thus scaling is lossless.
getImageSize( $image, $path)
Get an image size array like that returned by getimagesize(), or false if it can't be determined.
convertMetadataVersion( $metadata, $version=1)
Convert metadata version.
formatMetadata( $image, $context=false)
Get an array structure that looks like this:
getWarningConfig( $file)
Gets configuration for the file warning message.
logErrorForExternalProcess( $retval, $err, $cmd)
Log an error that occurred in an external process.
isEnabled()
False if the handler is disabled for all files.
parseParamString( $str)
Parse a param string made with makeParamString back into an array.
static getGeneralShortDesc( $file)
Used instead of getShortDesc if there is no handler registered for file.
isMultiPage( $file)
True if the type has multi-page capabilities.
getLongDesc( $file)
Long description.
static fitBoxWidth( $boxWidth, $boxHeight, $maxHeight)
Calculate the largest thumbnail width for a given original file size such that the thumbnail's height...
mustRender( $file)
True if handled types cannot be displayed directly in a browser but can be rendered.
getScriptedTransform( $image, $script, $params)
Get a MediaTransformOutput object representing an alternate of the transformed output which will call...
getMetadataType( $image)
Get a string describing the type of metadata, for display purposes.
isExpensiveToThumbnail( $file)
True if creating thumbnails from the file is large or otherwise resource-intensive.
getEntireText(File $file)
Get the text of the entire document.
getAvailableLanguages(File $file)
Get list of languages file can be viewed in.
filterThumbnailPurgeList(&$files, $options)
Remove files from the purge list.
getShortDesc( $file)
Short description.
makeParamString( $params)
Merge a parameter array into a string appropriate for inclusion in filenames.
formatMetadataHelper( $metadataArray, $context=false)
sorts the visible/invisible field.
validateParam( $name, $value)
Validate a thumbnail parameter at parse time.
static getPageRangesByDimensions( $pagesByDimensions)
Converts a dimensions array about a potentially multipage document from an exhaustive list of ordered...
getPageDimensions(File $image, $page)
Get an associative array of page dimensions Currently "width" and "height" are understood,...
getContentHeaders( $metadata)
Get useful response headers for GET/HEAD requests for a file with the given metadata.
const TRANSFORM_LATER
getParamMap()
Get an associative array mapping magic word IDs to parameter names.
const METADATA_GOOD
getThumbType( $ext, $mime, $params=null)
Get the thumbnail extension and MIME type for a given source MIME type.
removeBadFile( $dstPath, $retval=0)
Check for zero-sized thumbnails.
hasMostDerivedMethod( $name)
Check whether a method is implemented in the most derived class.
isMetadataValid( $image, $metadata)
Check if the metadata string is valid for this handler.
getMatchedLanguage( $userPreferredLanguage, array $availableLanguages)
When overridden in a descendant class, returns a language code most suiting.
static getMetadataVersion()
Get metadata version.
pageCount(File $file)
Page count for a multi-page document, false if unsupported or unknown.
Service locator for MediaWiki core services.
Trivial implementation of MediaHandlerState.
An interface to support process-local caching of handler data associated with a given file.
$mime
Definition router.php:60
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition router.php:42
if(!is_readable( $file)) $ext
Definition router.php:48