MediaWiki  REL1_19
Generic.php
Go to the documentation of this file.
00001 <?php
00014 abstract class MediaHandler {
00015         const TRANSFORM_LATER = 1;
00016         const METADATA_GOOD = true;
00017         const METADATA_BAD = false;
00018         const METADATA_COMPATIBLE = 2; // for old but backwards compatible.
00022         static $handlers = array();
00023 
00031         static function getHandler( $type ) {
00032                 global $wgMediaHandlers;
00033                 if ( !isset( $wgMediaHandlers[$type] ) ) {
00034                         wfDebug( __METHOD__ . ": no handler found for $type.\n");
00035                         return false;
00036                 }
00037                 $class = $wgMediaHandlers[$type];
00038                 if ( !isset( self::$handlers[$class] ) ) {
00039                         self::$handlers[$class] = new $class;
00040                         if ( !self::$handlers[$class]->isEnabled() ) {
00041                                 self::$handlers[$class] = false;
00042                         }
00043                 }
00044                 return self::$handlers[$class];
00045         }
00046 
00051         abstract function getParamMap();
00052 
00061         abstract function validateParam( $name, $value );
00062 
00068         abstract function makeParamString( $params );
00069 
00075         abstract function parseParamString( $str );
00076 
00084         abstract function normaliseParams( $image, &$params );
00085 
00094         abstract function getImageSize( $image, $path );
00095 
00104         function getMetadata( $image, $path ) { return ''; }
00105 
00121         static function getMetadataVersion () {
00122                 $version = Array( '2' ); // core metadata version
00123                 wfRunHooks('GetMetadataVersion', Array(&$version));
00124                 return implode( ';', $version);
00125          }
00126 
00137         function convertMetadataVersion( $metadata, $version = 1 ) {
00138                 if ( !is_array( $metadata ) ) {
00139 
00140                         //unserialize to keep return parameter consistent.
00141                         wfSuppressWarnings();
00142                         $ret = unserialize( $metadata );
00143                         wfRestoreWarnings();
00144                         return $ret;
00145                 }
00146                 return $metadata;
00147         }
00148 
00154         function getMetadataType( $image ) { return false; }
00155 
00164         function isMetadataValid( $image, $metadata ) {
00165                 return self::METADATA_GOOD;
00166         }
00167 
00168 
00177         function getScriptedTransform( $image, $script, $params ) {
00178                 return false;
00179         }
00180 
00190         final function getTransform( $image, $dstPath, $dstUrl, $params ) {
00191                 return $this->doTransform( $image, $dstPath, $dstUrl, $params, self::TRANSFORM_LATER );
00192         }
00193 
00206         abstract function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 );
00207 
00212         function getThumbType( $ext, $mime, $params = null ) {
00213                 $magic = MimeMagic::singleton();
00214                 if ( !$ext || $magic->isMatchingExtension( $ext, $mime ) === false ) {
00215                         // The extension is not valid for this mime type and we do
00216                         // recognize the mime type
00217                         $extensions = $magic->getExtensionsForType( $mime );
00218                         if ( $extensions ) {
00219                                 return array( strtok( $extensions, ' ' ), $mime );
00220                         }
00221                 }
00222 
00223                 // The extension is correct (true) or the mime type is unknown to
00224                 // MediaWiki (null)
00225                 return array( $ext, $mime );
00226         }
00227 
00231         function canRender( $file ) { return true; }
00236         function mustRender( $file ) { return false; }
00240         function isMultiPage( $file ) { return false; }
00244         function pageCount( $file ) { return false; }
00248         function isVectorized( $file ) { return false; }
00252         function isEnabled() { return true; }
00253 
00262         function getPageDimensions( $image, $page ) {
00263                 $gis = $this->getImageSize( $image, $image->getLocalRefPath() );
00264                 return array(
00265                         'width' => $gis[0],
00266                         'height' => $gis[1]
00267                 );
00268         }
00269 
00274         function getPageText( $image, $page ) {
00275                 return false;
00276         }
00277 
00304         function formatMetadata( $image ) {
00305                 return false;
00306         }
00307 
00317         function formatMetadataHelper( $metadataArray ) {
00318                  $result = array(
00319                         'visible' => array(),
00320                         'collapsed' => array()
00321                 );
00322 
00323                 $formatted = FormatMetadata::getFormattedData( $metadataArray );
00324                 // Sort fields into visible and collapsed
00325                 $visibleFields = $this->visibleMetadataFields();
00326                 foreach ( $formatted as $name => $value ) {
00327                         $tag = strtolower( $name );
00328                         self::addMeta( $result,
00329                                 in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed',
00330                                 'exif',
00331                                 $tag,
00332                                 $value
00333                         );
00334                 }
00335                 return $result;
00336         }
00337 
00345         function visibleMetadataFields() {
00346                 $fields = array();
00347                 $lines = explode( "\n", wfMsgForContent( 'metadata-fields' ) );
00348                 foreach( $lines as $line ) {
00349                         $matches = array();
00350                         if( preg_match( '/^\\*\s*(.*?)\s*$/', $line, $matches ) ) {
00351                                 $fields[] = $matches[1];
00352                         }
00353                 }
00354                 $fields = array_map( 'strtolower', $fields );
00355                 return $fields;
00356         }
00357 
00358 
00382         protected static function addMeta( &$array, $visibility, $type, $id, $value, $param = false ) {
00383                 $msg = wfMessage( "$type-$id", $param );
00384                 if ( $msg->exists() ) {
00385                         $name = $msg->text();
00386                 } else {
00387                         // This is for future compatibility when using instant commons.
00388                         // So as to not display as ugly a name if a new metadata
00389                         // property is defined that we don't know about
00390                         // (not a major issue since such a property would be collapsed
00391                         // by default).
00392                         wfDebug( __METHOD__ . ' Unknown metadata name: ' . $id . "\n" );
00393                         $name = wfEscapeWikiText( $id );
00394                 }
00395                 $array[$visibility][] = array(
00396                         'id' => "$type-$id",
00397                         'name' => $name,
00398                         'value' => $value
00399                 );
00400         }
00401 
00406         function getShortDesc( $file ) {
00407                 global $wgLang;
00408                 return htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
00409         }
00410 
00415         function getLongDesc( $file ) {
00416                 global $wgLang;
00417                 return wfMessage( 'file-info', htmlspecialchars( $wgLang->formatSize( $file->getSize() ) ),
00418                         $file->getMimeType() )->parse();
00419         }
00420 
00425         static function getGeneralShortDesc( $file ) {
00426                 global $wgLang;
00427                 return $wgLang->formatSize( $file->getSize() );
00428         }
00429 
00434         static function getGeneralLongDesc( $file ) {
00435                 global $wgLang;
00436                 return wfMessage( 'file-info', $wgLang->formatSize( $file->getSize() ),
00437                         $file->getMimeType() )->parse();
00438         }
00439 
00448         public static function fitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {
00449                 $idealWidth = $boxWidth * $maxHeight / $boxHeight;
00450                 $roundedUp = ceil( $idealWidth );
00451                 if( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight ) {
00452                         return floor( $idealWidth );
00453                 } else {
00454                         return $roundedUp;
00455                 }
00456         }
00457 
00458         function getDimensionsString( $file ) {
00459                 return '';
00460         }
00461 
00465         function parserTransformHook( $parser, $file ) {}
00466 
00477         function verifyUpload( $fileName ) {
00478                 return Status::newGood();
00479         }
00480 
00489         function removeBadFile( $dstPath, $retval = 0 ) {
00490                 if( file_exists( $dstPath ) ) {
00491                         $thumbstat = stat( $dstPath );
00492                         if( $thumbstat['size'] == 0 || $retval != 0 ) {
00493                                 $result = unlink( $dstPath );
00494 
00495                                 if ( $result ) {
00496                                         wfDebugLog( 'thumbnail',
00497                                                 sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() succeeded',
00498                                                         $thumbstat['size'], $dstPath ) );
00499                                 } else {
00500                                         wfDebugLog( 'thumbnail',
00501                                                 sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() failed',
00502                                                         $thumbstat['size'], $dstPath ) );
00503                                 }
00504                                 return true;
00505                         }
00506                 }
00507                 return false;
00508         }
00509 
00516         public function filterThumbnailPurgeList( &$files, $options ) {
00517                 // Do nothing
00518         }
00519 }
00520 
00526 abstract class ImageHandler extends MediaHandler {
00527 
00532         function canRender( $file ) {
00533                 return ( $file->getWidth() && $file->getHeight() );
00534         }
00535 
00536         function getParamMap() {
00537                 return array( 'img_width' => 'width' );
00538         }
00539 
00540         function validateParam( $name, $value ) {
00541                 if ( in_array( $name, array( 'width', 'height' ) ) ) {
00542                         if ( $value <= 0 ) {
00543                                 return false;
00544                         } else {
00545                                 return true;
00546                         }
00547                 } else {
00548                         return false;
00549                 }
00550         }
00551 
00552         function makeParamString( $params ) {
00553                 if ( isset( $params['physicalWidth'] ) ) {
00554                         $width = $params['physicalWidth'];
00555                 } elseif ( isset( $params['width'] ) ) {
00556                         $width = $params['width'];
00557                 } else {
00558                         throw new MWException( 'No width specified to '.__METHOD__ );
00559                 }
00560                 # Removed for ProofreadPage
00561                 #$width = intval( $width );
00562                 return "{$width}px";
00563         }
00564 
00565         function parseParamString( $str ) {
00566                 $m = false;
00567                 if ( preg_match( '/^(\d+)px$/', $str, $m ) ) {
00568                         return array( 'width' => $m[1] );
00569                 } else {
00570                         return false;
00571                 }
00572         }
00573 
00574         function getScriptParams( $params ) {
00575                 return array( 'width' => $params['width'] );
00576         }
00577 
00583         function normaliseParams( $image, &$params ) {
00584                 $mimeType = $image->getMimeType();
00585 
00586                 if ( !isset( $params['width'] ) ) {
00587                         return false;
00588                 }
00589 
00590                 if ( !isset( $params['page'] ) ) {
00591                         $params['page'] = 1;
00592                 } else  {
00593                         $params['page'] = intval( $params['page'] );
00594                         if ( $params['page'] > $image->pageCount() ) {
00595                                 $params['page'] = $image->pageCount();
00596                         }
00597 
00598                         if ( $params['page'] < 1 ) {
00599                                 $params['page'] = 1;
00600                         }
00601                 }
00602 
00603                 $srcWidth = $image->getWidth( $params['page'] );
00604                 $srcHeight = $image->getHeight( $params['page'] );
00605 
00606                 if ( isset( $params['height'] ) && $params['height'] != -1 ) {
00607                         # Height & width were both set
00608                         if ( $params['width'] * $srcHeight > $params['height'] * $srcWidth ) {
00609                                 # Height is the relative smaller dimension, so scale width accordingly
00610                                 $params['width'] = self::fitBoxWidth( $srcWidth, $srcHeight, $params['height'] );
00611 
00612                                 if ( $params['width'] == 0 ) {
00613                                         # Very small image, so we need to rely on client side scaling :(
00614                                         $params['width'] = 1;
00615                                 }
00616 
00617                                 $params['physicalWidth'] = $params['width'];
00618                         } else {
00619                                 # Height was crap, unset it so that it will be calculated later
00620                                 unset( $params['height'] );
00621                         }
00622                 }
00623 
00624                 if ( !isset( $params['physicalWidth'] ) ) {
00625                         # Passed all validations, so set the physicalWidth
00626                         $params['physicalWidth'] = $params['width'];
00627                 }
00628 
00629                 # Because thumbs are only referred to by width, the height always needs
00630                 # to be scaled by the width to keep the thumbnail sizes consistent,
00631                 # even if it was set inside the if block above
00632                 $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight,
00633                         $params['physicalWidth'] );
00634 
00635                 # Set the height if it was not validated in the if block higher up
00636                 if ( !isset( $params['height'] ) || $params['height'] == -1 ) {
00637                         $params['height'] = $params['physicalHeight'];
00638                 }
00639 
00640 
00641                 if ( !$this->validateThumbParams( $params['physicalWidth'],
00642                                 $params['physicalHeight'], $srcWidth, $srcHeight, $mimeType ) ) {
00643                         return false;
00644                 }
00645                 return true;
00646         }
00647 
00658         function validateThumbParams( &$width, &$height, $srcWidth, $srcHeight, $mimeType ) {
00659                 $width = intval( $width );
00660 
00661                 # Sanity check $width
00662                 if( $width <= 0) {
00663                         wfDebug( __METHOD__.": Invalid destination width: $width\n" );
00664                         return false;
00665                 }
00666                 if ( $srcWidth <= 0 ) {
00667                         wfDebug( __METHOD__.": Invalid source width: $srcWidth\n" );
00668                         return false;
00669                 }
00670 
00671                 $height = File::scaleHeight( $srcWidth, $srcHeight, $width );
00672                 if ( $height == 0 ) {
00673                         # Force height to be at least 1 pixel
00674                         $height = 1;
00675                 }
00676                 return true;
00677         }
00678 
00685         function getScriptedTransform( $image, $script, $params ) {
00686                 if ( !$this->normaliseParams( $image, $params ) ) {
00687                         return false;
00688                 }
00689                 $url = $script . '&' . wfArrayToCGI( $this->getScriptParams( $params ) );
00690                 $page = isset( $params['page'] ) ? $params['page'] : false;
00691 
00692                 if( $image->mustRender() || $params['width'] < $image->getWidth() ) {
00693                         return new ThumbnailImage( $image, $url, $params['width'], $params['height'], $page );
00694                 }
00695         }
00696 
00697         function getImageSize( $image, $path ) {
00698                 wfSuppressWarnings();
00699                 $gis = getimagesize( $path );
00700                 wfRestoreWarnings();
00701                 return $gis;
00702         }
00703 
00704         function isAnimatedImage( $image ) {
00705                 return false;
00706         }
00707 
00712         function getShortDesc( $file ) {
00713                 global $wgLang;
00714                 $nbytes = htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
00715                 $widthheight = wfMessage( 'widthheight' )->numParams( $file->getWidth(), $file->getHeight() )->escaped();
00716 
00717                 return "$widthheight ($nbytes)";
00718         }
00719 
00724         function getLongDesc( $file ) {
00725                 global $wgLang;
00726                 $pages = $file->pageCount();
00727                 $size = htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
00728                 if ( $pages === false || $pages <= 1 ) {
00729                         $msg = wfMessage( 'file-info-size' )->numParams( $file->getWidth(),
00730                                 $file->getHeight() )->params( $size,
00731                                 $file->getMimeType() )->parse();
00732                 } else {
00733                         $msg = wfMessage( 'file-info-size-pages' )->numParams( $file->getWidth(),
00734                                 $file->getHeight() )->params( $size,
00735                                 $file->getMimeType() )->numParams( $pages )->parse();
00736                 }
00737                 return $msg;
00738         }
00739 
00744         function getDimensionsString( $file ) {
00745                 $pages = $file->pageCount();
00746                 if ( $pages > 1 ) {
00747                         return wfMessage( 'widthheightpage' )->numParams( $file->getWidth(), $file->getHeight(), $pages )->text();
00748                 } else {
00749                         return wfMessage( 'widthheight' )->numParams( $file->getWidth(), $file->getHeight() )->text();
00750                 }
00751         }
00752 }