MediaWiki
REL1_19
|
00001 <?php 00035 abstract class File { 00036 const DELETED_FILE = 1; 00037 const DELETED_COMMENT = 2; 00038 const DELETED_USER = 4; 00039 const DELETED_RESTRICTED = 8; 00040 00042 const RENDER_NOW = 1; 00047 const RENDER_FORCE = 2; 00048 00049 const DELETE_SOURCE = 1; 00050 00073 var $repo; 00074 00078 var $title; 00079 00080 var $lastError, $redirected, $redirectedTitle; 00081 00085 protected $fsFile; 00086 00090 protected $handler; 00091 00095 protected $url, $extension, $name, $path, $hashPath, $pageCount, $transformScript; 00096 00100 protected $canRender, $isSafeFile; 00101 00105 protected $repoClass = 'FileRepo'; 00106 00117 function __construct( $title, $repo ) { 00118 if ( $title !== false ) { // subclasses may not use MW titles 00119 $title = self::normalizeTitle( $title, 'exception' ); 00120 } 00121 $this->title = $title; 00122 $this->repo = $repo; 00123 } 00124 00133 static function normalizeTitle( $title, $exception = false ) { 00134 $ret = $title; 00135 if ( $ret instanceof Title ) { 00136 # Normalize NS_MEDIA -> NS_FILE 00137 if ( $ret->getNamespace() == NS_MEDIA ) { 00138 $ret = Title::makeTitleSafe( NS_FILE, $ret->getDBkey() ); 00139 # Sanity check the title namespace 00140 } elseif ( $ret->getNamespace() !== NS_FILE ) { 00141 $ret = null; 00142 } 00143 } else { 00144 # Convert strings to Title objects 00145 $ret = Title::makeTitleSafe( NS_FILE, (string)$ret ); 00146 } 00147 if ( !$ret && $exception !== false ) { 00148 throw new MWException( "`$title` is not a valid file title." ); 00149 } 00150 return $ret; 00151 } 00152 00153 function __get( $name ) { 00154 $function = array( $this, 'get' . ucfirst( $name ) ); 00155 if ( !is_callable( $function ) ) { 00156 return null; 00157 } else { 00158 $this->$name = call_user_func( $function ); 00159 return $this->$name; 00160 } 00161 } 00162 00170 static function normalizeExtension( $ext ) { 00171 $lower = strtolower( $ext ); 00172 $squish = array( 00173 'htm' => 'html', 00174 'jpeg' => 'jpg', 00175 'mpeg' => 'mpg', 00176 'tiff' => 'tif', 00177 'ogv' => 'ogg' ); 00178 if( isset( $squish[$lower] ) ) { 00179 return $squish[$lower]; 00180 } elseif( preg_match( '/^[0-9a-z]+$/', $lower ) ) { 00181 return $lower; 00182 } else { 00183 return ''; 00184 } 00185 } 00186 00195 static function checkExtensionCompatibility( File $old, $new ) { 00196 $oldMime = $old->getMimeType(); 00197 $n = strrpos( $new, '.' ); 00198 $newExt = self::normalizeExtension( $n ? substr( $new, $n + 1 ) : '' ); 00199 $mimeMagic = MimeMagic::singleton(); 00200 return $mimeMagic->isMatchingExtension( $newExt, $oldMime ); 00201 } 00202 00208 function upgradeRow() {} 00209 00217 public static function splitMime( $mime ) { 00218 if( strpos( $mime, '/' ) !== false ) { 00219 return explode( '/', $mime, 2 ); 00220 } else { 00221 return array( $mime, 'unknown' ); 00222 } 00223 } 00224 00230 public function getName() { 00231 if ( !isset( $this->name ) ) { 00232 $this->assertRepoDefined(); 00233 $this->name = $this->repo->getNameFromTitle( $this->title ); 00234 } 00235 return $this->name; 00236 } 00237 00243 function getExtension() { 00244 if ( !isset( $this->extension ) ) { 00245 $n = strrpos( $this->getName(), '.' ); 00246 $this->extension = self::normalizeExtension( 00247 $n ? substr( $this->getName(), $n + 1 ) : '' ); 00248 } 00249 return $this->extension; 00250 } 00251 00257 public function getTitle() { 00258 return $this->title; 00259 } 00260 00266 public function getOriginalTitle() { 00267 if ( $this->redirected ) { 00268 return $this->getRedirectedTitle(); 00269 } 00270 return $this->title; 00271 } 00272 00278 public function getUrl() { 00279 if ( !isset( $this->url ) ) { 00280 $this->assertRepoDefined(); 00281 $this->url = $this->repo->getZoneUrl( 'public' ) . '/' . $this->getUrlRel(); 00282 } 00283 return $this->url; 00284 } 00285 00293 public function getFullUrl() { 00294 return wfExpandUrl( $this->getUrl(), PROTO_RELATIVE ); 00295 } 00296 00300 public function getCanonicalUrl() { 00301 return wfExpandUrl( $this->getUrl(), PROTO_CANONICAL ); 00302 } 00303 00307 function getViewURL() { 00308 if ( $this->mustRender() ) { 00309 if ( $this->canRender() ) { 00310 return $this->createThumb( $this->getWidth() ); 00311 } else { 00312 wfDebug( __METHOD__.': supposed to render ' . $this->getName() . 00313 ' (' . $this->getMimeType() . "), but can't!\n" ); 00314 return $this->getURL(); #hm... return NULL? 00315 } 00316 } else { 00317 return $this->getURL(); 00318 } 00319 } 00320 00334 public function getPath() { 00335 if ( !isset( $this->path ) ) { 00336 $this->assertRepoDefined(); 00337 $this->path = $this->repo->getZonePath( 'public' ) . '/' . $this->getRel(); 00338 } 00339 return $this->path; 00340 } 00341 00349 public function getLocalRefPath() { 00350 $this->assertRepoDefined(); 00351 if ( !isset( $this->fsFile ) ) { 00352 $this->fsFile = $this->repo->getLocalReference( $this->getPath() ); 00353 if ( !$this->fsFile ) { 00354 $this->fsFile = false; // null => false; cache negative hits 00355 } 00356 } 00357 return ( $this->fsFile ) 00358 ? $this->fsFile->getPath() 00359 : false; 00360 } 00361 00373 public function getWidth( $page = 1 ) { 00374 return false; 00375 } 00376 00388 public function getHeight( $page = 1 ) { 00389 return false; 00390 } 00391 00400 public function getUser( $type = 'text' ) { 00401 return null; 00402 } 00403 00409 public function getLength() { 00410 $handler = $this->getHandler(); 00411 if ( $handler ) { 00412 return $handler->getLength( $this ); 00413 } else { 00414 return 0; 00415 } 00416 } 00417 00423 public function isVectorized() { 00424 $handler = $this->getHandler(); 00425 if ( $handler ) { 00426 return $handler->isVectorized( $this ); 00427 } else { 00428 return false; 00429 } 00430 } 00431 00437 public function getMetadata() { 00438 return false; 00439 } 00440 00448 public function convertMetadataVersion($metadata, $version) { 00449 $handler = $this->getHandler(); 00450 if ( !is_array( $metadata ) ) { 00451 // Just to make the return type consistent 00452 $metadata = unserialize( $metadata ); 00453 } 00454 if ( $handler ) { 00455 return $handler->convertMetadataVersion( $metadata, $version ); 00456 } else { 00457 return $metadata; 00458 } 00459 } 00460 00466 public function getBitDepth() { 00467 return 0; 00468 } 00469 00475 public function getSize() { 00476 return false; 00477 } 00478 00486 function getMimeType() { 00487 return 'unknown/unknown'; 00488 } 00489 00496 function getMediaType() { 00497 return MEDIATYPE_UNKNOWN; 00498 } 00499 00512 function canRender() { 00513 if ( !isset( $this->canRender ) ) { 00514 $this->canRender = $this->getHandler() && $this->handler->canRender( $this ); 00515 } 00516 return $this->canRender; 00517 } 00518 00522 protected function getCanRender() { 00523 return $this->canRender(); 00524 } 00525 00536 function mustRender() { 00537 return $this->getHandler() && $this->handler->mustRender( $this ); 00538 } 00539 00545 function allowInlineDisplay() { 00546 return $this->canRender(); 00547 } 00548 00562 function isSafeFile() { 00563 if ( !isset( $this->isSafeFile ) ) { 00564 $this->isSafeFile = $this->_getIsSafeFile(); 00565 } 00566 return $this->isSafeFile; 00567 } 00568 00574 protected function getIsSafeFile() { 00575 return $this->isSafeFile(); 00576 } 00577 00583 protected function _getIsSafeFile() { 00584 global $wgTrustedMediaFormats; 00585 00586 if ( $this->allowInlineDisplay() ) { 00587 return true; 00588 } 00589 if ($this->isTrustedFile()) { 00590 return true; 00591 } 00592 00593 $type = $this->getMediaType(); 00594 $mime = $this->getMimeType(); 00595 #wfDebug("LocalFile::isSafeFile: type= $type, mime= $mime\n"); 00596 00597 if ( !$type || $type === MEDIATYPE_UNKNOWN ) { 00598 return false; #unknown type, not trusted 00599 } 00600 if ( in_array( $type, $wgTrustedMediaFormats ) ) { 00601 return true; 00602 } 00603 00604 if ( $mime === "unknown/unknown" ) { 00605 return false; #unknown type, not trusted 00606 } 00607 if ( in_array( $mime, $wgTrustedMediaFormats) ) { 00608 return true; 00609 } 00610 00611 return false; 00612 } 00613 00627 function isTrustedFile() { 00628 #this could be implemented to check a flag in the database, 00629 #look for signatures, etc 00630 return false; 00631 } 00632 00640 public function exists() { 00641 return $this->getPath() && $this->repo->fileExists( $this->path ); 00642 } 00643 00650 public function isVisible() { 00651 return $this->exists(); 00652 } 00653 00657 function getTransformScript() { 00658 if ( !isset( $this->transformScript ) ) { 00659 $this->transformScript = false; 00660 if ( $this->repo ) { 00661 $script = $this->repo->getThumbScriptUrl(); 00662 if ( $script ) { 00663 $this->transformScript = "$script?f=" . urlencode( $this->getName() ); 00664 } 00665 } 00666 } 00667 return $this->transformScript; 00668 } 00669 00677 function getUnscaledThumb( $handlerParams = array() ) { 00678 $hp =& $handlerParams; 00679 $page = isset( $hp['page'] ) ? $hp['page'] : false; 00680 $width = $this->getWidth( $page ); 00681 if ( !$width ) { 00682 return $this->iconThumb(); 00683 } 00684 $hp['width'] = $width; 00685 return $this->transform( $hp ); 00686 } 00687 00696 function thumbName( $params ) { 00697 return $this->generateThumbName( $this->getName(), $params ); 00698 } 00699 00708 function generateThumbName( $name, $params ) { 00709 if ( !$this->getHandler() ) { 00710 return null; 00711 } 00712 $extension = $this->getExtension(); 00713 list( $thumbExt, $thumbMime ) = $this->handler->getThumbType( 00714 $extension, $this->getMimeType(), $params ); 00715 $thumbName = $this->handler->makeParamString( $params ) . '-' . $name; 00716 if ( $thumbExt != $extension ) { 00717 $thumbName .= ".$thumbExt"; 00718 } 00719 return $thumbName; 00720 } 00721 00739 public function createThumb( $width, $height = -1 ) { 00740 $params = array( 'width' => $width ); 00741 if ( $height != -1 ) { 00742 $params['height'] = $height; 00743 } 00744 $thumb = $this->transform( $params ); 00745 if ( is_null( $thumb ) || $thumb->isError() ) { 00746 return ''; 00747 } 00748 return $thumb->getUrl(); 00749 } 00750 00760 protected function transformErrorOutput( $thumbPath, $thumbUrl, $params, $flags ) { 00761 global $wgIgnoreImageErrors; 00762 00763 if ( $wgIgnoreImageErrors && !( $flags & self::RENDER_NOW ) ) { 00764 return $this->handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); 00765 } else { 00766 return new MediaTransformError( 'thumbnail_error', 00767 $params['width'], 0, wfMsg( 'thumbnail-dest-create' ) ); 00768 } 00769 } 00770 00779 function transform( $params, $flags = 0 ) { 00780 global $wgUseSquid, $wgIgnoreImageErrors, $wgThumbnailEpoch; 00781 00782 wfProfileIn( __METHOD__ ); 00783 do { 00784 if ( !$this->canRender() ) { 00785 $thumb = $this->iconThumb(); 00786 break; // not a bitmap or renderable image, don't try 00787 } 00788 00789 // Get the descriptionUrl to embed it as comment into the thumbnail. Bug 19791. 00790 $descriptionUrl = $this->getDescriptionUrl(); 00791 if ( $descriptionUrl ) { 00792 $params['descriptionUrl'] = wfExpandUrl( $descriptionUrl, PROTO_CANONICAL ); 00793 } 00794 00795 $script = $this->getTransformScript(); 00796 if ( $script && !( $flags & self::RENDER_NOW ) ) { 00797 // Use a script to transform on client request, if possible 00798 $thumb = $this->handler->getScriptedTransform( $this, $script, $params ); 00799 if ( $thumb ) { 00800 break; 00801 } 00802 } 00803 00804 $normalisedParams = $params; 00805 $this->handler->normaliseParams( $this, $normalisedParams ); 00806 00807 $thumbName = $this->thumbName( $normalisedParams ); 00808 $thumbUrl = $this->getThumbUrl( $thumbName ); 00809 $thumbPath = $this->getThumbPath( $thumbName ); // final thumb path 00810 00811 if ( $this->repo ) { 00812 // Defer rendering if a 404 handler is set up... 00813 if ( $this->repo->canTransformVia404() && !( $flags & self::RENDER_NOW ) ) { 00814 wfDebug( __METHOD__ . " transformation deferred." ); 00815 // XXX: Pass in the storage path even though we are not rendering anything 00816 // and the path is supposed to be an FS path. This is due to getScalerType() 00817 // getting called on the path and clobbering $thumb->getUrl() if it's false. 00818 $thumb = $this->handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); 00819 break; 00820 } 00821 // Clean up broken thumbnails as needed 00822 $this->migrateThumbFile( $thumbName ); 00823 // Check if an up-to-date thumbnail already exists... 00824 wfDebug( __METHOD__.": Doing stat for $thumbPath\n" ); 00825 if ( $this->repo->fileExists( $thumbPath ) && !( $flags & self::RENDER_FORCE ) ) { 00826 $timestamp = $this->repo->getFileTimestamp( $thumbPath ); 00827 if ( $timestamp !== false && $timestamp >= $wgThumbnailEpoch ) { 00828 // XXX: Pass in the storage path even though we are not rendering anything 00829 // and the path is supposed to be an FS path. This is due to getScalerType() 00830 // getting called on the path and clobbering $thumb->getUrl() if it's false. 00831 $thumb = $this->handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); 00832 $thumb->setStoragePath( $thumbPath ); 00833 break; 00834 } 00835 } elseif ( $flags & self::RENDER_FORCE ) { 00836 wfDebug( __METHOD__ . " forcing rendering per flag File::RENDER_FORCE\n" ); 00837 } 00838 } 00839 00840 // Create a temp FS file with the same extension and the thumbnail 00841 $thumbExt = FileBackend::extensionFromPath( $thumbPath ); 00842 $tmpFile = TempFSFile::factory( 'transform_', $thumbExt ); 00843 if ( !$tmpFile ) { 00844 $thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $params, $flags ); 00845 break; 00846 } 00847 $tmpThumbPath = $tmpFile->getPath(); // path of 0-byte temp file 00848 00849 // Actually render the thumbnail... 00850 $thumb = $this->handler->doTransform( $this, $tmpThumbPath, $thumbUrl, $params ); 00851 $tmpFile->bind( $thumb ); // keep alive with $thumb 00852 00853 if ( !$thumb ) { // bad params? 00854 $thumb = null; 00855 } elseif ( $thumb->isError() ) { // transform error 00856 $this->lastError = $thumb->toText(); 00857 // Ignore errors if requested 00858 if ( $wgIgnoreImageErrors && !( $flags & self::RENDER_NOW ) ) { 00859 $thumb = $this->handler->getTransform( $this, $tmpThumbPath, $thumbUrl, $params ); 00860 } 00861 } elseif ( $this->repo && $thumb->hasFile() && !$thumb->fileIsSource() ) { 00862 $backend = $this->repo->getBackend(); 00863 // Copy the thumbnail from the file system into storage. This avoids using 00864 // FileRepo::store(); getThumbPath() uses a different zone in some subclasses. 00865 $backend->prepare( array( 'dir' => dirname( $thumbPath ) ) ); 00866 $status = $backend->store( 00867 array( 'src' => $tmpThumbPath, 'dst' => $thumbPath, 'overwrite' => 1 ), 00868 array( 'force' => 1, 'nonLocking' => 1, 'allowStale' => 1 ) 00869 ); 00870 if ( $status->isOK() ) { 00871 $thumb->setStoragePath( $thumbPath ); 00872 } else { 00873 $thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $params, $flags ); 00874 } 00875 } 00876 00877 // Purge. Useful in the event of Core -> Squid connection failure or squid 00878 // purge collisions from elsewhere during failure. Don't keep triggering for 00879 // "thumbs" which have the main image URL though (bug 13776) 00880 if ( $wgUseSquid ) { 00881 if ( !$thumb || $thumb->isError() || $thumb->getUrl() != $this->getURL() ) { 00882 SquidUpdate::purge( array( $thumbUrl ) ); 00883 } 00884 } 00885 } while ( false ); 00886 00887 wfProfileOut( __METHOD__ ); 00888 return is_object( $thumb ) ? $thumb : false; 00889 } 00890 00896 function migrateThumbFile( $thumbName ) {} 00897 00903 function getHandler() { 00904 if ( !isset( $this->handler ) ) { 00905 $this->handler = MediaHandler::getHandler( $this->getMimeType() ); 00906 } 00907 return $this->handler; 00908 } 00909 00915 function iconThumb() { 00916 global $wgStylePath, $wgStyleDirectory; 00917 00918 $try = array( 'fileicon-' . $this->getExtension() . '.png', 'fileicon.png' ); 00919 foreach ( $try as $icon ) { 00920 $path = '/common/images/icons/' . $icon; 00921 $filepath = $wgStyleDirectory . $path; 00922 if ( file_exists( $filepath ) ) { // always FS 00923 return new ThumbnailImage( $this, $wgStylePath . $path, 120, 120 ); 00924 } 00925 } 00926 return null; 00927 } 00928 00933 function getLastError() { 00934 return $this->lastError; 00935 } 00936 00942 function getThumbnails() { 00943 return array(); 00944 } 00945 00953 function purgeCache( $options = array() ) {} 00954 00960 function purgeDescription() { 00961 $title = $this->getTitle(); 00962 if ( $title ) { 00963 $title->invalidateCache(); 00964 $title->purgeSquid(); 00965 } 00966 } 00967 00972 function purgeEverything() { 00973 // Delete thumbnails and refresh file metadata cache 00974 $this->purgeCache(); 00975 $this->purgeDescription(); 00976 00977 // Purge cache of all pages using this file 00978 $title = $this->getTitle(); 00979 if ( $title ) { 00980 $update = new HTMLCacheUpdate( $title, 'imagelinks' ); 00981 $update->doUpdate(); 00982 } 00983 } 00984 00996 function getHistory($limit = null, $start = null, $end = null, $inc=true) { 00997 return array(); 00998 } 00999 01008 public function nextHistoryLine() { 01009 return false; 01010 } 01011 01018 public function resetHistory() {} 01019 01027 function getHashPath() { 01028 if ( !isset( $this->hashPath ) ) { 01029 $this->assertRepoDefined(); 01030 $this->hashPath = $this->repo->getHashPath( $this->getName() ); 01031 } 01032 return $this->hashPath; 01033 } 01034 01041 function getRel() { 01042 return $this->getHashPath() . $this->getName(); 01043 } 01044 01052 function getArchiveRel( $suffix = false ) { 01053 $path = 'archive/' . $this->getHashPath(); 01054 if ( $suffix === false ) { 01055 $path = substr( $path, 0, -1 ); 01056 } else { 01057 $path .= $suffix; 01058 } 01059 return $path; 01060 } 01061 01070 function getThumbRel( $suffix = false ) { 01071 $path = $this->getRel(); 01072 if ( $suffix !== false ) { 01073 $path .= '/' . $suffix; 01074 } 01075 return $path; 01076 } 01077 01084 function getUrlRel() { 01085 return $this->getHashPath() . rawurlencode( $this->getName() ); 01086 } 01087 01097 function getArchiveThumbRel( $archiveName, $suffix = false ) { 01098 $path = 'archive/' . $this->getHashPath() . $archiveName . "/"; 01099 if ( $suffix === false ) { 01100 $path = substr( $path, 0, -1 ); 01101 } else { 01102 $path .= $suffix; 01103 } 01104 return $path; 01105 } 01106 01114 function getArchivePath( $suffix = false ) { 01115 $this->assertRepoDefined(); 01116 return $this->repo->getZonePath( 'public' ) . '/' . $this->getArchiveRel( $suffix ); 01117 } 01118 01127 function getArchiveThumbPath( $archiveName, $suffix = false ) { 01128 $this->assertRepoDefined(); 01129 return $this->repo->getZonePath( 'thumb' ) . '/' . 01130 $this->getArchiveThumbRel( $archiveName, $suffix ); 01131 } 01132 01140 function getThumbPath( $suffix = false ) { 01141 $this->assertRepoDefined(); 01142 return $this->repo->getZonePath( 'thumb' ) . '/' . $this->getThumbRel( $suffix ); 01143 } 01144 01152 function getArchiveUrl( $suffix = false ) { 01153 $this->assertRepoDefined(); 01154 $path = $this->repo->getZoneUrl( 'public' ) . '/archive/' . $this->getHashPath(); 01155 if ( $suffix === false ) { 01156 $path = substr( $path, 0, -1 ); 01157 } else { 01158 $path .= rawurlencode( $suffix ); 01159 } 01160 return $path; 01161 } 01162 01171 function getArchiveThumbUrl( $archiveName, $suffix = false ) { 01172 $this->assertRepoDefined(); 01173 $path = $this->repo->getZoneUrl( 'thumb' ) . '/archive/' . 01174 $this->getHashPath() . rawurlencode( $archiveName ) . "/"; 01175 if ( $suffix === false ) { 01176 $path = substr( $path, 0, -1 ); 01177 } else { 01178 $path .= rawurlencode( $suffix ); 01179 } 01180 return $path; 01181 } 01182 01190 function getThumbUrl( $suffix = false ) { 01191 $this->assertRepoDefined(); 01192 $path = $this->repo->getZoneUrl( 'thumb' ) . '/' . $this->getUrlRel(); 01193 if ( $suffix !== false ) { 01194 $path .= '/' . rawurlencode( $suffix ); 01195 } 01196 return $path; 01197 } 01198 01206 function getVirtualUrl( $suffix = false ) { 01207 $this->assertRepoDefined(); 01208 $path = $this->repo->getVirtualUrl() . '/public/' . $this->getUrlRel(); 01209 if ( $suffix !== false ) { 01210 $path .= '/' . rawurlencode( $suffix ); 01211 } 01212 return $path; 01213 } 01214 01222 function getArchiveVirtualUrl( $suffix = false ) { 01223 $this->assertRepoDefined(); 01224 $path = $this->repo->getVirtualUrl() . '/public/archive/' . $this->getHashPath(); 01225 if ( $suffix === false ) { 01226 $path = substr( $path, 0, -1 ); 01227 } else { 01228 $path .= rawurlencode( $suffix ); 01229 } 01230 return $path; 01231 } 01232 01240 function getThumbVirtualUrl( $suffix = false ) { 01241 $this->assertRepoDefined(); 01242 $path = $this->repo->getVirtualUrl() . '/thumb/' . $this->getUrlRel(); 01243 if ( $suffix !== false ) { 01244 $path .= '/' . rawurlencode( $suffix ); 01245 } 01246 return $path; 01247 } 01248 01252 function isHashed() { 01253 $this->assertRepoDefined(); 01254 return $this->repo->isHashed(); 01255 } 01256 01260 function readOnlyError() { 01261 throw new MWException( get_class($this) . ': write operations are not supported' ); 01262 } 01263 01275 function recordUpload( $oldver, $desc, $license = '', $copyStatus = '', $source = '', $watch = false ) { 01276 $this->readOnlyError(); 01277 } 01278 01297 function publish( $srcPath, $flags = 0 ) { 01298 $this->readOnlyError(); 01299 } 01300 01304 function formatMetadata() { 01305 if ( !$this->getHandler() ) { 01306 return false; 01307 } 01308 return $this->getHandler()->formatMetadata( $this, $this->getMetadata() ); 01309 } 01310 01316 function isLocal() { 01317 return $this->repo && $this->repo->isLocal(); 01318 } 01319 01325 function getRepoName() { 01326 return $this->repo ? $this->repo->getName() : 'unknown'; 01327 } 01328 01334 function getRepo() { 01335 return $this->repo; 01336 } 01337 01344 function isOld() { 01345 return false; 01346 } 01347 01356 function isDeleted( $field ) { 01357 return false; 01358 } 01359 01364 function getVisibility() { 01365 return 0; 01366 } 01367 01373 function wasDeleted() { 01374 $title = $this->getTitle(); 01375 return $title && $title->isDeletedQuick(); 01376 } 01377 01390 function move( $target ) { 01391 $this->readOnlyError(); 01392 } 01393 01408 function delete( $reason, $suppress = false ) { 01409 $this->readOnlyError(); 01410 } 01411 01426 function restore( $versions = array(), $unsuppress = false ) { 01427 $this->readOnlyError(); 01428 } 01429 01437 function isMultipage() { 01438 return $this->getHandler() && $this->handler->isMultiPage( $this ); 01439 } 01440 01447 function pageCount() { 01448 if ( !isset( $this->pageCount ) ) { 01449 if ( $this->getHandler() && $this->handler->isMultiPage( $this ) ) { 01450 $this->pageCount = $this->handler->pageCount( $this ); 01451 } else { 01452 $this->pageCount = false; 01453 } 01454 } 01455 return $this->pageCount; 01456 } 01457 01467 static function scaleHeight( $srcWidth, $srcHeight, $dstWidth ) { 01468 // Exact integer multiply followed by division 01469 if ( $srcWidth == 0 ) { 01470 return 0; 01471 } else { 01472 return round( $srcHeight * $dstWidth / $srcWidth ); 01473 } 01474 } 01475 01483 function getImageSize( $fileName ) { 01484 if ( !$this->getHandler() ) { 01485 return false; 01486 } 01487 return $this->handler->getImageSize( $this, $fileName ); 01488 } 01489 01496 function getDescriptionUrl() { 01497 if ( $this->repo ) { 01498 return $this->repo->getDescriptionUrl( $this->getName() ); 01499 } else { 01500 return false; 01501 } 01502 } 01503 01509 function getDescriptionText() { 01510 global $wgMemc, $wgLang; 01511 if ( !$this->repo || !$this->repo->fetchDescription ) { 01512 return false; 01513 } 01514 $renderUrl = $this->repo->getDescriptionRenderUrl( $this->getName(), $wgLang->getCode() ); 01515 if ( $renderUrl ) { 01516 if ( $this->repo->descriptionCacheExpiry > 0 ) { 01517 wfDebug("Attempting to get the description from cache..."); 01518 $key = $this->repo->getLocalCacheKey( 'RemoteFileDescription', 'url', $wgLang->getCode(), 01519 $this->getName() ); 01520 $obj = $wgMemc->get($key); 01521 if ($obj) { 01522 wfDebug("success!\n"); 01523 return $obj; 01524 } 01525 wfDebug("miss\n"); 01526 } 01527 wfDebug( "Fetching shared description from $renderUrl\n" ); 01528 $res = Http::get( $renderUrl ); 01529 if ( $res && $this->repo->descriptionCacheExpiry > 0 ) { 01530 $wgMemc->set( $key, $res, $this->repo->descriptionCacheExpiry ); 01531 } 01532 return $res; 01533 } else { 01534 return false; 01535 } 01536 } 01537 01544 function getDescription() { 01545 return null; 01546 } 01547 01553 function getTimestamp() { 01554 $this->assertRepoDefined(); 01555 return $this->repo->getFileTimestamp( $this->getPath() ); 01556 } 01557 01563 function getSha1() { 01564 $this->assertRepoDefined(); 01565 return $this->repo->getFileSha1( $this->getPath() ); 01566 } 01567 01573 function getStorageKey() { 01574 $hash = $this->getSha1(); 01575 if ( !$hash ) { 01576 return false; 01577 } 01578 $ext = $this->getExtension(); 01579 $dotExt = $ext === '' ? '' : ".$ext"; 01580 return $hash . $dotExt; 01581 } 01582 01591 function userCan( $field, User $user = null ) { 01592 return true; 01593 } 01594 01604 static function getPropsFromPath( $path, $ext = true ) { 01605 wfDebug( __METHOD__.": Getting file info for $path\n" ); 01606 wfDeprecated( __METHOD__, '1.19' ); 01607 01608 $fsFile = new FSFile( $path ); 01609 return $fsFile->getProps(); 01610 } 01611 01623 static function sha1Base36( $path ) { 01624 wfDeprecated( __METHOD__, '1.19' ); 01625 01626 $fsFile = new FSFile( $path ); 01627 return $fsFile->getSha1Base36(); 01628 } 01629 01633 function getLongDesc() { 01634 $handler = $this->getHandler(); 01635 if ( $handler ) { 01636 return $handler->getLongDesc( $this ); 01637 } else { 01638 return MediaHandler::getGeneralLongDesc( $this ); 01639 } 01640 } 01641 01645 function getShortDesc() { 01646 $handler = $this->getHandler(); 01647 if ( $handler ) { 01648 return $handler->getShortDesc( $this ); 01649 } else { 01650 return MediaHandler::getGeneralShortDesc( $this ); 01651 } 01652 } 01653 01657 function getDimensionsString() { 01658 $handler = $this->getHandler(); 01659 if ( $handler ) { 01660 return $handler->getDimensionsString( $this ); 01661 } else { 01662 return ''; 01663 } 01664 } 01665 01669 function getRedirected() { 01670 return $this->redirected; 01671 } 01672 01676 function getRedirectedTitle() { 01677 if ( $this->redirected ) { 01678 if ( !$this->redirectTitle ) { 01679 $this->redirectTitle = Title::makeTitle( NS_FILE, $this->redirected ); 01680 } 01681 return $this->redirectTitle; 01682 } 01683 } 01684 01689 function redirectedFrom( $from ) { 01690 $this->redirected = $from; 01691 } 01692 01696 function isMissing() { 01697 return false; 01698 } 01699 01704 protected function assertRepoDefined() { 01705 if ( !( $this->repo instanceof $this->repoClass ) ) { 01706 throw new MWException( "A {$this->repoClass} object is not set for this File.\n" ); 01707 } 01708 } 01709 01714 protected function assertTitleDefined() { 01715 if ( !( $this->title instanceof Title ) ) { 01716 throw new MWException( "A Title object is not set for this File.\n" ); 01717 } 01718 } 01719 }