wp/wp-includes/compat.php
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
equal deleted inserted replaced
21:48c4eec2b7e6 22:8c2e4d02f4ef
     1 <?php
     1 <?php
     2 /**
     2 /**
     3  * WordPress implementation for PHP functions either missing from older PHP versions or not included by default.
     3  * WordPress implementation for PHP functions either missing from older PHP versions or not included by default.
       
     4  *
       
     5  * This file is loaded extremely early and the functions can be relied upon by drop-ins.
       
     6  * Ergo, please ensure you do not rely on external functions when writing code for this file.
       
     7  * Only use functions built into PHP or are defined in this file and have adequate testing
       
     8  * and error suppression to ensure the file will run correctly and not break websites.
     4  *
     9  *
     5  * @package PHP
    10  * @package PHP
     6  * @access private
    11  * @access private
     7  */
    12  */
     8 
    13 
   256 
   261 
   257 	// Fencepost: preg_split() always returns one extra item in the array.
   262 	// Fencepost: preg_split() always returns one extra item in the array.
   258 	return --$count;
   263 	return --$count;
   259 }
   264 }
   260 
   265 
   261 if ( ! function_exists( 'hash_hmac' ) ) :
       
   262 	/**
       
   263 	 * Compat function to mimic hash_hmac().
       
   264 	 *
       
   265 	 * The Hash extension is bundled with PHP by default since PHP 5.1.2.
       
   266 	 * However, the extension may be explicitly disabled on select servers.
       
   267 	 * As of PHP 7.4.0, the Hash extension is a core PHP extension and can no
       
   268 	 * longer be disabled.
       
   269 	 * I.e. when PHP 7.4.0 becomes the minimum requirement, this polyfill
       
   270 	 * and the associated `_hash_hmac()` function can be safely removed.
       
   271 	 *
       
   272 	 * @ignore
       
   273 	 * @since 3.2.0
       
   274 	 *
       
   275 	 * @see _hash_hmac()
       
   276 	 *
       
   277 	 * @param string $algo   Hash algorithm. Accepts 'md5' or 'sha1'.
       
   278 	 * @param string $data   Data to be hashed.
       
   279 	 * @param string $key    Secret key to use for generating the hash.
       
   280 	 * @param bool   $binary Optional. Whether to output raw binary data (true),
       
   281 	 *                       or lowercase hexits (false). Default false.
       
   282 	 * @return string|false The hash in output determined by `$binary`.
       
   283 	 *                      False if `$algo` is unknown or invalid.
       
   284 	 */
       
   285 	function hash_hmac( $algo, $data, $key, $binary = false ) {
       
   286 		return _hash_hmac( $algo, $data, $key, $binary );
       
   287 	}
       
   288 endif;
       
   289 
       
   290 /**
       
   291  * Internal compat function to mimic hash_hmac().
       
   292  *
       
   293  * @ignore
       
   294  * @since 3.2.0
       
   295  *
       
   296  * @param string $algo   Hash algorithm. Accepts 'md5' or 'sha1'.
       
   297  * @param string $data   Data to be hashed.
       
   298  * @param string $key    Secret key to use for generating the hash.
       
   299  * @param bool   $binary Optional. Whether to output raw binary data (true),
       
   300  *                       or lowercase hexits (false). Default false.
       
   301  * @return string|false The hash in output determined by `$binary`.
       
   302  *                      False if `$algo` is unknown or invalid.
       
   303  */
       
   304 function _hash_hmac( $algo, $data, $key, $binary = false ) {
       
   305 	$packs = array(
       
   306 		'md5'  => 'H32',
       
   307 		'sha1' => 'H40',
       
   308 	);
       
   309 
       
   310 	if ( ! isset( $packs[ $algo ] ) ) {
       
   311 		return false;
       
   312 	}
       
   313 
       
   314 	$pack = $packs[ $algo ];
       
   315 
       
   316 	if ( strlen( $key ) > 64 ) {
       
   317 		$key = pack( $pack, $algo( $key ) );
       
   318 	}
       
   319 
       
   320 	$key = str_pad( $key, 64, chr( 0 ) );
       
   321 
       
   322 	$ipad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x36 ), 64 ) );
       
   323 	$opad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x5C ), 64 ) );
       
   324 
       
   325 	$hmac = $algo( $opad . pack( $pack, $algo( $ipad . $data ) ) );
       
   326 
       
   327 	if ( $binary ) {
       
   328 		return pack( $pack, $hmac );
       
   329 	}
       
   330 
       
   331 	return $hmac;
       
   332 }
       
   333 
       
   334 if ( ! function_exists( 'hash_equals' ) ) :
       
   335 	/**
       
   336 	 * Timing attack safe string comparison.
       
   337 	 *
       
   338 	 * Compares two strings using the same time whether they're equal or not.
       
   339 	 *
       
   340 	 * Note: It can leak the length of a string when arguments of differing length are supplied.
       
   341 	 *
       
   342 	 * This function was added in PHP 5.6.
       
   343 	 * However, the Hash extension may be explicitly disabled on select servers.
       
   344 	 * As of PHP 7.4.0, the Hash extension is a core PHP extension and can no
       
   345 	 * longer be disabled.
       
   346 	 * I.e. when PHP 7.4.0 becomes the minimum requirement, this polyfill
       
   347 	 * can be safely removed.
       
   348 	 *
       
   349 	 * @since 3.9.2
       
   350 	 *
       
   351 	 * @param string $known_string Expected string.
       
   352 	 * @param string $user_string  Actual, user supplied, string.
       
   353 	 * @return bool Whether strings are equal.
       
   354 	 */
       
   355 	function hash_equals( $known_string, $user_string ) {
       
   356 		$known_string_length = strlen( $known_string );
       
   357 
       
   358 		if ( strlen( $user_string ) !== $known_string_length ) {
       
   359 			return false;
       
   360 		}
       
   361 
       
   362 		$result = 0;
       
   363 
       
   364 		// Do not attempt to "optimize" this.
       
   365 		for ( $i = 0; $i < $known_string_length; $i++ ) {
       
   366 			$result |= ord( $known_string[ $i ] ) ^ ord( $user_string[ $i ] );
       
   367 		}
       
   368 
       
   369 		return 0 === $result;
       
   370 	}
       
   371 endif;
       
   372 
       
   373 // sodium_crypto_box() was introduced in PHP 7.2.
   266 // sodium_crypto_box() was introduced in PHP 7.2.
   374 if ( ! function_exists( 'sodium_crypto_box' ) ) {
   267 if ( ! function_exists( 'sodium_crypto_box' ) ) {
   375 	require ABSPATH . WPINC . '/sodium_compat/autoload.php';
   268 	require ABSPATH . WPINC . '/sodium_compat/autoload.php';
   376 }
   269 }
   377 
   270 
   408 	 * @param array $array An array.
   301 	 * @param array $array An array.
   409 	 * @return string|int|null The first key of array if the array
   302 	 * @return string|int|null The first key of array if the array
   410 	 *                         is not empty; `null` otherwise.
   303 	 *                         is not empty; `null` otherwise.
   411 	 */
   304 	 */
   412 	function array_key_first( array $array ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
   305 	function array_key_first( array $array ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
       
   306 		if ( empty( $array ) ) {
       
   307 			return null;
       
   308 		}
       
   309 
   413 		foreach ( $array as $key => $value ) {
   310 		foreach ( $array as $key => $value ) {
   414 			return $key;
   311 			return $key;
   415 		}
   312 		}
   416 	}
   313 	}
   417 }
   314 }
   538 
   435 
   539 		return substr( $haystack, -$len, $len ) === $needle;
   436 		return substr( $haystack, -$len, $len ) === $needle;
   540 	}
   437 	}
   541 }
   438 }
   542 
   439 
       
   440 if ( ! function_exists( 'array_find' ) ) {
       
   441 	/**
       
   442 	 * Polyfill for `array_find()` function added in PHP 8.4.
       
   443 	 *
       
   444 	 * Searches an array for the first element that passes a given callback.
       
   445 	 *
       
   446 	 * @since 6.8.0
       
   447 	 *
       
   448 	 * @param array    $array    The array to search.
       
   449 	 * @param callable $callback The callback to run for each element.
       
   450 	 * @return mixed|null The first element in the array that passes the `$callback`, otherwise null.
       
   451 	 */
       
   452 	function array_find( array $array, callable $callback ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
       
   453 		foreach ( $array as $key => $value ) {
       
   454 			if ( $callback( $value, $key ) ) {
       
   455 				return $value;
       
   456 			}
       
   457 		}
       
   458 
       
   459 		return null;
       
   460 	}
       
   461 }
       
   462 
       
   463 if ( ! function_exists( 'array_find_key' ) ) {
       
   464 	/**
       
   465 	 * Polyfill for `array_find_key()` function added in PHP 8.4.
       
   466 	 *
       
   467 	 * Searches an array for the first key that passes a given callback.
       
   468 	 *
       
   469 	 * @since 6.8.0
       
   470 	 *
       
   471 	 * @param array    $array    The array to search.
       
   472 	 * @param callable $callback The callback to run for each element.
       
   473 	 * @return int|string|null The first key in the array that passes the `$callback`, otherwise null.
       
   474 	 */
       
   475 	function array_find_key( array $array, callable $callback ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
       
   476 		foreach ( $array as $key => $value ) {
       
   477 			if ( $callback( $value, $key ) ) {
       
   478 				return $key;
       
   479 			}
       
   480 		}
       
   481 
       
   482 		return null;
       
   483 	}
       
   484 }
       
   485 
       
   486 if ( ! function_exists( 'array_any' ) ) {
       
   487 	/**
       
   488 	 * Polyfill for `array_any()` function added in PHP 8.4.
       
   489 	 *
       
   490 	 * Checks if any element of an array passes a given callback.
       
   491 	 *
       
   492 	 * @since 6.8.0
       
   493 	 *
       
   494 	 * @param array    $array    The array to check.
       
   495 	 * @param callable $callback The callback to run for each element.
       
   496 	 * @return bool True if any element in the array passes the `$callback`, otherwise false.
       
   497 	 */
       
   498 	function array_any( array $array, callable $callback ): bool { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
       
   499 		foreach ( $array as $key => $value ) {
       
   500 			if ( $callback( $value, $key ) ) {
       
   501 				return true;
       
   502 			}
       
   503 		}
       
   504 
       
   505 		return false;
       
   506 	}
       
   507 }
       
   508 
       
   509 if ( ! function_exists( 'array_all' ) ) {
       
   510 	/**
       
   511 	 * Polyfill for `array_all()` function added in PHP 8.4.
       
   512 	 *
       
   513 	 * Checks if all elements of an array pass a given callback.
       
   514 	 *
       
   515 	 * @since 6.8.0
       
   516 	 *
       
   517 	 * @param array    $array    The array to check.
       
   518 	 * @param callable $callback The callback to run for each element.
       
   519 	 * @return bool True if all elements in the array pass the `$callback`, otherwise false.
       
   520 	 */
       
   521 	function array_all( array $array, callable $callback ): bool { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
       
   522 		foreach ( $array as $key => $value ) {
       
   523 			if ( ! $callback( $value, $key ) ) {
       
   524 				return false;
       
   525 			}
       
   526 		}
       
   527 
       
   528 		return true;
       
   529 	}
       
   530 }
       
   531 
   543 // IMAGETYPE_AVIF constant is only defined in PHP 8.x or later.
   532 // IMAGETYPE_AVIF constant is only defined in PHP 8.x or later.
   544 if ( ! defined( 'IMAGETYPE_AVIF' ) ) {
   533 if ( ! defined( 'IMAGETYPE_AVIF' ) ) {
   545 	define( 'IMAGETYPE_AVIF', 19 );
   534 	define( 'IMAGETYPE_AVIF', 19 );
   546 }
   535 }
   547 
   536 
   548 // IMG_AVIF constant is only defined in PHP 8.x or later.
   537 // IMG_AVIF constant is only defined in PHP 8.x or later.
   549 if ( ! defined( 'IMG_AVIF' ) ) {
   538 if ( ! defined( 'IMG_AVIF' ) ) {
   550 	define( 'IMG_AVIF', IMAGETYPE_AVIF );
   539 	define( 'IMG_AVIF', IMAGETYPE_AVIF );
   551 }
   540 }
       
   541 
       
   542 // IMAGETYPE_HEIC constant is not yet defined in PHP as of PHP 8.3.
       
   543 if ( ! defined( 'IMAGETYPE_HEIC' ) ) {
       
   544 	define( 'IMAGETYPE_HEIC', 99 );
       
   545 }