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.
Built from https://develop.svn.wordpress.org/trunk@52269


git-svn-id: http://core.svn.wordpress.org/trunk@51861 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
hellofromTonya 2021-11-29 19:36:05 +00:00
parent 2f6cf4ba81
commit 677e6e5b13
2 changed files with 38 additions and 11 deletions

View File

@ -646,19 +646,40 @@ function wp_generate_attachment_metadata( $attachment_id, $file ) {
* *
* @since 2.5.0 * @since 2.5.0
* *
* @param string $str * @param string $str Fraction string.
* @return int|float * @return int|float Returns calculated fraction or integer 0 on invalid input.
*/ */
function wp_exif_frac2dec( $str ) { function wp_exif_frac2dec( $str ) {
if ( false === strpos( $str, '/' ) ) { if ( ! is_scalar( $str ) || is_bool( $str ) ) {
return $str; return 0;
}
if ( ! is_string( $str ) ) {
return $str; // This can only be an integer or float, so this is fine.
}
// Fractions passed as a string must contain a single `/`.
if ( substr_count( $str, '/' ) !== 1 ) {
if ( is_numeric( $str ) ) {
return (float) $str;
}
return 0;
} }
list( $numerator, $denominator ) = explode( '/', $str ); list( $numerator, $denominator ) = explode( '/', $str );
if ( ! empty( $denominator ) ) {
return $numerator / $denominator; // Both the numerator and the denominator must be numbers.
if ( ! is_numeric( $numerator ) || ! is_numeric( $denominator ) ) {
return 0;
} }
return $str;
// The denominator must not be zero.
if ( 0 == $denominator ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison -- Deliberate loose comparison.
return 0;
}
return $numerator / $denominator;
} }
/** /**
@ -840,7 +861,7 @@ function wp_read_image_metadata( $file ) {
if ( empty( $meta['copyright'] ) && ! empty( $exif['Copyright'] ) ) { if ( empty( $meta['copyright'] ) && ! empty( $exif['Copyright'] ) ) {
$meta['copyright'] = trim( $exif['Copyright'] ); $meta['copyright'] = trim( $exif['Copyright'] );
} }
if ( ! empty( $exif['FNumber'] ) ) { if ( ! empty( $exif['FNumber'] ) && is_scalar( $exif['FNumber'] ) ) {
$meta['aperture'] = round( wp_exif_frac2dec( $exif['FNumber'] ), 2 ); $meta['aperture'] = round( wp_exif_frac2dec( $exif['FNumber'] ), 2 );
} }
if ( ! empty( $exif['Model'] ) ) { if ( ! empty( $exif['Model'] ) ) {
@ -850,15 +871,21 @@ function wp_read_image_metadata( $file ) {
$meta['created_timestamp'] = wp_exif_date2ts( $exif['DateTimeDigitized'] ); $meta['created_timestamp'] = wp_exif_date2ts( $exif['DateTimeDigitized'] );
} }
if ( ! empty( $exif['FocalLength'] ) ) { if ( ! empty( $exif['FocalLength'] ) ) {
$meta['focal_length'] = (string) $exif['FocalLength'];
if ( is_scalar( $exif['FocalLength'] ) ) {
$meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] ); $meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] );
} }
}
if ( ! empty( $exif['ISOSpeedRatings'] ) ) { if ( ! empty( $exif['ISOSpeedRatings'] ) ) {
$meta['iso'] = is_array( $exif['ISOSpeedRatings'] ) ? reset( $exif['ISOSpeedRatings'] ) : $exif['ISOSpeedRatings']; $meta['iso'] = is_array( $exif['ISOSpeedRatings'] ) ? reset( $exif['ISOSpeedRatings'] ) : $exif['ISOSpeedRatings'];
$meta['iso'] = trim( $meta['iso'] ); $meta['iso'] = trim( $meta['iso'] );
} }
if ( ! empty( $exif['ExposureTime'] ) ) { if ( ! empty( $exif['ExposureTime'] ) ) {
$meta['shutter_speed'] = (string) $exif['ExposureTime'];
if ( is_scalar( $exif['ExposureTime'] ) ) {
$meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] ); $meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] );
} }
}
if ( ! empty( $exif['Orientation'] ) ) { if ( ! empty( $exif['Orientation'] ) ) {
$meta['orientation'] = $exif['Orientation']; $meta['orientation'] = $exif['Orientation'];
} }

View File

@ -16,7 +16,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '5.9-alpha-52268'; $wp_version = '5.9-alpha-52269';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.