MediaWiki 1.41.2
MediaHandler.php
Go to the documentation of this file.
1<?php
25
40abstract class MediaHandler {
41 public const TRANSFORM_LATER = 1;
42 public const METADATA_GOOD = true;
43 public const METADATA_BAD = false;
44 public const METADATA_COMPATIBLE = 2; // for old but backwards compatible.
48 private const MAX_ERR_LOG_SIZE = 65535;
49
56 public static function getHandler( $type ) {
57 return MediaWikiServices::getInstance()
58 ->getMediaHandlerFactory()->getHandler( $type );
59 }
60
66 abstract public function getParamMap();
67
77 abstract public function validateParam( $name, $value );
78
85 abstract public function makeParamString( $params );
86
93 abstract public function parseParamString( $str );
94
103 abstract public function normaliseParams( $image, &$params );
104
127 public function getImageSize( $image, $path ) {
128 return false;
129 }
130
156 public function getSizeAndMetadata( $state, $path ) {
157 return null;
158 }
159
169 public function getMetadata( $image, $path ) {
170 return '';
171 }
172
182 protected function useLegacyMetadata() {
183 return $this->hasMostDerivedMethod( 'getMetadata' )
184 || $this->hasMostDerivedMethod( 'getImageSize' );
185 }
186
194 protected function hasMostDerivedMethod( $name ) {
195 $rc = new ReflectionClass( $this );
196 $rm = new ReflectionMethod( $this, $name );
197 return $rm->getDeclaringClass()->getName() === $rc->getName();
198 }
199
220 final public function getSizeAndMetadataWithFallback( $file, $path ) {
221 if ( !$this->useLegacyMetadata() ) {
222 if ( $file instanceof MediaHandlerState ) {
223 $state = $file;
224 } else {
225 $state = new TrivialMediaHandlerState;
226 }
227 $info = $this->getSizeAndMetadata( $state, $path );
228 if ( $info === false ) {
229 return false;
230 }
231 if ( $info !== null ) {
232 $info += [ 'width' => 0, 'height' => 0, 'metadata' => [] ];
233 if ( !is_array( $info['metadata'] ) ) {
234 throw new InvalidArgumentException( 'Media handler ' .
235 static::class . ' returned ' . gettype( $info['metadata'] ) .
236 ' for metadata, should be array' );
237 }
238 return $info;
239 }
240 }
241
242 $blob = $this->getMetadata( $file, $path );
243 // @phan-suppress-next-line PhanParamTooMany
244 $size = $this->getImageSize(
245 $file,
246 $path,
247 $blob // Secret TimedMediaHandler parameter
248 );
249 if ( $blob === false && $size === false ) {
250 return false;
251 }
252 if ( $size ) {
253 $info = [
254 'width' => $size[0] ?? 0,
255 'height' => $size[1] ?? 0
256 ];
257 if ( isset( $size['bits'] ) ) {
258 $info['bits'] = $size['bits'];
259 }
260 } else {
261 $info = [ 'width' => 0, 'height' => 0 ];
262 }
263 if ( $blob !== false ) {
264 // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
265 $metadata = @unserialize( $blob );
266 if ( $metadata === false ) {
267 // Unserialize error
268 $metadata = [ '_error' => $blob ];
269 } elseif ( !is_array( $metadata ) ) {
270 $metadata = [];
271 }
272 $info['metadata'] = $metadata;
273 } else {
274 $info['metadata'] = [];
275 }
276 return $info;
277 }
278
296 public static function getMetadataVersion() {
297 $version = [ '2' ]; // core metadata version
298 ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )->onGetMetadataVersion( $version );
299
300 return implode( ';', $version );
301 }
302
314 public function convertMetadataVersion( $metadata, $version = 1 ) {
315 return $metadata;
316 }
317
326 public function getMetadataType( $image ) {
327 return false;
328 }
329
348 public function isMetadataValid( $image, $metadata ) {
349 return self::METADATA_GOOD;
350 }
351
377 public function isFileMetadataValid( $image ) {
378 return self::METADATA_GOOD;
379 }
380
415 public function getCommonMetaArray( File $file ) {
416 return false;
417 }
418
434 public function getScriptedTransform( $image, $script, $params ) {
435 return false;
436 }
437
450 final public function getTransform( $image, $dstPath, $dstUrl, $params ) {
451 return $this->doTransform( $image, $dstPath, $dstUrl, $params, self::TRANSFORM_LATER );
452 }
453
468 abstract public function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 );
469
480 public function getThumbType( $ext, $mime, $params = null ) {
481 $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
482 if ( !$ext || $magic->isMatchingExtension( $ext, $mime ) === false ) {
483 // The extension is not valid for this MIME type and we do
484 // recognize the MIME type
485 $knownExt = $magic->getExtensionFromMimeTypeOrNull( $mime );
486 if ( $knownExt !== null ) {
487 return [ $knownExt, $mime ];
488 }
489 }
490
491 // The extension is correct (true) or the MIME type is unknown to
492 // MediaWiki (null)
493 return [ $ext, $mime ];
494 }
495
504 public function canRender( $file ) {
505 return true;
506 }
507
517 public function mustRender( $file ) {
518 return false;
519 }
520
529 public function isMultiPage( $file ) {
530 return false;
531 }
532
541 public function pageCount( File $file ) {
542 return false;
543 }
544
553 public function isVectorized( $file ) {
554 return false;
555 }
556
567 public function isAnimatedImage( $file ) {
568 return false;
569 }
570
580 public function canAnimateThumbnail( $file ) {
581 return true;
582 }
583
590 public function isEnabled() {
591 return true;
592 }
593
611 public function getPageDimensions( File $image, $page ) {
612 return false;
613 }
614
625 public function getPageText( File $image, $page ) {
626 return false;
627 }
628
634 public function getEntireText( File $file ) {
635 $numPages = $file->pageCount();
636 if ( !$numPages ) {
637 // Not a multipage document
638 return $this->getPageText( $file, 1 );
639 }
640 $document = '';
641 for ( $i = 1; $i <= $numPages; $i++ ) {
642 $curPage = $this->getPageText( $file, $i );
643 if ( is_string( $curPage ) ) {
644 $document .= $curPage . "\n";
645 }
646 }
647 if ( $document !== '' ) {
648 return $document;
649 }
650 return false;
651 }
652
683 public function formatMetadata( $image, $context = false ) {
684 return false;
685 }
686
699 protected function formatMetadataHelper( $metadataArray, $context = false ) {
700 $result = [
701 'visible' => [],
702 'collapsed' => []
703 ];
704
705 // Allow this MediaHandler to override formatting on certain values
706 foreach ( $metadataArray as $tag => $vals ) {
707 $v = $this->formatTag( $tag, $vals, $context );
708 if ( $v === false ) {
709 // Use default formatting
710 continue;
711 }
712 if ( $v === null ) {
713 // Remove this tag, don't format it for display
714 unset( $metadataArray[$tag] );
715 } else {
716 // Allow subclass to override default formatting.
717 $metadataArray[$tag] = [ '_formatted' => $v ];
718 if ( isset( $v['_type'] ) ) {
719 $metadataArray[$tag]['_type'] = $v['_type'];
720 unset( $metadataArray[$tag]['_formatted']['_type'] );
721 }
722 }
723 }
724
725 $formatted = FormatMetadata::getFormattedData( $metadataArray, $context );
726 // Sort fields into visible and collapsed
727 $visibleFields = $this->visibleMetadataFields();
728 foreach ( $formatted as $name => $value ) {
729 $tag = strtolower( $name );
730 self::addMeta( $result,
731 in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed',
732 'exif',
733 $tag,
734 $value
735 );
736 }
737
738 return $result;
739 }
740
753 protected function formatTag( string $key, $vals, $context = false ) {
754 return false; // Use default formatting
755 }
756
765 protected function visibleMetadataFields() {
767 }
768
792 protected static function addMeta( &$array, $visibility, $type, $id, $value, $param = false ) {
793 $msg = wfMessage( "$type-$id", $param );
794 if ( $msg->exists() ) {
795 $name = $msg->text();
796 } else {
797 // This is for future compatibility when using instant commons.
798 // So as to not display as ugly a name if a new metadata
799 // property is defined that we don't know about
800 // (not a major issue since such a property would be collapsed
801 // by default).
802 wfDebug( __METHOD__ . ' Unknown metadata name: ' . $id );
803 $name = wfEscapeWikiText( $id );
804 }
805 $array[$visibility][] = [
806 'id' => "$type-$id",
807 'name' => $name,
808 'value' => $value
809 ];
810 }
811
820 public function getShortDesc( $file ) {
822 }
823
832 public function getLongDesc( $file ) {
834 }
835
842 public static function getGeneralShortDesc( $file ) {
843 global $wgLang;
844
845 return htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
846 }
847
854 public static function getGeneralLongDesc( $file ) {
855 return wfMessage( 'file-info' )->sizeParams( $file->getSize() )
856 ->params( '<span class="mime-type">' . $file->getMimeType() . '</span>' )->parse();
857 }
858
867 public static function fitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {
868 $idealWidth = $boxWidth * $maxHeight / $boxHeight;
869 $roundedUp = ceil( $idealWidth );
870 if ( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight ) {
871 return (int)floor( $idealWidth );
872 }
873 return $roundedUp;
874 }
875
884 public function getDimensionsString( $file ) {
885 return '';
886 }
887
900 public function parserTransformHook( $parser, $file ) {
901 }
902
915 public function verifyUpload( $fileName ) {
916 return Status::newGood();
917 }
918
929 public function removeBadFile( $dstPath, $retval = 0 ) {
930 if ( file_exists( $dstPath ) ) {
931 $thumbstat = stat( $dstPath );
932 if ( $thumbstat['size'] == 0 || $retval != 0 ) {
933 $result = unlink( $dstPath );
934
935 if ( $result ) {
936 wfDebugLog( 'thumbnail',
937 sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() succeeded',
938 $thumbstat['size'], $dstPath ) );
939 } else {
940 wfDebugLog( 'thumbnail',
941 sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() failed',
942 $thumbstat['size'], $dstPath ) );
943 }
944
945 return true;
946 }
947 }
948
949 return false;
950 }
951
966 public function filterThumbnailPurgeList( &$files, $options ) {
967 // Do nothing
968 }
969
977 public function canRotate() {
978 return false;
979 }
980
997 public function getRotation( $file ) {
998 return 0;
999 }
1000
1012 protected function logErrorForExternalProcess( $retval, $err, $cmd ) {
1013 # Keep error output limited (T59985)
1014 $errMessage = trim( substr( $err, 0, self::MAX_ERR_LOG_SIZE ) );
1015
1016 wfDebugLog( 'thumbnail',
1017 sprintf( 'thumbnail failed on %s: error %d "%s" from "%s"',
1018 wfHostname(), $retval, $errMessage, $cmd ) );
1019 }
1020
1030 public function getAvailableLanguages( File $file ) {
1031 return [];
1032 }
1033
1045 public function getMatchedLanguage( $userPreferredLanguage, array $availableLanguages ) {
1046 return null;
1047 }
1048
1065 return null;
1066 }
1067
1080 public function getLength( $file ) {
1081 return 0.0;
1082 }
1083
1091 public function isExpensiveToThumbnail( $file ) {
1092 return false;
1093 }
1094
1103 public function supportsBucketing() {
1104 return false;
1105 }
1106
1115 public function sanitizeParamsForBucketing( $params ) {
1116 return $params;
1117 }
1118
1145 public function getWarningConfig( $file ) {
1146 return null;
1147 }
1148
1156 public static function getPageRangesByDimensions( $pagesByDimensions ) {
1157 $pageRangesByDimensions = [];
1158
1159 foreach ( $pagesByDimensions as $dimensions => $pageList ) {
1160 $ranges = [];
1161 $firstPage = $pageList[0];
1162 $lastPage = $firstPage - 1;
1163
1164 foreach ( $pageList as $page ) {
1165 if ( $page > $lastPage + 1 ) {
1166 if ( $firstPage !== $lastPage ) {
1167 $ranges[] = "$firstPage-$lastPage";
1168 } else {
1169 $ranges[] = "$firstPage";
1170 }
1171
1172 $firstPage = $page;
1173 }
1174
1175 $lastPage = $page;
1176 }
1177
1178 if ( $firstPage != $lastPage ) {
1179 $ranges[] = "$firstPage-$lastPage";
1180 } else {
1181 $ranges[] = "$firstPage";
1182 }
1183
1184 $pageRangesByDimensions[ $dimensions ] = $ranges;
1185 }
1186
1187 $dimensionsString = [];
1188 foreach ( $pageRangesByDimensions as $dimensions => $pageRanges ) {
1189 $dimensionsString[] = "$dimensions:" . implode( ',', $pageRanges );
1190 }
1191
1192 return implode( '/', $dimensionsString );
1193 }
1194
1203 public function getContentHeaders( $metadata ) {
1204 return [ 'X-Content-Dimensions' => '' ]; // T175689
1205 }
1206
1215 public function useSplitMetadata() {
1216 return false;
1217 }
1218}
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:535
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition File.php:70
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.
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Service locator for MediaWiki core services.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:58
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