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. |
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 /** |
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 } |