REST API: Fix rest_is_integer() returning false for large integers.

The previous `round( (float) $maybe_integer ) === (float) $maybe_integer` check rejected large integers on PHP 8.4. The check itself was fragile: a PHP `float` (a 64-bit IEEE-754 double) can represent every integer exactly only up to 2^53, so casting larger values is lossy. Nevertheless, that lossiness alone did not reject anything, since both sides of the comparison were munged identically. What actually broke it was a `round()` regression in PHP 8.4, where `round( (float) $x )` can return a value different from `(float) $x` for certain numbers. That inequality caused canonical integers still valid for a `BIGINT UNSIGNED` column (such as unusually high post IDs) to be incorrectly rejected by REST validation, only on PHP 8.4+.

The function now short-circuits returning true for native integers and canonical integer strings so that integer-like values of any magnitude are detected correctly. Decimal and scientific-notation strings (and floats) retain their historical behavior, including the existing float comparison, now rewritten as a `floor()` check whose strict equality compares a float to its own floor and is therefore exact. The limitations around `PHP_INT_MAX` and fractional magnitudes beyond `2 ** 53` are documented on the function, and the data provider gains coverage for large integers, negative floats, and scientific notation.

Developed in https://github.com/WordPress/wordpress-develop/pull/11893.
Follow-up to r48306.

Props siliconforks, gautam23, westonruter, kevinfodness, mboynes, desrosj.
Fixes #65271.

Built from https://develop.svn.wordpress.org/trunk@62474


git-svn-id: http://core.svn.wordpress.org/trunk@61755 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Weston Ruter
2026-06-08 21:25:37 +00:00
parent bd27c52787
commit 628bd24697
2 changed files with 33 additions and 3 deletions
+32 -2
View File
@@ -1564,13 +1564,43 @@ function rest_is_boolean( $maybe_bool ) {
/**
* Determines if a given value is integer-like.
*
* This reports whether the value represents an integer; it does not guarantee that the
* value can be represented as a native PHP integer. Values whose magnitude exceeds
* `PHP_INT_MAX` are still reported as integer-like, even though the `(int)` cast that
* {@see rest_sanitize_value_from_schema()} applies for the 'integer' type cannot round-trip
* them: an out-of-range numeric *string* saturates to `PHP_INT_MAX` or `PHP_INT_MIN`, while
* an out-of-range *float* is an undefined conversion in PHP that yields an arbitrary wrapped
* value. Likewise, a numeric value with a fractional part that is too large for the fraction
* to be represented as a float (greater than 2 ** 53) is reported as integer-like.
*
* @since 5.5.0
*
* @param mixed $maybe_integer The value being evaluated.
* @return bool True if an integer, otherwise false.
*/
function rest_is_integer( $maybe_integer ) {
return is_numeric( $maybe_integer ) && round( (float) $maybe_integer ) === (float) $maybe_integer;
function rest_is_integer( $maybe_integer ): bool {
if ( is_int( $maybe_integer ) ) {
return true;
}
// A canonical integer string of any magnitude — verified without float conversion.
if ( is_string( $maybe_integer ) && preg_match( '/^\s*[+-]?[0-9]+\s*$/', $maybe_integer ) ) {
return true;
}
// Decimal and scientific-notation strings (and floats) keep their historical behavior.
if ( ! is_numeric( $maybe_integer ) ) {
return false;
}
$float_value = (float) $maybe_integer;
/*
* The strict equality here is not the unreliable "are two computed floats equal" comparison
* (e.g. 0.1 + 0.2 === 0.3, which is false). It compares a float to its own floor() to ask
* "does this float have a fractional part?". A float is whole exactly when it equals its floor,
* so the comparison is exact and safe regardless of floating-point representation error.
*/
return floor( $float_value ) === $float_value;
}
/**
+1 -1
View File
@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '7.1-alpha-62473';
$wp_version = '7.1-alpha-62474';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.