wp/wp-includes/compat.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
     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 _( $message ) {
    12 		return $string;
    12 		return $message;
    13 	}
    13 	}
    14 }
    14 }
    15 
    15 
    16 /**
    16 /**
    17  * Returns whether PCRE/u (PCRE_UTF8 modifier) is available for use.
    17  * Returns whether PCRE/u (PCRE_UTF8 modifier) is available for use.
    38 	}
    38 	}
    39 
    39 
    40 	return $utf8_pcre;
    40 	return $utf8_pcre;
    41 }
    41 }
    42 
    42 
       
    43 /**
       
    44  * Indicates if a given slug for a character set represents the UTF-8 text encoding.
       
    45  *
       
    46  * A charset is considered to represent UTF-8 if it is a case-insensitive match
       
    47  * of "UTF-8" with or without the hyphen.
       
    48  *
       
    49  * Example:
       
    50  *
       
    51  *     true  === _is_utf8_charset( 'UTF-8' );
       
    52  *     true  === _is_utf8_charset( 'utf8' );
       
    53  *     false === _is_utf8_charset( 'latin1' );
       
    54  *     false === _is_utf8_charset( 'UTF 8' );
       
    55  *
       
    56  *     // Only strings match.
       
    57  *     false === _is_utf8_charset( [ 'charset' => 'utf-8' ] );
       
    58  *
       
    59  * `is_utf8_charset` should be used outside of this file.
       
    60  *
       
    61  * @ignore
       
    62  * @since 6.6.1
       
    63  *
       
    64  * @param string $charset_slug Slug representing a text character encoding, or "charset".
       
    65  *                             E.g. "UTF-8", "Windows-1252", "ISO-8859-1", "SJIS".
       
    66  *
       
    67  * @return bool Whether the slug represents the UTF-8 encoding.
       
    68  */
       
    69 function _is_utf8_charset( $charset_slug ) {
       
    70 	if ( ! is_string( $charset_slug ) ) {
       
    71 		return false;
       
    72 	}
       
    73 
       
    74 	return (
       
    75 		0 === strcasecmp( 'UTF-8', $charset_slug ) ||
       
    76 		0 === strcasecmp( 'UTF8', $charset_slug )
       
    77 	);
       
    78 }
       
    79 
    43 if ( ! function_exists( 'mb_substr' ) ) :
    80 if ( ! function_exists( 'mb_substr' ) ) :
    44 	/**
    81 	/**
    45 	 * Compat function to mimic mb_substr().
    82 	 * Compat function to mimic mb_substr().
    46 	 *
    83 	 *
    47 	 * @ignore
    84 	 * @ignore
    48 	 * @since 3.2.0
    85 	 * @since 3.2.0
    49 	 *
    86 	 *
    50 	 * @see _mb_substr()
    87 	 * @see _mb_substr()
    51 	 *
    88 	 *
    52 	 * @param string      $str      The string to extract the substring from.
    89 	 * @param string      $string   The string to extract the substring from.
    53 	 * @param int         $start    Position to being extraction from in `$str`.
    90 	 * @param int         $start    Position to being extraction from in `$string`.
    54 	 * @param int|null    $length   Optional. Maximum number of characters to extract from `$str`.
    91 	 * @param int|null    $length   Optional. Maximum number of characters to extract from `$string`.
    55 	 *                              Default null.
    92 	 *                              Default null.
    56 	 * @param string|null $encoding Optional. Character encoding to use. Default null.
    93 	 * @param string|null $encoding Optional. Character encoding to use. Default null.
    57 	 * @return string Extracted substring.
    94 	 * @return string Extracted substring.
    58 	 */
    95 	 */
    59 	function mb_substr( $str, $start, $length = null, $encoding = null ) {
    96 	function mb_substr( $string, $start, $length = null, $encoding = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.stringFound
    60 		return _mb_substr( $str, $start, $length, $encoding );
    97 		return _mb_substr( $string, $start, $length, $encoding );
    61 	}
    98 	}
    62 endif;
    99 endif;
    63 
   100 
    64 /**
   101 /**
    65  * Internal compat function to mimic mb_substr().
   102  * Internal compat function to mimic mb_substr().
    66  *
   103  *
    67  * Only understands UTF-8 and 8bit.  All other character sets will be treated as 8bit.
   104  * Only understands UTF-8 and 8bit. All other character sets will be treated as 8bit.
    68  * For $encoding === UTF-8, the $str input is expected to be a valid UTF-8 byte sequence.
   105  * For `$encoding === UTF-8`, the `$str` input is expected to be a valid UTF-8 byte
    69  * The behavior of this function for invalid inputs is undefined.
   106  * sequence. The behavior of this function for invalid inputs is undefined.
    70  *
   107  *
    71  * @ignore
   108  * @ignore
    72  * @since 3.2.0
   109  * @since 3.2.0
    73  *
   110  *
    74  * @param string      $str      The string to extract the substring from.
   111  * @param string      $str      The string to extract the substring from.
    89 
   126 
    90 	/*
   127 	/*
    91 	 * The solution below works only for UTF-8, so in case of a different
   128 	 * The solution below works only for UTF-8, so in case of a different
    92 	 * charset just use built-in substr().
   129 	 * charset just use built-in substr().
    93 	 */
   130 	 */
    94 	if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ), true ) ) {
   131 	if ( ! _is_utf8_charset( $encoding ) ) {
    95 		return is_null( $length ) ? substr( $str, $start ) : substr( $str, $start, $length );
   132 		return is_null( $length ) ? substr( $str, $start ) : substr( $str, $start, $length );
    96 	}
   133 	}
    97 
   134 
    98 	if ( _wp_can_use_pcre_u() ) {
   135 	if ( _wp_can_use_pcre_u() ) {
    99 		// Use the regex unicode support to separate the UTF-8 characters into an array.
   136 		// Use the regex unicode support to separate the UTF-8 characters into an array.
   114 		| \xF4[\x80-\x8F][\x80-\xBF]{2}
   151 		| \xF4[\x80-\x8F][\x80-\xBF]{2}
   115 	)/x';
   152 	)/x';
   116 
   153 
   117 	// Start with 1 element instead of 0 since the first thing we do is pop.
   154 	// Start with 1 element instead of 0 since the first thing we do is pop.
   118 	$chars = array( '' );
   155 	$chars = array( '' );
       
   156 
   119 	do {
   157 	do {
   120 		// We had some string left over from the last round, but we counted it in that last round.
   158 		// We had some string left over from the last round, but we counted it in that last round.
   121 		array_pop( $chars );
   159 		array_pop( $chars );
   122 
   160 
   123 		/*
   161 		/*
   141 	 * @ignore
   179 	 * @ignore
   142 	 * @since 4.2.0
   180 	 * @since 4.2.0
   143 	 *
   181 	 *
   144 	 * @see _mb_strlen()
   182 	 * @see _mb_strlen()
   145 	 *
   183 	 *
   146 	 * @param string      $str      The string to retrieve the character length from.
   184 	 * @param string      $string   The string to retrieve the character length from.
   147 	 * @param string|null $encoding Optional. Character encoding to use. Default null.
   185 	 * @param string|null $encoding Optional. Character encoding to use. Default null.
   148 	 * @return int String length of `$str`.
   186 	 * @return int String length of `$string`.
   149 	 */
   187 	 */
   150 	function mb_strlen( $str, $encoding = null ) {
   188 	function mb_strlen( $string, $encoding = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.stringFound
   151 		return _mb_strlen( $str, $encoding );
   189 		return _mb_strlen( $string, $encoding );
   152 	}
   190 	}
   153 endif;
   191 endif;
   154 
   192 
   155 /**
   193 /**
   156  * Internal compat function to mimic mb_strlen().
   194  * Internal compat function to mimic mb_strlen().
   157  *
   195  *
   158  * Only understands UTF-8 and 8bit.  All other character sets will be treated as 8bit.
   196  * Only understands UTF-8 and 8bit. All other character sets will be treated as 8bit.
   159  * For $encoding === UTF-8, the `$str` input is expected to be a valid UTF-8 byte
   197  * For `$encoding === UTF-8`, the `$str` input is expected to be a valid UTF-8 byte
   160  * sequence. The behavior of this function for invalid inputs is undefined.
   198  * sequence. The behavior of this function for invalid inputs is undefined.
   161  *
   199  *
   162  * @ignore
   200  * @ignore
   163  * @since 4.2.0
   201  * @since 4.2.0
   164  *
   202  *
   173 
   211 
   174 	/*
   212 	/*
   175 	 * The solution below works only for UTF-8, so in case of a different charset
   213 	 * The solution below works only for UTF-8, so in case of a different charset
   176 	 * just use built-in strlen().
   214 	 * just use built-in strlen().
   177 	 */
   215 	 */
   178 	if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ), true ) ) {
   216 	if ( ! _is_utf8_charset( $encoding ) ) {
   179 		return strlen( $str );
   217 		return strlen( $str );
   180 	}
   218 	}
   181 
   219 
   182 	if ( _wp_can_use_pcre_u() ) {
   220 	if ( _wp_can_use_pcre_u() ) {
   183 		// Use the regex unicode support to separate the UTF-8 characters into an array.
   221 		// Use the regex unicode support to separate the UTF-8 characters into an array.
   197 		| \xF4[\x80-\x8F][\x80-\xBF]{2}
   235 		| \xF4[\x80-\x8F][\x80-\xBF]{2}
   198 	)/x';
   236 	)/x';
   199 
   237 
   200 	// Start at 1 instead of 0 since the first thing we do is decrement.
   238 	// Start at 1 instead of 0 since the first thing we do is decrement.
   201 	$count = 1;
   239 	$count = 1;
       
   240 
   202 	do {
   241 	do {
   203 		// We had some string left over from the last round, but we counted it in that last round.
   242 		// We had some string left over from the last round, but we counted it in that last round.
   204 		$count--;
   243 		--$count;
   205 
   244 
   206 		/*
   245 		/*
   207 		 * Split by UTF-8 character, limit to 1000 characters (last array element will contain
   246 		 * Split by UTF-8 character, limit to 1000 characters (last array element will contain
   208 		 * the rest of the string).
   247 		 * the rest of the string).
   209 		 */
   248 		 */
   233 	 * @ignore
   272 	 * @ignore
   234 	 * @since 3.2.0
   273 	 * @since 3.2.0
   235 	 *
   274 	 *
   236 	 * @see _hash_hmac()
   275 	 * @see _hash_hmac()
   237 	 *
   276 	 *
   238 	 * @param string $algo       Hash algorithm. Accepts 'md5' or 'sha1'.
   277 	 * @param string $algo   Hash algorithm. Accepts 'md5' or 'sha1'.
   239 	 * @param string $data       Data to be hashed.
   278 	 * @param string $data   Data to be hashed.
   240 	 * @param string $key        Secret key to use for generating the hash.
   279 	 * @param string $key    Secret key to use for generating the hash.
   241 	 * @param bool   $raw_output Optional. Whether to output raw binary data (true),
   280 	 * @param bool   $binary Optional. Whether to output raw binary data (true),
   242 	 *                           or lowercase hexits (false). Default false.
   281 	 *                       or lowercase hexits (false). Default false.
   243 	 * @return string|false The hash in output determined by `$raw_output`. False if `$algo`
   282 	 * @return string|false The hash in output determined by `$binary`.
   244 	 *                      is unknown or invalid.
   283 	 *                      False if `$algo` is unknown or invalid.
   245 	 */
   284 	 */
   246 	function hash_hmac( $algo, $data, $key, $raw_output = false ) {
   285 	function hash_hmac( $algo, $data, $key, $binary = false ) {
   247 		return _hash_hmac( $algo, $data, $key, $raw_output );
   286 		return _hash_hmac( $algo, $data, $key, $binary );
   248 	}
   287 	}
   249 endif;
   288 endif;
   250 
   289 
   251 /**
   290 /**
   252  * Internal compat function to mimic hash_hmac().
   291  * Internal compat function to mimic hash_hmac().
   253  *
   292  *
   254  * @ignore
   293  * @ignore
   255  * @since 3.2.0
   294  * @since 3.2.0
   256  *
   295  *
   257  * @param string $algo       Hash algorithm. Accepts 'md5' or 'sha1'.
   296  * @param string $algo   Hash algorithm. Accepts 'md5' or 'sha1'.
   258  * @param string $data       Data to be hashed.
   297  * @param string $data   Data to be hashed.
   259  * @param string $key        Secret key to use for generating the hash.
   298  * @param string $key    Secret key to use for generating the hash.
   260  * @param bool   $raw_output Optional. Whether to output raw binary data (true),
   299  * @param bool   $binary Optional. Whether to output raw binary data (true),
   261  *                           or lowercase hexits (false). Default false.
   300  *                       or lowercase hexits (false). Default false.
   262  * @return string|false The hash in output determined by `$raw_output`. False if `$algo`
   301  * @return string|false The hash in output determined by `$binary`.
   263  *                      is unknown or invalid.
   302  *                      False if `$algo` is unknown or invalid.
   264  */
   303  */
   265 function _hash_hmac( $algo, $data, $key, $raw_output = false ) {
   304 function _hash_hmac( $algo, $data, $key, $binary = false ) {
   266 	$packs = array(
   305 	$packs = array(
   267 		'md5'  => 'H32',
   306 		'md5'  => 'H32',
   268 		'sha1' => 'H40',
   307 		'sha1' => 'H40',
   269 	);
   308 	);
   270 
   309 
   283 	$ipad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x36 ), 64 ) );
   322 	$ipad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x36 ), 64 ) );
   284 	$opad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x5C ), 64 ) );
   323 	$opad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x5C ), 64 ) );
   285 
   324 
   286 	$hmac = $algo( $opad . pack( $pack, $algo( $ipad . $data ) ) );
   325 	$hmac = $algo( $opad . pack( $pack, $algo( $ipad . $data ) ) );
   287 
   326 
   288 	if ( $raw_output ) {
   327 	if ( $binary ) {
   289 		return pack( $pack, $hmac );
   328 		return pack( $pack, $hmac );
   290 	}
   329 	}
       
   330 
   291 	return $hmac;
   331 	return $hmac;
   292 }
   332 }
   293 
   333 
   294 if ( ! function_exists( 'hash_equals' ) ) :
   334 if ( ! function_exists( 'hash_equals' ) ) :
   295 	/**
   335 	/**
   296 	 * Timing attack safe string comparison
   336 	 * Timing attack safe string comparison.
   297 	 *
   337 	 *
   298 	 * Compares two strings using the same time whether they're equal or not.
   338 	 * Compares two strings using the same time whether they're equal or not.
   299 	 *
   339 	 *
   300 	 * Note: It can leak the length of a string when arguments of differing length are supplied.
   340 	 * Note: It can leak the length of a string when arguments of differing length are supplied.
   301 	 *
   341 	 *
   306 	 * I.e. when PHP 7.4.0 becomes the minimum requirement, this polyfill
   346 	 * I.e. when PHP 7.4.0 becomes the minimum requirement, this polyfill
   307 	 * can be safely removed.
   347 	 * can be safely removed.
   308 	 *
   348 	 *
   309 	 * @since 3.9.2
   349 	 * @since 3.9.2
   310 	 *
   350 	 *
   311 	 * @param string $a Expected string.
   351 	 * @param string $known_string Expected string.
   312 	 * @param string $b Actual, user supplied, string.
   352 	 * @param string $user_string  Actual, user supplied, string.
   313 	 * @return bool Whether strings are equal.
   353 	 * @return bool Whether strings are equal.
   314 	 */
   354 	 */
   315 	function hash_equals( $a, $b ) {
   355 	function hash_equals( $known_string, $user_string ) {
   316 		$a_length = strlen( $a );
   356 		$known_string_length = strlen( $known_string );
   317 		if ( strlen( $b ) !== $a_length ) {
   357 
       
   358 		if ( strlen( $user_string ) !== $known_string_length ) {
   318 			return false;
   359 			return false;
   319 		}
   360 		}
       
   361 
   320 		$result = 0;
   362 		$result = 0;
   321 
   363 
   322 		// Do not attempt to "optimize" this.
   364 		// Do not attempt to "optimize" this.
   323 		for ( $i = 0; $i < $a_length; $i++ ) {
   365 		for ( $i = 0; $i < $known_string_length; $i++ ) {
   324 			$result |= ord( $a[ $i ] ) ^ ord( $b[ $i ] );
   366 			$result |= ord( $known_string[ $i ] ) ^ ord( $user_string[ $i ] );
   325 		}
   367 		}
   326 
   368 
   327 		return 0 === $result;
   369 		return 0 === $result;
   328 	}
   370 	}
   329 endif;
   371 endif;
   330 
   372 
   331 // random_int() was introduced in PHP 7.0.
       
   332 if ( ! function_exists( 'random_int' ) ) {
       
   333 	require ABSPATH . WPINC . '/random_compat/random.php';
       
   334 }
       
   335 // sodium_crypto_box() was introduced in PHP 7.2.
   373 // sodium_crypto_box() was introduced in PHP 7.2.
   336 if ( ! function_exists( 'sodium_crypto_box' ) ) {
   374 if ( ! function_exists( 'sodium_crypto_box' ) ) {
   337 	require ABSPATH . WPINC . '/sodium_compat/autoload.php';
   375 	require ABSPATH . WPINC . '/sodium_compat/autoload.php';
   338 }
   376 }
   339 
   377 
   344 	 * Verify that the content of a variable is an array or an object
   382 	 * Verify that the content of a variable is an array or an object
   345 	 * implementing the Countable interface.
   383 	 * implementing the Countable interface.
   346 	 *
   384 	 *
   347 	 * @since 4.9.6
   385 	 * @since 4.9.6
   348 	 *
   386 	 *
   349 	 * @param mixed $var The value to check.
   387 	 * @param mixed $value The value to check.
   350 	 * @return bool True if `$var` is countable, false otherwise.
   388 	 * @return bool True if `$value` is countable, false otherwise.
   351 	 */
   389 	 */
   352 	function is_countable( $var ) {
   390 	function is_countable( $value ) {
   353 		return ( is_array( $var )
   391 		return ( is_array( $value )
   354 			|| $var instanceof Countable
   392 			|| $value instanceof Countable
   355 			|| $var instanceof SimpleXMLElement
   393 			|| $value instanceof SimpleXMLElement
   356 			|| $var instanceof ResourceBundle
   394 			|| $value instanceof ResourceBundle
   357 		);
   395 		);
   358 	}
       
   359 }
       
   360 
       
   361 if ( ! function_exists( 'is_iterable' ) ) {
       
   362 	/**
       
   363 	 * Polyfill for is_iterable() function added in PHP 7.1.
       
   364 	 *
       
   365 	 * Verify that the content of a variable is an array or an object
       
   366 	 * implementing the Traversable interface.
       
   367 	 *
       
   368 	 * @since 4.9.6
       
   369 	 *
       
   370 	 * @param mixed $var The value to check.
       
   371 	 * @return bool True if `$var` is iterable, false otherwise.
       
   372 	 */
       
   373 	function is_iterable( $var ) {
       
   374 		return ( is_array( $var ) || $var instanceof Traversable );
       
   375 	}
   396 	}
   376 }
   397 }
   377 
   398 
   378 if ( ! function_exists( 'array_key_first' ) ) {
   399 if ( ! function_exists( 'array_key_first' ) ) {
   379 	/**
   400 	/**
   382 	 * Get the first key of the given array without affecting
   403 	 * Get the first key of the given array without affecting
   383 	 * the internal array pointer.
   404 	 * the internal array pointer.
   384 	 *
   405 	 *
   385 	 * @since 5.9.0
   406 	 * @since 5.9.0
   386 	 *
   407 	 *
   387 	 * @param array $arr An array.
   408 	 * @param array $array An array.
   388 	 * @return string|int|null The first key of array if the array
   409 	 * @return string|int|null The first key of array if the array
   389 	 *                         is not empty; `null` otherwise.
   410 	 *                         is not empty; `null` otherwise.
   390 	 */
   411 	 */
   391 	function array_key_first( array $arr ) {
   412 	function array_key_first( array $array ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
   392 		foreach ( $arr as $key => $value ) {
   413 		foreach ( $array as $key => $value ) {
   393 			return $key;
   414 			return $key;
   394 		}
   415 		}
   395 	}
   416 	}
   396 }
   417 }
   397 
   418 
   402 	 * Get the last key of the given array without affecting the
   423 	 * Get the last key of the given array without affecting the
   403 	 * internal array pointer.
   424 	 * internal array pointer.
   404 	 *
   425 	 *
   405 	 * @since 5.9.0
   426 	 * @since 5.9.0
   406 	 *
   427 	 *
   407 	 * @param array $arr An array.
   428 	 * @param array $array An array.
   408 	 * @return string|int|null The last key of array if the array
   429 	 * @return string|int|null The last key of array if the array
   409 	 *.                        is not empty; `null` otherwise.
   430 	 *.                        is not empty; `null` otherwise.
   410 	 */
   431 	 */
   411 	function array_key_last( array $arr ) {
   432 	function array_key_last( array $array ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
   412 		if ( empty( $arr ) ) {
   433 		if ( empty( $array ) ) {
   413 			return null;
   434 			return null;
   414 		}
   435 		}
   415 		end( $arr );
   436 
   416 		return key( $arr );
   437 		end( $array );
       
   438 
       
   439 		return key( $array );
       
   440 	}
       
   441 }
       
   442 
       
   443 if ( ! function_exists( 'array_is_list' ) ) {
       
   444 	/**
       
   445 	 * Polyfill for `array_is_list()` function added in PHP 8.1.
       
   446 	 *
       
   447 	 * Determines if the given array is a list.
       
   448 	 *
       
   449 	 * An array is considered a list if its keys consist of consecutive numbers from 0 to count($array)-1.
       
   450 	 *
       
   451 	 * @see https://github.com/symfony/polyfill-php81/tree/main
       
   452 	 *
       
   453 	 * @since 6.5.0
       
   454 	 *
       
   455 	 * @param array<mixed> $arr The array being evaluated.
       
   456 	 * @return bool True if array is a list, false otherwise.
       
   457 	 */
       
   458 	function array_is_list( $arr ) {
       
   459 		if ( ( array() === $arr ) || ( array_values( $arr ) === $arr ) ) {
       
   460 			return true;
       
   461 		}
       
   462 
       
   463 		$next_key = -1;
       
   464 
       
   465 		foreach ( $arr as $k => $v ) {
       
   466 			if ( ++$next_key !== $k ) {
       
   467 				return false;
       
   468 			}
       
   469 		}
       
   470 
       
   471 		return true;
   417 	}
   472 	}
   418 }
   473 }
   419 
   474 
   420 if ( ! function_exists( 'str_contains' ) ) {
   475 if ( ! function_exists( 'str_contains' ) ) {
   421 	/**
   476 	/**
   425 	 * contained in haystack.
   480 	 * contained in haystack.
   426 	 *
   481 	 *
   427 	 * @since 5.9.0
   482 	 * @since 5.9.0
   428 	 *
   483 	 *
   429 	 * @param string $haystack The string to search in.
   484 	 * @param string $haystack The string to search in.
   430 	 * @param string $needle   The substring to search for in the haystack.
   485 	 * @param string $needle   The substring to search for in the `$haystack`.
   431 	 * @return bool True if `$needle` is in `$haystack`, otherwise false.
   486 	 * @return bool True if `$needle` is in `$haystack`, otherwise false.
   432 	 */
   487 	 */
   433 	function str_contains( $haystack, $needle ) {
   488 	function str_contains( $haystack, $needle ) {
   434 		return ( '' === $needle || false !== strpos( $haystack, $needle ) );
   489 		if ( '' === $needle ) {
       
   490 			return true;
       
   491 		}
       
   492 
       
   493 		return false !== strpos( $haystack, $needle );
   435 	}
   494 	}
   436 }
   495 }
   437 
   496 
   438 if ( ! function_exists( 'str_starts_with' ) ) {
   497 if ( ! function_exists( 'str_starts_with' ) ) {
   439 	/**
   498 	/**
   450 	 */
   509 	 */
   451 	function str_starts_with( $haystack, $needle ) {
   510 	function str_starts_with( $haystack, $needle ) {
   452 		if ( '' === $needle ) {
   511 		if ( '' === $needle ) {
   453 			return true;
   512 			return true;
   454 		}
   513 		}
       
   514 
   455 		return 0 === strpos( $haystack, $needle );
   515 		return 0 === strpos( $haystack, $needle );
   456 	}
   516 	}
   457 }
   517 }
   458 
   518 
   459 if ( ! function_exists( 'str_ends_with' ) ) {
   519 if ( ! function_exists( 'str_ends_with' ) ) {
   468 	 * @param string $haystack The string to search in.
   528 	 * @param string $haystack The string to search in.
   469 	 * @param string $needle   The substring to search for in the `$haystack`.
   529 	 * @param string $needle   The substring to search for in the `$haystack`.
   470 	 * @return bool True if `$haystack` ends with `$needle`, otherwise false.
   530 	 * @return bool True if `$haystack` ends with `$needle`, otherwise false.
   471 	 */
   531 	 */
   472 	function str_ends_with( $haystack, $needle ) {
   532 	function str_ends_with( $haystack, $needle ) {
   473 		if ( '' === $haystack && '' !== $needle ) {
   533 		if ( '' === $haystack ) {
   474 			return false;
   534 			return '' === $needle;
   475 		}
   535 		}
       
   536 
   476 		$len = strlen( $needle );
   537 		$len = strlen( $needle );
   477 		return 0 === substr_compare( $haystack, $needle, -$len, $len );
   538 
   478 	}
   539 		return substr( $haystack, -$len, $len ) === $needle;
   479 }
   540 	}
   480 
   541 }
   481 // IMAGETYPE_WEBP constant is only defined in PHP 7.1 or later.
   542 
   482 if ( ! defined( 'IMAGETYPE_WEBP' ) ) {
   543 // IMAGETYPE_AVIF constant is only defined in PHP 8.x or later.
   483 	define( 'IMAGETYPE_WEBP', 18 );
   544 if ( ! defined( 'IMAGETYPE_AVIF' ) ) {
   484 }
   545 	define( 'IMAGETYPE_AVIF', 19 );
   485 
   546 }
   486 // IMG_WEBP constant is only defined in PHP 7.0.10 or later.
   547 
   487 if ( ! defined( 'IMG_WEBP' ) ) {
   548 // IMG_AVIF constant is only defined in PHP 8.x or later.
   488 	define( 'IMG_WEBP', IMAGETYPE_WEBP );
   549 if ( ! defined( 'IMG_AVIF' ) ) {
   489 }
   550 	define( 'IMG_AVIF', IMAGETYPE_AVIF );
       
   551 }