Make WordPress Core


Ignore:
Timestamp:
11/29/2021 07:34:51 PM (3 years ago)
Author:
hellofromTonya
Message:

Media: Fix TypeError and improve wp_exif_frac2dec() to only return int or float.

For certain images, wp_exif_frac2dec() unexpectedly returned a string instead of int or float. This can occur when an image is missing meta and calls the function with '0/0'. For those images, a fatal error was thrown on PHP 8.0+:

TypeError: round(): Argument #1 ($num) must be of type int|float, string given

Upon deeper review, inconsistent and unexpected results were returned from different types of input values passed to the function.

Changes are:

  • Maintains backwards-compatibility for valid input values.
  • Fixes handling of invalid input values by bailing out to return the documented type of int|float by returning 0.
  • Improves the fractional conditional check.
  • Improves the calculated fraction handling to ensure (a) the numerator and denominator are both numeric and (b) the denominator is not equal to zero.
  • Safeguards the behavior via tests for all possible ways code could flow through the function.
  • Safeguards the backwards-compatibility of the wp_read_image_metadata() by adding some defensive coding around the calls to the wp_exif_frac2dec() function.

These changes fix the fatal error and make the function more secure, stable, and predictable while maintaining backwards-compatibility for valid input values.

Follow-up to [6313], [9119], [22319], [28367], [45611], [47287].

