--- a/wp/wp-includes/functions.php Fri Sep 05 18:40:08 2025 +0200
+++ b/wp/wp-includes/functions.php Fri Sep 05 18:52:52 2025 +0200
@@ -5,6 +5,11 @@
* @package WordPress
*/
+// Don't load directly.
+if ( ! defined( 'ABSPATH' ) ) {
+ die( '-1' );
+}
+
require ABSPATH . WPINC . '/option.php';
/**
@@ -73,7 +78,7 @@
function current_time( $type, $gmt = 0 ) {
// Don't use non-GMT timestamp, unless you know the difference and really need to.
if ( 'timestamp' === $type || 'U' === $type ) {
- return $gmt ? time() : time() + (int) ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
+ return $gmt ? time() : time() + (int) ( (float) get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
}
if ( 'mysql' === $type ) {
@@ -594,10 +599,10 @@
$day = mktime( 0, 0, 0, $md, $mm, $my );
// The day of the week from the timestamp.
- $weekday = gmdate( 'w', $day );
+ $weekday = (int) gmdate( 'w', $day );
if ( ! is_numeric( $start_of_week ) ) {
- $start_of_week = get_option( 'start_of_week' );
+ $start_of_week = (int) get_option( 'start_of_week' );
}
if ( $weekday < $start_of_week ) {
@@ -609,6 +614,7 @@
// $start + 1 week - 1 second.
$end = $start + WEEK_IN_SECONDS - 1;
+
return compact( 'start', 'end' );
}
@@ -1483,18 +1489,18 @@
* Gets the HTTP header information to prevent caching.
*
* The several different headers cover the different ways cache prevention
- * is handled by different browsers.
+ * is handled by different browsers or intermediate caches such as proxy servers.
*
* @since 2.8.0
* @since 6.3.0 The `Cache-Control` header for logged in users now includes the
* `no-store` and `private` directives.
+ * @since 6.8.0 The `Cache-Control` header now includes the `no-store` and `private`
+ * directives regardless of whether a user is logged in.
*
* @return array The associative array of header names and field values.
*/
function wp_get_nocache_headers() {
- $cache_control = ( function_exists( 'is_user_logged_in' ) && is_user_logged_in() )
- ? 'no-cache, must-revalidate, max-age=0, no-store, private'
- : 'no-cache, must-revalidate, max-age=0';
+ $cache_control = 'no-cache, must-revalidate, max-age=0, no-store, private';
$headers = array(
'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
@@ -1709,7 +1715,7 @@
do_action( 'do_robotstxt' );
$output = "User-agent: *\n";
- $public = get_option( 'blog_public' );
+ $public = (bool) get_option( 'blog_public' );
$site_url = parse_url( site_url() );
$path = ( ! empty( $site_url['path'] ) ) ? $site_url['path'] : '';
@@ -2257,11 +2263,11 @@
* @return bool Whether the path is writable.
*/
function wp_is_writable( $path ) {
- if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) ) {
+ if ( 'Windows' === PHP_OS_FAMILY ) {
return win_is_writable( $path );
- } else {
- return @is_writable( $path );
- }
+ }
+
+ return @is_writable( $path );
}
/**
@@ -2706,8 +2712,7 @@
* when regenerated. If yes, ensure the new file name will be unique and will produce unique sub-sizes.
*/
if ( $is_image ) {
- /** This filter is documented in wp-includes/class-wp-image-editor.php */
- $output_formats = apply_filters( 'image_editor_output_format', array(), $_dir . $filename, $mime_type );
+ $output_formats = wp_get_image_editor_output_format( $_dir . $filename, $mime_type );
$alt_types = array();
if ( ! empty( $output_formats[ $mime_type ] ) ) {
@@ -3102,7 +3107,13 @@
// Attempt to figure out what type of image it actually is.
$real_mime = wp_get_image_mime( $file );
- if ( $real_mime && $real_mime !== $type ) {
+ $heic_images_extensions = array(
+ 'heif',
+ 'heics',
+ 'heifs',
+ );
+
+ if ( $real_mime && ( $real_mime !== $type || in_array( $ext, $heic_images_extensions, true ) ) ) {
/**
* Filters the list mapping image mime types to their respective extensions.
*
@@ -3113,19 +3124,31 @@
$mime_to_ext = apply_filters(
'getimagesize_mimes_to_exts',
array(
- 'image/jpeg' => 'jpg',
- 'image/png' => 'png',
- 'image/gif' => 'gif',
- 'image/bmp' => 'bmp',
- 'image/tiff' => 'tif',
- 'image/webp' => 'webp',
- 'image/avif' => 'avif',
+ 'image/jpeg' => 'jpg',
+ 'image/png' => 'png',
+ 'image/gif' => 'gif',
+ 'image/bmp' => 'bmp',
+ 'image/tiff' => 'tif',
+ 'image/webp' => 'webp',
+ 'image/avif' => 'avif',
+
+ /*
+ * In theory there are/should be file extensions that correspond to the
+ * mime types: .heif, .heics and .heifs. However it seems that HEIC images
+ * with any of the mime types commonly have a .heic file extension.
+ * Seems keeping the status quo here is best for compatibility.
+ */
+ 'image/heic' => 'heic',
+ 'image/heif' => 'heic',
+ 'image/heic-sequence' => 'heic',
+ 'image/heif-sequence' => 'heic',
)
);
// Replace whatever is after the last period in the filename with the correct extension.
if ( ! empty( $mime_to_ext[ $real_mime ] ) ) {
$filename_parts = explode( '.', $filename );
+
array_pop( $filename_parts );
$filename_parts[] = $mime_to_ext[ $real_mime ];
$new_filename = implode( '.', $filename_parts );
@@ -3299,6 +3322,7 @@
* @since 4.7.1
* @since 5.8.0 Added support for WebP images.
* @since 6.5.0 Added support for AVIF images.
+ * @since 6.7.0 Added support for HEIC images.
*
* @param string $file Full path to the file.
* @return string|false The actual mime type or false if the type cannot be determined.
@@ -3315,9 +3339,7 @@
$mime = ( $imagetype ) ? image_type_to_mime_type( $imagetype ) : false;
} elseif ( function_exists( 'getimagesize' ) ) {
// Don't silence errors when in debug mode, unless running unit tests.
- if ( defined( 'WP_DEBUG' ) && WP_DEBUG
- && ! defined( 'WP_RUN_CORE_TESTS' )
- ) {
+ if ( defined( 'WP_DEBUG' ) && WP_DEBUG && ! defined( 'WP_RUN_CORE_TESTS' ) ) {
// Not using wp_getimagesize() here to avoid an infinite loop.
$imagesize = getimagesize( $file );
} else {
@@ -3364,13 +3386,28 @@
// Divide the header string into 4 byte groups.
$magic = str_split( $magic, 8 );
- if (
- isset( $magic[1] ) &&
- isset( $magic[2] ) &&
- 'ftyp' === hex2bin( $magic[1] ) &&
- ( 'avif' === hex2bin( $magic[2] ) || 'avis' === hex2bin( $magic[2] ) )
- ) {
- $mime = 'image/avif';
+ if ( isset( $magic[1] ) && isset( $magic[2] ) && 'ftyp' === hex2bin( $magic[1] ) ) {
+ if ( 'avif' === hex2bin( $magic[2] ) || 'avis' === hex2bin( $magic[2] ) ) {
+ $mime = 'image/avif';
+ } elseif ( 'heic' === hex2bin( $magic[2] ) ) {
+ $mime = 'image/heic';
+ } elseif ( 'heif' === hex2bin( $magic[2] ) ) {
+ $mime = 'image/heif';
+ } else {
+ /*
+ * HEIC/HEIF images and image sequences/animations may have other strings here
+ * like mif1, msf1, etc. For now fall back to using finfo_file() to detect these.
+ */
+ if ( extension_loaded( 'fileinfo' ) ) {
+ $fileinfo = finfo_open( FILEINFO_MIME_TYPE );
+ $mime_type = finfo_file( $fileinfo, $file );
+ finfo_close( $fileinfo );
+
+ if ( wp_is_heic_image_mime_type( $mime_type ) ) {
+ $mime = $mime_type;
+ }
+ }
+ }
}
} catch ( Exception $e ) {
$mime = false;
@@ -3386,6 +3423,7 @@
* @since 4.2.0 Support was added for GIMP (.xcf) files.
* @since 4.9.2 Support was added for Flac (.flac) files.
* @since 4.9.6 Support was added for AAC (.aac) files.
+ * @since 6.8.0 Support was added for `audio/x-wav`.
*
* @return string[] Array of mime types keyed by the file extension regex corresponding to those types.
*/
@@ -3413,7 +3451,13 @@
'webp' => 'image/webp',
'avif' => 'image/avif',
'ico' => 'image/x-icon',
+
+ // TODO: Needs improvement. All images with the following mime types seem to have .heic file extension.
'heic' => 'image/heic',
+ 'heif' => 'image/heif',
+ 'heics' => 'image/heic-sequence',
+ 'heifs' => 'image/heif-sequence',
+
// Video formats.
'asf|asx' => 'video/x-ms-asf',
'wmv' => 'video/x-ms-wmv',
@@ -3444,7 +3488,7 @@
'mp3|m4a|m4b' => 'audio/mpeg',
'aac' => 'audio/aac',
'ra|ram' => 'audio/x-realaudio',
- 'wav' => 'audio/wav',
+ 'wav|x-wav' => 'audio/wav',
'ogg|oga' => 'audio/ogg',
'flac' => 'audio/flac',
'mid|midi' => 'audio/midi',
@@ -3533,7 +3577,7 @@
return apply_filters(
'ext2type',
array(
- 'image' => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico', 'heic', 'webp', 'avif' ),
+ 'image' => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico', 'heic', 'heif', 'webp', 'avif' ),
'audio' => array( 'aac', 'ac3', 'aif', 'aiff', 'flac', 'm3a', 'm4a', 'm4b', 'mka', 'mp1', 'mp2', 'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
'video' => array( '3g2', '3gp', '3gpp', 'asf', 'avi', 'divx', 'dv', 'flv', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt', 'rm', 'vob', 'wmv' ),
'document' => array( 'doc', 'docx', 'docm', 'dotm', 'odt', 'pages', 'pdf', 'xps', 'oxps', 'rtf', 'wp', 'wpd', 'psd', 'xcf' ),
@@ -3628,7 +3672,7 @@
*/
function wp_nonce_ays( $action ) {
// Default title and response code.
- $title = __( 'Something went wrong.' );
+ $title = __( 'An error occurred.' );
$response_code = 403;
if ( 'log-out' === $action ) {
@@ -3858,7 +3902,7 @@
<html <?php echo $dir_attr; ?>>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $parsed_args['charset']; ?>" />
- <meta name="viewport" content="width=device-width">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
<?php
if ( function_exists( 'wp_robots' ) && function_exists( 'wp_robots_no_robots' ) && function_exists( 'add_filter' ) ) {
add_filter( 'wp_robots', 'wp_robots_no_robots' );
@@ -4695,7 +4739,7 @@
* @access private
*/
function _delete_option_fresh_site() {
- update_option( 'fresh_site', '0' );
+ update_option( 'fresh_site', '0', false );
}
/**
@@ -5467,18 +5511,6 @@
}
/**
- * Converts a value to non-negative integer.
- *
- * @since 2.5.0
- *
- * @param mixed $maybeint Data you wish to have converted to a non-negative integer.
- * @return int A non-negative integer.
- */
-function absint( $maybeint ) {
- return abs( (int) $maybeint );
-}
-
-/**
* Marks a function as deprecated and inform when it has been used.
*
* There is a {@see 'deprecated_function_run'} hook that will be called that can be used
@@ -6082,6 +6114,10 @@
array( 'http', 'https' )
);
+ if ( E_USER_ERROR === $error_level ) {
+ throw new WP_Exception( $message );
+ }
+
trigger_error( $message, $error_level );
}
@@ -6237,7 +6273,7 @@
*
* @since 2.6.0
*
- * @param string|bool $force Optional. Whether to force SSL in admin screens. Default null.
+ * @param string|bool|null $force Optional. Whether to force SSL in admin screens. Default null.
* @return bool True if forced, false if not forced.
*/
function force_ssl_admin( $force = null ) {
@@ -6245,7 +6281,7 @@
if ( ! is_null( $force ) ) {
$old_forced = $forced;
- $forced = $force;
+ $forced = (bool) $force;
return $old_forced;
}
@@ -7109,6 +7145,30 @@
}
/**
+ * Sends a referrer policy header so referrers are not sent externally from administration screens.
+ *
+ * @since 4.9.0
+ * @since 6.8.0 This function was moved from `wp-admin/includes/misc.php` to `wp-includes/functions.php`.
+ */
+function wp_admin_headers() {
+ $policy = 'strict-origin-when-cross-origin';
+
+ /**
+ * Filters the admin referrer policy header value.
+ *
+ * @since 4.9.0
+ * @since 4.9.5 The default value was changed to 'strict-origin-when-cross-origin'.
+ *
+ * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
+ *
+ * @param string $policy The admin referrer policy header value. Default 'strict-origin-when-cross-origin'.
+ */
+ $policy = apply_filters( 'admin_referrer_policy', $policy );
+
+ header( sprintf( 'Referrer-Policy: %s', $policy ) );
+}
+
+/**
* Retrieves a list of protocols to allow in HTML attributes.
*
* @since 3.3.0
@@ -7635,8 +7695,10 @@
* Deletes a file.
*
* @since 4.2.0
+ * @since 6.7.0 A return value was added.
*
* @param string $file The path to the file to delete.
+ * @return bool True on success, false on failure.
*/
function wp_delete_file( $file ) {
/**
@@ -7647,9 +7709,12 @@
* @param string $file Path to the file to delete.
*/
$delete = apply_filters( 'wp_delete_file', $file );
+
if ( ! empty( $delete ) ) {
- @unlink( $delete );
- }
+ return @unlink( $delete );
+ }
+
+ return false;
}
/**
@@ -7682,9 +7747,7 @@
return false;
}
- wp_delete_file( $file );
-
- return true;
+ return wp_delete_file( $file );
}
/**
@@ -8007,9 +8070,9 @@
*
* @since 6.3.0
*
- * @param string $group The cache group name.
- * @param int $time The new last changed time.
- * @param int|false $previous_time The previous last changed time. False if not previously set.
+ * @param string $group The cache group name.
+ * @param string $time The new last changed time (msec sec).
+ * @param string|false $previous_time The previous last changed time. False if not previously set.
*/
do_action( 'wp_cache_set_last_changed', $group, $time, $previous_time );
@@ -8500,7 +8563,7 @@
echo '<p class="button-container">';
printf(
- '<a class="button button-primary" href="%1$s" target="_blank" rel="noopener">%2$s<span class="screen-reader-text"> %3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
+ '<a class="button button-primary" href="%1$s" target="_blank">%2$s<span class="screen-reader-text"> %3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
esc_url( $direct_update_url ),
__( 'Update PHP' ),
/* translators: Hidden accessibility text. */
@@ -8805,17 +8868,46 @@
}
/**
+ * 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 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;
+}
+
+/**
* Checks compatibility with the current WordPress version.
*
* @since 5.2.0
*
- * @global string $wp_version The WordPress version string.
+ * @global string $_wp_tests_wp_version The WordPress version string. Used only in Core tests.
*
* @param string $required Minimum required WordPress version.
* @return bool True if required version is compatible or empty, false if not.
*/
function is_wp_version_compatible( $required ) {
- global $wp_version;
+ if (
+ defined( 'WP_RUN_CORE_TESTS' )
+ && WP_RUN_CORE_TESTS
+ && isset( $GLOBALS['_wp_tests_wp_version'] )
+ ) {
+ $wp_version = $GLOBALS['_wp_tests_wp_version'];
+ } else {
+ $wp_version = wp_get_wp_version();
+ }
// Strip off any -alpha, -RC, -beta, -src suffixes.
list( $version ) = explode( '-', $wp_version );
@@ -9003,3 +9095,113 @@
echo wp_kses_post( wp_get_admin_notice( $message, $args ) );
}
+
+/**
+ * Checks if a mime type is for a HEIC/HEIF image.
+ *
+ * @since 6.7.0
+ *
+ * @param string $mime_type The mime type to check.
+ * @return bool Whether the mime type is for a HEIC/HEIF image.
+ */
+function wp_is_heic_image_mime_type( $mime_type ) {
+ $heic_mime_types = array(
+ 'image/heic',
+ 'image/heif',
+ 'image/heic-sequence',
+ 'image/heif-sequence',
+ );
+
+ return in_array( $mime_type, $heic_mime_types, true );
+}
+
+/**
+ * Returns a cryptographically secure hash of a message using a fast generic hash function.
+ *
+ * Use the wp_verify_fast_hash() function to verify the hash.
+ *
+ * This function does not salt the value prior to being hashed, therefore input to this function must originate from
+ * a random generator with sufficiently high entropy, preferably greater than 128 bits. This function is used internally
+ * in WordPress to hash security keys and application passwords which are generated with high entropy.
+ *
+ * Important:
+ *
+ * - This function must not be used for hashing user-generated passwords. Use wp_hash_password() for that.
+ * - This function must not be used for hashing other low-entropy input. Use wp_hash() for that.
+ *
+ * The BLAKE2b algorithm is used by Sodium to hash the message.
+ *
+ * @since 6.8.0
+ *
+ * @throws TypeError Thrown by Sodium if the message is not a string.
+ *
+ * @param string $message The message to hash.
+ * @return string The hash of the message.
+ */
+function wp_fast_hash(
+ #[\SensitiveParameter]
+ string $message
+): string {
+ $hashed = sodium_crypto_generichash( $message, 'wp_fast_hash_6.8+', 30 );
+ return '$generic$' . sodium_bin2base64( $hashed, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING );
+}
+
+/**
+ * Checks whether a plaintext message matches the hashed value. Used to verify values hashed via wp_fast_hash().
+ *
+ * The function uses Sodium to hash the message and compare it to the hashed value. If the hash is not a generic hash,
+ * the hash is treated as a phpass portable hash in order to provide backward compatibility for passwords and security
+ * keys which were hashed using phpass prior to WordPress 6.8.0.
+ *
+ * @since 6.8.0
+ *
+ * @throws TypeError Thrown by Sodium if the message is not a string.
+ *
+ * @param string $message The plaintext message.
+ * @param string $hash Hash of the message to check against.
+ * @return bool Whether the message matches the hashed message.
+ */
+function wp_verify_fast_hash(
+ #[\SensitiveParameter]
+ string $message,
+ string $hash
+): bool {
+ if ( ! str_starts_with( $hash, '$generic$' ) ) {
+ // Back-compat for old phpass hashes.
+ require_once ABSPATH . WPINC . '/class-phpass.php';
+ return ( new PasswordHash( 8, true ) )->CheckPassword( $message, $hash );
+ }
+
+ return hash_equals( $hash, wp_fast_hash( $message ) );
+}
+
+/**
+ * Generates a unique ID based on the structure and values of a given array.
+ *
+ * This function serializes the array into a JSON string and generates a hash
+ * that serves as a unique identifier. Optionally, a prefix can be added to
+ * the generated ID for context or categorization.
+ *
+ * @since 6.8.0
+ *
+ * @param array $data The input array to generate an ID from.
+ * @param string $prefix Optional. A prefix to prepend to the generated ID. Default ''.
+ *
+ * @return string The generated unique ID for the array.
+ */
+function wp_unique_id_from_values( array $data, string $prefix = '' ): string {
+ if ( empty( $data ) ) {
+ _doing_it_wrong(
+ __FUNCTION__,
+ sprintf(
+ /* translators: %s: parameter name. */
+ __( 'The %s argument must not be empty.' ),
+ '$data'
+ ),
+ '6.8.0'
+ );
+ }
+ $serialized = wp_json_encode( $data );
+ $hash = substr( md5( $serialized ), 0, 8 );
+ return $prefix . $hash;
+}