diff --git a/src/wp-admin/includes/class-wp-debug-data.php b/src/wp-admin/includes/class-wp-debug-data.php
index a921fc4dcb..6fb5cf1253 100644
--- a/src/wp-admin/includes/class-wp-debug-data.php
+++ b/src/wp-admin/includes/class-wp-debug-data.php
@@ -544,7 +544,7 @@ class WP_Debug_Data {
 			$post_max_size       = ini_get( 'post_max_size' );
 			$upload_max_filesize = ini_get( 'upload_max_filesize' );
 			$max_file_uploads    = ini_get( 'max_file_uploads' );
-			$effective           = min( wp_convert_hr_to_bytes( $post_max_size ), wp_convert_hr_to_bytes( $upload_max_filesize ) );
+			$effective           = wp_ini_lesser_quantity( $post_max_size, $upload_max_filesize );
 
 			// Add info in Media section.
 			$info['wp-media']['fields']['file_uploads']        = array(
diff --git a/src/wp-admin/includes/class-wp-site-health.php b/src/wp-admin/includes/class-wp-site-health.php
index 7c94e8be10..542fbc280f 100644
--- a/src/wp-admin/includes/class-wp-site-health.php
+++ b/src/wp-admin/includes/class-wp-site-health.php
@@ -2163,7 +2163,7 @@ class WP_Site_Health {
 		$post_max_size       = ini_get( 'post_max_size' );
 		$upload_max_filesize = ini_get( 'upload_max_filesize' );
 
-		if ( wp_convert_hr_to_bytes( $post_max_size ) < wp_convert_hr_to_bytes( $upload_max_filesize ) ) {
+		if ( wp_ini_quantity_cmp( $post_max_size, $upload_max_filesize ) < 0 ) {
 			$result['label'] = sprintf(
 				/* translators: 1: post_max_size, 2: upload_max_filesize */
 				__( 'The "%1$s" value is smaller than "%2$s"' ),
@@ -2172,7 +2172,7 @@ class WP_Site_Health {
 			);
 			$result['status'] = 'recommended';
 
-			if ( 0 === wp_convert_hr_to_bytes( $post_max_size ) ) {
+			if ( wp_ini_parse_quantity( $post_max_size ) <= 0 ) {
 				$result['description'] = sprintf(
 					'<p>%s</p>',
 					sprintf(
diff --git a/src/wp-includes/default-constants.php b/src/wp-includes/default-constants.php
index 56754033a0..dff6db37aa 100644
--- a/src/wp-includes/default-constants.php
+++ b/src/wp-includes/default-constants.php
@@ -39,8 +39,7 @@ function wp_initial_constants() {
 		define( 'WP_START_TIMESTAMP', microtime( true ) );
 	}
 
-	$current_limit     = ini_get( 'memory_limit' );
-	$current_limit_int = wp_convert_hr_to_bytes( $current_limit );
+	$current_limit = ini_get( 'memory_limit' );
 
 	// Define memory limits.
 	if ( ! defined( 'WP_MEMORY_LIMIT' ) ) {
@@ -56,7 +55,7 @@ function wp_initial_constants() {
 	if ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) ) {
 		if ( false === wp_is_ini_value_changeable( 'memory_limit' ) ) {
 			define( 'WP_MAX_MEMORY_LIMIT', $current_limit );
-		} elseif ( -1 === $current_limit_int || $current_limit_int > 268435456 /* = 256M */ ) {
+		} elseif ( wp_ini_quantity_cmp( $current_limit, '256M' ) > 0 ) {
 			define( 'WP_MAX_MEMORY_LIMIT', $current_limit );
 		} else {
 			define( 'WP_MAX_MEMORY_LIMIT', '256M' );
@@ -64,8 +63,7 @@ function wp_initial_constants() {
 	}
 
 	// Set memory limits.
-	$wp_limit_int = wp_convert_hr_to_bytes( WP_MEMORY_LIMIT );
-	if ( -1 !== $current_limit_int && ( -1 === $wp_limit_int || $wp_limit_int > $current_limit_int ) ) {
+	if ( wp_ini_quantity_cmp( WP_MEMORY_LIMIT, $current_limit ) > 0 ) {
 		ini_set( 'memory_limit', WP_MEMORY_LIMIT );
 	}
 
diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php
index 946853c361..587ec21ed9 100644
--- a/src/wp-includes/functions.php
+++ b/src/wp-includes/functions.php
@@ -7454,16 +7454,15 @@ function wp_raise_memory_limit( $context = 'admin' ) {
 		return false;
 	}
 
-	$current_limit     = ini_get( 'memory_limit' );
-	$current_limit_int = wp_convert_hr_to_bytes( $current_limit );
+	$current_limit = ini_get( 'memory_limit' );
 
-	if ( -1 === $current_limit_int ) {
+	// If we're already set to an unlimited value there's no higher limit to set.
+	if ( wp_ini_parse_quantity( $current_limit ) <= 0 ) {
 		return false;
 	}
 
-	$wp_max_limit     = WP_MAX_MEMORY_LIMIT;
-	$wp_max_limit_int = wp_convert_hr_to_bytes( $wp_max_limit );
-	$filtered_limit   = $wp_max_limit;
+	$wp_max_limit   = WP_MAX_MEMORY_LIMIT;
+	$filtered_limit = $wp_max_limit;
 
 	switch ( $context ) {
 		case 'admin':
@@ -7523,23 +7522,19 @@ function wp_raise_memory_limit( $context = 'admin' ) {
 			break;
 	}
 
-	$filtered_limit_int = wp_convert_hr_to_bytes( $filtered_limit );
+	// Set the memory limit to the greatest of all the filtered value, the MAX limit, and the current limit.
+	$new_limit = wp_ini_greater_quantity( $current_limit, WP_MAX_MEMORY_LIMIT );
+	$new_limit = wp_ini_greater_quantity( $filtered_limit, $new_limit );
 
-	if ( -1 === $filtered_limit_int || ( $filtered_limit_int > $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) {
-		if ( false !== ini_set( 'memory_limit', $filtered_limit ) ) {
-			return $filtered_limit;
-		} else {
-			return false;
-		}
-	} elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) {
-		if ( false !== ini_set( 'memory_limit', $wp_max_limit ) ) {
-			return $wp_max_limit;
-		} else {
-			return false;
-		}
+	// If we're already set at the greatest limit we don't need to change it.
+	if ( 0 === wp_ini_quantity_cmp( $new_limit, $current_limit ) ) {
+		return false;
 	}
 
-	return false;
+	// Otherwise attempt to set the new limit and return the new value if it succeeded.
+	return false !== ini_set( 'memory_limit', $new_limit )
+		? $new_limit
+		: false;
 }
 
 /**
diff --git a/src/wp-includes/load.php b/src/wp-includes/load.php
index d4bc58b9c2..af2148b9f0 100644
--- a/src/wp-includes/load.php
+++ b/src/wp-includes/load.php
@@ -5,6 +5,8 @@
  * @package WordPress
  */
 
+require_once __DIR__ . '/php-compat.php';
+
 /**
  * Return the HTTP protocol sent by the server.
  *
@@ -1465,6 +1467,7 @@ function is_ssl() {
  *
  * @since 2.3.0
  * @since 4.6.0 Moved from media.php to load.php.
+ * @deprecated 6.1.0 Use wp_ini_parse_quantity() or wp_hr_bytes() instead.
  *
  * @link https://www.php.net/manual/en/function.ini-get.php
  * @link https://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
@@ -1473,6 +1476,19 @@ function is_ssl() {
  * @return int An integer byte value.
  */
 function wp_convert_hr_to_bytes( $value ) {
+	_deprecated_function( __FUNCTION__, '6.1.0', 'wp_ini_parse_quantity' );
+	return wp_hr_bytes( $value );
+}
+
+/**
+ * Parses a "human-readable" byte value into an integer.
+ *
+ * @since 6.1.0
+ *
+ * @param string $value Human-readable description of a byte size
+ * @return int An integer byte value.
+ */
+function wp_hr_bytes( $value ) {
 	$value = strtolower( trim( $value ) );
 	$bytes = (int) $value;
 
diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php
index caf8d247f5..51a6382f1e 100644
--- a/src/wp-includes/media.php
+++ b/src/wp-includes/media.php
@@ -3787,8 +3787,9 @@ function wp_expand_dimensions( $example_width, $example_height, $max_width, $max
  * @return int Allowed upload size.
  */
 function wp_max_upload_size() {
-	$u_bytes = wp_convert_hr_to_bytes( ini_get( 'upload_max_filesize' ) );
-	$p_bytes = wp_convert_hr_to_bytes( ini_get( 'post_max_size' ) );
+	$upload_max_filesize = ini_get( 'upload_max_filesize' );
+	$post_max_size       = ini_get( 'post_max_size' );
+	$max_upload          = wp_ini_lesser_quantity( $upload_max_filesize, $post_max_size );
 
 	/**
 	 * Filters the maximum upload size allowed in php.ini.
@@ -3799,7 +3800,12 @@ function wp_max_upload_size() {
 	 * @param int $u_bytes Maximum upload filesize in bytes.
 	 * @param int $p_bytes Maximum size of POST data in bytes.
 	 */
-	return apply_filters( 'upload_size_limit', min( $u_bytes, $p_bytes ), $u_bytes, $p_bytes );
+	return apply_filters(
+		'upload_size_limit',
+		wp_ini_parse_quantity( $max_upload ),
+		wp_ini_parse_quantity( $upload_max_filesize ),
+		wp_ini_parse_quantity( $post_max_size )
+	);
 }
 
 /**
diff --git a/src/wp-includes/php-compat.php b/src/wp-includes/php-compat.php
new file mode 100644
index 0000000000..584bfa63a0
--- /dev/null
+++ b/src/wp-includes/php-compat.php
@@ -0,0 +1,340 @@
+<?php
+
+defined( 'IS_32_BIT_SYSTEM' ) || define( 'IS_32_BIT_SYSTEM', 2147483647 === PHP_INT_MAX );
+defined( 'PHP_INT_MAX' ) || define( 'PHP_INT_MAX', IS_32_BIT_SYSTEM ? 2147483647 : 9223372036854775807 );
+defined( 'PHP_INT_MIN' ) || define( 'PHP_INT_MIN', IS_32_BIT_SYSTEM ? -2147483648 : -9223372036854775808 );
+
+/*
+ * Returns byte size represented in a numeric php.ini directive.
+ *
+ * Generally this can be used in combination with `ini_get( $option )`
+ * for values that accept a numeric "byte" size, such as `post_max_size`.
+ * It will return the value which PHP interprets from the "shorthand"
+ * syntax, such as "128m" being 128 MiB and "128mb" being 128 B.
+ *
+ * Since PHP 8.2 this may return inaccurate results if passed the value
+ * for the `memory_limit` INI directive as it uses the new unsigned
+ * parser.
+ *
+ * @param false|int|string $value
+ * @return int
+ */
+function wp_ini_parse_quantity( $value ) {
+	// A missing value is an implicit lack of limit, thus we return `0`, meaning "no limit."
+	if ( false === $value ) {
+		return 0;
+	}
+
+	/*
+	 * Directly return pre-parsed values so we can repeatedly call
+	 * this without tracking if we've already parsed a given value.
+	 */
+	if ( is_int( $value ) ) {
+		return $value;
+	}
+
+	/*
+	 * Non-string inputs "fail" to no limit, because there's
+	 * no limit we could ascribe to this invalid value.
+	 */
+	if ( ! is_string( $value ) ) {
+		return 0;
+	}
+
+	return ini_parse_quantity( $value );
+}
+
+/**
+ * Returns larger of two php.ini directive quantity values.
+ *
+ * Example:
+ *     wp_ini_greater_quantity( '256m', -1 ) === -1
+ *     wp_ini_greater_quantity( '64K', '64') === '64K'
+ *     wp_ini_greater_quantity( 1000, 2000 ) === 2000
+ *
+ * @param int|string|false $a Quantity value.
+ * @param int|string|false $b Quantity value.
+ * @return int|string|false   Larger quantity value.
+ */
+function wp_ini_greater_quantity( $a, $b ) {
+	return wp_ini_quantity_cmp( $a, $b ) >= 0 ? $a : $b;
+}
+
+/**
+ * Returns smaller of two php.ini directive quantity values.
+ *
+ * Example:
+ *     wp_ini_lesser_quantity( '256m', -1 ) === '256m'
+ *     wp_ini_lesser_quantity( '64K', '64') === '64'
+ *     wp_ini_lesser_quantity( 1000, 2000 ) === 1000
+ *
+ * @param int|string|false $a Quantity value.
+ * @param int|string|false $b Quantity value.
+ * @return int|string|false   Smaller quantity value.
+ */
+function wp_ini_lesser_quantity( $a, $b ) {
+	return wp_ini_quantity_cmp( $a, $b ) <= 0 ? $a : $b;
+}
+
+/**
+ * Comparator for php.ini quantity values, can be used
+ * as the callback for functions such as `usort()`.
+ *
+ * Example:
+ *     $a  <  $b => -1
+ *     $a === $b =>  0
+ *     $a  >  $b =>  1
+ *
+ * @param int|string|false $a Quantity being compared.
+ * @param int|string|false $b Quantity against which $a is compared.
+ * @return int
+ */
+function wp_ini_quantity_cmp( $a, $b ) {
+	$a_scalar = wp_ini_parse_quantity( $a );
+	$b_scalar = wp_ini_parse_quantity( $b );
+
+	if ( $a_scalar === $b_scalar ) {
+		return 0;
+	}
+
+	// No limit on $a means it's at least as large as any $b value.
+	if ( $a_scalar <= 0 ) {
+		return 1;
+	}
+
+	// No limit on $b means it's at least as large as any $a value.
+	if ( $b_scalar <= 0 ) {
+		return -1;
+	}
+
+	return $a_scalar > $b_scalar ? 1 : -1;
+}
+
+// ini_parse_quantity added to PHP in PHP 8.2
+if ( ! function_exists( 'ini_parse_quantity' ) ) :
+	/**
+	 * Returns quantity represented by a php.ini directive's "byte size shorthand."
+	 *
+	 * php.ini directives may use a string representation of a number of bytes
+	 * or a "shorthand" byte size to reference larger values. Multiple numeric
+	 * php.ini directive use these shorthands even when they don't refer to bytes.
+	 *
+	 * Example:
+	 *
+	 *     ini_parse_quantity( "1m" ) == 1048576
+	 *     ini_parse_quantity( "2K" ) == 2048 // 2 * 1024
+	 *     ini_parse_quantity( "0.5g" ) == 0
+	 *     ini_parse_quantity( "14.6e-13g" ) == 15032385536 // 14 * 1024^3
+	 *     ini_parse_quantity( "-813k" ) == -832512; // -813 * 1024
+	 *     ini_parse_quantity( "boat" ) == 0;
+	 *
+	 *     // This gives an answer, but it's _wrong_ because
+	 *     // the underlying mechanism in PHP overflowed and
+	 *     // the real return value depends on whether PHP
+	 *     // was built with 64-bit support.
+	 *     ini_parse_quantity( "9223372036854775807g" ) == ??
+	 *
+	 * Notes:
+	 *  - Suffixes are specifically _the last character_ and case-insensitive.
+	 *  - Suffixes k/m/g intentionally report powers of 1024 to agree with PHP.
+	 *  - This function does not fail on invalid input; it returns `0` in such cses.
+	 *  - As noted in the PHP documentation, overflow behavior is unspecified and
+	 *    platform-dependant. Values that trigger overflow are likely wrong
+	 *  - In PHP 8.2+ this function may return an invalid count for shorthand values
+	 *    parsed with the new unsigned parser. Currently only affects "memory_limit"
+	 *    and only when the value overflows an unsigned integer on the platform.
+	 *
+	 * @since 6.1.
+	 *
+	 * @link https://www.php.net/manual/en/function.ini-get.php
+	 * @link https://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
+
+	 * @param string $value Numeric string value possibly in "shorthand notation."
+	 * @return int          Parsed numeric value represented by given string.
+	 */
+	function ini_parse_quantity( $value ) {
+		/**
+		 * Number of bytes in input string; because we're only assessing 7-bit
+		 * ASCII/Unicode characters we can safely count bytes vs. needing to
+		 * worry about code units, code points, or grapheme clusters.
+		 *
+		 * @var int
+		 */
+		$strlen = strlen( $value );
+
+		/** @var int|float Numeric quantity represented by value string. */
+		$scalar = 0;
+
+		/** @var int Sign of numeric quantity, either positive (1) or negative (-1). */
+		$sign = 1;
+
+		/**
+		 * Numeric base of digits determined by string prefix (e.g. "0x" or "0").
+		 * Must be 8 for octal, 10 for decimal, or 16 for hexadecimal.
+		 *
+		 * @var int
+		 */
+		$base = 10;
+
+		/** @var int Index into input string as we walk through it and analyze each character. */
+		$i = 0;
+
+		/*
+		 * Trim leading whitespace.
+		 *
+		 * We could also do this with `ltrim()` but that adds a needless
+		 * string copy and makes it appear like we could add `+` to the
+		 * list of values to trim, which we cannot, because that
+		 * results in the wrong parse for strings with multiple
+		 * `+` or `-` characters in a row.
+		 */
+		for ( ; $i < $strlen; $i++ ) {
+			$c = $value[ $i ];
+
+			if ( ' ' === $c || "\t" === $c || "\r" === $c || "\v" === $c || "\f" === $c ) {
+				continue;
+			}
+
+			break;
+		}
+
+		// Handle optional sign indicator.
+		switch ( $value[ $i ] ) {
+			case '+':
+				$i++;
+				break;
+
+			case '-':
+				$sign = -1;
+				$i++;
+				break;
+		}
+
+		// Determine base for digit conversion, if not decimal.
+		$base_a = $i < $strlen ? $value[ $i ] : '';
+		$base_b = $i + 1 < $strlen ? $value[ $i + 1 ] : '';
+
+		if ( '0' === $base_a && ( 'x' === $base_b || 'X' === $base_b ) ) {
+			$base = 16;
+			$i += 2;
+		} else if ( '0' === $base_a && ctype_digit( $base_b ) ) {
+			$base = 8;
+			$i += 1;
+		}
+
+		// Trim leading zeros.
+		for ( ; $i < $strlen; $i++ ) {
+			if ( '0' !== $value[ $i ] ) {
+				break;
+			}
+		}
+
+		/**
+		 * Numeric values for scanned digits.
+		 *
+		 * These are used to determine the decimal value the digit
+		 * represents and whether it's an allowed character in
+		 * the given base. It's allowed if its value is less
+		 * than the base: e.g. '7' is allowed in octal (base 8)
+		 * but '8' and '9' aren't because they are greater than 8.
+		 *
+		 * @var array
+		 */
+		$digits = array(
+			'0' => 0,
+			'1' => 1,
+			'2' => 2,
+			'3' => 3,
+			'4' => 4,
+			'5' => 5,
+			'6' => 6,
+			'7' => 7,
+			'8' => 8,
+			'9' => 9,
+			'A' => 10,
+			'a' => 10,
+			'B' => 11,
+			'b' => 11,
+			'C' => 12,
+			'c' => 12,
+			'D' => 13,
+			'd' => 13,
+			'E' => 14,
+			'e' => 14,
+			'F' => 15,
+			'f' => 15,
+		);
+
+		// Build the scalar value by consuming the next sequence of contiguous digits.
+		for ( ; $i < $strlen; $i++ ) {
+			$c = $value[ $i ];
+
+			/*
+			 * Only digits recognized in this base system can be used.
+			 * Once we find an unrecognized digit we abort and move
+			 * on to the next step in parsing the size suffix.
+			 */
+			if ( ! isset( $digits[ $c ] ) || $digits[ $c ] >= $base ) {
+				break;
+			}
+
+			/*
+			 * This is the step that computes our integer as we see new digits.
+			 *
+			 * Example:
+			 *      4   = (0 * 10) + 4
+			 *      45  = ((0 * 10 + 4) * 10) + 5
+			 *      458 = ((0 * 10 + 4) * 10 + 5) * 10 + 8
+			 */
+			$scalar = $scalar * $base + $digits[ $c ];
+
+			// Stop processing if we're already at the maximum magnitude for the sign.
+			if (
+				( $sign > 0 && $scalar > PHP_INT_MAX ) ||
+				( $sign < 0 && $scalar > -PHP_INT_MIN )
+			) {
+				break;
+			}
+		}
+
+		// Clamp the parsed digits to an integer value as PHP does internally.
+		if ( $sign > 0 && $scalar >= PHP_INT_MAX ) {
+			$scalar = PHP_INT_MAX;
+		} else if ( $sign < 0 && $scalar >= -PHP_INT_MIN ) {
+			$scalar = PHP_INT_MIN;
+		} else if ( $sign < 0 ) {
+			$scalar = -$scalar;
+		}
+
+		/*
+		 * Do not use WP constants here (GB_IN_BYTES, MB_IN_BYTES, KB_IN_BYTES)
+		 * since they are re-definable; PHP shorthand values are hard-coded
+		 * in PHP itself and stay the same regardless of these constants.
+		 *
+		 * Note that we can overflow here, as happens in PHP itself.
+		 * Overflow results will likely not match PHP's value, but
+		 * will likely break in most cases anyway and so leaving
+		 * this loose is the best we can do until we can read these
+		 * values directly from PHP.
+		 */
+		switch ( $value[ $strlen - 1 ] ) {
+			case 'g':
+			case 'G':
+				$scalar *= 1073741824; // 1024^3
+				break;
+
+			case 'm':
+			case 'M':
+				$scalar *= 1048576; // 1024^2
+				break;
+
+			case 'k':
+			case 'K':
+				$scalar *= 1024;
+				break;
+		}
+
+		return (int) $scalar;
+	}
+
+endif;
diff --git a/tests/phpunit/tests/load/wpConvertHrToBytes.php b/tests/phpunit/tests/load/wpConvertHrToBytes.php
index 66f4d4329b..cf08e58761 100644
--- a/tests/phpunit/tests/load/wpConvertHrToBytes.php
+++ b/tests/phpunit/tests/load/wpConvertHrToBytes.php
@@ -44,7 +44,15 @@ class Tests_Load_wpConvertHrToBytes extends WP_UnitTestCase {
 			array( '128m', 134217728 ),
 			array( '256M', 268435456 ),
 			array( '1g', 1073741824 ),
-			array( '128m ', 134217728 ), // Leading/trailing whitespace gets trimmed.
+
+			/**
+			 * Leading/trailing whitespace gets trimmed.
+			 * Note that this is not the value that PHP uses internally.
+			 * PHP interprets the value as 128, not 128 MiB.
+			 *
+			 * @see wp_ini_parse_quantity()
+			 */
+			array( '128m ', 134217728 ),
 			array( '1024', 1024 ), // No letter will be interpreted as integer value.
 
 			// Edge cases.
diff --git a/tests/phpunit/tests/php-compat/ini_parse_quantity.php b/tests/phpunit/tests/php-compat/ini_parse_quantity.php
new file mode 100644
index 0000000000..5f6233615c
--- /dev/null
+++ b/tests/phpunit/tests/php-compat/ini_parse_quantity.php
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * Tests for PHP compatability functions.
+ *
+ * @group php-compat.php
+ * @covers ::wp_ini_parse_quantity
+ */
+class Tests_PHP_Compat_wpIniParseQuantity extends WP_UnitTestCase {
+	public function test_unset_limit_is_no_limit() {
+		$this->assertEquals( 0, wp_ini_parse_quantity( false ) );
+	}
+
+	public function test_absent_limit_is_no_limit() {
+		$this->assertEquals( 0, wp_ini_parse_quantity( '' ) );
+	}
+
+	public function test_unlimited_is_unlimited() {
+		$this->assertEquals( -1, wp_ini_parse_quantity( '-1' ) );
+	}
+
+	public function test_unlimited_is_same_as_missing_limit() {
+		$this->assertEqual( '', wp_ini_greater_quantity( '', '-1' ) );
+		$this->assertEqual( '-1', wp_ini_greater_quantity( '-1', '' ) );
+		$this->assertEqual( '', wp_ini_lesser_quantity( '', '-1' ) );
+		$this->assertEqual( '-1', wp_ini_lesser_quantity( '-1', '' ) );
+	}
+
+	public function test_unlimited_is_greater_than_hard_limit() {
+		$this->assertEqual( 1, wp_ini_quantity_cmp( -1, 1348 ) );
+		$this->assertEqual( 1, wp_ini_quantity_cmp( -1, '1348g' ) );
+		$this->assertEqual( 1, wp_ini_quantity_cmp( '', 1348 ) );
+		$this->assertEqual( 1, wp_ini_quantity_cmp( '', '1348g' ) );
+		$this->assertEqual( 1, wp_ini_quantity_cmp( 0, 1348 ) );
+		$this->assertEqual( 1, wp_ini_quantity_cmp( 0, '1348g' ) );
+		$this->assertEqual( 1, wp_ini_quantity_cmp( false, 1348 ) );
+		$this->assertEqual( 1, wp_ini_quantity_cmp( false, '1348g' ) );
+	}
+
+	public function test_invalid_data_is_no_limit() {
+		$this->assertEquals( 0, wp_ini_parse_quantity( true ) );
+		$this->assertEquals( 0, wp_ini_parse_quantity( false ) );
+		$this->assertEquals( 0, wp_ini_parse_quantity( array( 1, 2, 3 ) ) );
+		$this->assertEquals( 0, wp_ini_parse_quantity( new stdClass ) );
+	}
+
+	public function test_returns_already_parsed_values() {
+		$this->assertEquals( 15, wp_ini_parse_quantity( 15 ) );
+		$this->assertEquals( -1543, wp_ini_parse_quantity( -1543 ) );
+	}
+
+	public function test_clamped_to_max_int_before_suffix() {
+		if ( IS_32_BIT_SYSTEM ) {
+			$this->assertEquals( PHP_INT_MAX, wp_ini_parse_quantity( '2147483648' ) );
+			$this->assertEquals( PHP_INT_MIN, wp_ini_parse_quantity( '-2147483649' ) );
+		} else {
+			$this->assertEquals( PHP_INT_MAX, wp_ini_parse_quantity( '9223372036854775808' ) );
+			$this->assertEquals( PHP_INT_MIN, wp_ini_parse_quantity( '-9223372036854775809' ) );
+		}
+	}
+
+	public function test_suffix_math_may_overflow() {
+		if ( IS_32_BIT_SYSTEM ) {
+			$this->assertNotEquals( PHP_INT_MAX, wp_ini_parse_quantity( '2147483648g' ) );
+			$this->assertNotEquals( PHP_INT_MIN, wp_ini_parse_quantity( '-2147483648g' ) );
+		} else {
+			$this->assertNotEquals( PHP_INT_MAX, wp_ini_parse_quantity( '9223372036854775807g' ) );
+			$this->assertNotEquals( PHP_INT_MIN, wp_ini_parse_quantity( '-9223372036854775807g' ) );
+		}
+	}
+
+	/**
+	 * Tests converting numeric php.ini directive strings into their scalar equivalents.
+	 *
+	 * @ticket 55635
+	 *
+	 * @dataProvider data_php_numeric_strings
+	 *
+	 * @param $value
+	 * @param $expected
+	 */
+	public function test_parse_matches_php_internal_value( $value, $expected ) {
+		$this->assertEquals( $expected, wp_ini_parse_quantity( $value ) );
+	}
+
+	public function data_php_numeric_strings() {
+		return array(
+			// Decimal integer input.
+			array( '0', 0 ),
+			array( '100', 100 ),
+			array( '-14', -14 ),
+
+			// Octal integer input.
+			array( '0100', 64 ),
+			array( '-0654', -428 ),
+
+			// Hex input.
+			array( '0x14', 20 ),
+			array( '0X14', 20 ),
+			array( '-0xAA', -170 ),
+
+			// Size suffixes.
+			array( '1g', 1073741824 ),
+			array( '1gb', 0 ),
+			array( '32k', 32768 ),
+			array( '64K', 65536 ),
+			array( '07k', 7168 ),
+			array( '-0xF3d7m', -65455259648 ),
+			array( '128m', 134217728 ),
+			array( '128m ', 128 ),
+			array( '128mk', 131072 ),
+			array( '128km', 134217728 ),
+			array( '1.28 kmg', 1073741824 ),
+			array( '256M', 268435456 ),
+
+			// Leading characters.
+			array( '    68', 68 ),
+			array( '+1', 1 ),
+			array( '    -0xdeadbeef', -3735928559 ),
+			array( ' 00000077', 63 ),
+
+			// Things that don't look valid but are still possible.
+			array( '', 0 ),
+			array( '3km', 3145728 ),
+			array( '1mg', 1073741824 ),
+			array( 'boat', 0 ),
+			array( '-14chairsk', -14336 ),
+			array( '0xt', 0 ),
+			array( '++3', 0 ),
+			array( '0x5ome 🅰🅱🅲 attack', 5120 ),
+		);
+	}
+}