Props adamsilverstein, jrf, peterwilsoncc, praem90, stevegs, tobiasbg.
Fixes #54385.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/image/meta.php

    r52010 r52269  
    3333        $out = wp_read_image_metadata( DIR_TESTDATA . '/images/2004-07-22-DSC_0008.jpg' );
    3434
    35         $this->assertEquals( 6.3, $out['aperture'] );
    36         $this->assertSame( '', $out['credit'] );
    37         $this->assertSame( 'NIKON D70', $out['camera'] );
    38         $this->assertSame( '', $out['caption'] );
    39         $this->assertEquals( strtotime( '2004-07-22 17:14:59' ), $out['created_timestamp'] );
    40         $this->assertSame( '', $out['copyright'] );
    41         $this->assertEquals( 27, $out['focal_length'] );
    42         $this->assertEquals( 400, $out['iso'] );
    43         $this->assertEquals( 1 / 40, $out['shutter_speed'] );
    44         $this->assertSame( '', $out['title'] );
     35        $this->assertEquals( 6.3, $out['aperture'], 'Aperture value not equivalent' );
     36        $this->assertSame( '', $out['credit'], 'Credit value not the same' );
     37        $this->assertSame( 'NIKON D70', $out['camera'], 'Camera value not the same' );
     38        $this->assertSame( '', $out['caption'], 'Caption value not the same' );
     39        $this->assertEquals( strtotime( '2004-07-22 17:14:59' ), $out['created_timestamp'], 'Timestamp value not equivalent' );
     40        $this->assertSame( '', $out['copyright'], 'Copyright value not the same' );
     41        $this->assertEquals( 27, $out['focal_length'], 'Focal length value not equivalent' );
     42        $this->assertEquals( 400, $out['iso'], 'Iso value not equivalent' );
     43        $this->assertEquals( 1 / 40, $out['shutter_speed'], 'Shutter speed value not equivalent' );
     44        $this->assertSame( '', $out['title'], 'Title value not the same' );
    4545    }
    4646
     
    4949        $out = wp_read_image_metadata( DIR_TESTDATA . '/images/2007-06-17DSC_4173.JPG' );
    5050
    51         $this->assertSame( '0', $out['aperture'] );
    52         $this->assertSame( '', $out['credit'] );
    53         $this->assertSame( 'NIKON D70', $out['camera'] );
    54         $this->assertSame( '', $out['caption'] );
    55         $this->assertEquals( strtotime( '2007-06-17 21:18:00' ), $out['created_timestamp'] );
    56         $this->assertSame( '', $out['copyright'] );
    57         $this->assertEquals( 0, $out['focal_length'] );
    58         $this->assertEquals( 0, $out['iso'] ); // Interesting - a Nikon bug?
    59         $this->assertEquals( 1 / 500, $out['shutter_speed'] );
    60         $this->assertSame( '', $out['title'] );
     51        $this->assertSame( '0', $out['aperture'], 'Aperture value not the same' );
     52        $this->assertSame( '', $out['credit'], 'Credit value not the same' );
     53        $this->assertSame( 'NIKON D70', $out['camera'], 'Camera value not the same' );
     54        $this->assertSame( '', $out['caption'], 'Caption value not the same' );
     55        $this->assertEquals( strtotime( '2007-06-17 21:18:00' ), $out['created_timestamp'], 'Timestamp value not equivalent' );
     56        $this->assertSame( '', $out['copyright'], 'Copyright value not the same' );
     57        $this->assertEquals( 0, $out['focal_length'], 'Focal length value not equivalent' );
     58        $this->assertEquals( 0, $out['iso'], 'Iso value not equivalent' ); // Interesting - a Nikon bug?
     59        $this->assertEquals( 1 / 500, $out['shutter_speed'], 'Shutter speed value not equivalent' );
     60        $this->assertSame( '', $out['title'], 'Title value not the same' );
    6161        // $this->assertSame( array( 'Flowers' ), $out['keywords'] );
    6262    }
     
    6666        $out = wp_read_image_metadata( DIR_TESTDATA . '/images/2004-07-22-DSC_0007.jpg' );
    6767
    68         $this->assertEquals( 6.3, $out['aperture'] );
    69         $this->assertSame( 'IPTC Creator', $out['credit'] );
    70         $this->assertSame( 'NIKON D70', $out['camera'] );
    71         $this->assertSame( 'IPTC Caption', $out['caption'] );
    72         $this->assertEquals( strtotime( '2004-07-22 17:14:35' ), $out['created_timestamp'] );
    73         $this->assertSame( 'IPTC Copyright', $out['copyright'] );
    74         $this->assertEquals( 18, $out['focal_length'] );
    75         $this->assertEquals( 200, $out['iso'] );
    76         $this->assertEquals( 1 / 25, $out['shutter_speed'] );
    77         $this->assertSame( 'IPTC Headline', $out['title'] );
     68        $this->assertEquals( 6.3, $out['aperture'], 'Aperture value not equivalent' );
     69        $this->assertSame( 'IPTC Creator', $out['credit'], 'Credit value not the same' );
     70        $this->assertSame( 'NIKON D70', $out['camera'], 'Camera value not the same' );
     71        $this->assertSame( 'IPTC Caption', $out['caption'], 'Caption value not the same' );
     72        $this->assertEquals( strtotime( '2004-07-22 17:14:35' ), $out['created_timestamp'], 'Timestamp value not equivalent' );
     73        $this->assertSame( 'IPTC Copyright', $out['copyright'], 'Copyright value not the same' );
     74        $this->assertEquals( 18, $out['focal_length'], 'Focal length value not equivalent' );
     75        $this->assertEquals( 200, $out['iso'], 'Iso value not equivalent' );
     76        $this->assertEquals( 1 / 25, $out['shutter_speed'], 'Shutter speed value not equivalent' );
     77        $this->assertSame( 'IPTC Headline', $out['title'], 'Title value not the same' );
    7878    }
    7979
     
    8282        $out = wp_read_image_metadata( DIR_TESTDATA . '/images/a2-small.jpg' );
    8383
    84         $this->assertEquals( 4.5, $out['aperture'] );
    85         $this->assertSame( '', $out['credit'] );
    86         $this->assertSame( 'FinePix S5600', $out['camera'] );
    87         $this->assertSame( '', $out['caption'] );
    88         $this->assertEquals( strtotime( '2007-09-03 10:17:03' ), $out['created_timestamp'] );
    89         $this->assertSame( '', $out['copyright'] );
    90         $this->assertEquals( 6.3, $out['focal_length'] );
    91         $this->assertEquals( 64, $out['iso'] );
    92         $this->assertEquals( 1 / 320, $out['shutter_speed'] );
    93         $this->assertSame( '', $out['title'] );
    94 
     84        $this->assertEquals( 4.5, $out['aperture'], 'Aperture value not equivalent' );
     85        $this->assertSame( '', $out['credit'], 'Credit value not the same' );
     86        $this->assertSame( 'FinePix S5600', $out['camera'], 'Camera value not the same' );
     87        $this->assertSame( '', $out['caption'], 'Caption value not the same' );
     88        $this->assertEquals( strtotime( '2007-09-03 10:17:03' ), $out['created_timestamp'], 'Timestamp value not equivalent' );
     89        $this->assertSame( '', $out['copyright'], 'Copyright value not the same' );
     90        $this->assertEquals( 6.3, $out['focal_length'], 'Focal length value not equivalent' );
     91        $this->assertEquals( 64, $out['iso'], 'Iso value not equivalent' );
     92        $this->assertEquals( 1 / 320, $out['shutter_speed'], 'Shutter speed value not equivalent' );
     93        $this->assertSame( '', $out['title'], 'Title value not the same' );
    9594    }
    9695
     
    103102        $out = wp_read_image_metadata( DIR_TESTDATA . '/images/waffles.jpg' );
    104103
    105         $this->assertEquals( 0, $out['aperture'] );
    106         $this->assertSame( '', $out['credit'] );
    107         $this->assertSame( '', $out['camera'] );
    108         $this->assertSame( '', $out['caption'] );
    109         $this->assertEquals( 0, $out['created_timestamp'] );
    110         $this->assertSame( '', $out['copyright'] );
    111         $this->assertEquals( 0, $out['focal_length'] );
    112         $this->assertEquals( 0, $out['iso'] );
    113         $this->assertEquals( 0, $out['shutter_speed'] );
    114         $this->assertSame( '', $out['title'] );
     104        $this->assertEquals( 0, $out['aperture'], 'Aperture value not equivalent' );
     105        $this->assertSame( '', $out['credit'], 'Credit value not the same' );
     106        $this->assertSame( '', $out['camera'], 'Camera value not the same' );
     107        $this->assertSame( '', $out['caption'], 'Caption value not the same' );
     108        $this->assertEquals( 0, $out['created_timestamp'], 'Timestamp value not equivalent' );
     109        $this->assertSame( '', $out['copyright'], 'Copyright value not the same' );
     110        $this->assertEquals( 0, $out['focal_length'], 'Focal length value not equivalent' );
     111        $this->assertEquals( 0, $out['iso'], 'Iso value not equivalent' );
     112        $this->assertEquals( 0, $out['shutter_speed'], 'Shutter speed value not equivalent' );
     113        $this->assertSame( '', $out['title'], 'Title value not the same' );
    115114    }
    116115
     
    119118        $out = wp_read_image_metadata( DIR_TESTDATA . '/images/canola.jpg' );
    120119
    121         $this->assertEquals( 0, $out['aperture'] );
    122         $this->assertSame( '', $out['credit'] );
    123         $this->assertSame( '', $out['camera'] );
    124         $this->assertSame( '', $out['caption'] );
    125         $this->assertEquals( 0, $out['created_timestamp'] );
    126         $this->assertSame( '', $out['copyright'] );
    127         $this->assertEquals( 0, $out['focal_length'] );
    128         $this->assertEquals( 0, $out['iso'] );
    129         $this->assertEquals( 0, $out['shutter_speed'] );
    130         $this->assertSame( '', $out['title'] );
     120        $this->assertEquals( 0, $out['aperture'], 'Aperture value not equivalent' );
     121        $this->assertSame( '', $out['credit'], 'Credit value not the same' );
     122        $this->assertSame( '', $out['camera'], 'Camera value not the same' );
     123        $this->assertSame( '', $out['caption'], 'Caption value not the same' );
     124        $this->assertEquals( 0, $out['created_timestamp'], 'Timestamp value not equivalent' );
     125        $this->assertSame( '', $out['copyright'], 'Copyright value not the same' );
     126        $this->assertEquals( 0, $out['focal_length'], 'Focal length value not equivalent' );
     127        $this->assertEquals( 0, $out['iso'], 'Iso value not equivalent' );
     128        $this->assertEquals( 0, $out['shutter_speed'], 'Shutter speed value not equivalent' );
     129        $this->assertSame( '', $out['title'], 'Title value not the same' );
    131130    }
    132131
     
    156155        $out = wp_read_image_metadata( DIR_TESTDATA . '/images/33772.jpg' );
    157156
    158         $this->assertSame( '8', $out['aperture'] );
    159         $this->assertSame( 'Photoshop Author', $out['credit'] );
    160         $this->assertSame( 'DMC-LX2', $out['camera'] );
    161         $this->assertSame( 'Photoshop Description', $out['caption'] );
    162         $this->assertEquals( 1306315327, $out['created_timestamp'] );
    163         $this->assertSame( 'Photoshop Copyrright Notice', $out['copyright'] );
    164         $this->assertSame( '6.3', $out['focal_length'] );
    165         $this->assertSame( '100', $out['iso'] );
    166         $this->assertSame( '0.0025', $out['shutter_speed'] );
    167         $this->assertSame( 'Photoshop Document Ttitle', $out['title'] );
    168         $this->assertEquals( 1, $out['orientation'] );
    169         $this->assertSame( array( 'beach', 'baywatch', 'LA', 'sunset' ), $out['keywords'] );
     157        $this->assertSame( '8', $out['aperture'], 'Aperture value not the same' );
     158        $this->assertSame( 'Photoshop Author', $out['credit'], 'Credit value not the same' );
     159        $this->assertSame( 'DMC-LX2', $out['camera'], 'Camera value not the same' );
     160        $this->assertSame( 'Photoshop Description', $out['caption'], 'Caption value not the same' );
     161        $this->assertEquals( 1306315327, $out['created_timestamp'], 'Timestamp value not equivalent' );
     162        $this->assertSame( 'Photoshop Copyrright Notice', $out['copyright'], 'Copyright value not the same' );
     163        $this->assertSame( '6.3', $out['focal_length'], 'Focal length value not the same' );
     164        $this->assertSame( '100', $out['iso'], 'Iso value not the same' );
     165        $this->assertSame( '0.0025', $out['shutter_speed'], 'Shutter speed value not the same' );
     166        $this->assertSame( 'Photoshop Document Ttitle', $out['title'], 'Title value not the same' );
     167        $this->assertEquals( 1, $out['orientation'], 'Orientation value not equivalent' );
     168        $this->assertSame( array( 'beach', 'baywatch', 'LA', 'sunset' ), $out['keywords'], 'Keywords not the same' );
    170169    }
    171170
     
    240239        );
    241240    }
     241
     242    /**
     243     * @ticket 54385
     244     */
     245    public function test_exif_unexpected_data() {
     246        // Unexpected Exif data: FNumber is "0/0", aperture should be 0.
     247        $out = wp_read_image_metadata( DIR_TESTDATA . '/images/sugarloaf-mountain.jpg' );
     248
     249        $this->assertEquals( 0, $out['aperture'], 'Aperture value not equivalent' );
     250        $this->assertSame( '', $out['credit'], 'Credit value not the same' );
     251        $this->assertSame( 'X-T1', $out['camera'], 'Camera value not the same' );
     252        $this->assertSame( '', $out['caption'], 'Caption value not the same' );
     253        $this->assertEquals( 0, $out['created_timestamp'], 'Timestamp value not equivalent' );
     254        $this->assertSame( '', $out['copyright'], 'Copyright value not the same' );
     255        $this->assertEquals( 50, $out['focal_length'], 'Focal length value not equivalent' );
     256        $this->assertEquals( 200, $out['iso'], 'Iso value not equivalent' );
     257        $this->assertEquals( 2, $out['shutter_speed'], 'Shutter speed value not equivalent' );
     258        $this->assertSame( 'Sugarloaf Panorama', $out['title'], 'Title value not the same' );
     259    }
    242260}
Note: See TracChangeset for help on using the changeset viewer.