* @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
+/**
+ * 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
+ */
if ($wgShowEXIF)
require_once('Exif.php');
+/**
+ * Bump this number when serialized cache records may be incompatible.
+ */
+define( 'MW_IMAGE_VERSION', 1 );
/**
* Class to represent an image
$mime, # MIME type, determined by MimeMagic::guessMimeType
$size, # Size in bytes (loadFromXxx)
$metadata, # Metadata
- $exif, # The Exif class
$dataLoaded; # Whether or not all this has been loaded from the database (loadFromXxx)
function Image( $title ) {
global $wgShowEXIF;
+ if( !is_object( $title ) ) {
+ wfDebugDieBacktrace( 'Image constructor given bogus title.' );
+ }
$this->title =& $title;
$this->name = $title->getDBkey();
$this->metadata = serialize ( array() ) ;
$this->historyLine = 0;
$this->dataLoaded = false;
-
- if ($wgShowEXIF)
- $this->exif = new Exif;
}
/**
$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['width'])
+ 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']) {
# in shared repository has not changed
if ( isset( $keys[1] ) ) {
$commonsCachedValues = $wgMemc->get( $keys[1] );
- if (!empty($commonsCachedValues) && is_array($commonsCachedValues) && isset($commonsCachedValues['mime'])) {
+ 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->imagePath = $this->getFullPath(true);
}
}
- }
- else {
+ } else {
+ wfDebug( "Pulling image metadata from local cache\n" );
$this->name = $cachedValues['name'];
$this->imagePath = $cachedValues['imagePath'];
$this->fileExists = $cachedValues['fileExists'];
function saveToCache() {
global $wgMemc;
$this->load();
- // We can't cache metadata for non-existent files, because if the file later appears
- // in commons, the local keys won't be purged.
+ $keys = $this->getCacheKeys();
if ( $this->fileExists ) {
- $keys = $this->getCacheKeys();
-
- $cachedValues = array('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);
+ // 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 );
+ } else {
+ // However we should clear them, so they aren't leftover
+ // if we've deleted the file.
+ $wgMemc->delete( $keys[0] );
}
}
* Load image metadata from the DB
*/
function loadFromDB() {
- global $wgUseSharedUploads, $wgSharedUploadDBname, $wgLang;
+ global $wgUseSharedUploads, $wgSharedUploadDBname, $wgSharedUploadDBprefix, $wgLang;
$fname = 'Image::loadFromDB';
wfProfileIn( $fname );
# looking it up in the shared repository.
$name = $wgLang->ucfirst($this->name);
- $row = $dbr->selectRow( "`$wgSharedUploadDBname`.image",
+ $row = $dbr->selectRow( "`$wgSharedUploadDBname`.{$wgSharedUploadDBprefix}image",
array(
'img_size', 'img_width', 'img_height', 'img_bits',
'img_media_type', 'img_major_mime', 'img_minor_mime', 'img_metadata' ),
* This is currently synonymous to canRender(), but this could be
* extended to also allow inline display of other media,
* like flash animations or videos. If you do so, please keep in mind that
- * that could be a scurity risc.
+ * that could be a security risk.
*/
function allowInlineDisplay() {
return $this->canRender();
}
/**
- * Determines if this media file is in a format that is unlikely to contain viruses
- * or malicious content. It uses the global $wgTrustedMediaFormats list to determine
- * if the file is safe.
+ * Determines if this media file is in a format that is unlikely to
+ * contain viruses or malicious content. It uses the global
+ * $wgTrustedMediaFormats list to determine if the file is safe.
*
* This is used to show a warning on the description page of non-safe files.
* It may also be used to disallow direct [[media:...]] links to such files.
return false;
}
- /** Returns true if the file is flagegd as trusted. Files flagged that way can be
- * linked to directly, even if that is not allowed for this type of file normally.
+ /** Returns true if the file is flagegd as trusted. Files flagged that way
+ * can be linked to directly, even if that is not allowed for this type of
+ * file normally.
*
- * This is a dummy function right now and always returns false. It could be implemented
- * to extract a flag from the database. The trusted flag could be set on upload, if the
- * user has sufficient privileges, to bypass script- and html-filters. It may even be
- * coupeled with cryptographics signatures or such.
+ * This is a dummy function right now and always returns false. It could be
+ * implemented to extract a flag from the database. The trusted flag could be
+ * set on upload, if the user has sufficient privileges, to bypass script-
+ * and html-filters. It may even be coupeled with cryptographics signatures
+ * or such.
*/
function isTrustedFile() {
#this could be implemented to check a flag in the databas,
*
* @param string $name Name of the image, without the leading "Image:"
* @param boolean $fromSharedDirectory Should this be in $wgSharedUploadPath?
+ * @return string URL of $name image
* @access public
* @static
*/
/**
* Returns true if the image file exists on disk.
- *
+ * @return boolean Whether image file exist on disk.
* @access public
*/
function exists() {
}
/**
- *
+ * @todo document
* @access private
*/
function thumbUrl( $width, $subdir='thumb') {
# First find out what kind of file this is, and select the correct
# input routine for this.
- $truecolor = false;
+ $typemap = array(
+ 'image/gif' => array( 'imagecreatefromgif', 'palette', 'imagegif' ),
+ 'image/jpeg' => array( 'imagecreatefromjpeg', 'truecolor', array( &$this, 'imageJpegWrapper' ) ),
+ 'image/png' => array( 'imagecreatefrompng', 'bits', 'imagepng' ),
+ 'image/vnd.wap.wmbp' => array( 'imagecreatefromwbmp', 'palette', 'imagewbmp' ),
+ 'image/xbm' => array( 'imagecreatefromxbm', 'palette', 'imagexbm' ),
+ );
+ if( !isset( $typemap[$this->mime] ) ) {
+ $err = 'Image type not supported';
+ wfDebug( "$err\n" );
+ return $err;
+ }
+ list( $loader, $colorStyle, $saveType ) = $typemap[$this->mime];
- switch( $this->type ) {
- case 1: # GIF
- $src_image = imagecreatefromgif( $this->imagePath );
- break;
- case 2: # JPG
- $src_image = imagecreatefromjpeg( $this->imagePath );
- $truecolor = true;
- break;
- case 3: # PNG
- $src_image = imagecreatefrompng( $this->imagePath );
- $truecolor = ( $this->bits > 8 );
- break;
- case 15: # WBMP for WML
- $src_image = imagecreatefromwbmp( $this->imagePath );
- break;
- case 16: # XBM
- $src_image = imagecreatefromxbm( $this->imagePath );
- break;
- default:
- return 'Image type not supported';
- break;
+ if( !function_exists( $loader ) ) {
+ $err = "Incomplete GD library configuration: missing function $loader";
+ wfDebug( "$err\n" );
+ return $err;
}
+ if( $colorStyle == 'palette' ) {
+ $truecolor = false;
+ } elseif( $colorStyle == 'truecolor' ) {
+ $truecolor = true;
+ } elseif( $colorStyle == 'bits' ) {
+ $truecolor = ( $this->bits > 8 );
+ }
+
+ $src_image = call_user_func( $loader, $this->imagePath );
if ( $truecolor ) {
$dst_image = imagecreatetruecolor( $width, $height );
} else {
imagecopyresampled( $dst_image, $src_image,
0,0,0,0,
$width, $height, $this->width, $this->height );
- switch( $this->type ) {
- case 1: # GIF
- case 3: # PNG
- case 15: # WBMP
- case 16: # XBM
- imagepng( $dst_image, $thumbPath );
- break;
- case 2: # JPEG
- imageinterlace( $dst_image );
- imagejpeg( $dst_image, $thumbPath, 95 );
- break;
- default:
- break;
- }
+ call_user_func( $saveType, $dst_image, $thumbPath );
imagedestroy( $dst_image );
imagedestroy( $src_image );
}
}
}
+ function imageJpegWrapper( $dst_image, $thumbPath ) {
+ imageinterlace( $dst_image );
+ imagejpeg( $dst_image, $thumbPath, 95 );
+ }
+
/**
* Get all thumbnail names previously generated for this image
*/
array(
'img_name' => $this->name,
'img_size'=> $this->size,
- 'img_width' => $this->width,
- 'img_height' => $this->height,
+ 'img_width' => IntVal( $this->width ),
+ 'img_height' => IntVal( $this->height ),
'img_bits' => $this->bits,
'img_media_type' => $this->type,
'img_major_mime' => $major,
$dbw->update( 'image',
array( /* SET */
'img_size' => $this->size,
- 'img_width' => $this->width,
- 'img_height' => $this->height,
+ 'img_width' => intval( $this->width ),
+ 'img_height' => intval( $this->height ),
'img_bits' => $this->bits,
'img_media_type' => $this->type,
'img_major_mime' => $major,
function retrieveExifData () {
if ( $this->getMimeType() !== "image/jpeg" ) return array ();
- $exif = exif_read_data( $this->imagePath );
- foreach($exif as $k => $v) {
- if ( !in_array($k, array_keys($this->exif->mFlatExif)) ) {
- wfDebug( "Image::retrieveExifData: '$k' is not a valid Exif tag (type: '" . gettype($v) . "'; data: '$v')\n");
- unset($exif[$k]);
- }
- }
-
- foreach($exif as $k => $v) {
- if ( !$this->exif->validate($k, $v) ) {
- wfDebug( "Image::retrieveExifData: '$k' contained invalid data (type: '" . gettype($v) . "'; data: '$v')\n");
- unset($exif[$k]);
- }
- }
- return $exif;
+ $exif = new Exif( $this->imagePath );
+ return $exif->getFilteredData();
}
function getExifData () {
$ret = unserialize ( $this->metadata );
$oldver = isset( $ret['MEDIAWIKI_EXIF_VERSION'] ) ? $ret['MEDIAWIKI_EXIF_VERSION'] : 0;
- $newver = $this->exif->version();
+ $newver = Exif::version();
if ( !count( $ret ) || $purge || $oldver != $newver ) {
$this->updateExifData( $newver );
}
if ( isset( $ret['MEDIAWIKI_EXIF_VERSION'] ) )
unset( $ret['MEDIAWIKI_EXIF_VERSION'] );
-
- foreach($ret as $k => $v) {
- $ret[$k] = $this->exif->format($k, $v);
- }
-
- return $ret;
+ $format = new FormatExif( $ret );
+ return $format->getFormattedData();
}
function updateExifData( $version ) {