📄 image.php
字号:
<?php/** * @package MediaWiki *//** * NOTE FOR WINDOWS USERS: * To enable EXIF functions, add the folloing lines to the * "Windows extensions" section of php.ini: * * extension=extensions/php_mbstring.dll * extension=extensions/php_exif.dll *//** * Bump this number when serialized cache records may be incompatible. */define( 'MW_IMAGE_VERSION', 1 );/** * Class to represent an image * * Provides methods to retrieve paths (physical, logical, URL), * to generate thumbnails or for uploading. * @package MediaWiki */class Image{ /**#@+ * @private */ var $name, # name of the image (constructor) $imagePath, # Path of the image (loadFromXxx) $url, # Image URL (accessor) $title, # Title object for this image (constructor) $fileExists, # does the image file exist on disk? (loadFromXxx) $fromSharedDirectory, # load this image from $wgSharedUploadDirectory (loadFromXxx) $historyLine, # Number of line to return by nextHistoryLine() (constructor) $historyRes, # result of the query for the image's history (nextHistoryLine) $width, # \ $height, # | $bits, # --- returned by getimagesize (loadFromXxx) $attr, # / $type, # MEDIATYPE_xxx (bitmap, drawing, audio...) $mime, # MIME type, determined by MimeMagic::guessMimeType $size, # Size in bytes (loadFromXxx) $metadata, # Metadata $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx) $lastError; # Error string associated with a thumbnail display error /**#@-*/ /** * Create an Image object from an image name * * @param string $name name of the image, used to create a title object using Title::makeTitleSafe * @public */ function newFromName( $name ) { $title = Title::makeTitleSafe( NS_IMAGE, $name ); if ( is_object( $title ) ) { return new Image( $title ); } else { return NULL; } } /** * Obsolete factory function, use constructor * @deprecated */ function newFromTitle( $title ) { return new Image( $title ); } function Image( $title ) { if( !is_object( $title ) ) { throw new MWException( 'Image constructor given bogus title.' ); } $this->title =& $title; $this->name = $title->getDBkey(); $this->metadata = serialize ( array() ) ; $n = strrpos( $this->name, '.' ); $this->extension = Image::normalizeExtension( $n ? substr( $this->name, $n + 1 ) : '' ); $this->historyLine = 0; $this->dataLoaded = false; } /** * Normalize a file extension to the common form, and ensure it's clean. * Extensions with non-alphanumeric characters will be discarded. * * @param $ext string (without the .) * @return string */ static function normalizeExtension( $ext ) { $lower = strtolower( $ext ); $squish = array( 'htm' => 'html', 'jpeg' => 'jpg', 'mpeg' => 'mpg', 'tiff' => 'tif' ); if( isset( $squish[$lower] ) ) { return $squish[$lower]; } elseif( preg_match( '/^[0-9a-z]+$/', $lower ) ) { return $lower; } else { return ''; } } /** * Get the memcached keys * Returns an array, first element is the local cache key, second is the shared cache key, if there is one */ function getCacheKeys( ) { global $wgDBname, $wgUseSharedUploads, $wgSharedUploadDBname, $wgCacheSharedUploads; $hashedName = md5($this->name); $keys = array( "$wgDBname:Image:$hashedName" ); if ( $wgUseSharedUploads && $wgSharedUploadDBname && $wgCacheSharedUploads ) { $keys[] = "$wgSharedUploadDBname:Image:$hashedName"; } return $keys; } /** * Try to load image metadata from memcached. Returns true on success. */ function loadFromCache() { global $wgUseSharedUploads, $wgMemc; wfProfileIn( __METHOD__ ); $this->dataLoaded = false; $keys = $this->getCacheKeys(); $cachedValues = $wgMemc->get( $keys[0] ); // Check if the key existed and belongs to this version of MediaWiki if (!empty($cachedValues) && is_array($cachedValues) && isset($cachedValues['version']) && ( $cachedValues['version'] == MW_IMAGE_VERSION ) && $cachedValues['fileExists'] && isset( $cachedValues['mime'] ) && isset( $cachedValues['metadata'] ) ) { if ( $wgUseSharedUploads && $cachedValues['fromShared']) { # if this is shared file, we need to check if image # in shared repository has not changed if ( isset( $keys[1] ) ) { $commonsCachedValues = $wgMemc->get( $keys[1] ); if (!empty($commonsCachedValues) && is_array($commonsCachedValues) && isset($commonsCachedValues['version']) && ( $commonsCachedValues['version'] == MW_IMAGE_VERSION ) && isset($commonsCachedValues['mime'])) { wfDebug( "Pulling image metadata from shared repository cache\n" ); $this->name = $commonsCachedValues['name']; $this->imagePath = $commonsCachedValues['imagePath']; $this->fileExists = $commonsCachedValues['fileExists']; $this->width = $commonsCachedValues['width']; $this->height = $commonsCachedValues['height']; $this->bits = $commonsCachedValues['bits']; $this->type = $commonsCachedValues['type']; $this->mime = $commonsCachedValues['mime']; $this->metadata = $commonsCachedValues['metadata']; $this->size = $commonsCachedValues['size']; $this->fromSharedDirectory = true; $this->dataLoaded = true; $this->imagePath = $this->getFullPath(true); } } } else { wfDebug( "Pulling image metadata from local cache\n" ); $this->name = $cachedValues['name']; $this->imagePath = $cachedValues['imagePath']; $this->fileExists = $cachedValues['fileExists']; $this->width = $cachedValues['width']; $this->height = $cachedValues['height']; $this->bits = $cachedValues['bits']; $this->type = $cachedValues['type']; $this->mime = $cachedValues['mime']; $this->metadata = $cachedValues['metadata']; $this->size = $cachedValues['size']; $this->fromSharedDirectory = false; $this->dataLoaded = true; $this->imagePath = $this->getFullPath(); } } if ( $this->dataLoaded ) { wfIncrStats( 'image_cache_hit' ); } else { wfIncrStats( 'image_cache_miss' ); } wfProfileOut( __METHOD__ ); return $this->dataLoaded; } /** * Save the image metadata to memcached */ function saveToCache() { global $wgMemc; $this->load(); $keys = $this->getCacheKeys(); if ( $this->fileExists ) { // We can't cache negative metadata for non-existent files, // because if the file later appears in commons, the local // keys won't be purged. $cachedValues = array( 'version' => MW_IMAGE_VERSION, 'name' => $this->name, 'imagePath' => $this->imagePath, 'fileExists' => $this->fileExists, 'fromShared' => $this->fromSharedDirectory, 'width' => $this->width, 'height' => $this->height, 'bits' => $this->bits, 'type' => $this->type, 'mime' => $this->mime, 'metadata' => $this->metadata, 'size' => $this->size ); $wgMemc->set( $keys[0], $cachedValues, 60 * 60 * 24 * 7 ); // A week } else { // However we should clear them, so they aren't leftover // if we've deleted the file. $wgMemc->delete( $keys[0] ); } } /** * Load metadata from the file itself */ function loadFromFile() { global $wgUseSharedUploads, $wgSharedUploadDirectory, $wgContLang, $wgShowEXIF; wfProfileIn( __METHOD__ ); $this->imagePath = $this->getFullPath(); $this->fileExists = file_exists( $this->imagePath ); $this->fromSharedDirectory = false; $gis = array(); if (!$this->fileExists) wfDebug(__METHOD__.': '.$this->imagePath." not found locally!\n"); # If the file is not found, and a shared upload directory is used, look for it there. if (!$this->fileExists && $wgUseSharedUploads && $wgSharedUploadDirectory) { # In case we're on a wgCapitalLinks=false wiki, we # capitalize the first letter of the filename before # looking it up in the shared repository. $sharedImage = Image::newFromName( $wgContLang->ucfirst($this->name) ); $this->fileExists = $sharedImage && file_exists( $sharedImage->getFullPath(true) ); if ( $this->fileExists ) { $this->name = $sharedImage->name; $this->imagePath = $this->getFullPath(true); $this->fromSharedDirectory = true; } } if ( $this->fileExists ) { $magic=& wfGetMimeMagic(); $this->mime = $magic->guessMimeType($this->imagePath,true); $this->type = $magic->getMediaType($this->imagePath,$this->mime); # Get size in bytes $this->size = filesize( $this->imagePath ); $magic=& wfGetMimeMagic(); # Height and width wfSuppressWarnings(); if( $this->mime == 'image/svg' ) { $gis = wfGetSVGsize( $this->imagePath ); } elseif( $this->mime == 'image/vnd.djvu' ) { $deja = new DjVuImage( $this->imagePath ); $gis = $deja->getImageSize(); } elseif ( !$magic->isPHPImageType( $this->mime ) ) { # Don't try to get the width and height of sound and video files, that's bad for performance $gis = false; } else { $gis = getimagesize( $this->imagePath ); } wfRestoreWarnings(); wfDebug(__METHOD__.': '.$this->imagePath." loaded, ".$this->size." bytes, ".$this->mime.".\n"); } else { $this->mime = NULL; $this->type = MEDIATYPE_UNKNOWN; wfDebug(__METHOD__.': '.$this->imagePath." NOT FOUND!\n"); } if( $gis ) { $this->width = $gis[0]; $this->height = $gis[1]; } else { $this->width = 0; $this->height = 0; } #NOTE: $gis[2] contains a code for the image type. This is no longer used. #NOTE: we have to set this flag early to avoid load() to be called # be some of the functions below. This may lead to recursion or other bad things! # as ther's only one thread of execution, this should be safe anyway. $this->dataLoaded = true; $this->metadata = serialize( $this->retrieveExifData( $this->imagePath ) ); if ( isset( $gis['bits'] ) ) $this->bits = $gis['bits']; else $this->bits = 0; wfProfileOut( __METHOD__ ); } /** * Load image metadata from the DB */ function loadFromDB() { global $wgUseSharedUploads, $wgSharedUploadDBname, $wgSharedUploadDBprefix, $wgContLang; wfProfileIn( __METHOD__ ); $dbr =& wfGetDB( DB_SLAVE ); $this->checkDBSchema($dbr); $row = $dbr->selectRow( 'image', array( 'img_size', 'img_width', 'img_height', 'img_bits', 'img_media_type', 'img_major_mime', 'img_minor_mime', 'img_metadata' ), array( 'img_name' => $this->name ), __METHOD__ ); if ( $row ) { $this->fromSharedDirectory = false; $this->fileExists = true; $this->loadFromRow( $row ); $this->imagePath = $this->getFullPath(); // Check for rows from a previous schema, quietly upgrade them if ( is_null($this->type) ) { $this->upgradeRow(); } } elseif ( $wgUseSharedUploads && $wgSharedUploadDBname ) { # In case we're on a wgCapitalLinks=false wiki, we # capitalize the first letter of the filename before # looking it up in the shared repository. $name = $wgContLang->ucfirst($this->name); $dbc =& wfGetDB( DB_SLAVE, 'commons' ); $row = $dbc->selectRow( "`$wgSharedUploadDBname`.{$wgSharedUploadDBprefix}image", array( 'img_size', 'img_width', 'img_height', 'img_bits', 'img_media_type', 'img_major_mime', 'img_minor_mime', 'img_metadata' ), array( 'img_name' => $name ), __METHOD__ ); if ( $row ) { $this->fromSharedDirectory = true; $this->fileExists = true; $this->imagePath = $this->getFullPath(true); $this->name = $name; $this->loadFromRow( $row ); // Check for rows from a previous schema, quietly upgrade them if ( is_null($this->type) ) { $this->upgradeRow(); } } } if ( !$row ) { $this->size = 0; $this->width = 0; $this->height = 0; $this->bits = 0; $this->type = 0; $this->fileExists = false; $this->fromSharedDirectory = false; $this->metadata = serialize ( array() ) ; } # Unconditionally set loaded=true, we don't want the accessors constantly rechecking $this->dataLoaded = true; wfProfileOut( __METHOD__ ); } /* * Load image metadata from a DB result row */ function loadFromRow( &$row ) { $this->size = $row->img_size; $this->width = $row->img_width; $this->height = $row->img_height; $this->bits = $row->img_bits; $this->type = $row->img_media_type; $major= $row->img_major_mime; $minor= $row->img_minor_mime; if (!$major) $this->mime = "unknown/unknown"; else { if (!$minor) $minor= "unknown"; $this->mime = $major.'/'.$minor; } $this->metadata = $row->img_metadata; if ( $this->metadata == "" ) $this->metadata = serialize ( array() ) ; $this->dataLoaded = true; } /** * Load image metadata from cache or DB, unless already loaded */ function load() { global $wgSharedUploadDBname, $wgUseSharedUploads; if ( !$this->dataLoaded ) { if ( !$this->loadFromCache() ) { $this->loadFromDB(); if ( !$wgSharedUploadDBname && $wgUseSharedUploads ) { $this->loadFromFile(); } elseif ( $this->fileExists ) { $this->saveToCache(); } } $this->dataLoaded = true; } } /** * Metadata was loaded from the database, but the row had a marker indicating it needs to be * upgraded from the 1.4 schema, which had no width, height, bits or type. Upgrade the row. */ function upgradeRow() { global $wgDBname, $wgSharedUploadDBname; wfProfileIn( __METHOD__ ); $this->loadFromFile(); if ( $this->fromSharedDirectory ) { if ( !$wgSharedUploadDBname ) { wfProfileOut( __METHOD__ ); return; } // Write to the other DB using selectDB, not database selectors // This avoids breaking replication in MySQL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -