| Index: trunk/phase3/RELEASE-NOTES-1.19 |
| — | — | @@ -223,6 +223,8 @@ |
| 224 | 224 | * (bug 33321) Adding a line to MediaWiki:Sidebar that contains a pipe, but doesn't |
| 225 | 225 | have any pipes after being transformed by MessageCache, causes exception on |
| 226 | 226 | all pages. |
| | 227 | +* Files with IPTC blocks we can't read no longer prevent extraction of exif |
| | 228 | + or other metadata. |
| 227 | 229 | |
| 228 | 230 | === API changes in 1.19 === |
| 229 | 231 | * (bug 19838) siprop=interwikimap can now use the interwiki cache. |
| Index: trunk/phase3/tests/phpunit/includes/media/BitmapMetadataHandlerTest.php |
| — | — | @@ -56,6 +56,16 @@ |
| 57 | 57 | $meta['JPEGFileComment'][0] ); |
| 58 | 58 | } |
| 59 | 59 | |
| | 60 | + /** |
| | 61 | + * Make sure a bad iptc block doesn't stop the other metadata |
| | 62 | + * from being extracted. |
| | 63 | + */ |
| | 64 | + public function testBadIPTC() { |
| | 65 | + $meta = BitmapMetadataHandler::Jpeg( $this->filePath . |
| | 66 | + 'iptc-invalid-psir.jpg' ); |
| | 67 | + $this->assertEquals( 'Created with GIMP', $meta['JPEGFileComment'][0] ); |
| | 68 | + } |
| | 69 | + |
| 60 | 70 | public function testIPTCDates() { |
| 61 | 71 | $meta = BitmapMetadataHandler::Jpeg( $this->filePath . |
| 62 | 72 | 'iptc-timetest.jpg' ); |
| Index: trunk/phase3/tests/phpunit/includes/media/JpegMetadataExtractorTest.php |
| — | — | @@ -59,7 +59,7 @@ |
| 60 | 60 | public function testPSIRExtraction() { |
| 61 | 61 | $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' ); |
| 62 | 62 | $expected = '50686f746f73686f7020332e30003842494d04040000000000181c02190004746573741c02190003666f6f1c020000020004'; |
| 63 | | - $this->assertEquals( $expected, bin2hex( $res['PSIR'] ) ); |
| | 63 | + $this->assertEquals( $expected, bin2hex( $res['PSIR'][0] ) ); |
| 64 | 64 | } |
| 65 | 65 | public function testXMPExtractionAltAppId() { |
| 66 | 66 | $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-alt.jpg' ); |
| — | — | @@ -70,19 +70,19 @@ |
| 71 | 71 | |
| 72 | 72 | public function testIPTCHashComparisionNoHash() { |
| 73 | 73 | $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' ); |
| 74 | | - $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] ); |
| | 74 | + $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] ); |
| 75 | 75 | |
| 76 | 76 | $this->assertEquals( 'iptc-no-hash', $res ); |
| 77 | 77 | } |
| 78 | 78 | public function testIPTCHashComparisionBadHash() { |
| 79 | 79 | $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-bad-hash.jpg' ); |
| 80 | | - $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] ); |
| | 80 | + $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] ); |
| 81 | 81 | |
| 82 | 82 | $this->assertEquals( 'iptc-bad-hash', $res ); |
| 83 | 83 | } |
| 84 | 84 | public function testIPTCHashComparisionGoodHash() { |
| 85 | 85 | $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-good-hash.jpg' ); |
| 86 | | - $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] ); |
| | 86 | + $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] ); |
| 87 | 87 | |
| 88 | 88 | $this->assertEquals( 'iptc-good-hash', $res ); |
| 89 | 89 | } |
| Index: trunk/phase3/tests/phpunit/data/media/iptc-invalid-psir.jpg |
| Cannot display: file marked as a binary type. |
| svn:mime-type = image/jpeg |
| Property changes on: trunk/phase3/tests/phpunit/data/media/iptc-invalid-psir.jpg |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| 90 | 90 | + image/jpeg |
| Index: trunk/phase3/includes/media/BitmapMetadataHandler.php |
| — | — | @@ -32,7 +32,15 @@ |
| 33 | 33 | * @param String $app13 String containing app13 block from jpeg file |
| 34 | 34 | */ |
| 35 | 35 | private function doApp13 ( $app13 ) { |
| 36 | | - $this->iptcType = JpegMetadataExtractor::doPSIR( $app13 ); |
| | 36 | + try { |
| | 37 | + $this->iptcType = JpegMetadataExtractor::doPSIR( $app13 ); |
| | 38 | + } catch ( MWException $e ) { |
| | 39 | + // Error reading the iptc hash information. |
| | 40 | + // This probably means the App13 segment is something other than what we expect. |
| | 41 | + // However, still try to read it, and treat it as if the hash didn't exist. |
| | 42 | + wfDebug( "Error parsing iptc data of file: " . $e->getMessage() . "\n" ); |
| | 43 | + $this->iptcType = 'iptc-no-hash'; |
| | 44 | + } |
| 37 | 45 | |
| 38 | 46 | $iptc = IPTC::parse( $app13 ); |
| 39 | 47 | $this->addMetadata( $iptc, $this->iptcType ); |
| — | — | @@ -122,8 +130,10 @@ |
| 123 | 131 | if ( isset( $seg['COM'] ) && isset( $seg['COM'][0] ) ) { |
| 124 | 132 | $meta->addMetadata( Array( 'JPEGFileComment' => $seg['COM'] ), 'native' ); |
| 125 | 133 | } |
| 126 | | - if ( isset( $seg['PSIR'] ) ) { |
| 127 | | - $meta->doApp13( $seg['PSIR'] ); |
| | 134 | + if ( isset( $seg['PSIR'] ) && count( $seg['PSIR'] ) > 0 ) { |
| | 135 | + foreach( $seg['PSIR'] as $curPSIRValue ) { |
| | 136 | + $meta->doApp13( $curPSIRValue ); |
| | 137 | + } |
| 128 | 138 | } |
| 129 | 139 | if ( isset( $seg['XMP'] ) && $showXMP ) { |
| 130 | 140 | $xmp = new XMPReader(); |
| Index: trunk/phase3/includes/media/JpegMetadataExtractor.php |
| — | — | @@ -31,6 +31,7 @@ |
| 32 | 32 | $segments = array( |
| 33 | 33 | 'XMP_ext' => array(), |
| 34 | 34 | 'COM' => array(), |
| | 35 | + 'PSIR' => array(), |
| 35 | 36 | ); |
| 36 | 37 | |
| 37 | 38 | if ( !$filename ) { |
| — | — | @@ -122,7 +123,7 @@ |
| 123 | 124 | // APP13 - PSIR. IPTC and some photoshop stuff |
| 124 | 125 | $temp = self::jpegExtractMarker( $fh ); |
| 125 | 126 | if ( substr( $temp, 0, 14 ) === "Photoshop 3.0\x00" ) { |
| 126 | | - $segments["PSIR"] = $temp; |
| | 127 | + $segments["PSIR"][] = $temp; |
| 127 | 128 | } |
| 128 | 129 | } elseif ( $buffer === "\xD9" || $buffer === "\xDA" ) { |
| 129 | 130 | // EOI - end of image or SOS - start of scan. either way we're past any interesting segments |
| — | — | @@ -162,11 +163,12 @@ |
| 163 | 164 | * This should generally be called by BitmapMetadataHandler::doApp13() |
| 164 | 165 | * |
| 165 | 166 | * @param String $app13 photoshop psir app13 block from jpg. |
| | 167 | + * @throws MWException (It gets caught next level up though) |
| 166 | 168 | * @return String if the iptc hash is good or not. |
| 167 | 169 | */ |
| 168 | 170 | public static function doPSIR ( $app13 ) { |
| 169 | 171 | if ( !$app13 ) { |
| 170 | | - return; |
| | 172 | + throw new MWException( "No App13 segment given" ); |
| 171 | 173 | } |
| 172 | 174 | // First compare hash with real thing |
| 173 | 175 | // 0x404 contains IPTC, 0x425 has hash |
| — | — | @@ -218,8 +220,8 @@ |
| 219 | 221 | |
| 220 | 222 | // this should not happen, but check. |
| 221 | 223 | if ( $lenData['len'] + $offset > $appLen ) { |
| 222 | | - wfDebug( __METHOD__ . " PSIR data too long.\n" ); |
| 223 | | - return 'iptc-no-hash'; |
| | 224 | + throw new MWException( "PSIR data too long. (item length=" . $lenData['len'] |
| | 225 | + . "; offset=$offset; total length=$appLen)" ); |
| 224 | 226 | } |
| 225 | 227 | |
| 226 | 228 | if ( $valid ) { |