mirror of
https://ghproxy.net/https://github.com/fairpm/fair-plugin.git
synced 2025-09-04 08:39:02 +08:00
Split compat.php into php-polyfill.php and wp-polyfill.php (#170)
Signed-off-by: Andy Fragen <andy@thefragens.com> Co-authored-by: Colin Stewart <79332690+costdev@users.noreply.github.com>
This commit is contained in:
parent
6b5d9b772c
commit
fede6b6413
5 changed files with 556 additions and 570 deletions
|
@ -1,567 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* WordPress implementation for PHP functions either missing from older PHP versions or not included by default.
|
||||
*
|
||||
* This file is loaded extremely early and the functions can be relied upon by drop-ins.
|
||||
* Ergo, please ensure you do not rely on external functions when writing code for this file.
|
||||
* Only use functions built into PHP or are defined in this file and have adequate testing
|
||||
* and error suppression to ensure the file will run correctly and not break websites.
|
||||
*
|
||||
* @package PHP
|
||||
* @access private
|
||||
*/
|
||||
|
||||
// If gettext isn't available.
|
||||
if ( ! function_exists( '_' ) ) {
|
||||
/**
|
||||
* Compat function to mimic _(), an alias of gettext().
|
||||
*
|
||||
* @since 0.71
|
||||
*
|
||||
* @see https://php.net/manual/en/function.gettext.php
|
||||
*
|
||||
* @param string $message The message being translated.
|
||||
* @return string
|
||||
*/
|
||||
function _( $message ) {
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
|
||||
// If _wp_can_use_pcre_u is already loaded.
|
||||
if ( ! function_exists( '_wp_can_use_pcre_u' ) ) {
|
||||
/**
|
||||
* Returns whether PCRE/u (PCRE_UTF8 modifier) is available for use.
|
||||
*
|
||||
* @ignore
|
||||
* @since 4.2.2
|
||||
* @access private
|
||||
*
|
||||
* @param bool $set - Used for testing only
|
||||
* null : default - get PCRE/u capability
|
||||
* false : Used for testing - return false for future calls to this function
|
||||
* 'reset': Used for testing - restore default behavior of this function
|
||||
*/
|
||||
function _wp_can_use_pcre_u( $set = null ) {
|
||||
static $utf8_pcre = 'reset';
|
||||
|
||||
if ( null !== $set ) {
|
||||
$utf8_pcre = $set;
|
||||
}
|
||||
|
||||
if ( 'reset' === $utf8_pcre ) {
|
||||
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- intentional error generated to detect PCRE/u support.
|
||||
$utf8_pcre = @preg_match( '/^./u', 'a' );
|
||||
}
|
||||
|
||||
return $utf8_pcre;
|
||||
}
|
||||
}
|
||||
|
||||
// If _is_utf8_charset is already loaded.
|
||||
if ( ! function_exists( '_is_utf8_charset' ) ) {
|
||||
/**
|
||||
* Indicates if a given slug for a character set represents the UTF-8 text encoding.
|
||||
*
|
||||
* A charset is considered to represent UTF-8 if it is a case-insensitive match
|
||||
* of "UTF-8" with or without the hyphen.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* true === _is_utf8_charset( 'UTF-8' );
|
||||
* true === _is_utf8_charset( 'utf8' );
|
||||
* false === _is_utf8_charset( 'latin1' );
|
||||
* false === _is_utf8_charset( 'UTF 8' );
|
||||
*
|
||||
* // Only strings match.
|
||||
* false === _is_utf8_charset( [ 'charset' => 'utf-8' ] );
|
||||
*
|
||||
* `is_utf8_charset` should be used outside of this file.
|
||||
*
|
||||
* @ignore
|
||||
* @since 6.6.1
|
||||
*
|
||||
* @param string $charset_slug Slug representing a text character encoding, or "charset".
|
||||
* E.g. "UTF-8", "Windows-1252", "ISO-8859-1", "SJIS".
|
||||
*
|
||||
* @return bool Whether the slug represents the UTF-8 encoding.
|
||||
*/
|
||||
function _is_utf8_charset( $charset_slug ) {
|
||||
if ( ! is_string( $charset_slug ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
0 === strcasecmp( 'UTF-8', $charset_slug ) ||
|
||||
0 === strcasecmp( 'UTF8', $charset_slug )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'mb_substr' ) ) {
|
||||
/**
|
||||
* Compat function to mimic mb_substr().
|
||||
*
|
||||
* @ignore
|
||||
* @since 3.2.0
|
||||
*
|
||||
* @see _mb_substr()
|
||||
*
|
||||
* @param string $string The string to extract the substring from.
|
||||
* @param int $start Position to being extraction from in `$string`.
|
||||
* @param int|null $length Optional. Maximum number of characters to extract from `$string`.
|
||||
* Default null.
|
||||
* @param string|null $encoding Optional. Character encoding to use. Default null.
|
||||
* @return string Extracted substring.
|
||||
*/
|
||||
function mb_substr( $string, $start, $length = null, $encoding = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.stringFound
|
||||
return _mb_substr( $string, $start, $length, $encoding );
|
||||
}
|
||||
}
|
||||
|
||||
// If _mb_substr already loaded.
|
||||
if ( ! function_exists( '_mb_substr' ) ) {
|
||||
/**
|
||||
* Internal compat function to mimic mb_substr().
|
||||
*
|
||||
* Only understands UTF-8 and 8bit. All other character sets will be treated as 8bit.
|
||||
* For `$encoding === UTF-8`, the `$str` input is expected to be a valid UTF-8 byte
|
||||
* sequence. The behavior of this function for invalid inputs is undefined.
|
||||
*
|
||||
* @ignore
|
||||
* @since 3.2.0
|
||||
*
|
||||
* @param string $str The string to extract the substring from.
|
||||
* @param int $start Position to being extraction from in `$str`.
|
||||
* @param int|null $length Optional. Maximum number of characters to extract from `$str`.
|
||||
* Default null.
|
||||
* @param string|null $encoding Optional. Character encoding to use. Default null.
|
||||
* @return string Extracted substring.
|
||||
*/
|
||||
function _mb_substr( $str, $start, $length = null, $encoding = null ) {
|
||||
if ( null === $str ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( null === $encoding ) {
|
||||
$encoding = get_option( 'blog_charset' );
|
||||
}
|
||||
|
||||
/*
|
||||
* The solution below works only for UTF-8, so in case of a different
|
||||
* charset just use built-in substr().
|
||||
*/
|
||||
if ( ! _is_utf8_charset( $encoding ) ) {
|
||||
return is_null( $length ) ? substr( $str, $start ) : substr( $str, $start, $length );
|
||||
}
|
||||
|
||||
if ( _wp_can_use_pcre_u() ) {
|
||||
// Use the regex unicode support to separate the UTF-8 characters into an array.
|
||||
preg_match_all( '/./us', $str, $match );
|
||||
$chars = is_null( $length ) ? array_slice( $match[0], $start ) : array_slice( $match[0], $start, $length );
|
||||
return implode( '', $chars );
|
||||
}
|
||||
|
||||
$regex = '/(
|
||||
[\x00-\x7F] # single-byte sequences 0xxxxxxx
|
||||
| [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
|
||||
| \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
|
||||
| [\xE1-\xEC][\x80-\xBF]{2}
|
||||
| \xED[\x80-\x9F][\x80-\xBF]
|
||||
| [\xEE-\xEF][\x80-\xBF]{2}
|
||||
| \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
|
||||
| [\xF1-\xF3][\x80-\xBF]{3}
|
||||
| \xF4[\x80-\x8F][\x80-\xBF]{2}
|
||||
)/x';
|
||||
|
||||
// Start with 1 element instead of 0 since the first thing we do is pop.
|
||||
$chars = [ '' ];
|
||||
|
||||
do {
|
||||
// We had some string left over from the last round, but we counted it in that last round.
|
||||
array_pop( $chars );
|
||||
|
||||
/*
|
||||
* Split by UTF-8 character, limit to 1000 characters (last array element will contain
|
||||
* the rest of the string).
|
||||
*/
|
||||
$pieces = preg_split( $regex, $str, 1000, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
|
||||
|
||||
$chars = array_merge( $chars, $pieces );
|
||||
|
||||
// If there's anything left over, repeat the loop.
|
||||
} while ( count( $pieces ) > 1 && $str = array_pop( $pieces ) ); // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
|
||||
|
||||
return implode( '', array_slice( $chars, $start, $length ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'mb_strlen' ) ) {
|
||||
/**
|
||||
* Compat function to mimic mb_strlen().
|
||||
*
|
||||
* @ignore
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @see _mb_strlen()
|
||||
*
|
||||
* @param string $string The string to retrieve the character length from.
|
||||
* @param string|null $encoding Optional. Character encoding to use. Default null.
|
||||
* @return int String length of `$string`.
|
||||
*/
|
||||
function mb_strlen( $string, $encoding = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.stringFound
|
||||
return _mb_strlen( $string, $encoding );
|
||||
}
|
||||
}
|
||||
|
||||
// If _mb_strlen is already loaded.
|
||||
if ( ! function_exists( '_mb_strlen' ) ) {
|
||||
/**
|
||||
* Internal compat function to mimic mb_strlen().
|
||||
*
|
||||
* Only understands UTF-8 and 8bit. All other character sets will be treated as 8bit.
|
||||
* For `$encoding === UTF-8`, the `$str` input is expected to be a valid UTF-8 byte
|
||||
* sequence. The behavior of this function for invalid inputs is undefined.
|
||||
*
|
||||
* @ignore
|
||||
* @since 4.2.0
|
||||
*
|
||||
* @param string $str The string to retrieve the character length from.
|
||||
* @param string|null $encoding Optional. Character encoding to use. Default null.
|
||||
* @return int String length of `$str`.
|
||||
*/
|
||||
function _mb_strlen( $str, $encoding = null ) {
|
||||
if ( null === $encoding ) {
|
||||
$encoding = get_option( 'blog_charset' );
|
||||
}
|
||||
|
||||
/*
|
||||
* The solution below works only for UTF-8, so in case of a different charset
|
||||
* just use built-in strlen().
|
||||
*/
|
||||
if ( ! _is_utf8_charset( $encoding ) ) {
|
||||
return strlen( $str );
|
||||
}
|
||||
|
||||
if ( _wp_can_use_pcre_u() ) {
|
||||
// Use the regex unicode support to separate the UTF-8 characters into an array.
|
||||
preg_match_all( '/./us', $str, $match );
|
||||
return count( $match[0] );
|
||||
}
|
||||
|
||||
$regex = '/(?:
|
||||
[\x00-\x7F] # single-byte sequences 0xxxxxxx
|
||||
| [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
|
||||
| \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
|
||||
| [\xE1-\xEC][\x80-\xBF]{2}
|
||||
| \xED[\x80-\x9F][\x80-\xBF]
|
||||
| [\xEE-\xEF][\x80-\xBF]{2}
|
||||
| \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
|
||||
| [\xF1-\xF3][\x80-\xBF]{3}
|
||||
| \xF4[\x80-\x8F][\x80-\xBF]{2}
|
||||
)/x';
|
||||
|
||||
// Start at 1 instead of 0 since the first thing we do is decrement.
|
||||
$count = 1;
|
||||
|
||||
do {
|
||||
// We had some string left over from the last round, but we counted it in that last round.
|
||||
--$count;
|
||||
|
||||
/*
|
||||
* Split by UTF-8 character, limit to 1000 characters (last array element will contain
|
||||
* the rest of the string).
|
||||
*/
|
||||
$pieces = preg_split( $regex, $str, 1000 );
|
||||
|
||||
// Increment.
|
||||
$count += count( $pieces );
|
||||
|
||||
// If there's anything left over, repeat the loop.
|
||||
} while ( $str = array_pop( $pieces ) ); // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
|
||||
|
||||
// Fencepost: preg_split() always returns one extra item in the array.
|
||||
return --$count;
|
||||
}
|
||||
}
|
||||
|
||||
// sodium_crypto_box() was introduced in PHP 7.2.
|
||||
if ( ! function_exists( 'sodium_crypto_box' ) ) {
|
||||
require ABSPATH . WPINC . '/sodium_compat/autoload.php';
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'is_countable' ) ) {
|
||||
/**
|
||||
* Polyfill for is_countable() function added in PHP 7.3.
|
||||
*
|
||||
* Verify that the content of a variable is an array or an object
|
||||
* implementing the Countable interface.
|
||||
*
|
||||
* @since 4.9.6
|
||||
*
|
||||
* @param mixed $value The value to check.
|
||||
* @return bool True if `$value` is countable, false otherwise.
|
||||
*/
|
||||
function is_countable( $value ) {
|
||||
return ( is_array( $value )
|
||||
|| $value instanceof Countable
|
||||
|| $value instanceof SimpleXMLElement
|
||||
|| $value instanceof ResourceBundle
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_key_first' ) ) {
|
||||
/**
|
||||
* Polyfill for array_key_first() function added in PHP 7.3.
|
||||
*
|
||||
* Get the first key of the given array without affecting
|
||||
* the internal array pointer.
|
||||
*
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $array An array.
|
||||
* @return string|int|null The first key of array if the array
|
||||
* is not empty; `null` otherwise.
|
||||
*/
|
||||
function array_key_first( array $array ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
|
||||
if ( empty( $array ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ( $array as $key => $value ) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_key_last' ) ) {
|
||||
/**
|
||||
* Polyfill for `array_key_last()` function added in PHP 7.3.
|
||||
*
|
||||
* Get the last key of the given array without affecting the
|
||||
* internal array pointer.
|
||||
*
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $array An array.
|
||||
* @return string|int|null The last key of array if the array
|
||||
* is not empty; `null` otherwise.
|
||||
*/
|
||||
function array_key_last( array $array ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
|
||||
if ( empty( $array ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
end( $array );
|
||||
|
||||
return key( $array );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_is_list' ) ) {
|
||||
/**
|
||||
* Polyfill for `array_is_list()` function added in PHP 8.1.
|
||||
*
|
||||
* Determines if the given array is a list.
|
||||
*
|
||||
* An array is considered a list if its keys consist of consecutive numbers from 0 to count($array)-1.
|
||||
*
|
||||
* @see https://github.com/symfony/polyfill-php81/tree/main
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param array<mixed> $arr The array being evaluated.
|
||||
* @return bool True if array is a list, false otherwise.
|
||||
*/
|
||||
function array_is_list( $arr ) {
|
||||
if ( ( [] === $arr ) || ( array_values( $arr ) === $arr ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$next_key = -1;
|
||||
|
||||
foreach ( $arr as $k => $v ) {
|
||||
if ( ++$next_key !== $k ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'str_contains' ) ) {
|
||||
/**
|
||||
* Polyfill for `str_contains()` function added in PHP 8.0.
|
||||
*
|
||||
* Performs a case-sensitive check indicating if needle is
|
||||
* contained in haystack.
|
||||
*
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $haystack The string to search in.
|
||||
* @param string $needle The substring to search for in the `$haystack`.
|
||||
* @return bool True if `$needle` is in `$haystack`, otherwise false.
|
||||
*/
|
||||
function str_contains( $haystack, $needle ) {
|
||||
if ( '' === $needle ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false !== strpos( $haystack, $needle );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'str_starts_with' ) ) {
|
||||
/**
|
||||
* Polyfill for `str_starts_with()` function added in PHP 8.0.
|
||||
*
|
||||
* Performs a case-sensitive check indicating if
|
||||
* the haystack begins with needle.
|
||||
*
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $haystack The string to search in.
|
||||
* @param string $needle The substring to search for in the `$haystack`.
|
||||
* @return bool True if `$haystack` starts with `$needle`, otherwise false.
|
||||
*/
|
||||
function str_starts_with( $haystack, $needle ) {
|
||||
if ( '' === $needle ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0 === strpos( $haystack, $needle );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'str_ends_with' ) ) {
|
||||
/**
|
||||
* Polyfill for `str_ends_with()` function added in PHP 8.0.
|
||||
*
|
||||
* Performs a case-sensitive check indicating if
|
||||
* the haystack ends with needle.
|
||||
*
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $haystack The string to search in.
|
||||
* @param string $needle The substring to search for in the `$haystack`.
|
||||
* @return bool True if `$haystack` ends with `$needle`, otherwise false.
|
||||
*/
|
||||
function str_ends_with( $haystack, $needle ) {
|
||||
if ( '' === $haystack ) {
|
||||
return '' === $needle;
|
||||
}
|
||||
|
||||
$len = strlen( $needle );
|
||||
|
||||
return substr( $haystack, -$len, $len ) === $needle;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_find' ) ) {
|
||||
/**
|
||||
* Polyfill for `array_find()` function added in PHP 8.4.
|
||||
*
|
||||
* Searches an array for the first element that passes a given callback.
|
||||
*
|
||||
* @since 6.8.0
|
||||
*
|
||||
* @param array $array The array to search.
|
||||
* @param callable $callback The callback to run for each element.
|
||||
* @return mixed|null The first element in the array that passes the `$callback`, otherwise null.
|
||||
*/
|
||||
function array_find( array $array, callable $callback ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
|
||||
foreach ( $array as $key => $value ) {
|
||||
if ( $callback( $value, $key ) ) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_find_key' ) ) {
|
||||
/**
|
||||
* Polyfill for `array_find_key()` function added in PHP 8.4.
|
||||
*
|
||||
* Searches an array for the first key that passes a given callback.
|
||||
*
|
||||
* @since 6.8.0
|
||||
*
|
||||
* @param array $array The array to search.
|
||||
* @param callable $callback The callback to run for each element.
|
||||
* @return int|string|null The first key in the array that passes the `$callback`, otherwise null.
|
||||
*/
|
||||
function array_find_key( array $array, callable $callback ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
|
||||
foreach ( $array as $key => $value ) {
|
||||
if ( $callback( $value, $key ) ) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_any' ) ) {
|
||||
/**
|
||||
* Polyfill for `array_any()` function added in PHP 8.4.
|
||||
*
|
||||
* Checks if any element of an array passes a given callback.
|
||||
*
|
||||
* @since 6.8.0
|
||||
*
|
||||
* @param array $array The array to check.
|
||||
* @param callable $callback The callback to run for each element.
|
||||
* @return bool True if any element in the array passes the `$callback`, otherwise false.
|
||||
*/
|
||||
function array_any( array $array, callable $callback ): bool { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
|
||||
foreach ( $array as $key => $value ) {
|
||||
if ( $callback( $value, $key ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_all' ) ) {
|
||||
/**
|
||||
* Polyfill for `array_all()` function added in PHP 8.4.
|
||||
*
|
||||
* Checks if all elements of an array pass a given callback.
|
||||
*
|
||||
* @since 6.8.0
|
||||
*
|
||||
* @param array $array The array to check.
|
||||
* @param callable $callback The callback to run for each element.
|
||||
* @return bool True if all elements in the array pass the `$callback`, otherwise false.
|
||||
*/
|
||||
function array_all( array $array, callable $callback ): bool { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
|
||||
foreach ( $array as $key => $value ) {
|
||||
if ( ! $callback( $value, $key ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// IMAGETYPE_AVIF constant is only defined in PHP 8.x or later.
|
||||
if ( ! defined( 'IMAGETYPE_AVIF' ) ) {
|
||||
define( 'IMAGETYPE_AVIF', 19 );
|
||||
}
|
||||
|
||||
// IMG_AVIF constant is only defined in PHP 8.x or later.
|
||||
if ( ! defined( 'IMG_AVIF' ) ) {
|
||||
define( 'IMG_AVIF', IMAGETYPE_AVIF );
|
||||
}
|
||||
|
||||
// IMAGETYPE_HEIC constant is not yet defined in PHP as of PHP 8.3.
|
||||
if ( ! defined( 'IMAGETYPE_HEIC' ) ) {
|
||||
define( 'IMAGETYPE_HEIC', 99 );
|
||||
}
|
212
inc/compatibility/php-polyfill.php
Normal file
212
inc/compatibility/php-polyfill.php
Normal file
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
/**
|
||||
* Polyfill for PHP functions not included in minimum supported version.
|
||||
* Requires PHP 7.4
|
||||
*/
|
||||
|
||||
if ( ! function_exists( 'str_contains' ) ) {
|
||||
/**
|
||||
* Polyfill for `str_contains()` function added in PHP 8.0.
|
||||
*
|
||||
* Performs a case-sensitive check indicating if needle is
|
||||
* contained in haystack.
|
||||
*
|
||||
* @since WordPress 5.9.0
|
||||
*
|
||||
* @param string $haystack The string to search in.
|
||||
* @param string $needle The substring to search for in the `$haystack`.
|
||||
* @return bool True if `$needle` is in `$haystack`, otherwise false.
|
||||
*/
|
||||
function str_contains( $haystack, $needle ) {
|
||||
if ( '' === $needle ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false !== strpos( $haystack, $needle );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'str_starts_with' ) ) {
|
||||
/**
|
||||
* Polyfill for `str_starts_with()` function added in PHP 8.0.
|
||||
*
|
||||
* Performs a case-sensitive check indicating if
|
||||
* the haystack begins with needle.
|
||||
*
|
||||
* @since WordPress 5.9.0
|
||||
*
|
||||
* @param string $haystack The string to search in.
|
||||
* @param string $needle The substring to search for in the `$haystack`.
|
||||
* @return bool True if `$haystack` starts with `$needle`, otherwise false.
|
||||
*/
|
||||
function str_starts_with( $haystack, $needle ) {
|
||||
if ( '' === $needle ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0 === strpos( $haystack, $needle );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'str_ends_with' ) ) {
|
||||
/**
|
||||
* Polyfill for `str_ends_with()` function added in PHP 8.0.
|
||||
*
|
||||
* Performs a case-sensitive check indicating if
|
||||
* the haystack ends with needle.
|
||||
*
|
||||
* @since WordPress 5.9.0
|
||||
*
|
||||
* @param string $haystack The string to search in.
|
||||
* @param string $needle The substring to search for in the `$haystack`.
|
||||
* @return bool True if `$haystack` ends with `$needle`, otherwise false.
|
||||
*/
|
||||
function str_ends_with( $haystack, $needle ) {
|
||||
if ( '' === $haystack ) {
|
||||
return '' === $needle;
|
||||
}
|
||||
|
||||
$len = strlen( $needle );
|
||||
|
||||
return substr( $haystack, -$len, $len ) === $needle;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_is_list' ) ) {
|
||||
/**
|
||||
* Polyfill for `array_is_list()` function added in PHP 8.1.
|
||||
*
|
||||
* Determines if the given array is a list.
|
||||
*
|
||||
* An array is considered a list if its keys consist of consecutive numbers from 0 to count($array)-1.
|
||||
*
|
||||
* @see https://github.com/symfony/polyfill-php81/tree/main
|
||||
*
|
||||
* @since WordPress 6.5.0
|
||||
*
|
||||
* @param array<mixed> $arr The array being evaluated.
|
||||
* @return bool True if array is a list, false otherwise.
|
||||
*/
|
||||
function array_is_list( $arr ) {
|
||||
if ( ( [] === $arr ) || ( array_values( $arr ) === $arr ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$next_key = -1;
|
||||
|
||||
foreach ( $arr as $k => $v ) {
|
||||
if ( ++$next_key !== $k ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_find' ) ) {
|
||||
/**
|
||||
* Polyfill for `array_find()` function added in PHP 8.4.
|
||||
*
|
||||
* Searches an array for the first element that passes a given callback.
|
||||
*
|
||||
* @since WordPress 6.8.0
|
||||
*
|
||||
* @param array $array The array to search.
|
||||
* @param callable $callback The callback to run for each element.
|
||||
* @return mixed|null The first element in the array that passes the `$callback`, otherwise null.
|
||||
*/
|
||||
function array_find( array $array, callable $callback ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
|
||||
foreach ( $array as $key => $value ) {
|
||||
if ( $callback( $value, $key ) ) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_find_key' ) ) {
|
||||
/**
|
||||
* Polyfill for `array_find_key()` function added in PHP 8.4.
|
||||
*
|
||||
* Searches an array for the first key that passes a given callback.
|
||||
*
|
||||
* @since WordPress 6.8.0
|
||||
*
|
||||
* @param array $array The array to search.
|
||||
* @param callable $callback The callback to run for each element.
|
||||
* @return int|string|null The first key in the array that passes the `$callback`, otherwise null.
|
||||
*/
|
||||
function array_find_key( array $array, callable $callback ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
|
||||
foreach ( $array as $key => $value ) {
|
||||
if ( $callback( $value, $key ) ) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_any' ) ) {
|
||||
/**
|
||||
* Polyfill for `array_any()` function added in PHP 8.4.
|
||||
*
|
||||
* Checks if any element of an array passes a given callback.
|
||||
*
|
||||
* @since WordPress 6.8.0
|
||||
*
|
||||
* @param array $array The array to check.
|
||||
* @param callable $callback The callback to run for each element.
|
||||
* @return bool True if any element in the array passes the `$callback`, otherwise false.
|
||||
*/
|
||||
function array_any( array $array, callable $callback ): bool { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
|
||||
foreach ( $array as $key => $value ) {
|
||||
if ( $callback( $value, $key ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_all' ) ) {
|
||||
/**
|
||||
* Polyfill for `array_all()` function added in PHP 8.4.
|
||||
*
|
||||
* Checks if all elements of an array pass a given callback.
|
||||
*
|
||||
* @since WordPress 6.8.0
|
||||
*
|
||||
* @param array $array The array to check.
|
||||
* @param callable $callback The callback to run for each element.
|
||||
* @return bool True if all elements in the array pass the `$callback`, otherwise false.
|
||||
*/
|
||||
function array_all( array $array, callable $callback ): bool { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound
|
||||
foreach ( $array as $key => $value ) {
|
||||
if ( ! $callback( $value, $key ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// IMAGETYPE_AVIF constant is only defined in PHP 8.x or later.
|
||||
if ( ! defined( 'IMAGETYPE_AVIF' ) ) {
|
||||
define( 'IMAGETYPE_AVIF', 19 );
|
||||
}
|
||||
|
||||
// IMG_AVIF constant is only defined in PHP 8.x or later.
|
||||
if ( ! defined( 'IMG_AVIF' ) ) {
|
||||
define( 'IMG_AVIF', IMAGETYPE_AVIF );
|
||||
}
|
||||
|
||||
// IMAGETYPE_HEIC constant is not yet defined in PHP as of PHP 8.3.
|
||||
if ( ! defined( 'IMAGETYPE_HEIC' ) ) {
|
||||
define( 'IMAGETYPE_HEIC', 99 );
|
||||
}
|
340
inc/compatibility/wp-polyfill.php
Normal file
340
inc/compatibility/wp-polyfill.php
Normal file
|
@ -0,0 +1,340 @@
|
|||
<?php
|
||||
/**
|
||||
* Polyfill for WordPress functions not included in minimum supported version.
|
||||
* Requires WordPress 5.3
|
||||
*/
|
||||
|
||||
if ( ! function_exists( 'esc_xml' ) ) {
|
||||
/**
|
||||
* Escaping for XML blocks.
|
||||
*
|
||||
* @since WordPress 5.5.0
|
||||
*
|
||||
* @param string $text Text to escape.
|
||||
* @return string Escaped text.
|
||||
*/
|
||||
function esc_xml( $text ) {
|
||||
$safe_text = wp_check_invalid_utf8( $text );
|
||||
|
||||
$cdata_regex = '\<\!\[CDATA\[.*?\]\]\>';
|
||||
$regex = <<<EOF
|
||||
/
|
||||
(?=.*?{$cdata_regex}) # lookahead that will match anything followed by a CDATA Section
|
||||
(?<non_cdata_followed_by_cdata>(.*?)) # the "anything" matched by the lookahead
|
||||
(?<cdata>({$cdata_regex})) # the CDATA Section matched by the lookahead
|
||||
|
||||
| # alternative
|
||||
|
||||
(?<non_cdata>(.*)) # non-CDATA Section
|
||||
/sx
|
||||
EOF;
|
||||
|
||||
$safe_text = (string) preg_replace_callback(
|
||||
$regex,
|
||||
static function ( $matches ) {
|
||||
if ( ! isset( $matches[0] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( isset( $matches['non_cdata'] ) ) {
|
||||
// escape HTML entities in the non-CDATA Section.
|
||||
return _wp_specialchars( $matches['non_cdata'], ENT_XML1 );
|
||||
}
|
||||
|
||||
// Return the CDATA Section unchanged, escape HTML entities in the rest.
|
||||
return _wp_specialchars( $matches['non_cdata_followed_by_cdata'], ENT_XML1 ) . $matches['cdata'];
|
||||
},
|
||||
$safe_text
|
||||
);
|
||||
|
||||
/**
|
||||
* Filters a string cleaned and escaped for output in XML.
|
||||
*
|
||||
* Text passed to esc_xml() is stripped of invalid or special characters
|
||||
* before output. HTML named character references are converted to their
|
||||
* equivalent code points.
|
||||
*
|
||||
* @since WordPress 5.5.0
|
||||
*
|
||||
* @param string $safe_text The text after it has been escaped.
|
||||
* @param string $text The text prior to being escaped.
|
||||
*/
|
||||
return apply_filters( 'esc_xml', $safe_text, $text );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'is_post_status_viewable' ) ) {
|
||||
/**
|
||||
* Determines whether a post status is considered "viewable".
|
||||
*
|
||||
* For built-in post statuses such as publish and private, the 'public' value will be evaluated.
|
||||
* For all others, the 'publicly_queryable' value will be used.
|
||||
*
|
||||
* @since WordPress 5.7.0
|
||||
* @since WordPress 5.9.0 Added `is_post_status_viewable` hook to filter the result.
|
||||
*
|
||||
* @param string|stdClass $post_status Post status name or object.
|
||||
* @return bool Whether the post status should be considered viewable.
|
||||
*/
|
||||
function is_post_status_viewable( $post_status ) {
|
||||
if ( is_scalar( $post_status ) ) {
|
||||
$post_status = get_post_status_object( $post_status );
|
||||
|
||||
if ( ! $post_status ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
! is_object( $post_status )
|
||||
|| $post_status->internal
|
||||
|| $post_status->protected
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$is_viewable = $post_status->publicly_queryable || ( $post_status->_builtin && $post_status->public );
|
||||
|
||||
/**
|
||||
* Filters whether a post status is considered "viewable".
|
||||
*
|
||||
* The returned filtered value must be a boolean type to ensure
|
||||
* `is_post_status_viewable()` only returns a boolean. This strictness
|
||||
* is by design to maintain backwards-compatibility and guard against
|
||||
* potential type errors in PHP 8.1+. Non-boolean values (even falsey
|
||||
* and truthy values) will result in the function returning false.
|
||||
*
|
||||
* @since WordPress 5.9.0
|
||||
*
|
||||
* @param bool $is_viewable Whether the post status is "viewable" (strict type).
|
||||
* @param stdClass $post_status Post status object.
|
||||
*/
|
||||
return true === apply_filters( 'is_post_status_viewable', $is_viewable, $post_status );
|
||||
}
|
||||
}
|
||||
|
||||
// If _is_utf8_charset is already loaded.
|
||||
if ( ! function_exists( '_is_utf8_charset' ) ) {
|
||||
/**
|
||||
* Indicates if a given slug for a character set represents the UTF-8 text encoding.
|
||||
*
|
||||
* A charset is considered to represent UTF-8 if it is a case-insensitive match
|
||||
* of "UTF-8" with or without the hyphen.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* true === _is_utf8_charset( 'UTF-8' );
|
||||
* true === _is_utf8_charset( 'utf8' );
|
||||
* false === _is_utf8_charset( 'latin1' );
|
||||
* false === _is_utf8_charset( 'UTF 8' );
|
||||
*
|
||||
* // Only strings match.
|
||||
* false === _is_utf8_charset( [ 'charset' => 'utf-8' ] );
|
||||
*
|
||||
* `is_utf8_charset` should be used outside of this file.
|
||||
*
|
||||
* @ignore
|
||||
* @since WordPress 6.6.1
|
||||
*
|
||||
* @param string $charset_slug Slug representing a text character encoding, or "charset".
|
||||
* E.g. "UTF-8", "Windows-1252", "ISO-8859-1", "SJIS".
|
||||
*
|
||||
* @return bool Whether the slug represents the UTF-8 encoding.
|
||||
*/
|
||||
function _is_utf8_charset( $charset_slug ) {
|
||||
if ( ! is_string( $charset_slug ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
0 === strcasecmp( 'UTF-8', $charset_slug ) ||
|
||||
0 === strcasecmp( 'UTF8', $charset_slug )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'wp_get_admin_notice' ) ) {
|
||||
/**
|
||||
* Creates and returns the markup for an admin notice.
|
||||
*
|
||||
* @since WordPress 6.4.0
|
||||
*
|
||||
* @param string $message The message.
|
||||
* @param array $args {
|
||||
* Optional. An array of arguments for the admin notice. Default empty array.
|
||||
*
|
||||
* @type string $type Optional. The type of admin notice.
|
||||
* For example, 'error', 'success', 'warning', 'info'.
|
||||
* Default empty string.
|
||||
* @type bool $dismissible Optional. Whether the admin notice is dismissible. Default false.
|
||||
* @type string $id Optional. The value of the admin notice's ID attribute. Default empty string.
|
||||
* @type string[] $additional_classes Optional. A string array of class names. Default empty array.
|
||||
* @type string[] $attributes Optional. Additional attributes for the notice div. Default empty array.
|
||||
* @type bool $paragraph_wrap Optional. Whether to wrap the message in paragraph tags. Default true.
|
||||
* }
|
||||
* @return string The markup for an admin notice.
|
||||
*/
|
||||
function wp_get_admin_notice( $message, $args = [] ) {
|
||||
$defaults = [
|
||||
'type' => '',
|
||||
'dismissible' => false,
|
||||
'id' => '',
|
||||
'additional_classes' => [],
|
||||
'attributes' => [],
|
||||
'paragraph_wrap' => true,
|
||||
];
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
/**
|
||||
* Filters the arguments for an admin notice.
|
||||
*
|
||||
* @since WordPress 6.4.0
|
||||
*
|
||||
* @param array $args The arguments for the admin notice.
|
||||
* @param string $message The message for the admin notice.
|
||||
*/
|
||||
$args = apply_filters( 'wp_admin_notice_args', $args, $message );
|
||||
$id = '';
|
||||
$classes = 'notice';
|
||||
$attributes = '';
|
||||
|
||||
if ( is_string( $args['id'] ) ) {
|
||||
$trimmed_id = trim( $args['id'] );
|
||||
|
||||
if ( '' !== $trimmed_id ) {
|
||||
$id = 'id="' . $trimmed_id . '" ';
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_string( $args['type'] ) ) {
|
||||
$type = trim( $args['type'] );
|
||||
|
||||
if ( str_contains( $type, ' ' ) ) {
|
||||
_doing_it_wrong(
|
||||
__FUNCTION__,
|
||||
sprintf(
|
||||
/* translators: %s: The "type" key. */
|
||||
__( 'The %s key must be a string without spaces.' ), // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- This intentionally uses WordPress Core's translation string.
|
||||
'<code>type</code>'
|
||||
),
|
||||
'6.4.0'
|
||||
);
|
||||
}
|
||||
|
||||
if ( '' !== $type ) {
|
||||
$classes .= ' notice-' . $type;
|
||||
}
|
||||
}
|
||||
|
||||
if ( true === $args['dismissible'] ) {
|
||||
$classes .= ' is-dismissible';
|
||||
}
|
||||
|
||||
if ( is_array( $args['additional_classes'] ) && ! empty( $args['additional_classes'] ) ) {
|
||||
$classes .= ' ' . implode( ' ', $args['additional_classes'] );
|
||||
}
|
||||
|
||||
if ( is_array( $args['attributes'] ) && ! empty( $args['attributes'] ) ) {
|
||||
$attributes = '';
|
||||
foreach ( $args['attributes'] as $attr => $val ) {
|
||||
if ( is_bool( $val ) ) {
|
||||
$attributes .= $val ? ' ' . $attr : '';
|
||||
} elseif ( is_int( $attr ) ) {
|
||||
$attributes .= ' ' . esc_attr( trim( $val ) );
|
||||
} elseif ( $val ) {
|
||||
$attributes .= ' ' . $attr . '="' . esc_attr( trim( $val ) ) . '"';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( false !== $args['paragraph_wrap'] ) {
|
||||
$message = "<p>$message</p>";
|
||||
}
|
||||
|
||||
$markup = sprintf( '<div %1$sclass="%2$s"%3$s>%4$s</div>', $id, $classes, $attributes, $message );
|
||||
|
||||
/**
|
||||
* Filters the markup for an admin notice.
|
||||
*
|
||||
* @since WordPress 6.4.0
|
||||
*
|
||||
* @param string $markup The HTML markup for the admin notice.
|
||||
* @param string $message The message for the admin notice.
|
||||
* @param array $args The arguments for the admin notice.
|
||||
*/
|
||||
return apply_filters( 'wp_admin_notice_markup', $markup, $message, $args );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'wp_admin_notice' ) ) {
|
||||
/**
|
||||
* Outputs an admin notice.
|
||||
*
|
||||
* @since WordPress 6.4.0
|
||||
*
|
||||
* @param string $message The message to output.
|
||||
* @param array $args {
|
||||
* Optional. An array of arguments for the admin notice. Default empty array.
|
||||
*
|
||||
* @type string $type Optional. The type of admin notice.
|
||||
* For example, 'error', 'success', 'warning', 'info'.
|
||||
* Default empty string.
|
||||
* @type bool $dismissible Optional. Whether the admin notice is dismissible. Default false.
|
||||
* @type string $id Optional. The value of the admin notice's ID attribute. Default empty string.
|
||||
* @type string[] $additional_classes Optional. A string array of class names. Default empty array.
|
||||
* @type string[] $attributes Optional. Additional attributes for the notice div. Default empty array.
|
||||
* @type bool $paragraph_wrap Optional. Whether to wrap the message in paragraph tags. Default true.
|
||||
* }
|
||||
*/
|
||||
function wp_admin_notice( $message, $args = [] ) {
|
||||
/**
|
||||
* Fires before an admin notice is output.
|
||||
*
|
||||
* @since WordPress 6.4.0
|
||||
*
|
||||
* @param string $message The message for the admin notice.
|
||||
* @param array $args The arguments for the admin notice.
|
||||
*/
|
||||
do_action( 'wp_admin_notice', $message, $args );
|
||||
|
||||
echo wp_kses_post( wp_get_admin_notice( $message, $args ) );
|
||||
}
|
||||
}
|
||||
if ( ! function_exists( 'wp_get_wp_version' ) ) {
|
||||
/**
|
||||
* Returns the current WordPress version.
|
||||
*
|
||||
* Returns an unmodified value of `$wp_version`. Some plugins modify the global
|
||||
* in an attempt to improve security through obscurity. This practice can cause
|
||||
* errors in WordPress, so the ability to get an unmodified version is needed.
|
||||
*
|
||||
* @since WordPress 6.7.0
|
||||
*
|
||||
* @return string The current WordPress version.
|
||||
*/
|
||||
function wp_get_wp_version() {
|
||||
static $wp_version;
|
||||
|
||||
if ( ! isset( $wp_version ) ) {
|
||||
require ABSPATH . WPINC . '/version.php';
|
||||
}
|
||||
|
||||
return $wp_version;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'get_user' ) ) {
|
||||
/**
|
||||
* Retrieves user info by user ID.
|
||||
*
|
||||
* @since WordPress 6.7.0
|
||||
*
|
||||
* @param int $user_id User ID.
|
||||
*
|
||||
* @return WP_User|false WP_User object on success, false on failure.
|
||||
*/
|
||||
function get_user( $user_id ) {
|
||||
return get_user_by( 'id', $user_id );
|
||||
}
|
||||
}
|
|
@ -55,8 +55,9 @@
|
|||
</rule>
|
||||
|
||||
<rule ref="HM.Functions.NamespacedFunctions.MissingNamespace">
|
||||
<exclude-pattern>inc/compatibility/compat\.php</exclude-pattern>
|
||||
<exclude-pattern>inc/icons/svg\.php</exclude-pattern>
|
||||
<exclude-pattern>inc/compatibility/php-polyfill\.php</exclude-pattern>
|
||||
<exclude-pattern>inc/compatibility/wp-polyfill\.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<!-- Exclude the unit tests from the namespace rules -->
|
||||
|
@ -70,7 +71,6 @@
|
|||
<!-- Exclude some files from the side effects rules -->
|
||||
<rule ref="PSR1.Files.SideEffects">
|
||||
<exclude-pattern>plugin\.php</exclude-pattern>
|
||||
<exclude-pattern>inc/compatibility/compat\.php</exclude-pattern>
|
||||
<exclude-pattern>inc/icons/svg\.php</exclude-pattern>
|
||||
<exclude-pattern>tests/phpunit/bootstrap\.php</exclude-pattern>
|
||||
</rule>
|
||||
|
|
|
@ -38,7 +38,8 @@ require_once __DIR__ . '/inc/user-notification/namespace.php';
|
|||
require_once __DIR__ . '/inc/version-check/namespace.php';
|
||||
|
||||
// External dependencies.
|
||||
require_once __DIR__ . '/inc/compatibility/compat.php';
|
||||
require_once __DIR__ . '/inc/compatibility/php-polyfill.php';
|
||||
require_once __DIR__ . '/inc/compatibility/wp-polyfill.php';
|
||||
require_once __DIR__ . '/inc/updater/class-lite.php';
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue