diff -r be944660c56a -r 3d72ae0968f4 wp/wp-includes/functions.php --- a/wp/wp-includes/functions.php Wed Sep 21 18:19:35 2022 +0200 +++ b/wp/wp-includes/functions.php Tue Sep 27 16:37:53 2022 +0200 @@ -10,9 +10,9 @@ /** * Convert given MySQL date string into a different format. * - * `$format` should be a PHP date format string. - * 'U' and 'G' formats will return a sum of timestamp with timezone offset. - * `$date` is expected to be local time in MySQL format (`Y-m-d H:i:s`). + * - `$format` should be a PHP date format string. + * - 'U' and 'G' formats will return an integer sum of timestamp with timezone offset. + * - `$date` is expected to be local time in MySQL format (`Y-m-d H:i:s`). * * Historically UTC time could be passed to the function to produce Unix timestamp. * @@ -24,7 +24,7 @@ * @param string $format Format of the date to return. * @param string $date Date string to convert. * @param bool $translate Whether the return date should be translated. Default true. - * @return string|int|false Formatted date string or sum of Unix timestamp and timezone offset. + * @return string|int|false Integer if `$format` is 'U' or 'G', string otherwise. * False on failure. */ function mysql2date( $format, $date, $translate = true ) { @@ -53,20 +53,21 @@ /** * Retrieves the current time based on specified type. * - * The 'mysql' type will return the time in the format for MySQL DATETIME field. - * The 'timestamp' type will return the current timestamp or a sum of timestamp - * and timezone offset, depending on `$gmt`. - * Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d'). - * - * If $gmt is set to either '1' or 'true', then both types will use GMT time. - * if $gmt is false, the output is adjusted with the GMT offset in the WordPress option. + * - The 'mysql' type will return the time in the format for MySQL DATETIME field. + * - The 'timestamp' or 'U' types will return the current timestamp or a sum of timestamp + * and timezone offset, depending on `$gmt`. + * - Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d'). + * + * If `$gmt` is a truthy value then both types will use GMT time, otherwise the + * output is adjusted with the GMT offset for the site. * * @since 1.0.0 - * - * @param string $type Type of time to retrieve. Accepts 'mysql', 'timestamp', + * @since 5.3.0 Now returns an integer if `$type` is 'U'. Previously a string was returned. + * + * @param string $type Type of time to retrieve. Accepts 'mysql', 'timestamp', 'U', * or PHP date format string (e.g. 'Y-m-d'). * @param int|bool $gmt Optional. Whether to use GMT timezone. Default false. - * @return int|string Integer if $type is 'timestamp', string otherwise. + * @return int|string Integer if `$type` is 'timestamp' or 'U', string otherwise. */ function current_time( $type, $gmt = 0 ) { // Don't use non-GMT timestamp, unless you know the difference and really need to. @@ -85,7 +86,7 @@ } /** - * Retrieves the current time as an object with the timezone from settings. + * Retrieves the current time as an object using the site's timezone. * * @since 5.3.0 * @@ -96,14 +97,23 @@ } /** - * Retrieves the timezone from site settings as a string. - * - * Uses the `timezone_string` option to get a proper timezone if available, - * otherwise falls back to an offset. + * Retrieves the timezone of the site as a string. + * + * Uses the `timezone_string` option to get a proper timezone name if available, + * otherwise falls back to a manual UTC ± offset. + * + * Example return values: + * + * - 'Europe/Rome' + * - 'America/North_Dakota/New_Salem' + * - 'UTC' + * - '-06:30' + * - '+00:00' + * - '+08:45' * * @since 5.3.0 * - * @return string PHP timezone string or a ±HH:MM offset. + * @return string PHP timezone name or a ±HH:MM offset. */ function wp_timezone_string() { $timezone_string = get_option( 'timezone_string' ); @@ -125,7 +135,7 @@ } /** - * Retrieves the timezone from site settings as a `DateTimeZone` object. + * Retrieves the timezone of the site as a `DateTimeZone` object. * * Timezone can be based on a PHP timezone string or a ±HH:MM offset. * @@ -167,6 +177,7 @@ // If timestamp is omitted it should be current time (summed with offset, unless `$gmt` is true). if ( ! is_numeric( $timestamp ) ) { + // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested $timestamp = current_time( 'timestamp', $gmt ); } @@ -218,6 +229,8 @@ * * @since 5.3.0 * + * @global WP_Locale $wp_locale WordPress date and time locale object. + * * @param string $format PHP date format. * @param int $timestamp Optional. Unix timestamp. Defaults to current time. * @param DateTimeZone $timezone Optional. Timezone to output result in. Defaults to timezone @@ -428,11 +441,11 @@ } /** - * Convert number of bytes largest unit bytes will fit into. + * Converts a number of bytes to the largest unit the bytes will fit into. * * It is easier to read 1 KB than 1024 bytes and 1 MB than 1048576 bytes. Converts * number of bytes to human readable number by taking the number of that unit - * that the bytes will go into it. Supports TB value. + * that the bytes will go into it. Supports YB value. * * Please note that integers in PHP are limited to 32 bits, unless they are on * 64 bit architecture, then they have 64 bit size. If you need to place the @@ -442,6 +455,7 @@ * Technically the correct unit names for powers of 1024 are KiB, MiB etc. * * @since 2.3.0 + * @since 6.0.0 Support for PB, EB, ZB, and YB was added. * * @param int|string $bytes Number of bytes. Note max integer size for integers. * @param int $decimals Optional. Precision of number of decimal places. Default 0. @@ -449,6 +463,14 @@ */ function size_format( $bytes, $decimals = 0 ) { $quant = array( + /* translators: Unit symbol for yottabyte. */ + _x( 'YB', 'unit symbol' ) => YB_IN_BYTES, + /* translators: Unit symbol for zettabyte. */ + _x( 'ZB', 'unit symbol' ) => ZB_IN_BYTES, + /* translators: Unit symbol for exabyte. */ + _x( 'EB', 'unit symbol' ) => EB_IN_BYTES, + /* translators: Unit symbol for petabyte. */ + _x( 'PB', 'unit symbol' ) => PB_IN_BYTES, /* translators: Unit symbol for terabyte. */ _x( 'TB', 'unit symbol' ) => TB_IN_BYTES, /* translators: Unit symbol for gigabyte. */ @@ -552,7 +574,12 @@ * * @param string $mysqlstring Date or datetime field type from MySQL. * @param int|string $start_of_week Optional. Start of the week as an integer. Default empty string. - * @return array Keys are 'start' and 'end'. + * @return int[] { + * Week start and end dates as Unix timestamps. + * + * @type int $start The week start date as a Unix timestamp. + * @type int $end The week end date as a Unix timestamp. + * } */ function get_weekstartend( $mysqlstring, $start_of_week = '' ) { // MySQL string year. @@ -793,6 +820,7 @@ * Use RegEx to extract URLs from arbitrary content. * * @since 3.7.0 + * @since 6.0.0 Fixes support for HTML entities (Trac 30580). * * @param string $content Content to extract URLs from. * @return string[] Array of URLs found in passed string. @@ -806,7 +834,7 @@ . '(?:' . '\([\w\d]+\)|' . '(?:' - . "[^`!()\[\]{};:'\".,<>«»“”‘’\s]|" + . "[^`!()\[\]{}:'\".,<>«»“”‘’\s]|" . '(?:[:]\d+)?/?' . ')+' . ')' @@ -815,7 +843,17 @@ $post_links ); - $post_links = array_unique( array_map( 'html_entity_decode', $post_links[2] ) ); + $post_links = array_unique( + array_map( + static function( $link ) { + // Decode to replace valid entities, like &. + $link = html_entity_decode( $link ); + // Maintain backward compatibility by removing extraneous semi-colons (`;`). + return str_replace( ';', '', $link ); + }, + $post_links[2] + ) + ); return array_values( $post_links ); } @@ -1151,6 +1189,7 @@ $ret = preg_replace( '#=(&|$)#', '$1', $ret ); $ret = $protocol . $base . $ret . $frag; $ret = rtrim( $ret, '?' ); + $ret = str_replace( '?#', '#', $ret ); return $ret; } @@ -1530,7 +1569,7 @@ * @since 1.0.0 * * @param string $yn Character string containing either 'y' (yes) or 'n' (no). - * @return bool True if yes, false on anything else. + * @return bool True if 'y', false on anything else. */ function bool_from_yn( $yn ) { return ( 'y' === strtolower( $yn ) ); @@ -1561,7 +1600,7 @@ } if ( ! has_action( "do_feed_{$feed}" ) ) { - wp_die( __( 'Error: This is not a valid feed template.' ), '', array( 'response' => 404 ) ); + wp_die( __( 'Error: This is not a valid feed template.' ), '', array( 'response' => 404 ) ); } /** @@ -2121,7 +2160,7 @@ $wrapper .= '://'; } - // Standardise all paths to use '/'. + // Standardize all paths to use '/'. $path = str_replace( '\\', '/', $path ); // Replace multiple slashes down to a singular, allowing for network shares having two slashes. @@ -2519,8 +2558,10 @@ $filename = str_replace( "{$fname}{$ext}", "{$fname}-{$number}{$ext}", $filename ); } - // Get the mime type. Uploaded files were already checked with wp_check_filetype_and_ext() - // in _wp_handle_upload(). Using wp_check_filetype() would be sufficient here. + /* + * Get the mime type. Uploaded files were already checked with wp_check_filetype_and_ext() + * in _wp_handle_upload(). Using wp_check_filetype() would be sufficient here. + */ $file_type = wp_check_filetype( $filename ); $mime_type = $file_type['type']; @@ -2531,27 +2572,40 @@ $lc_ext = strtolower( $ext ); $_dir = trailingslashit( $dir ); - // If the extension is uppercase add an alternate file name with lowercase extension. Both need to be tested - // for uniqueness as the extension will be changed to lowercase for better compatibility with different filesystems. - // Fixes an inconsistency in WP < 2.9 where uppercase extensions were allowed but image sub-sizes were created with - // lowercase extensions. + /* + * If the extension is uppercase add an alternate file name with lowercase extension. + * Both need to be tested for uniqueness as the extension will be changed to lowercase + * for better compatibility with different filesystems. Fixes an inconsistency in WP < 2.9 + * where uppercase extensions were allowed but image sub-sizes were created with + * lowercase extensions. + */ if ( $ext && $lc_ext !== $ext ) { $lc_filename = preg_replace( '|' . preg_quote( $ext ) . '$|', $lc_ext, $filename ); } - // Increment the number added to the file name if there are any files in $dir whose names match one of the - // possible name variations. + /* + * Increment the number added to the file name if there are any files in $dir + * whose names match one of the possible name variations. + */ while ( file_exists( $_dir . $filename ) || ( $lc_filename && file_exists( $_dir . $lc_filename ) ) ) { $new_number = (int) $number + 1; if ( $lc_filename ) { - $lc_filename = str_replace( array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), "-{$new_number}{$lc_ext}", $lc_filename ); + $lc_filename = str_replace( + array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), + "-{$new_number}{$lc_ext}", + $lc_filename + ); } if ( '' === "{$number}{$ext}" ) { $filename = "{$filename}-{$new_number}"; } else { - $filename = str_replace( array( "-{$number}{$ext}", "{$number}{$ext}" ), "-{$new_number}{$ext}", $filename ); + $filename = str_replace( + array( "-{$number}{$ext}", "{$number}{$ext}" ), + "-{$new_number}{$ext}", + $filename + ); } $number = $new_number; @@ -2562,8 +2616,10 @@ $filename = $lc_filename; } - // Prevent collisions with existing file names that contain dimension-like strings - // (whether they are subsizes or originals uploaded prior to #42437). + /* + * Prevent collisions with existing file names that contain dimension-like strings + * (whether they are subsizes or originals uploaded prior to #42437). + */ $files = array(); $count = 10000; @@ -2598,15 +2654,21 @@ if ( ! empty( $files ) ) { $count = count( $files ); - // Ensure this never goes into infinite loop - // as it uses pathinfo() and regex in the check, but string replacement for the changes. + /* + * Ensure this never goes into infinite loop as it uses pathinfo() and regex in the check, + * but string replacement for the changes. + */ $i = 0; while ( $i <= $count && _wp_check_existing_file_names( $filename, $files ) ) { $new_number = (int) $number + 1; // If $ext is uppercase it was replaced with the lowercase version after the previous loop. - $filename = str_replace( array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), "-{$new_number}{$lc_ext}", $filename ); + $filename = str_replace( + array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), + "-{$new_number}{$lc_ext}", + $filename + ); $number = $new_number; $i++; @@ -2614,9 +2676,12 @@ } } - // Check if an image will be converted after uploading or some existing images sub-sizes file names may conflict - // when regenerated. If yes, ensure the new file name will be unique and will produce unique sub-sizes. + /* + * Check if an image will be converted after uploading or some existing image sub-size file names may conflict + * 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 ); $alt_types = array(); @@ -2648,8 +2713,10 @@ } if ( ! empty( $alt_filenames ) ) { - // Add the original filename. It needs to be checked again together with the alternate filenames - // when $number is incremented. + /* + * Add the original filename. It needs to be checked again + * together with the alternate filenames when $number is incremented. + */ $alt_filenames[ $lc_ext ] = $filename; // Ensure no infinite loop. @@ -2659,12 +2726,22 @@ $new_number = (int) $number + 1; foreach ( $alt_filenames as $alt_ext => $alt_filename ) { - $alt_filenames[ $alt_ext ] = str_replace( array( "-{$number}{$alt_ext}", "{$number}{$alt_ext}" ), "-{$new_number}{$alt_ext}", $alt_filename ); + $alt_filenames[ $alt_ext ] = str_replace( + array( "-{$number}{$alt_ext}", "{$number}{$alt_ext}" ), + "-{$new_number}{$alt_ext}", + $alt_filename + ); } - // Also update the $number in (the output) $filename. - // If the extension was uppercase it was already replaced with the lowercase version. - $filename = str_replace( array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), "-{$new_number}{$lc_ext}", $filename ); + /* + * Also update the $number in (the output) $filename. + * If the extension was uppercase it was already replaced with the lowercase version. + */ + $filename = str_replace( + array( "-{$number}{$lc_ext}", "{$number}{$lc_ext}" ), + "-{$new_number}{$lc_ext}", + $filename + ); $number = $new_number; $i++; @@ -2680,7 +2757,7 @@ * @since 5.8.1 The `$alt_filenames` and `$number` parameters were added. * * @param string $filename Unique file name. - * @param string $ext File extension, eg. ".png". + * @param string $ext File extension. Example: ".png". * @param string $dir Directory path. * @param callable|null $unique_filename_callback Callback function that generates the unique file name. * @param string[] $alt_filenames Array of alternate file names that were checked for collisions. @@ -2790,7 +2867,7 @@ $wp_filetype = wp_check_filetype( $name ); if ( ! $wp_filetype['ext'] && ! current_user_can( 'unfiltered_upload' ) ) { - return array( 'error' => __( 'Sorry, this file type is not permitted for security reasons.' ) ); + return array( 'error' => __( 'Sorry, you are not allowed to upload this file type.' ) ); } $upload = wp_upload_dir( $time ); @@ -3180,7 +3257,7 @@ function wp_get_image_mime( $file ) { /* * Use exif_imagetype() to check the mimetype if available or fall back to - * getimagesize() if exif isn't avaialbe. If either function throws an Exception + * getimagesize() if exif isn't available. If either function throws an Exception * we assume the file could not be validated. */ try { @@ -3208,12 +3285,8 @@ return $mime; } - $handle = fopen( $file, 'rb' ); - if ( false === $handle ) { - return false; - } - - $magic = fread( $handle, 12 ); + $magic = file_get_contents( $file, false, null, 0, 12 ); + if ( false === $magic ) { return false; } @@ -3232,8 +3305,6 @@ ) { $mime = 'image/webp'; } - - fclose( $handle ); } catch ( Exception $e ) { $mime = false; } @@ -3408,6 +3479,44 @@ } /** + * Wrapper for PHP filesize with filters and casting the result as an integer. + * + * @since 6.0.0 + * + * @link https://www.php.net/manual/en/function.filesize.php + * + * @param string $path Path to the file. + * @return int The size of the file in bytes, or 0 in the event of an error. + */ +function wp_filesize( $path ) { + /** + * Filters the result of wp_filesize before the PHP function is run. + * + * @since 6.0.0 + * + * @param null|int $size The unfiltered value. Returning an int from the callback bypasses the filesize call. + * @param string $path Path to the file. + */ + $size = apply_filters( 'pre_wp_filesize', null, $path ); + + if ( is_int( $size ) ) { + return $size; + } + + $size = file_exists( $path ) ? (int) filesize( $path ) : 0; + + /** + * Filters the size of the file. + * + * @since 6.0.0 + * + * @param int $size The result of PHP filesize on the file. + * @param string $path Path to the file. + */ + return (int) apply_filters( 'wp_filesize', $size, $path ); +} + +/** * Retrieve list of allowed mime types and file extensions. * * @since 2.8.6 @@ -3450,12 +3559,17 @@ * @param string $action The nonce action. */ function wp_nonce_ays( $action ) { + // Default title and response code. + $title = __( 'Something went wrong.' ); + $response_code = 403; + if ( 'log-out' === $action ) { - $html = sprintf( + $title = sprintf( /* translators: %s: Site title. */ __( 'You are attempting to log out of %s' ), get_bloginfo( 'name' ) ); + $html = $title; $html .= '

'; $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : ''; $html .= sprintf( @@ -3475,7 +3589,7 @@ } } - wp_die( $html, __( 'Something went wrong.' ), 403 ); + wp_die( $html, $title, $response_code ); } /** @@ -3542,36 +3656,36 @@ * * @since 3.4.0 * - * @param callable $function Callback function name. + * @param callable $callback Callback function name. */ - $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' ); + $callback = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' ); } elseif ( wp_is_json_request() ) { /** * Filters the callback for killing WordPress execution for JSON requests. * * @since 5.1.0 * - * @param callable $function Callback function name. + * @param callable $callback Callback function name. */ - $function = apply_filters( 'wp_die_json_handler', '_json_wp_die_handler' ); + $callback = apply_filters( 'wp_die_json_handler', '_json_wp_die_handler' ); } elseif ( defined( 'REST_REQUEST' ) && REST_REQUEST && wp_is_jsonp_request() ) { /** * Filters the callback for killing WordPress execution for JSONP REST requests. * * @since 5.2.0 * - * @param callable $function Callback function name. + * @param callable $callback Callback function name. */ - $function = apply_filters( 'wp_die_jsonp_handler', '_jsonp_wp_die_handler' ); + $callback = apply_filters( 'wp_die_jsonp_handler', '_jsonp_wp_die_handler' ); } elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) { /** * Filters the callback for killing WordPress execution for XML-RPC requests. * * @since 3.4.0 * - * @param callable $function Callback function name. + * @param callable $callback Callback function name. */ - $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' ); + $callback = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' ); } elseif ( wp_is_xml_request() || isset( $wp_query ) && ( function_exists( 'is_feed' ) && is_feed() @@ -3582,21 +3696,21 @@ * * @since 5.2.0 * - * @param callable $function Callback function name. + * @param callable $callback Callback function name. */ - $function = apply_filters( 'wp_die_xml_handler', '_xml_wp_die_handler' ); + $callback = apply_filters( 'wp_die_xml_handler', '_xml_wp_die_handler' ); } else { /** * Filters the callback for killing WordPress execution for all non-Ajax, non-JSON, non-XML requests. * * @since 3.0.0 * - * @param callable $function Callback function name. + * @param callable $callback Callback function name. */ - $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' ); - } - - call_user_func( $function, $message, $title, $args ); + $callback = apply_filters( 'wp_die_handler', '_default_wp_die_handler' ); + } + + call_user_func( $callback, $message, $title, $args ); } /** @@ -4393,6 +4507,54 @@ } /** + * Reads and decodes a JSON file. + * + * @since 5.9.0 + * + * @param string $filename Path to the JSON file. + * @param array $options { + * Optional. Options to be used with `json_decode()`. + * + * @type bool $associative Optional. When `true`, JSON objects will be returned as associative arrays. + * When `false`, JSON objects will be returned as objects. + * } + * + * @return mixed Returns the value encoded in JSON in appropriate PHP type. + * `null` is returned if the file is not found, or its content can't be decoded. + */ +function wp_json_file_decode( $filename, $options = array() ) { + $result = null; + $filename = wp_normalize_path( realpath( $filename ) ); + if ( ! file_exists( $filename ) ) { + trigger_error( + sprintf( + /* translators: %s: Path to the JSON file. */ + __( "File %s doesn't exist!" ), + $filename + ) + ); + return $result; + } + + $options = wp_parse_args( $options, array( 'associative' => false ) ); + $decoded_file = json_decode( file_get_contents( $filename ), $options['associative'] ); + + if ( JSON_ERROR_NONE !== json_last_error() ) { + trigger_error( + sprintf( + /* translators: 1: Path to the JSON file, 2: Error message. */ + __( 'Error when decoding a JSON file at path %1$s: %2$s' ), + $filename, + json_last_error_msg() + ) + ); + return $result; + } + + return $decoded_file; +} + +/** * Retrieve the WordPress home page URL. * * If the constant named 'WP_HOME' exists, then it will be used and returned @@ -4427,7 +4589,7 @@ * @see WP_SITEURL * * @param string $url URL to set the WordPress site location. - * @return string The WordPress Site URL. + * @return string The WordPress site URL. */ function _config_wp_siteurl( $url = '' ) { if ( defined( 'WP_SITEURL' ) ) { @@ -4980,6 +5142,7 @@ * * @since 3.1.0 * @since 4.7.0 Uses `WP_List_Util` class. + * @since 5.9.0 Converted into a wrapper for `wp_filter_object_list()`. * * @param array $list An array of objects to filter. * @param array $args Optional. An array of key => value arguments to match @@ -4991,17 +5154,11 @@ * @return array Array of found values. */ function wp_list_filter( $list, $args = array(), $operator = 'AND' ) { - if ( ! is_array( $list ) ) { - return array(); - } - - $util = new WP_List_Util( $list ); - - return $util->filter( $args, $operator ); -} - -/** - * Pluck a certain field out of each object in a list. + return wp_filter_object_list( $list, $args, $operator ); +} + +/** + * Plucks a certain field out of each object or array in an array. * * This has the same functionality and prototype of * array_column() (PHP 5.5) but also supports objects. @@ -5019,13 +5176,17 @@ * `$list` will be preserved in the results. */ function wp_list_pluck( $list, $field, $index_key = null ) { + if ( ! is_array( $list ) ) { + return array(); + } + $util = new WP_List_Util( $list ); return $util->pluck( $field, $index_key ); } /** - * Sorts a list of objects, based on one or more orderby arguments. + * Sorts an array of objects or arrays based on one or more orderby arguments. * * @since 4.7.0 * @@ -5080,6 +5241,7 @@ * Append the Widgets menu to the themes main menu. * * @since 2.2.0 + * @since 5.9.3 Don't specify menu order when the active theme is a block theme. * * @global array $submenu */ @@ -5090,7 +5252,13 @@ return; } - $submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' ); + $menu_name = __( 'Widgets' ); + if ( wp_is_block_theme() ) { + $submenu['themes.php'][] = array( $menu_name, 'edit_theme_options', 'widgets.php' ); + } else { + $submenu['themes.php'][7] = array( $menu_name, 'edit_theme_options', 'widgets.php' ); + } + ksort( $submenu['themes.php'], SORT_NUMERIC ); } @@ -5203,7 +5371,7 @@ trigger_error( sprintf( /* translators: 1: PHP function name, 2: Version number, 3: Alternative function name. */ - __( '%1$s is deprecated since version %2$s! Use %3$s instead.' ), + __( 'Function %1$s is deprecated since version %2$s! Use %3$s instead.' ), $function, $version, $replacement @@ -5214,7 +5382,7 @@ trigger_error( sprintf( /* translators: 1: PHP function name, 2: Version number. */ - __( '%1$s is deprecated since version %2$s with no alternative available.' ), + __( 'Function %1$s is deprecated since version %2$s with no alternative available.' ), $function, $version ), @@ -5225,7 +5393,7 @@ if ( $replacement ) { trigger_error( sprintf( - '%1$s is deprecated since version %2$s! Use %3$s instead.', + 'Function %1$s is deprecated since version %2$s! Use %3$s instead.', $function, $version, $replacement @@ -5235,7 +5403,7 @@ } else { trigger_error( sprintf( - '%1$s is deprecated since version %2$s with no alternative available.', + 'Function %1$s is deprecated since version %2$s with no alternative available.', $function, $version ), @@ -5295,7 +5463,7 @@ trigger_error( sprintf( /* translators: 1: PHP class name, 2: PHP parent class name, 3: Version number, 4: __construct() method. */ - __( 'The called constructor method for %1$s in %2$s is deprecated since version %3$s! Use %4$s instead.' ), + __( 'The called constructor method for %1$s class in %2$s is deprecated since version %3$s! Use %4$s instead.' ), $class, $parent_class, $version, @@ -5307,7 +5475,7 @@ trigger_error( sprintf( /* translators: 1: PHP class name, 2: Version number, 3: __construct() method. */ - __( 'The called constructor method for %1$s is deprecated since version %2$s! Use %3$s instead.' ), + __( 'The called constructor method for %1$s class is deprecated since version %2$s! Use %3$s instead.' ), $class, $version, '__construct()' @@ -5319,7 +5487,7 @@ if ( $parent_class ) { trigger_error( sprintf( - 'The called constructor method for %1$s in %2$s is deprecated since version %3$s! Use %4$s instead.', + 'The called constructor method for %1$s class in %2$s is deprecated since version %3$s! Use %4$s instead.', $class, $parent_class, $version, @@ -5330,7 +5498,7 @@ } else { trigger_error( sprintf( - 'The called constructor method for %1$s is deprecated since version %2$s! Use %3$s instead.', + 'The called constructor method for %1$s class is deprecated since version %2$s! Use %3$s instead.', $class, $version, '__construct()' @@ -5393,7 +5561,7 @@ trigger_error( sprintf( /* translators: 1: PHP file name, 2: Version number, 3: Alternative file name. */ - __( '%1$s is deprecated since version %2$s! Use %3$s instead.' ), + __( 'File %1$s is deprecated since version %2$s! Use %3$s instead.' ), $file, $version, $replacement @@ -5404,7 +5572,7 @@ trigger_error( sprintf( /* translators: 1: PHP file name, 2: Version number. */ - __( '%1$s is deprecated since version %2$s with no alternative available.' ), + __( 'File %1$s is deprecated since version %2$s with no alternative available.' ), $file, $version ) . $message, @@ -5415,7 +5583,7 @@ if ( $replacement ) { trigger_error( sprintf( - '%1$s is deprecated since version %2$s! Use %3$s instead.', + 'File %1$s is deprecated since version %2$s! Use %3$s instead.', $file, $version, $replacement @@ -5425,7 +5593,7 @@ } else { trigger_error( sprintf( - '%1$s is deprecated since version %2$s with no alternative available.', + 'File %1$s is deprecated since version %2$s with no alternative available.', $file, $version ) . $message, @@ -5487,7 +5655,7 @@ trigger_error( sprintf( /* translators: 1: PHP function name, 2: Version number, 3: Optional message regarding the change. */ - __( '%1$s was called with an argument that is deprecated since version %2$s! %3$s' ), + __( 'Function %1$s was called with an argument that is deprecated since version %2$s! %3$s' ), $function, $version, $message @@ -5498,7 +5666,7 @@ trigger_error( sprintf( /* translators: 1: PHP function name, 2: Version number. */ - __( '%1$s was called with an argument that is deprecated since version %2$s with no alternative available.' ), + __( 'Function %1$s was called with an argument that is deprecated since version %2$s with no alternative available.' ), $function, $version ), @@ -5509,7 +5677,7 @@ if ( $message ) { trigger_error( sprintf( - '%1$s was called with an argument that is deprecated since version %2$s! %3$s', + 'Function %1$s was called with an argument that is deprecated since version %2$s! %3$s', $function, $version, $message @@ -5519,7 +5687,7 @@ } else { trigger_error( sprintf( - '%1$s was called with an argument that is deprecated since version %2$s with no alternative available.', + 'Function %1$s was called with an argument that is deprecated since version %2$s with no alternative available.', $function, $version ), @@ -5578,7 +5746,7 @@ trigger_error( sprintf( /* translators: 1: WordPress hook name, 2: Version number, 3: Alternative hook name. */ - __( '%1$s is deprecated since version %2$s! Use %3$s instead.' ), + __( 'Hook %1$s is deprecated since version %2$s! Use %3$s instead.' ), $hook, $version, $replacement @@ -5589,7 +5757,7 @@ trigger_error( sprintf( /* translators: 1: WordPress hook name, 2: Version number. */ - __( '%1$s is deprecated since version %2$s with no alternative available.' ), + __( 'Hook %1$s is deprecated since version %2$s with no alternative available.' ), $hook, $version ) . $message, @@ -5655,7 +5823,7 @@ trigger_error( sprintf( /* translators: Developer debugging message. 1: PHP function name, 2: Explanatory message, 3: WordPress version number. */ - __( '%1$s was called incorrectly. %2$s %3$s' ), + __( 'Function %1$s was called incorrectly. %2$s %3$s' ), $function, $message, $version @@ -5674,7 +5842,7 @@ trigger_error( sprintf( - '%1$s was called incorrectly. %2$s %3$s', + 'Function %1$s was called incorrectly. %2$s %3$s', $function, $message, $version @@ -5786,12 +5954,16 @@ * @return int 0 means nothing is wrong, greater than 0 means something was wrong. */ function validate_file( $file, $allowed_files = array() ) { + if ( ! is_scalar( $file ) || '' === $file ) { + return 0; + } + // `../` on its own is not allowed: if ( '../' === $file ) { return 1; } - // More than one occurence of `../` is not allowed: + // More than one occurrence of `../` is not allowed: if ( preg_match_all( '#\.\./#', $file, $matches, PREG_SET_ORDER ) && ( count( $matches ) > 1 ) ) { return 1; } @@ -6457,16 +6629,10 @@ * @return string[] Array of file header values keyed by header name. */ function get_file_data( $file, $default_headers, $context = '' ) { - // We don't need to write to the file, so just open for reading. - $fp = fopen( $file, 'r' ); - - if ( $fp ) { - // Pull only the first 8 KB of the file in. - $file_data = fread( $fp, 8 * KB_IN_BYTES ); - - // PHP will close file handle, but we are good citizens. - fclose( $fp ); - } else { + // Pull only the first 8 KB of the file in. + $file_data = file_get_contents( $file, false, null, 0, 8 * KB_IN_BYTES ); + + if ( false === $file_data ) { $file_data = ''; } @@ -6706,7 +6872,7 @@ * * @since 3.1.3 * - * @see https://developer.mozilla.org/en/the_x-frame-options_response_header + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options */ function send_frame_options_header() { header( 'X-Frame-Options: SAMEORIGIN' ); @@ -6752,7 +6918,7 @@ } /** - * Return a comma-separated string of functions that have been called to get + * Returns a comma-separated string or array of functions that have been called to get * to the current point in code. * * @since 3.4.0 @@ -6763,8 +6929,8 @@ * when you want to just give info about the callee. Default null. * @param int $skip_frames Optional. A number of stack frames to skip - useful for unwinding * back to the source of the issue. Default 0. - * @param bool $pretty Optional. Whether or not you want a comma separated string or raw - * array returned. Default true. + * @param bool $pretty Optional. Whether you want a comma separated string instead of + * the raw array returned. Default true. * @return string|array Either a string containing a reversed comma separated trace or an array * of individual calls. */ @@ -7563,6 +7729,10 @@ * @return string The anonymized IP address. */ function wp_privacy_anonymize_ip( $ip_addr, $ipv6_fallback = false ) { + if ( empty( $ip_addr ) ) { + return '0.0.0.0'; + } + // Detect what kind of IP address this is. $ip_prefix = ''; $is_ipv6 = substr_count( $ip_addr, ':' ) > 1; @@ -8058,12 +8228,13 @@ * @since 5.2.0 The `$max_execution_time` parameter was added. * @since 5.6.0 The `$directory_cache` parameter was added. * - * @param string $directory Full path of a directory. - * @param string|array $exclude Optional. Full path of a subdirectory to exclude from the total, - * or array of paths. Expected without trailing slash(es). - * @param int $max_execution_time Maximum time to run before giving up. In seconds. The timeout is global - * and is measured from the moment WordPress started to load. - * @param array $directory_cache Optional. Array of cached directory paths. + * @param string $directory Full path of a directory. + * @param string|string[] $exclude Optional. Full path of a subdirectory to exclude from the total, + * or array of paths. Expected without trailing slash(es). + * @param int $max_execution_time Optional. Maximum time to run before giving up. In seconds. + * The timeout is global and is measured from the moment + * WordPress started to load. + * @param array $directory_cache Optional. Array of cached directory paths. * * @return int|false|null Size in bytes if a valid directory. False if not. Null if timeout. */ @@ -8114,7 +8285,12 @@ * * @since 5.6.0 * - * @param int|false $space_used The amount of used space, in bytes. Default false. + * @param int|false $space_used The amount of used space, in bytes. Default false. + * @param string $directory Full path of a directory. + * @param string|string[]|null $exclude Full path of a subdirectory to exclude from the total, + * or array of paths. + * @param int $max_execution_time Maximum time to run before giving up. In seconds. + * @param array $directory_cache Array of cached directory paths. */ $size = apply_filters( 'pre_recurse_dirsize', false, $directory, $exclude, $max_execution_time, $directory_cache ); @@ -8135,7 +8311,9 @@ } } - if ( $max_execution_time > 0 && microtime( true ) - WP_START_TIMESTAMP > $max_execution_time ) { + if ( $max_execution_time > 0 && + ( microtime( true ) - WP_START_TIMESTAMP ) > $max_execution_time + ) { // Time exceeded. Give up instead of risking a fatal timeout. $size = null; break; @@ -8146,6 +8324,10 @@ } } + if ( ! is_array( $directory_cache ) ) { + $directory_cache = array(); + } + $directory_cache[ $directory ] = $size; // Only write the transient on the top level call and not on recursive calls. @@ -8162,21 +8344,50 @@ * Removes the current directory and all parent directories from the `dirsize_cache` transient. * * @since 5.6.0 + * @since 5.9.0 Added input validation with a notice for invalid input. * * @param string $path Full path of a directory or file. */ function clean_dirsize_cache( $path ) { + if ( ! is_string( $path ) || empty( $path ) ) { + trigger_error( + sprintf( + /* translators: 1: Function name, 2: A variable type, like "boolean" or "integer". */ + __( '%1$s only accepts a non-empty path string, received %2$s.' ), + 'clean_dirsize_cache()', + '' . gettype( $path ) . '' + ) + ); + return; + } + $directory_cache = get_transient( 'dirsize_cache' ); if ( empty( $directory_cache ) ) { return; } - $path = untrailingslashit( $path ); + if ( + strpos( $path, '/' ) === false && + strpos( $path, '\\' ) === false + ) { + unset( $directory_cache[ $path ] ); + set_transient( 'dirsize_cache', $directory_cache ); + return; + } + + $last_path = null; + $path = untrailingslashit( $path ); unset( $directory_cache[ $path ] ); - while ( DIRECTORY_SEPARATOR !== $path && '.' !== $path && '..' !== $path ) { - $path = dirname( $path ); + while ( + $last_path !== $path && + DIRECTORY_SEPARATOR !== $path && + '.' !== $path && + '..' !== $path + ) { + $last_path = $path; + $path = dirname( $path ); unset( $directory_cache[ $path ] ); } @@ -8188,11 +8399,18 @@ * * @since 5.2.0 * + * @global string $wp_version The WordPress version string. + * * @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 ) { - return empty( $required ) || version_compare( get_bloginfo( 'version' ), $required, '>=' ); + global $wp_version; + + // Strip off any -alpha, -RC, -beta, -src suffixes. + list( $version ) = explode( '-', $wp_version ); + + return empty( $required ) || version_compare( $version, $required, '>=' ); } /** @@ -8208,7 +8426,7 @@ } /** - * Check if two numbers are nearly the same. + * Checks if two numbers are nearly the same. * * This is similar to using `round()` but the precision is more fine-grained. * @@ -8217,8 +8435,26 @@ * @param int|float $expected The expected value. * @param int|float $actual The actual number. * @param int|float $precision The allowed variation. - * @return bool Whether the numbers match whithin the specified precision. + * @return bool Whether the numbers match within the specified precision. */ function wp_fuzzy_number_match( $expected, $actual, $precision = 1 ) { return abs( (float) $expected - (float) $actual ) <= $precision; } + +/** + * Sorts the keys of an array alphabetically. + * The array is passed by reference so it doesn't get returned + * which mimics the behaviour of ksort. + * + * @since 6.0.0 + * + * @param array $array The array to sort, passed by reference. + */ +function wp_recursive_ksort( &$array ) { + foreach ( $array as &$value ) { + if ( is_array( $value ) ) { + wp_recursive_ksort( $value ); + } + } + ksort( $array ); +}