wp/wp-includes/compat.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     4  *
     4  *
     5  * @package PHP
     5  * @package PHP
     6  * @access private
     6  * @access private
     7  */
     7  */
     8 
     8 
     9 // If gettext isn't available
     9 // If gettext isn't available.
    10 if ( ! function_exists( '_' ) ) {
    10 if ( ! function_exists( '_' ) ) {
    11 	function _( $string ) {
    11 	function _( $string ) {
    12 		return $string;
    12 		return $string;
    13 	}
    13 	}
    14 }
    14 }
    17  * Returns whether PCRE/u (PCRE_UTF8 modifier) is available for use.
    17  * Returns whether PCRE/u (PCRE_UTF8 modifier) is available for use.
    18  *
    18  *
    19  * @ignore
    19  * @ignore
    20  * @since 4.2.2
    20  * @since 4.2.2
    21  * @access private
    21  * @access private
    22  *
       
    23  * @staticvar string $utf8_pcre
       
    24  *
    22  *
    25  * @param bool $set - Used for testing only
    23  * @param bool $set - Used for testing only
    26  *             null   : default - get PCRE/u capability
    24  *             null   : default - get PCRE/u capability
    27  *             false  : Used for testing - return false for future calls to this function
    25  *             false  : Used for testing - return false for future calls to this function
    28  *             'reset': Used for testing - restore default behavior of this function
    26  *             'reset': Used for testing - restore default behavior of this function
    33 	if ( null !== $set ) {
    31 	if ( null !== $set ) {
    34 		$utf8_pcre = $set;
    32 		$utf8_pcre = $set;
    35 	}
    33 	}
    36 
    34 
    37 	if ( 'reset' === $utf8_pcre ) {
    35 	if ( 'reset' === $utf8_pcre ) {
       
    36 		// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- intentional error generated to detect PCRE/u support.
    38 		$utf8_pcre = @preg_match( '/^./u', 'a' );
    37 		$utf8_pcre = @preg_match( '/^./u', 'a' );
    39 	}
    38 	}
    40 
    39 
    41 	return $utf8_pcre;
    40 	return $utf8_pcre;
    42 }
    41 }
    86 
    85 
    87 	/*
    86 	/*
    88 	 * The solution below works only for UTF-8, so in case of a different
    87 	 * The solution below works only for UTF-8, so in case of a different
    89 	 * charset just use built-in substr().
    88 	 * charset just use built-in substr().
    90 	 */
    89 	 */
    91 	if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) ) {
    90 	if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ), true ) ) {
    92 		return is_null( $length ) ? substr( $str, $start ) : substr( $str, $start, $length );
    91 		return is_null( $length ) ? substr( $str, $start ) : substr( $str, $start, $length );
    93 	}
    92 	}
    94 
    93 
    95 	if ( _wp_can_use_pcre_u() ) {
    94 	if ( _wp_can_use_pcre_u() ) {
    96 		// Use the regex unicode support to separate the UTF-8 characters into an array.
    95 		// Use the regex unicode support to separate the UTF-8 characters into an array.
    98 		$chars = is_null( $length ) ? array_slice( $match[0], $start ) : array_slice( $match[0], $start, $length );
    97 		$chars = is_null( $length ) ? array_slice( $match[0], $start ) : array_slice( $match[0], $start, $length );
    99 		return implode( '', $chars );
    98 		return implode( '', $chars );
   100 	}
    99 	}
   101 
   100 
   102 	$regex = '/(
   101 	$regex = '/(
   103 		  [\x00-\x7F]                  # single-byte sequences   0xxxxxxx
   102 		[\x00-\x7F]                  # single-byte sequences   0xxxxxxx
   104 		| [\xC2-\xDF][\x80-\xBF]       # double-byte sequences   110xxxxx 10xxxxxx
   103 		| [\xC2-\xDF][\x80-\xBF]       # double-byte sequences   110xxxxx 10xxxxxx
   105 		| \xE0[\xA0-\xBF][\x80-\xBF]   # triple-byte sequences   1110xxxx 10xxxxxx * 2
   104 		| \xE0[\xA0-\xBF][\x80-\xBF]   # triple-byte sequences   1110xxxx 10xxxxxx * 2
   106 		| [\xE1-\xEC][\x80-\xBF]{2}
   105 		| [\xE1-\xEC][\x80-\xBF]{2}
   107 		| \xED[\x80-\x9F][\x80-\xBF]
   106 		| \xED[\x80-\x9F][\x80-\xBF]
   108 		| [\xEE-\xEF][\x80-\xBF]{2}
   107 		| [\xEE-\xEF][\x80-\xBF]{2}
   170 
   169 
   171 	/*
   170 	/*
   172 	 * The solution below works only for UTF-8, so in case of a different charset
   171 	 * The solution below works only for UTF-8, so in case of a different charset
   173 	 * just use built-in strlen().
   172 	 * just use built-in strlen().
   174 	 */
   173 	 */
   175 	if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) ) {
   174 	if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ), true ) ) {
   176 		return strlen( $str );
   175 		return strlen( $str );
   177 	}
   176 	}
   178 
   177 
   179 	if ( _wp_can_use_pcre_u() ) {
   178 	if ( _wp_can_use_pcre_u() ) {
   180 		// Use the regex unicode support to separate the UTF-8 characters into an array.
   179 		// Use the regex unicode support to separate the UTF-8 characters into an array.
   181 		preg_match_all( '/./us', $str, $match );
   180 		preg_match_all( '/./us', $str, $match );
   182 		return count( $match[0] );
   181 		return count( $match[0] );
   183 	}
   182 	}
   184 
   183 
   185 	$regex = '/(?:
   184 	$regex = '/(?:
   186 		  [\x00-\x7F]                  # single-byte sequences   0xxxxxxx
   185 		[\x00-\x7F]                  # single-byte sequences   0xxxxxxx
   187 		| [\xC2-\xDF][\x80-\xBF]       # double-byte sequences   110xxxxx 10xxxxxx
   186 		| [\xC2-\xDF][\x80-\xBF]       # double-byte sequences   110xxxxx 10xxxxxx
   188 		| \xE0[\xA0-\xBF][\x80-\xBF]   # triple-byte sequences   1110xxxx 10xxxxxx * 2
   187 		| \xE0[\xA0-\xBF][\x80-\xBF]   # triple-byte sequences   1110xxxx 10xxxxxx * 2
   189 		| [\xE1-\xEC][\x80-\xBF]{2}
   188 		| [\xE1-\xEC][\x80-\xBF]{2}
   190 		| \xED[\x80-\x9F][\x80-\xBF]
   189 		| \xED[\x80-\x9F][\x80-\xBF]
   191 		| [\xEE-\xEF][\x80-\xBF]{2}
   190 		| [\xEE-\xEF][\x80-\xBF]{2}
   218 
   217 
   219 if ( ! function_exists( 'hash_hmac' ) ) :
   218 if ( ! function_exists( 'hash_hmac' ) ) :
   220 	/**
   219 	/**
   221 	 * Compat function to mimic hash_hmac().
   220 	 * Compat function to mimic hash_hmac().
   222 	 *
   221 	 *
       
   222 	 * The Hash extension is bundled with PHP by default since PHP 5.1.2.
       
   223 	 * However, the extension may be explicitly disabled on select servers.
       
   224 	 * As of PHP 7.4.0, the Hash extension is a core PHP extension and can no
       
   225 	 * longer be disabled.
       
   226 	 * I.e. when PHP 7.4.0 becomes the minimum requirement, this polyfill
       
   227 	 * and the associated `_hash_hmac()` function can be safely removed.
       
   228 	 *
   223 	 * @ignore
   229 	 * @ignore
   224 	 * @since 3.2.0
   230 	 * @since 3.2.0
   225 	 *
   231 	 *
   226 	 * @see _hash_hmac()
   232 	 * @see _hash_hmac()
   227 	 *
   233 	 *
   279 		return pack( $pack, $hmac );
   285 		return pack( $pack, $hmac );
   280 	}
   286 	}
   281 	return $hmac;
   287 	return $hmac;
   282 }
   288 }
   283 
   289 
   284 if ( ! function_exists( 'json_encode' ) ) {
       
   285 	function json_encode( $string ) {
       
   286 		global $wp_json;
       
   287 
       
   288 		if ( ! ( $wp_json instanceof Services_JSON ) ) {
       
   289 			require_once( ABSPATH . WPINC . '/class-json.php' );
       
   290 			$wp_json = new Services_JSON();
       
   291 		}
       
   292 
       
   293 		return $wp_json->encodeUnsafe( $string );
       
   294 	}
       
   295 }
       
   296 
       
   297 if ( ! function_exists( 'json_decode' ) ) {
       
   298 	/**
       
   299 	 * @global Services_JSON $wp_json
       
   300 	 * @param string $string
       
   301 	 * @param bool   $assoc_array
       
   302 	 * @return object|array
       
   303 	 */
       
   304 	function json_decode( $string, $assoc_array = false ) {
       
   305 		global $wp_json;
       
   306 
       
   307 		if ( ! ( $wp_json instanceof Services_JSON ) ) {
       
   308 			require_once( ABSPATH . WPINC . '/class-json.php' );
       
   309 			$wp_json = new Services_JSON();
       
   310 		}
       
   311 
       
   312 		$res = $wp_json->decode( $string );
       
   313 		if ( $assoc_array ) {
       
   314 			$res = _json_decode_object_helper( $res );
       
   315 		}
       
   316 		return $res;
       
   317 	}
       
   318 
       
   319 	/**
       
   320 	 * @param object $data
       
   321 	 * @return array
       
   322 	 */
       
   323 	function _json_decode_object_helper( $data ) {
       
   324 		if ( is_object( $data ) ) {
       
   325 			$data = get_object_vars( $data );
       
   326 		}
       
   327 		return is_array( $data ) ? array_map( __FUNCTION__, $data ) : $data;
       
   328 	}
       
   329 }
       
   330 
       
   331 if ( ! function_exists( 'hash_equals' ) ) :
   290 if ( ! function_exists( 'hash_equals' ) ) :
   332 	/**
   291 	/**
   333 	 * Timing attack safe string comparison
   292 	 * Timing attack safe string comparison
   334 	 *
   293 	 *
   335 	 * Compares two strings using the same time whether they're equal or not.
   294 	 * Compares two strings using the same time whether they're equal or not.
   336 	 *
   295 	 *
       
   296 	 * Note: It can leak the length of a string when arguments of differing length are supplied.
       
   297 	 *
   337 	 * This function was added in PHP 5.6.
   298 	 * This function was added in PHP 5.6.
   338 	 *
   299 	 * However, the Hash extension may be explicitly disabled on select servers.
   339 	 * Note: It can leak the length of a string when arguments of differing length are supplied.
   300 	 * As of PHP 7.4.0, the Hash extension is a core PHP extension and can no
       
   301 	 * longer be disabled.
       
   302 	 * I.e. when PHP 7.4.0 becomes the minimum requirement, this polyfill
       
   303 	 * can be safely removed.
   340 	 *
   304 	 *
   341 	 * @since 3.9.2
   305 	 * @since 3.9.2
   342 	 *
   306 	 *
   343 	 * @param string $a Expected string.
   307 	 * @param string $a Expected string.
   344 	 * @param string $b Actual, user supplied, string.
   308 	 * @param string $b Actual, user supplied, string.
   345 	 * @return bool Whether strings are equal.
   309 	 * @return bool Whether strings are equal.
   346 	 */
   310 	 */
   347 	function hash_equals( $a, $b ) {
   311 	function hash_equals( $a, $b ) {
   348 		$a_length = strlen( $a );
   312 		$a_length = strlen( $a );
   349 		if ( $a_length !== strlen( $b ) ) {
   313 		if ( strlen( $b ) !== $a_length ) {
   350 			return false;
   314 			return false;
   351 		}
   315 		}
   352 		$result = 0;
   316 		$result = 0;
   353 
   317 
   354 		// Do not attempt to "optimize" this.
   318 		// Do not attempt to "optimize" this.
   355 		for ( $i = 0; $i < $a_length; $i++ ) {
   319 		for ( $i = 0; $i < $a_length; $i++ ) {
   356 			$result |= ord( $a[ $i ] ) ^ ord( $b[ $i ] );
   320 			$result |= ord( $a[ $i ] ) ^ ord( $b[ $i ] );
   357 		}
   321 		}
   358 
   322 
   359 		return $result === 0;
   323 		return 0 === $result;
   360 	}
   324 	}
   361 endif;
   325 endif;
   362 
   326 
   363 // JSON_PRETTY_PRINT was introduced in PHP 5.4
   327 // random_int() was introduced in PHP 7.0.
   364 // Defined here to prevent a notice when using it with wp_json_encode()
       
   365 if ( ! defined( 'JSON_PRETTY_PRINT' ) ) {
       
   366 	define( 'JSON_PRETTY_PRINT', 128 );
       
   367 }
       
   368 
       
   369 if ( ! function_exists( 'json_last_error_msg' ) ) :
       
   370 	/**
       
   371 	 * Retrieves the error string of the last json_encode() or json_decode() call.
       
   372 	 *
       
   373 	 * @since 4.4.0
       
   374 	 *
       
   375 	 * @internal This is a compatibility function for PHP <5.5
       
   376 	 *
       
   377 	 * @return bool|string Returns the error message on success, "No Error" if no error has occurred,
       
   378 	 *                     or false on failure.
       
   379 	 */
       
   380 	function json_last_error_msg() {
       
   381 		// See https://core.trac.wordpress.org/ticket/27799.
       
   382 		if ( ! function_exists( 'json_last_error' ) ) {
       
   383 			return false;
       
   384 		}
       
   385 
       
   386 		$last_error_code = json_last_error();
       
   387 
       
   388 		// Just in case JSON_ERROR_NONE is not defined.
       
   389 		$error_code_none = defined( 'JSON_ERROR_NONE' ) ? JSON_ERROR_NONE : 0;
       
   390 
       
   391 		switch ( true ) {
       
   392 			case $last_error_code === $error_code_none:
       
   393 				return 'No error';
       
   394 
       
   395 			case defined( 'JSON_ERROR_DEPTH' ) && JSON_ERROR_DEPTH === $last_error_code:
       
   396 				return 'Maximum stack depth exceeded';
       
   397 
       
   398 			case defined( 'JSON_ERROR_STATE_MISMATCH' ) && JSON_ERROR_STATE_MISMATCH === $last_error_code:
       
   399 				return 'State mismatch (invalid or malformed JSON)';
       
   400 
       
   401 			case defined( 'JSON_ERROR_CTRL_CHAR' ) && JSON_ERROR_CTRL_CHAR === $last_error_code:
       
   402 				return 'Control character error, possibly incorrectly encoded';
       
   403 
       
   404 			case defined( 'JSON_ERROR_SYNTAX' ) && JSON_ERROR_SYNTAX === $last_error_code:
       
   405 				return 'Syntax error';
       
   406 
       
   407 			case defined( 'JSON_ERROR_UTF8' ) && JSON_ERROR_UTF8 === $last_error_code:
       
   408 				return 'Malformed UTF-8 characters, possibly incorrectly encoded';
       
   409 
       
   410 			case defined( 'JSON_ERROR_RECURSION' ) && JSON_ERROR_RECURSION === $last_error_code:
       
   411 				return 'Recursion detected';
       
   412 
       
   413 			case defined( 'JSON_ERROR_INF_OR_NAN' ) && JSON_ERROR_INF_OR_NAN === $last_error_code:
       
   414 				return 'Inf and NaN cannot be JSON encoded';
       
   415 
       
   416 			case defined( 'JSON_ERROR_UNSUPPORTED_TYPE' ) && JSON_ERROR_UNSUPPORTED_TYPE === $last_error_code:
       
   417 				return 'Type is not supported';
       
   418 
       
   419 			default:
       
   420 				return 'An unknown error occurred';
       
   421 		}
       
   422 	}
       
   423 endif;
       
   424 
       
   425 if ( ! interface_exists( 'JsonSerializable' ) ) {
       
   426 	define( 'WP_JSON_SERIALIZE_COMPATIBLE', true );
       
   427 	/**
       
   428 	 * JsonSerializable interface.
       
   429 	 *
       
   430 	 * Compatibility shim for PHP <5.4
       
   431 	 *
       
   432 	 * @link https://secure.php.net/jsonserializable
       
   433 	 *
       
   434 	 * @since 4.4.0
       
   435 	 */
       
   436 	interface JsonSerializable {
       
   437 		public function jsonSerialize();
       
   438 	}
       
   439 }
       
   440 
       
   441 // random_int was introduced in PHP 7.0
       
   442 if ( ! function_exists( 'random_int' ) ) {
   328 if ( ! function_exists( 'random_int' ) ) {
   443 	require ABSPATH . WPINC . '/random_compat/random.php';
   329 	require ABSPATH . WPINC . '/random_compat/random.php';
   444 }
   330 }
   445 // sodium_crypto_box was introduced in PHP 7.2
   331 // sodium_crypto_box() was introduced in PHP 7.2.
   446 if ( ! function_exists( 'sodium_crypto_box' ) ) {
   332 if ( ! function_exists( 'sodium_crypto_box' ) ) {
   447 	require ABSPATH . WPINC . '/sodium_compat/autoload.php';
   333 	require ABSPATH . WPINC . '/sodium_compat/autoload.php';
   448 }
   334 }
   449 
   335 
   450 if ( ! function_exists( 'array_replace_recursive' ) ) :
       
   451 	/**
       
   452 	 * PHP-agnostic version of {@link array_replace_recursive()}.
       
   453 	 *
       
   454 	 * The array_replace_recursive() function is a PHP 5.3 function. WordPress
       
   455 	 * currently supports down to PHP 5.2, so this method is a workaround
       
   456 	 * for PHP 5.2.
       
   457 	 *
       
   458 	 * Note: array_replace_recursive() supports infinite arguments, but for our use-
       
   459 	 * case, we only need to support two arguments.
       
   460 	 *
       
   461 	 * Subject to removal once WordPress makes PHP 5.3.0 the minimum requirement.
       
   462 	 *
       
   463 	 * @since 4.5.3
       
   464 	 *
       
   465 	 * @see https://secure.php.net/manual/en/function.array-replace-recursive.php#109390
       
   466 	 *
       
   467 	 * @param  array $base         Array with keys needing to be replaced.
       
   468 	 * @param  array $replacements Array with the replaced keys.
       
   469 	 *
       
   470 	 * @return array
       
   471 	 */
       
   472 	function array_replace_recursive( $base = array(), $replacements = array() ) {
       
   473 		foreach ( array_slice( func_get_args(), 1 ) as $replacements ) {
       
   474 			$bref_stack = array( &$base );
       
   475 			$head_stack = array( $replacements );
       
   476 
       
   477 			do {
       
   478 				end( $bref_stack );
       
   479 
       
   480 				$bref = &$bref_stack[ key( $bref_stack ) ];
       
   481 				$head = array_pop( $head_stack );
       
   482 
       
   483 				unset( $bref_stack[ key( $bref_stack ) ] );
       
   484 
       
   485 				foreach ( array_keys( $head ) as $key ) {
       
   486 					if ( isset( $key, $bref ) &&
       
   487 						isset( $bref[ $key ] ) && is_array( $bref[ $key ] ) &&
       
   488 						isset( $head[ $key ] ) && is_array( $head[ $key ] ) ) {
       
   489 
       
   490 						$bref_stack[] = &$bref[ $key ];
       
   491 						$head_stack[] = $head[ $key ];
       
   492 					} else {
       
   493 						$bref[ $key ] = $head[ $key ];
       
   494 					}
       
   495 				}
       
   496 			} while ( count( $head_stack ) );
       
   497 		}
       
   498 
       
   499 		return $base;
       
   500 	}
       
   501 endif;
       
   502 
       
   503 /**
       
   504  * Polyfill for the SPL autoloader. In PHP 5.2 (but not 5.3 and later), SPL can
       
   505  * be disabled, and PHP 7.2 raises notices if the compiler finds an __autoload()
       
   506  * function declaration. Function availability is checked here, and the
       
   507  * autoloader is included only if necessary.
       
   508  */
       
   509 if ( ! function_exists( 'spl_autoload_register' ) ) {
       
   510 	require_once ABSPATH . WPINC . '/spl-autoload-compat.php';
       
   511 }
       
   512 
       
   513 if ( ! function_exists( 'is_countable' ) ) {
   336 if ( ! function_exists( 'is_countable' ) ) {
   514 	/**
   337 	/**
   515 	 * Polyfill for is_countable() function added in PHP 7.3.
   338 	 * Polyfill for is_countable() function added in PHP 7.3.
   516 	 *
   339 	 *
   517 	 * Verify that the content of a variable is an array or an object
   340 	 * Verify that the content of a variable is an array or an object
   518 	 * implementing the Countable interface.
   341 	 * implementing the Countable interface.
   519 	 *
   342 	 *
   520 	 * @since 4.9.6
   343 	 * @since 4.9.6
   521 	 *
   344 	 *
   522 	 * @param mixed $var The value to check.
   345 	 * @param mixed $var The value to check.
   523 	 *
       
   524 	 * @return bool True if `$var` is countable, false otherwise.
   346 	 * @return bool True if `$var` is countable, false otherwise.
   525 	 */
   347 	 */
   526 	function is_countable( $var ) {
   348 	function is_countable( $var ) {
   527 		return ( is_array( $var )
   349 		return ( is_array( $var )
   528 			|| $var instanceof Countable
   350 			|| $var instanceof Countable
   540 	 * implementing the Traversable interface.
   362 	 * implementing the Traversable interface.
   541 	 *
   363 	 *
   542 	 * @since 4.9.6
   364 	 * @since 4.9.6
   543 	 *
   365 	 *
   544 	 * @param mixed $var The value to check.
   366 	 * @param mixed $var The value to check.
   545 	 *
       
   546 	 * @return bool True if `$var` is iterable, false otherwise.
   367 	 * @return bool True if `$var` is iterable, false otherwise.
   547 	 */
   368 	 */
   548 	function is_iterable( $var ) {
   369 	function is_iterable( $var ) {
   549 		return ( is_array( $var ) || $var instanceof Traversable );
   370 		return ( is_array( $var ) || $var instanceof Traversable );
   550 	}
   371 	}