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/src/wp-admin/includes/image.php

    r51166 r52269  
    647647 * @since 2.5.0
    648648 *
    649  * @param string $str
    650  * @return int|float
     649 * @param string $str Fraction string.
     650 * @return int|float Returns calculated fraction or integer 0 on invalid input.
    651651 */
    652652function wp_exif_frac2dec( $str ) {
    653     if ( false === strpos( $str, '/' ) ) {
    654         return $str;
     653    if ( ! is_scalar( $str ) || is_bool( $str ) ) {
     654        return 0;
     655    }
     656
     657    if ( ! is_string( $str ) ) {
     658        return $str; // This can only be an integer or float, so this is fine.
     659    }
     660
     661    // Fractions passed as a string must contain a single `/`.
     662    if ( substr_count( $str, '/' ) !== 1 ) {
     663        if ( is_numeric( $str ) ) {
     664            return (float) $str;
     665        }
     666
     667        return 0;
    655668    }
    656669
    657670    list( $numerator, $denominator ) = explode( '/', $str );
    658     if ( ! empty( $denominator ) ) {
    659         return $numerator / $denominator;
    660     }
    661     return $str;
     671
     672    // Both the numerator and the denominator must be numbers.
     673    if ( ! is_numeric( $numerator ) || ! is_numeric( $denominator ) ) {
     674        return 0;
     675    }
     676
     677    // The denominator must not be zero.
     678    if ( 0 == $denominator ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison -- Deliberate loose comparison.
     679        return 0;
     680    }
     681
     682    return $numerator / $denominator;
    662683}
    663684
     
    841862            $meta['copyright'] = trim( $exif['Copyright'] );
    842863        }
    843         if ( ! empty( $exif['FNumber'] ) ) {
     864        if ( ! empty( $exif['FNumber'] ) && is_scalar( $exif['FNumber'] ) ) {
    844865            $meta['aperture'] = round( wp_exif_frac2dec( $exif['FNumber'] ), 2 );
    845866        }
     
    851872        }
    852873        if ( ! empty( $exif['FocalLength'] ) ) {
    853             $meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] );
     874            $meta['focal_length'] = (string) $exif['FocalLength'];
     875            if ( is_scalar( $exif['FocalLength'] ) ) {
     876                $meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] );
     877            }
    854878        }
    855879        if ( ! empty( $exif['ISOSpeedRatings'] ) ) {
     
    858882        }
    859883        if ( ! empty( $exif['ExposureTime'] ) ) {
    860             $meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] );
     884            $meta['shutter_speed'] = (string) $exif['ExposureTime'];
     885            if ( is_scalar( $exif['ExposureTime'] ) ) {
     886                $meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] );
     887            }
    861888        }
    862889        if ( ! empty( $exif['Orientation'] ) ) {
Note: See TracChangeset for help on using the changeset viewer.