Merge "Deleting a page and then immediately create-protecting it caused a PHP Fatal...
[lhc/web/wiklou.git] / includes / media / Exif.php
index d7c45d3..bb5e344 100644 (file)
  * @ingroup Media
  */
 class Exif {
+       /** An 8-bit (1-byte) unsigned integer. */
+       const BYTE = 1;
 
-       const BYTE = 1; //!< An 8-bit (1-byte) unsigned integer.
-       const ASCII = 2; //!< An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated with NULL.
-       const SHORT = 3; //!< A 16-bit (2-byte) unsigned integer.
-       const LONG = 4; //!< A 32-bit (4-byte) unsigned integer.
-       const RATIONAL = 5; //!< Two LONGs. The first LONG is the numerator and the second LONG expresses the denominator
-       const SHORT_OR_LONG = 6; //!< A 16-bit (2-byte) or 32-bit (4-byte) unsigned integer.
-       const UNDEFINED = 7; //!< An 8-bit byte that can take any value depending on the field definition
-       const SLONG = 9; //!< A 32-bit (4-byte) signed integer (2's complement notation),
-       const SRATIONAL = 10; //!< Two SLONGs. The first SLONG is the numerator and the second SLONG is the denominator.
-       const IGNORE = -1; // A fake value for things we don't want or don't support.
-
-       //@{
-       /* @var array
-        * @private
+       /** An 8-bit byte containing one 7-bit ASCII code.
+        *  The final byte is terminated with NULL.
         */
+       const ASCII = 2;
 
-       /**
-        * Exif tags grouped by category, the tagname itself is the key and the type
-        * is the value, in the case of more than one possible value type they are
-        * separated by commas.
-        */
-       var $mExifTags;
+       /** A 16-bit (2-byte) unsigned integer. */
+       const SHORT = 3;
 
-       /**
-        * The raw Exif data returned by exif_read_data()
-        */
-       var $mRawExifData;
+       /** A 32-bit (4-byte) unsigned integer. */
+       const LONG = 4;
 
-       /**
-        * A Filtered version of $mRawExifData that has been pruned of invalid
-        * tags and tags that contain content they shouldn't contain according
-        * to the Exif specification
+       /** Two LONGs. The first LONG is the numerator and the second LONG expresses
+        *  the denominator
         */
-       var $mFilteredExifData;
+       const RATIONAL = 5;
 
-       /**
-        * Filtered and formatted Exif data, see FormatMetadata::getFormattedData()
-        */
-       var $mFormattedExifData;
+       /** A 16-bit (2-byte) or 32-bit (4-byte) unsigned integer. */
+       const SHORT_OR_LONG = 6;
 
-       //@}
+       /** An 8-bit byte that can take any value depending on the field definition */
+       const UNDEFINED = 7;
 
-       //@{
-       /* @var string
-        * @private
-        */
+       /** A 32-bit (4-byte) signed integer (2's complement notation), */
+       const SLONG = 9;
 
-       /**
-        * The file being processed
+       /** Two SLONGs. The first SLONG is the numerator and the second SLONG is
+        *  the denominator.
         */
-       var $file;
+       const SRATIONAL = 10;
 
-       /**
-        * The basename of the file being processed
+       /** A fake value for things we don't want or don't support. */
+       const IGNORE = -1;
+
+       /** @var array Exif tags grouped by category, the tagname itself is the key
+        *    and the type is the value, in the case of more than one possible value
+        *    type they are separated by commas.
         */
-       var $basename;
+       private $mExifTags;
 
-       /**
-        * The private log to log to, e.g. 'exif'
+       /** @var array The raw Exif data returned by exif_read_data() */
+       private $mRawExifData;
+
+       /** @var array A Filtered version of $mRawExifData that has been pruned
+        *    of invalid tags and tags that contain content they shouldn't contain
+        *    according to the Exif specification
         */
-       var $log = false;
+       private $mFilteredExifData;
 
-       /**
-        * The byte order of the file. Needed because php's
-        * extension doesn't fully process some obscure props.
+       /** @var array Filtered and formatted Exif data, see FormatMetadata::getFormattedData() */
+       private $mFormattedExifData;
+
+       /** @var string The file being processed */
+       private $file;
+
+       /** @var string The basename of the file being processed */
+       private $basename;
+
+       /** @var string The private log to log to, e.g. 'exif' */
+       private $log = false;
+
+       /** @var string The byte order of the file. Needed because php's extension
+        *    doesn't fully process some obscure props.
         */
        private $byteOrder;
-       //@}
 
        /**
         * Constructor
         *
-        * @param string $file filename.
-        * @param string $byteOrder Type of byte ordering either 'BE' (Big Endian) or 'LE' (Little Endian). Default ''.
+        * @param string $file Filename.
+        * @param string $byteOrder Type of byte ordering either 'BE' (Big Endian)
+        *   or 'LE' (Little Endian). Default ''.
         * @throws MWException
         * @todo FIXME: The following are broke:
-        * SubjectArea. Need to test the more obscure tags.
-        *
-        * DigitalZoomRatio = 0/0 is rejected. need to determine if that's valid.
-        * possibly should treat 0/0 = 0. need to read exif spec on that.
+        *   SubjectArea. Need to test the more obscure tags.
+        *   DigitalZoomRatio = 0/0 is rejected. need to determine if that's valid.
+        *   Possibly should treat 0/0 = 0. need to read exif spec on that.
         */
        function __construct( $file, $byteOrder = '' ) {
                /**
-                * Page numbers here refer to pages in the EXIF 2.2 standard
+                * Page numbers here refer to pages in the Exif 2.2 standard
                 *
                 * Note, Exif::UNDEFINED is treated as a string, not as an array of bytes
                 * so don't put a count parameter for any UNDEFINED values.
@@ -125,122 +123,123 @@ class Exif {
                        # TIFF Rev. 6.0 Attribute Information (p22)
                        'IFD0' => array(
                                # Tags relating to image structure
-                               'ImageWidth' => Exif::SHORT_OR_LONG,            # Image width
-                               'ImageLength' => Exif::SHORT_OR_LONG,           # Image height
-                               'BitsPerSample' => array( Exif::SHORT, 3 ),             # Number of bits per component
+                               'ImageWidth' => Exif::SHORT_OR_LONG, # Image width
+                               'ImageLength' => Exif::SHORT_OR_LONG, # Image height
+                               'BitsPerSample' => array( Exif::SHORT, 3 ), # Number of bits per component
                                # "When a primary image is JPEG compressed, this designation is not"
                                # "necessary and is omitted." (p23)
-                               'Compression' => Exif::SHORT,                           # Compression scheme #p23
-                               'PhotometricInterpretation' => Exif::SHORT,             # Pixel composition #p23
-                               'Orientation' => Exif::SHORT,                           # Orientation of image #p24
-                               'SamplesPerPixel' => Exif::SHORT,                       # Number of components
-                               'PlanarConfiguration' => Exif::SHORT,                   # Image data arrangement #p24
-                               'YCbCrSubSampling' => array( Exif::SHORT, 2 ),          # Subsampling ratio of Y to C #p24
-                               'YCbCrPositioning' => Exif::SHORT,                      # Y and C positioning #p24-25
-                               'XResolution' => Exif::RATIONAL,                        # Image resolution in width direction
-                               'YResolution' => Exif::RATIONAL,                        # Image resolution in height direction
-                               'ResolutionUnit' => Exif::SHORT,                        # Unit of X and Y resolution #(p26)
+                               'Compression' => Exif::SHORT, # Compression scheme #p23
+                               'PhotometricInterpretation' => Exif::SHORT, # Pixel composition #p23
+                               'Orientation' => Exif::SHORT, # Orientation of image #p24
+                               'SamplesPerPixel' => Exif::SHORT, # Number of components
+                               'PlanarConfiguration' => Exif::SHORT, # Image data arrangement #p24
+                               'YCbCrSubSampling' => array( Exif::SHORT, 2 ), # Subsampling ratio of Y to C #p24
+                               'YCbCrPositioning' => Exif::SHORT, # Y and C positioning #p24-25
+                               'XResolution' => Exif::RATIONAL, # Image resolution in width direction
+                               'YResolution' => Exif::RATIONAL, # Image resolution in height direction
+                               'ResolutionUnit' => Exif::SHORT, # Unit of X and Y resolution #(p26)
 
                                # Tags relating to recording offset
-                               'StripOffsets' => Exif::SHORT_OR_LONG,                  # Image data location
-                               'RowsPerStrip' => Exif::SHORT_OR_LONG,                  # Number of rows per strip
-                               'StripByteCounts' => Exif::SHORT_OR_LONG,               # Bytes per compressed strip
-                               'JPEGInterchangeFormat' => Exif::SHORT_OR_LONG,         # Offset to JPEG SOI
-                               'JPEGInterchangeFormatLength' => Exif::SHORT_OR_LONG,   # Bytes of JPEG data
+                               'StripOffsets' => Exif::SHORT_OR_LONG, # Image data location
+                               'RowsPerStrip' => Exif::SHORT_OR_LONG, # Number of rows per strip
+                               'StripByteCounts' => Exif::SHORT_OR_LONG, # Bytes per compressed strip
+                               'JPEGInterchangeFormat' => Exif::SHORT_OR_LONG, # Offset to JPEG SOI
+                               'JPEGInterchangeFormatLength' => Exif::SHORT_OR_LONG, # Bytes of JPEG data
 
                                # Tags relating to image data characteristics
-                               'TransferFunction' => Exif::IGNORE,                     # Transfer function
-                               'WhitePoint' => array( Exif::RATIONAL, 2 ),             # White point chromaticity
-                               'PrimaryChromaticities' => array( Exif::RATIONAL, 6 ),  # Chromaticities of primarities
-                               'YCbCrCoefficients' => array( Exif::RATIONAL, 3 ),      # Color space transformation matrix coefficients #p27
-                               'ReferenceBlackWhite' => array( Exif::RATIONAL, 6 ),    # Pair of black and white reference values
+                               'TransferFunction' => Exif::IGNORE, # Transfer function
+                               'WhitePoint' => array( Exif::RATIONAL, 2 ), # White point chromaticity
+                               'PrimaryChromaticities' => array( Exif::RATIONAL, 6 ), # Chromaticities of primarities
+                               # Color space transformation matrix coefficients #p27
+                               'YCbCrCoefficients' => array( Exif::RATIONAL, 3 ),
+                               'ReferenceBlackWhite' => array( Exif::RATIONAL, 6 ), # Pair of black and white reference values
 
                                # Other tags
-                               'DateTime' => Exif::ASCII,                              # File change date and time
-                               'ImageDescription' => Exif::ASCII,                      # Image title
-                               'Make' => Exif::ASCII,                                  # Image input equipment manufacturer
-                               'Model' => Exif::ASCII,                                 # Image input equipment model
-                               'Software' => Exif::ASCII,                              # Software used
-                               'Artist' => Exif::ASCII,                                # Person who created the image
-                               'Copyright' => Exif::ASCII,                             # Copyright holder
+                               'DateTime' => Exif::ASCII, # File change date and time
+                               'ImageDescription' => Exif::ASCII, # Image title
+                               'Make' => Exif::ASCII, # Image input equipment manufacturer
+                               'Model' => Exif::ASCII, # Image input equipment model
+                               'Software' => Exif::ASCII, # Software used
+                               'Artist' => Exif::ASCII, # Person who created the image
+                               'Copyright' => Exif::ASCII, # Copyright holder
                        ),
 
                        # Exif IFD Attribute Information (p30-31)
                        'EXIF' => array(
-                               # TODO: NOTE: Nonexistence of this field is taken to mean nonconformance
-                               # to the EXIF 2.1 AND 2.2 standards
-                               'ExifVersion' => Exif::UNDEFINED,                       # Exif version
-                               'FlashPixVersion' => Exif::UNDEFINED,                   # Supported Flashpix version #p32
+                               # @todo NOTE: Nonexistence of this field is taken to mean nonconformance
+                               # to the Exif 2.1 AND 2.2 standards
+                               'ExifVersion' => Exif::UNDEFINED, # Exif version
+                               'FlashPixVersion' => Exif::UNDEFINED, # Supported Flashpix version #p32
 
                                # Tags relating to Image Data Characteristics
-                               'ColorSpace' => Exif::SHORT,                            # Color space information #p32
+                               'ColorSpace' => Exif::SHORT, # Color space information #p32
 
                                # Tags relating to image configuration
-                               'ComponentsConfiguration' => Exif::UNDEFINED,                   # Meaning of each component #p33
-                               'CompressedBitsPerPixel' => Exif::RATIONAL,                     # Image compression mode
-                               'PixelYDimension' => Exif::SHORT_OR_LONG,               # Valid image width
-                               'PixelXDimension' => Exif::SHORT_OR_LONG,               # Valid image height
+                               'ComponentsConfiguration' => Exif::UNDEFINED, # Meaning of each component #p33
+                               'CompressedBitsPerPixel' => Exif::RATIONAL, # Image compression mode
+                               'PixelYDimension' => Exif::SHORT_OR_LONG, # Valid image width
+                               'PixelXDimension' => Exif::SHORT_OR_LONG, # Valid image height
 
                                # Tags relating to related user information
-                               'MakerNote' => Exif::IGNORE,                            # Manufacturer notes
-                               'UserComment' => Exif::UNDEFINED,                       # User comments #p34
+                               'MakerNote' => Exif::IGNORE, # Manufacturer notes
+                               'UserComment' => Exif::UNDEFINED, # User comments #p34
 
                                # Tags relating to related file information
-                               'RelatedSoundFile' => Exif::ASCII,                      # Related audio file
+                               'RelatedSoundFile' => Exif::ASCII, # Related audio file
 
                                # Tags relating to date and time
-                               'DateTimeOriginal' => Exif::ASCII,                      # Date and time of original data generation #p36
-                               'DateTimeDigitized' => Exif::ASCII,                     # Date and time of original data generation
-                               'SubSecTime' => Exif::ASCII,                            # DateTime subseconds
-                               'SubSecTimeOriginal' => Exif::ASCII,                    # DateTimeOriginal subseconds
-                               'SubSecTimeDigitized' => Exif::ASCII,                   # DateTimeDigitized subseconds
+                               'DateTimeOriginal' => Exif::ASCII, # Date and time of original data generation #p36
+                               'DateTimeDigitized' => Exif::ASCII, # Date and time of original data generation
+                               'SubSecTime' => Exif::ASCII, # DateTime subseconds
+                               'SubSecTimeOriginal' => Exif::ASCII, # DateTimeOriginal subseconds
+                               'SubSecTimeDigitized' => Exif::ASCII, # DateTimeDigitized subseconds
 
                                # Tags relating to picture-taking conditions (p31)
-                               'ExposureTime' => Exif::RATIONAL,                       # Exposure time
-                               'FNumber' => Exif::RATIONAL,                            # F Number
-                               'ExposureProgram' => Exif::SHORT,                       # Exposure Program #p38
-                               'SpectralSensitivity' => Exif::ASCII,                   # Spectral sensitivity
-                               'ISOSpeedRatings' => Exif::SHORT,                       # ISO speed rating
+                               'ExposureTime' => Exif::RATIONAL, # Exposure time
+                               'FNumber' => Exif::RATIONAL, # F Number
+                               'ExposureProgram' => Exif::SHORT, # Exposure Program #p38
+                               'SpectralSensitivity' => Exif::ASCII, # Spectral sensitivity
+                               'ISOSpeedRatings' => Exif::SHORT, # ISO speed rating
                                'OECF' => Exif::IGNORE,
                                # Optoelectronic conversion factor. Note: We don't have support for this atm.
-                               'ShutterSpeedValue' => Exif::SRATIONAL,                 # Shutter speed
-                               'ApertureValue' => Exif::RATIONAL,                      # Aperture
-                               'BrightnessValue' => Exif::SRATIONAL,                   # Brightness
-                               'ExposureBiasValue' => Exif::SRATIONAL,                 # Exposure bias
-                               'MaxApertureValue' => Exif::RATIONAL,                   # Maximum land aperture
-                               'SubjectDistance' => Exif::RATIONAL,                    # Subject distance
-                               'MeteringMode' => Exif::SHORT,                          # Metering mode #p40
-                               'LightSource' => Exif::SHORT,                           # Light source #p40-41
-                               'Flash' => Exif::SHORT,                                 # Flash #p41-42
-                               'FocalLength' => Exif::RATIONAL,                        # Lens focal length
-                               'SubjectArea' => array( Exif::SHORT, 4 ),               # Subject area
-                               'FlashEnergy' => Exif::RATIONAL,                        # Flash energy
-                               'SpatialFrequencyResponse' => Exif::IGNORE,             # Spatial frequency response. Not supported atm.
-                               'FocalPlaneXResolution' => Exif::RATIONAL,              # Focal plane X resolution
-                               'FocalPlaneYResolution' => Exif::RATIONAL,              # Focal plane Y resolution
-                               'FocalPlaneResolutionUnit' => Exif::SHORT,              # Focal plane resolution unit #p46
-                               'SubjectLocation' => array( Exif::SHORT, 2 ),           # Subject location
-                               'ExposureIndex' => Exif::RATIONAL,                      # Exposure index
-                               'SensingMethod' => Exif::SHORT,                         # Sensing method #p46
-                               'FileSource' => Exif::UNDEFINED,                        # File source #p47
-                               'SceneType' => Exif::UNDEFINED,                         # Scene type #p47
-                               'CFAPattern' => Exif::IGNORE,                           # CFA pattern. not supported atm.
-                               'CustomRendered' => Exif::SHORT,                        # Custom image processing #p48
-                               'ExposureMode' => Exif::SHORT,                          # Exposure mode #p48
-                               'WhiteBalance' => Exif::SHORT,                          # White Balance #p49
-                               'DigitalZoomRatio' => Exif::RATIONAL,                   # Digital zoom ration
-                               'FocalLengthIn35mmFilm' => Exif::SHORT,                 # Focal length in 35 mm film
-                               'SceneCaptureType' => Exif::SHORT,                      # Scene capture type #p49
-                               'GainControl' => Exif::SHORT,                           # Scene control #p49-50
-                               'Contrast' => Exif::SHORT,                              # Contrast #p50
-                               'Saturation' => Exif::SHORT,                            # Saturation #p50
-                               'Sharpness' => Exif::SHORT,                             # Sharpness #p50
+                               'ShutterSpeedValue' => Exif::SRATIONAL, # Shutter speed
+                               'ApertureValue' => Exif::RATIONAL, # Aperture
+                               'BrightnessValue' => Exif::SRATIONAL, # Brightness
+                               'ExposureBiasValue' => Exif::SRATIONAL, # Exposure bias
+                               'MaxApertureValue' => Exif::RATIONAL, # Maximum land aperture
+                               'SubjectDistance' => Exif::RATIONAL, # Subject distance
+                               'MeteringMode' => Exif::SHORT, # Metering mode #p40
+                               'LightSource' => Exif::SHORT, # Light source #p40-41
+                               'Flash' => Exif::SHORT, # Flash #p41-42
+                               'FocalLength' => Exif::RATIONAL, # Lens focal length
+                               'SubjectArea' => array( Exif::SHORT, 4 ), # Subject area
+                               'FlashEnergy' => Exif::RATIONAL, # Flash energy
+                               'SpatialFrequencyResponse' => Exif::IGNORE, # Spatial frequency response. Not supported atm.
+                               'FocalPlaneXResolution' => Exif::RATIONAL, # Focal plane X resolution
+                               'FocalPlaneYResolution' => Exif::RATIONAL, # Focal plane Y resolution
+                               'FocalPlaneResolutionUnit' => Exif::SHORT, # Focal plane resolution unit #p46
+                               'SubjectLocation' => array( Exif::SHORT, 2 ), # Subject location
+                               'ExposureIndex' => Exif::RATIONAL, # Exposure index
+                               'SensingMethod' => Exif::SHORT, # Sensing method #p46
+                               'FileSource' => Exif::UNDEFINED, # File source #p47
+                               'SceneType' => Exif::UNDEFINED, # Scene type #p47
+                               'CFAPattern' => Exif::IGNORE, # CFA pattern. not supported atm.
+                               'CustomRendered' => Exif::SHORT, # Custom image processing #p48
+                               'ExposureMode' => Exif::SHORT, # Exposure mode #p48
+                               'WhiteBalance' => Exif::SHORT, # White Balance #p49
+                               'DigitalZoomRatio' => Exif::RATIONAL, # Digital zoom ration
+                               'FocalLengthIn35mmFilm' => Exif::SHORT, # Focal length in 35 mm film
+                               'SceneCaptureType' => Exif::SHORT, # Scene capture type #p49
+                               'GainControl' => Exif::SHORT, # Scene control #p49-50
+                               'Contrast' => Exif::SHORT, # Contrast #p50
+                               'Saturation' => Exif::SHORT, # Saturation #p50
+                               'Sharpness' => Exif::SHORT, # Sharpness #p50
                                'DeviceSettingDescription' => Exif::IGNORE,
                                # Device settings description. This could maybe be supported. Need to find an
                                # example file that uses this to see if it has stuff of interest in it.
-                               'SubjectDistanceRange' => Exif::SHORT,                  # Subject distance range #p51
+                               'SubjectDistanceRange' => Exif::SHORT, # Subject distance range #p51
 
-                               'ImageUniqueID' => Exif::ASCII,                         # Unique image ID
+                               'ImageUniqueID' => Exif::ASCII, # Unique image ID
                        ),
 
                        # GPS Attribute Information (p52)
@@ -248,38 +247,38 @@ class Exif {
                                'GPSVersion' => Exif::UNDEFINED,
                                # Should be an array of 4 Exif::BYTE's. However php treats it as an undefined
                                # Note exif standard calls this GPSVersionID, but php doesn't like the id suffix
-                               'GPSLatitudeRef' => Exif::ASCII,                        # North or South Latitude #p52-53
-                               'GPSLatitude' => array( Exif::RATIONAL, 3 ),            # Latitude
-                               'GPSLongitudeRef' => Exif::ASCII,                       # East or West Longitude #p53
-                               'GPSLongitude' => array( Exif::RATIONAL, 3 ),           # Longitude
+                               'GPSLatitudeRef' => Exif::ASCII, # North or South Latitude #p52-53
+                               'GPSLatitude' => array( Exif::RATIONAL, 3 ), # Latitude
+                               'GPSLongitudeRef' => Exif::ASCII, # East or West Longitude #p53
+                               'GPSLongitude' => array( Exif::RATIONAL, 3 ), # Longitude
                                'GPSAltitudeRef' => Exif::UNDEFINED,
                                # Altitude reference. Note, the exif standard says this should be an EXIF::Byte,
                                # but php seems to disagree.
-                               'GPSAltitude' => Exif::RATIONAL,                        # Altitude
-                               'GPSTimeStamp' => array( Exif::RATIONAL, 3 ),           # GPS time (atomic clock)
-                               'GPSSatellites' => Exif::ASCII,                         # Satellites used for measurement
-                               'GPSStatus' => Exif::ASCII,                             # Receiver status #p54
-                               'GPSMeasureMode' => Exif::ASCII,                        # Measurement mode #p54-55
-                               'GPSDOP' => Exif::RATIONAL,                             # Measurement precision
-                               'GPSSpeedRef' => Exif::ASCII,                           # Speed unit #p55
-                               'GPSSpeed' => Exif::RATIONAL,                           # Speed of GPS receiver
-                               'GPSTrackRef' => Exif::ASCII,                           # Reference for direction of movement #p55
-                               'GPSTrack' => Exif::RATIONAL,                           # Direction of movement
-                               'GPSImgDirectionRef' => Exif::ASCII,                    # Reference for direction of image #p56
-                               'GPSImgDirection' => Exif::RATIONAL,                    # Direction of image
-                               'GPSMapDatum' => Exif::ASCII,                           # Geodetic survey data used
-                               'GPSDestLatitudeRef' => Exif::ASCII,                    # Reference for latitude of destination #p56
-                               'GPSDestLatitude' => array( Exif::RATIONAL, 3 ),        # Latitude destination
-                               'GPSDestLongitudeRef' => Exif::ASCII,                   # Reference for longitude of destination #p57
-                               'GPSDestLongitude' => array( Exif::RATIONAL, 3 ),       # Longitude of destination
-                               'GPSDestBearingRef' => Exif::ASCII,                     # Reference for bearing of destination #p57
-                               'GPSDestBearing' => Exif::RATIONAL,                     # Bearing of destination
-                               'GPSDestDistanceRef' => Exif::ASCII,                    # Reference for distance to destination #p57-58
-                               'GPSDestDistance' => Exif::RATIONAL,                    # Distance to destination
-                               'GPSProcessingMethod' => Exif::UNDEFINED,               # Name of GPS processing method
-                               'GPSAreaInformation' => Exif::UNDEFINED,                # Name of GPS area
-                               'GPSDateStamp' => Exif::ASCII,                          # GPS date
-                               'GPSDifferential' => Exif::SHORT,                       # GPS differential correction
+                               'GPSAltitude' => Exif::RATIONAL, # Altitude
+                               'GPSTimeStamp' => array( Exif::RATIONAL, 3 ), # GPS time (atomic clock)
+                               'GPSSatellites' => Exif::ASCII, # Satellites used for measurement
+                               'GPSStatus' => Exif::ASCII, # Receiver status #p54
+                               'GPSMeasureMode' => Exif::ASCII, # Measurement mode #p54-55
+                               'GPSDOP' => Exif::RATIONAL, # Measurement precision
+                               'GPSSpeedRef' => Exif::ASCII, # Speed unit #p55
+                               'GPSSpeed' => Exif::RATIONAL, # Speed of GPS receiver
+                               'GPSTrackRef' => Exif::ASCII, # Reference for direction of movement #p55
+                               'GPSTrack' => Exif::RATIONAL, # Direction of movement
+                               'GPSImgDirectionRef' => Exif::ASCII, # Reference for direction of image #p56
+                               'GPSImgDirection' => Exif::RATIONAL, # Direction of image
+                               'GPSMapDatum' => Exif::ASCII, # Geodetic survey data used
+                               'GPSDestLatitudeRef' => Exif::ASCII, # Reference for latitude of destination #p56
+                               'GPSDestLatitude' => array( Exif::RATIONAL, 3 ), # Latitude destination
+                               'GPSDestLongitudeRef' => Exif::ASCII, # Reference for longitude of destination #p57
+                               'GPSDestLongitude' => array( Exif::RATIONAL, 3 ), # Longitude of destination
+                               'GPSDestBearingRef' => Exif::ASCII, # Reference for bearing of destination #p57
+                               'GPSDestBearing' => Exif::RATIONAL, # Bearing of destination
+                               'GPSDestDistanceRef' => Exif::ASCII, # Reference for distance to destination #p57-58
+                               'GPSDestDistance' => Exif::RATIONAL, # Distance to destination
+                               'GPSProcessingMethod' => Exif::UNDEFINED, # Name of GPS processing method
+                               'GPSAreaInformation' => Exif::UNDEFINED, # Name of GPS area
+                               'GPSDateStamp' => Exif::ASCII, # GPS date
+                               'GPSDifferential' => Exif::SHORT, # GPS differential correction
                        ),
                );
 
@@ -302,14 +301,15 @@ class Exif {
                        $data = exif_read_data( $this->file, 0, true );
                        wfRestoreWarnings();
                } else {
-                       throw new MWException( "Internal error: exif_read_data not present. \$wgShowEXIF may be incorrectly set or not checked by an extension." );
+                       throw new MWException( "Internal error: exif_read_data not present. " .
+                               "\$wgShowEXIF may be incorrectly set or not checked by an extension." );
                }
                /**
                 * exif_read_data() will return false on invalid input, such as
                 * when somebody uploads a file called something.jpeg
                 * containing random gibberish.
                 */
-               $this->mRawExifData = $data ? $data : array();
+               $this->mRawExifData = $data ?: array();
                $this->makeFilteredData();
                $this->collapseData();
                $this->debugFile( __FUNCTION__, false );
@@ -319,7 +319,7 @@ class Exif {
         * Make $this->mFilteredExifData
         */
        function makeFilteredData() {
-               $this->mFilteredExifData = Array();
+               $this->mFilteredExifData = array();
 
                foreach ( array_keys( $this->mRawExifData ) as $section ) {
                        if ( !in_array( $section, array_keys( $this->mExifTags ) ) ) {
@@ -371,15 +371,17 @@ class Exif {
                $this->exifGPStoNumber( 'GPSLongitude' );
                $this->exifGPStoNumber( 'GPSDestLongitude' );
 
-               if ( isset( $this->mFilteredExifData['GPSAltitude'] ) && isset( $this->mFilteredExifData['GPSAltitudeRef'] ) ) {
-
-                       // We know altitude data is a <num>/<denom> from the validation functions ran earlier.
-                       // But multiplying such a string by -1 doesn't work well, so convert.
+               if ( isset( $this->mFilteredExifData['GPSAltitude'] )
+                       && isset( $this->mFilteredExifData['GPSAltitudeRef'] )
+               ) {
+                       // We know altitude data is a <num>/<denom> from the validation
+                       // functions ran earlier. But multiplying such a string by -1
+                       // doesn't work well, so convert.
                        list( $num, $denom ) = explode( '/', $this->mFilteredExifData['GPSAltitude'] );
                        $this->mFilteredExifData['GPSAltitude'] = $num / $denom;
 
                        if ( $this->mFilteredExifData['GPSAltitudeRef'] === "\1" ) {
-                               $this->mFilteredExifData['GPSAltitude'] *= - 1;
+                               $this->mFilteredExifData['GPSAltitude'] *= -1;
                        }
                        unset( $this->mFilteredExifData['GPSAltitudeRef'] );
                }
@@ -397,7 +399,9 @@ class Exif {
                if ( isset( $this->mFilteredExifData['ComponentsConfiguration'] ) ) {
                        $val = $this->mFilteredExifData['ComponentsConfiguration'];
                        $ccVals = array();
-                       for ( $i = 0; $i < strlen( $val ); $i++ ) {
+
+                       $strLen = strlen( $val );
+                       for ( $i = 0; $i < $strLen; $i++ ) {
                                $ccVals[$i] = ord( substr( $val, $i, 1 ) );
                        }
                        $ccVals['_type'] = 'ol'; //this is for formatting later.
@@ -414,12 +418,15 @@ class Exif {
                if ( isset( $this->mFilteredExifData['GPSVersion'] ) ) {
                        $val = $this->mFilteredExifData['GPSVersion'];
                        $newVal = '';
-                       for ( $i = 0; $i < strlen( $val ); $i++ ) {
+
+                       $strLen = strlen( $val );
+                       for ( $i = 0; $i < $strLen; $i++ ) {
                                if ( $i !== 0 ) {
                                        $newVal .= '.';
                                }
                                $newVal .= ord( substr( $val, $i, 1 ) );
                        }
+
                        if ( $this->byteOrder === 'LE' ) {
                                // Need to reverse the string
                                $newVal2 = '';
@@ -432,8 +439,8 @@ class Exif {
                        }
                        unset( $this->mFilteredExifData['GPSVersion'] );
                }
-
        }
+
        /**
         * Do userComment tags and similar. See pg. 34 of exif standard.
         * basically first 8 bytes is charset, rest is value.
@@ -448,6 +455,7 @@ class Exif {
 
                                $this->debug( $this->mFilteredExifData[$prop], __FUNCTION__, false );
                                unset( $this->mFilteredExifData[$prop] );
+
                                return;
                        }
                        $charCode = substr( $this->mFilteredExifData[$prop], 0, 8 );
@@ -488,6 +496,7 @@ class Exif {
                                //only whitespace.
                                $this->debug( $this->mFilteredExifData[$prop], __FUNCTION__, "$prop: Is only whitespace" );
                                unset( $this->mFilteredExifData[$prop] );
+
                                return;
                        }
 
@@ -495,28 +504,32 @@ class Exif {
                        $this->mFilteredExifData[$prop] = $val;
                }
        }
+
        /**
         * Convert an Exif::UNDEFINED from a raw binary string
         * to its value. This is sometimes needed depending on
         * the type of UNDEFINED field
-        * @param string $prop name of property
+        * @param string $prop Name of property
         */
        private function exifPropToOrd( $prop ) {
                if ( isset( $this->mFilteredExifData[$prop] ) ) {
                        $this->mFilteredExifData[$prop] = ord( $this->mFilteredExifData[$prop] );
                }
        }
+
        /**
         * Convert gps in exif form to a single floating point number
         * for example 10 degress 20`40`` S -> -10.34444
-        * @param string $prop a gps coordinate exif tag name (like GPSLongitude)
+        * @param string $prop A GPS coordinate exif tag name (like GPSLongitude)
         */
        private function exifGPStoNumber( $prop ) {
                $loc =& $this->mFilteredExifData[$prop];
                $dir =& $this->mFilteredExifData[$prop . 'Ref'];
                $res = false;
 
-               if ( isset( $loc ) && isset( $dir ) && ( $dir === 'N' || $dir === 'S' || $dir === 'E' || $dir === 'W' ) ) {
+               if ( isset( $loc ) && isset( $dir )
+                       && ( $dir === 'N' || $dir === 'S' || $dir === 'E' || $dir === 'W' )
+               ) {
                        list( $num, $denom ) = explode( '/', $loc[0] );
                        $res = $num / $denom;
                        list( $num, $denom ) = explode( '/', $loc[1] );
@@ -525,7 +538,7 @@ class Exif {
                        $res += ( $num / $denom ) * ( 1 / 3600 );
 
                        if ( $dir === 'S' || $dir === 'W' ) {
-                               $res *= - 1; // make negative
+                               $res *= -1; // make negative
                        }
                }
 
@@ -551,6 +564,7 @@ class Exif {
                $this->mFormattedExifData = FormatMetadata::getFormattedData(
                        $this->mFilteredExifData );
        }
+
        /**#@-*/
 
        /**#@+
@@ -584,8 +598,10 @@ class Exif {
                if ( !$this->mFormattedExifData ) {
                        $this->makeFormattedData();
                }
+
                return $this->mFormattedExifData;
        }
+
        /**#@-*/
 
        /**
@@ -607,23 +623,23 @@ class Exif {
        /**#@+
         * Validates if a tag value is of the type it should be according to the Exif spec
         *
-        * @private
-        *
-        * @param $in Mixed: the input value to check
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isByte( $in ) {
                if ( !is_array( $in ) && sprintf( '%d', $in ) == $in && $in >= 0 && $in <= 255 ) {
                        $this->debug( $in, __FUNCTION__, true );
+
                        return true;
                } else {
                        $this->debug( $in, __FUNCTION__, false );
+
                        return false;
                }
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isASCII( $in ) {
@@ -633,11 +649,13 @@ class Exif {
 
                if ( preg_match( "/[^\x0a\x20-\x7e]/", $in ) ) {
                        $this->debug( $in, __FUNCTION__, 'found a character not in our whitelist' );
+
                        return false;
                }
 
                if ( preg_match( '/^\s*$/', $in ) ) {
                        $this->debug( $in, __FUNCTION__, 'input consisted solely of whitespace' );
+
                        return false;
                }
 
@@ -645,93 +663,110 @@ class Exif {
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isShort( $in ) {
                if ( !is_array( $in ) && sprintf( '%d', $in ) == $in && $in >= 0 && $in <= 65536 ) {
                        $this->debug( $in, __FUNCTION__, true );
+
                        return true;
                } else {
                        $this->debug( $in, __FUNCTION__, false );
+
                        return false;
                }
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isLong( $in ) {
                if ( !is_array( $in ) && sprintf( '%d', $in ) == $in && $in >= 0 && $in <= 4294967296 ) {
                        $this->debug( $in, __FUNCTION__, true );
+
                        return true;
                } else {
                        $this->debug( $in, __FUNCTION__, false );
+
                        return false;
                }
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isRational( $in ) {
                $m = array();
-               if ( !is_array( $in ) && preg_match( '/^(\d+)\/(\d+[1-9]|[1-9]\d*)$/', $in, $m ) ) { # Avoid division by zero
+
+               # Avoid division by zero
+               if ( !is_array( $in )
+                       && preg_match( '/^(\d+)\/(\d+[1-9]|[1-9]\d*)$/', $in, $m )
+               ) {
                        return $this->isLong( $m[1] ) && $this->isLong( $m[2] );
                } else {
                        $this->debug( $in, __FUNCTION__, 'fed a non-fraction value' );
+
                        return false;
                }
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isUndefined( $in ) {
                $this->debug( $in, __FUNCTION__, true );
+
                return true;
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isSlong( $in ) {
                if ( $this->isLong( abs( $in ) ) ) {
                        $this->debug( $in, __FUNCTION__, true );
+
                        return true;
                } else {
                        $this->debug( $in, __FUNCTION__, false );
+
                        return false;
                }
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isSrational( $in ) {
                $m = array();
-               if ( !is_array( $in ) && preg_match( '/^(-?\d+)\/(\d+[1-9]|[1-9]\d*)$/', $in, $m ) ) { # Avoid division by zero
+
+               # Avoid division by zero
+               if ( !is_array( $in ) &&
+                       preg_match( '/^(-?\d+)\/(\d+[1-9]|[1-9]\d*)$/', $in, $m )
+               ) {
                        return $this->isSlong( $m[0] ) && $this->isSlong( $m[1] );
                } else {
                        $this->debug( $in, __FUNCTION__, 'fed a non-fraction value' );
+
                        return false;
                }
        }
+
        /**#@-*/
 
        /**
         * Validates if a tag has a legal value according to the Exif spec
         *
-        * @private
         * @param string $section section where tag is located.
         * @param string $tag the tag to check.
-        * @param $val Mixed: the value of the tag.
-        * @param $recursive Boolean: true if called recursively for array types.
+        * @param mixed $val The value of the tag.
+        * @param bool $recursive True if called recursively for array types.
         * @return bool
         */
        private function validate( $section, $tag, $val, $recursive = false ) {
@@ -747,6 +782,7 @@ class Exif {
                $count = count( $val );
                if ( $ecount != $count ) {
                        $this->debug( $val, __FUNCTION__, "Expected $ecount elements for $tag but got $count" );
+
                        return false;
                }
                if ( $count > 1 ) {
@@ -755,42 +791,54 @@ class Exif {
                                        return false;
                                }
                        }
+
                        return true;
                }
                // Does not work if not typecast
                switch ( (string)$etype ) {
                        case (string)Exif::BYTE:
                                $this->debug( $val, __FUNCTION__, $debug );
+
                                return $this->isByte( $val );
                        case (string)Exif::ASCII:
                                $this->debug( $val, __FUNCTION__, $debug );
+
                                return $this->isASCII( $val );
                        case (string)Exif::SHORT:
                                $this->debug( $val, __FUNCTION__, $debug );
+
                                return $this->isShort( $val );
                        case (string)Exif::LONG:
                                $this->debug( $val, __FUNCTION__, $debug );
+
                                return $this->isLong( $val );
                        case (string)Exif::RATIONAL:
                                $this->debug( $val, __FUNCTION__, $debug );
+
                                return $this->isRational( $val );
                        case (string)Exif::SHORT_OR_LONG:
                                $this->debug( $val, __FUNCTION__, $debug );
+
                                return $this->isShort( $val ) || $this->isLong( $val );
                        case (string)Exif::UNDEFINED:
                                $this->debug( $val, __FUNCTION__, $debug );
+
                                return $this->isUndefined( $val );
                        case (string)Exif::SLONG:
                                $this->debug( $val, __FUNCTION__, $debug );
+
                                return $this->isSlong( $val );
                        case (string)Exif::SRATIONAL:
                                $this->debug( $val, __FUNCTION__, $debug );
+
                                return $this->isSrational( $val );
                        case (string)Exif::IGNORE:
                                $this->debug( $val, __FUNCTION__, $debug );
+
                                return false;
                        default:
                                $this->debug( $val, __FUNCTION__, "The tag '$tag' is unknown" );
+
                                return false;
                }
        }
@@ -798,11 +846,9 @@ class Exif {
        /**
         * Convenience function for debugging output
         *
-        * @private
-        *
-        * @param $in Mixed:
-        * @param $fname String:
-        * @param $action Mixed: , default NULL.
+        * @param mixed $in Arrays will be processed with print_r().
+        * @param string $fname Function name to log.
+        * @param string|bool|null $action Default null.
         */
        private function debug( $in, $fname, $action = null ) {
                if ( !$this->log ) {
@@ -828,10 +874,8 @@ class Exif {
        /**
         * Convenience function for debugging output
         *
-        * @private
-        *
         * @param string $fname the name of the function calling this function
-        * @param $io Boolean: Specify whether we're beginning or ending
+        * @param bool $io Specify whether we're beginning or ending
         */
        private function debugFile( $fname, $io ) {
                if ( !$this->log ) {