diff -r 3d4e9c994f10 -r a86126ab1dd4 wp/wp-includes/functions.php --- a/wp/wp-includes/functions.php Tue Oct 22 16:11:46 2019 +0200 +++ b/wp/wp-includes/functions.php Tue Dec 15 13:49:49 2020 +0100 @@ -5,51 +5,57 @@ * @package WordPress */ -require( ABSPATH . WPINC . '/option.php' ); - -/** - * Convert given date string into a different format. - * - * $format should be either a PHP date format string, e.g. 'U' for a Unix - * timestamp, or 'G' for a Unix timestamp assuming that $date is GMT. - * - * If $translate is true then the given date and format string will - * be passed to date_i18n() for translation. +require ABSPATH . WPINC . '/option.php'; + +/** + * 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`). + * + * Historically UTC time could be passed to the function to produce Unix timestamp. + * + * If `$translate` is true then the given date and format string will + * be passed to `wp_date()` for translation. * * @since 0.71 * * @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|bool Formatted date string or Unix timestamp. False if $date is empty. + * @return string|int|false Formatted date string or sum of Unix timestamp and timezone offset. + * False on failure. */ function mysql2date( $format, $date, $translate = true ) { if ( empty( $date ) ) { return false; } - if ( 'G' == $format ) { - return strtotime( $date . ' +0000' ); - } - - $i = strtotime( $date ); - - if ( 'U' == $format ) { - return $i; + $datetime = date_create( $date, wp_timezone() ); + + if ( false === $datetime ) { + return false; + } + + // Returns a sum of timestamp with timezone offset. Ideally should never be used. + if ( 'G' === $format || 'U' === $format ) { + return $datetime->getTimestamp() + $datetime->getOffset(); } if ( $translate ) { - return date_i18n( $format, $i ); - } else { - return date( $format, $i ); - } -} - -/** - * Retrieve the current time based on specified type. + return wp_date( $format, $datetime->getTimestamp() ); + } + + return $datetime->format( $format ); +} + +/** + * 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. + * 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. @@ -57,141 +63,245 @@ * * @since 1.0.0 * - * @param string $type Type of time to retrieve. Accepts 'mysql', 'timestamp', or PHP date - * format string (e.g. 'Y-m-d'). + * @param string $type Type of time to retrieve. Accepts 'mysql', 'timestamp', + * 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. */ function current_time( $type, $gmt = 0 ) { - switch ( $type ) { - case 'mysql': - return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', ( time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ) ); - case 'timestamp': - return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ); - default: - return ( $gmt ) ? gmdate( $type ) : gmdate( $type, time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ); - } -} - -/** - * Retrieve the date in localized format, based on a sum of Unix timestamp and + // 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 ); + } + + if ( 'mysql' === $type ) { + $type = 'Y-m-d H:i:s'; + } + + $timezone = $gmt ? new DateTimeZone( 'UTC' ) : wp_timezone(); + $datetime = new DateTime( 'now', $timezone ); + + return $datetime->format( $type ); +} + +/** + * Retrieves the current time as an object with the timezone from settings. + * + * @since 5.3.0 + * + * @return DateTimeImmutable Date and time object. + */ +function current_datetime() { + return new DateTimeImmutable( 'now', wp_timezone() ); +} + +/** + * 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. + * + * @since 5.3.0 + * + * @return string PHP timezone string or a ±HH:MM offset. + */ +function wp_timezone_string() { + $timezone_string = get_option( 'timezone_string' ); + + if ( $timezone_string ) { + return $timezone_string; + } + + $offset = (float) get_option( 'gmt_offset' ); + $hours = (int) $offset; + $minutes = ( $offset - $hours ); + + $sign = ( $offset < 0 ) ? '-' : '+'; + $abs_hour = abs( $hours ); + $abs_mins = abs( $minutes * 60 ); + $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins ); + + return $tz_offset; +} + +/** + * Retrieves the timezone from site settings as a `DateTimeZone` object. + * + * Timezone can be based on a PHP timezone string or a ±HH:MM offset. + * + * @since 5.3.0 + * + * @return DateTimeZone Timezone object. + */ +function wp_timezone() { + return new DateTimeZone( wp_timezone_string() ); +} + +/** + * Retrieves the date in localized format, based on a sum of Unix timestamp and * timezone offset in seconds. * * If the locale specifies the locale month and weekday, then the locale will * take over the format for the date. If it isn't, then the date format string * will be used instead. * + * Note that due to the way WP typically generates a sum of timestamp and offset + * with `strtotime()`, it implies offset added at a _current_ time, not at the time + * the timestamp represents. Storing such timestamps or calculating them differently + * will lead to invalid output. + * * @since 0.71 - * - * @global WP_Locale $wp_locale - * - * @param string $dateformatstring Format to display the date. - * @param int|bool $timestamp_with_offset Optional. A sum of Unix timestamp and timezone offset in seconds. - * Default false. - * @param bool $gmt Optional. Whether to use GMT timezone. Only applies if timestamp is - * not provided. Default false. - * + * @since 5.3.0 Converted into a wrapper for wp_date(). + * + * @global WP_Locale $wp_locale WordPress date and time locale object. + * + * @param string $format Format to display the date. + * @param int|bool $timestamp_with_offset Optional. A sum of Unix timestamp and timezone offset + * in seconds. Default false. + * @param bool $gmt Optional. Whether to use GMT timezone. Only applies + * if timestamp is not provided. Default false. * @return string The date, translated if locale specifies it. */ -function date_i18n( $dateformatstring, $timestamp_with_offset = false, $gmt = false ) { - global $wp_locale; - $i = $timestamp_with_offset; - - if ( false === $i ) { - $i = current_time( 'timestamp', $gmt ); +function date_i18n( $format, $timestamp_with_offset = false, $gmt = false ) { + $timestamp = $timestamp_with_offset; + + // If timestamp is omitted it should be current time (summed with offset, unless `$gmt` is true). + if ( ! is_numeric( $timestamp ) ) { + $timestamp = current_time( 'timestamp', $gmt ); } /* - * Store original value for language with untypical grammars. - * See https://core.trac.wordpress.org/ticket/9396 + * This is a legacy implementation quirk that the returned timestamp is also with offset. + * Ideally this function should never be used to produce a timestamp. */ - $req_format = $dateformatstring; - - $dateformatstring = preg_replace( '/(?month ) ) && ( ! empty( $wp_locale->weekday ) ) ) { - $datemonth = $wp_locale->get_month( date( 'm', $i ) ); - $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth ); - $dateweekday = $wp_locale->get_weekday( date( 'w', $i ) ); - $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday ); - $datemeridiem = $wp_locale->get_meridiem( date( 'a', $i ) ); - $datemeridiem_capital = $wp_locale->get_meridiem( date( 'A', $i ) ); - $dateformatstring = ' ' . $dateformatstring; - $dateformatstring = preg_replace( '/([^\\\])D/', "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring ); - $dateformatstring = preg_replace( '/([^\\\])F/', "\\1" . backslashit( $datemonth ), $dateformatstring ); - $dateformatstring = preg_replace( '/([^\\\])l/', "\\1" . backslashit( $dateweekday ), $dateformatstring ); - $dateformatstring = preg_replace( '/([^\\\])M/', "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring ); - $dateformatstring = preg_replace( '/([^\\\])a/', "\\1" . backslashit( $datemeridiem ), $dateformatstring ); - $dateformatstring = preg_replace( '/([^\\\])A/', "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring ); - - $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) - 1 ); - } - $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' ); - $timezone_formats_re = implode( '|', $timezone_formats ); - if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) { - $timezone_string = get_option( 'timezone_string' ); - if ( false === $timestamp_with_offset && $gmt ) { - $timezone_string = 'UTC'; - } - if ( $timezone_string ) { - $timezone_object = timezone_open( $timezone_string ); - $date_object = date_create( null, $timezone_object ); - foreach ( $timezone_formats as $timezone_format ) { - if ( false !== strpos( $dateformatstring, $timezone_format ) ) { - $formatted = date_format( $date_object, $timezone_format ); - $dateformatstring = ' ' . $dateformatstring; - $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring ); - $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) - 1 ); - } - } - } else { - $offset = get_option( 'gmt_offset' ); - foreach ( $timezone_formats as $timezone_format ) { - if ( 'I' === $timezone_format ) { - continue; - } - - if ( false !== strpos( $dateformatstring, $timezone_format ) ) { - if ( 'Z' === $timezone_format ) { - $formatted = (string) ( $offset * HOUR_IN_SECONDS ); - } else { - $prefix = ''; - $hours = (int) $offset; - $separator = ''; - $minutes = abs( ( $offset - $hours ) * 60 ); - - if ( 'T' === $timezone_format ) { - $prefix = 'GMT'; - } elseif ( 'e' === $timezone_format || 'P' === $timezone_format ) { - $separator = ':'; - } - - $formatted = sprintf( '%s%+03d%s%02d', $prefix, $hours, $separator, $minutes ); - } - - $dateformatstring = ' ' . $dateformatstring; - $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring ); - $dateformatstring = substr( $dateformatstring, 1 ); - } - } - } - } - $j = @date( $dateformatstring, $i ); + if ( 'U' === $format ) { + $date = $timestamp; + } elseif ( $gmt && false === $timestamp_with_offset ) { // Current time in UTC. + $date = wp_date( $format, null, new DateTimeZone( 'UTC' ) ); + } elseif ( false === $timestamp_with_offset ) { // Current time in site's timezone. + $date = wp_date( $format ); + } else { + /* + * Timestamp with offset is typically produced by a UTC `strtotime()` call on an input without timezone. + * This is the best attempt to reverse that operation into a local time to use. + */ + $local_time = gmdate( 'Y-m-d H:i:s', $timestamp ); + $timezone = wp_timezone(); + $datetime = date_create( $local_time, $timezone ); + $date = wp_date( $format, $datetime->getTimestamp(), $timezone ); + } /** * Filters the date formatted based on the locale. * * @since 2.8.0 * - * @param string $j Formatted date string. - * @param string $req_format Format to display the date. - * @param int $i A sum of Unix timestamp and timezone offset in seconds. - * @param bool $gmt Whether to use GMT timezone. Only applies if timestamp was - * not provided. Default false. + * @param string $date Formatted date string. + * @param string $format Format to display the date. + * @param int $timestamp A sum of Unix timestamp and timezone offset in seconds. + * Might be without offset if input omitted timestamp but requested GMT. + * @param bool $gmt Whether to use GMT timezone. Only applies if timestamp was not provided. + * Default false. */ - $j = apply_filters( 'date_i18n', $j, $req_format, $i, $gmt ); - return $j; + $date = apply_filters( 'date_i18n', $date, $format, $timestamp, $gmt ); + + return $date; +} + +/** + * Retrieves the date, in localized format. + * + * This is a newer function, intended to replace `date_i18n()` without legacy quirks in it. + * + * Note that, unlike `date_i18n()`, this function accepts a true Unix timestamp, not summed + * with timezone offset. + * + * @since 5.3.0 + * + * @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 + * from site settings. + * @return string|false The date, translated if locale specifies it. False on invalid timestamp input. + */ +function wp_date( $format, $timestamp = null, $timezone = null ) { + global $wp_locale; + + if ( null === $timestamp ) { + $timestamp = time(); + } elseif ( ! is_numeric( $timestamp ) ) { + return false; + } + + if ( ! $timezone ) { + $timezone = wp_timezone(); + } + + $datetime = date_create( '@' . $timestamp ); + $datetime->setTimezone( $timezone ); + + if ( empty( $wp_locale->month ) || empty( $wp_locale->weekday ) ) { + $date = $datetime->format( $format ); + } else { + // We need to unpack shorthand `r` format because it has parts that might be localized. + $format = preg_replace( '/(?get_month( $datetime->format( 'm' ) ); + $weekday = $wp_locale->get_weekday( $datetime->format( 'w' ) ); + + for ( $i = 0; $i < $format_length; $i ++ ) { + switch ( $format[ $i ] ) { + case 'D': + $new_format .= addcslashes( $wp_locale->get_weekday_abbrev( $weekday ), '\\A..Za..z' ); + break; + case 'F': + $new_format .= addcslashes( $month, '\\A..Za..z' ); + break; + case 'l': + $new_format .= addcslashes( $weekday, '\\A..Za..z' ); + break; + case 'M': + $new_format .= addcslashes( $wp_locale->get_month_abbrev( $month ), '\\A..Za..z' ); + break; + case 'a': + $new_format .= addcslashes( $wp_locale->get_meridiem( $datetime->format( 'a' ) ), '\\A..Za..z' ); + break; + case 'A': + $new_format .= addcslashes( $wp_locale->get_meridiem( $datetime->format( 'A' ) ), '\\A..Za..z' ); + break; + case '\\': + $new_format .= $format[ $i ]; + + // If character follows a slash, we add it without translating. + if ( $i < $format_length ) { + $new_format .= $format[ ++$i ]; + } + break; + default: + $new_format .= $format[ $i ]; + break; + } + } + + $date = $datetime->format( $new_format ); + $date = wp_maybe_decline_date( $date, $format ); + } + + /** + * Filters the date formatted based on the locale. + * + * @since 5.3.0 + * + * @param string $date Formatted date string. + * @param string $format Format to display the date. + * @param int $timestamp Unix timestamp. + * @param DateTimeZone $timezone Timezone. + */ + $date = apply_filters( 'wp_date', $date, $format, $timestamp, $timezone ); + + return $date; } /** @@ -201,42 +311,79 @@ * formats (like 'j F Y'), the month name will be replaced with a correct form. * * @since 4.4.0 - * - * @global WP_Locale $wp_locale - * - * @param string $date Formatted date string. + * @since 5.4.0 The `$format` parameter was added. + * + * @global WP_Locale $wp_locale WordPress date and time locale object. + * + * @param string $date Formatted date string. + * @param string $format Optional. Date format to check. Default empty string. * @return string The date, declined if locale specifies it. */ -function wp_maybe_decline_date( $date ) { +function wp_maybe_decline_date( $date, $format = '' ) { global $wp_locale; - // i18n functions are not available in SHORTINIT mode + // i18n functions are not available in SHORTINIT mode. if ( ! function_exists( '_x' ) ) { return $date; } - /* translators: If months in your language require a genitive case, + /* + * translators: If months in your language require a genitive case, * translate this to 'on'. Do not translate into your own language. */ if ( 'on' === _x( 'off', 'decline months names: on or off' ) ) { - // Match a format like 'j F Y' or 'j. F' - if ( @preg_match( '#^\d{1,2}\.? [^\d ]+#u', $date ) ) { - $months = $wp_locale->month; - $months_genitive = $wp_locale->month_genitive; - + + $months = $wp_locale->month; + $months_genitive = $wp_locale->month_genitive; + + /* + * Match a format like 'j F Y' or 'j. F' (day of the month, followed by month name) + * and decline the month. + */ + if ( $format ) { + $decline = preg_match( '#[dj]\.? F#', $format ); + } else { + // If the format is not passed, try to guess it from the date string. + $decline = preg_match( '#\b\d{1,2}\.? [^\d ]+\b#u', $date ); + } + + if ( $decline ) { foreach ( $months as $key => $month ) { - $months[ $key ] = '# ' . $month . '( |$)#u'; + $months[ $key ] = '# ' . preg_quote( $month, '#' ) . '\b#u'; } foreach ( $months_genitive as $key => $month ) { - $months_genitive[ $key ] = ' ' . $month . '$1'; + $months_genitive[ $key ] = ' ' . $month; } $date = preg_replace( $months, $months_genitive, $date ); } - } - - // Used for locale-specific rules + + /* + * Match a format like 'F jS' or 'F j' (month name, followed by day with an optional ordinal suffix) + * and change it to declined 'j F'. + */ + if ( $format ) { + $decline = preg_match( '#F [dj]#', $format ); + } else { + // If the format is not passed, try to guess it from the date string. + $decline = preg_match( '#\b[^\d ]+ \d{1,2}(st|nd|rd|th)?\b#u', trim( $date ) ); + } + + if ( $decline ) { + foreach ( $months as $key => $month ) { + $months[ $key ] = '#\b' . preg_quote( $month, '#' ) . ' (\d{1,2})(st|nd|rd|th)?([-–]\d{1,2})?(st|nd|rd|th)?\b#u'; + } + + foreach ( $months_genitive as $key => $month ) { + $months_genitive[ $key ] = '$1$3 ' . $month; + } + + $date = preg_replace( $months, $months_genitive, $date ); + } + } + + // Used for locale-specific rules. $locale = get_locale(); if ( 'ca' === $locale ) { @@ -252,7 +399,7 @@ * * @since 2.3.0 * - * @global WP_Locale $wp_locale + * @global WP_Locale $wp_locale WordPress date and time locale object. * * @param float $number The number to convert based on locale. * @param int $decimals Optional. Precision of the number of decimal places. Default 0. @@ -298,19 +445,25 @@ * * @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. - * @return string|false False on failure. Number string on success. + * @return string|false Number string on success, false on failure. */ function size_format( $bytes, $decimals = 0 ) { $quant = array( - 'TB' => TB_IN_BYTES, - 'GB' => GB_IN_BYTES, - 'MB' => MB_IN_BYTES, - 'KB' => KB_IN_BYTES, - 'B' => 1, + /* translators: Unit symbol for terabyte. */ + _x( 'TB', 'unit symbol' ) => TB_IN_BYTES, + /* translators: Unit symbol for gigabyte. */ + _x( 'GB', 'unit symbol' ) => GB_IN_BYTES, + /* translators: Unit symbol for megabyte. */ + _x( 'MB', 'unit symbol' ) => MB_IN_BYTES, + /* translators: Unit symbol for kilobyte. */ + _x( 'KB', 'unit symbol' ) => KB_IN_BYTES, + /* translators: Unit symbol for byte. */ + _x( 'B', 'unit symbol' ) => 1, ); if ( 0 === $bytes ) { - return number_format_i18n( 0, $decimals ) . ' B'; + /* translators: Unit symbol for byte. */ + return number_format_i18n( 0, $decimals ) . ' ' . _x( 'B', 'unit symbol' ); } foreach ( $quant as $unit => $mag ) { @@ -373,19 +526,19 @@ // Add the hour part to the string. if ( is_numeric( $hour ) ) { - /* translators: Time duration in hour or hours. */ + /* translators: %s: Time duration in hour or hours. */ $human_readable_duration[] = sprintf( _n( '%s hour', '%s hours', $hour ), (int) $hour ); } // Add the minute part to the string. if ( is_numeric( $minute ) ) { - /* translators: Time duration in minute or minutes. */ + /* translators: %s: Time duration in minute or minutes. */ $human_readable_duration[] = sprintf( _n( '%s minute', '%s minutes', $minute ), (int) $minute ); } // Add the second part to the string. if ( is_numeric( $second ) ) { - /* translators: Time duration in second or seconds. */ + /* translators: %s: Time duration in second or seconds. */ $human_readable_duration[] = sprintf( _n( '%s second', '%s seconds', $second ), (int) $second ); } @@ -415,7 +568,7 @@ $day = mktime( 0, 0, 0, $md, $mm, $my ); // The day of the week from the timestamp. - $weekday = date( 'w', $day ); + $weekday = gmdate( 'w', $day ); if ( ! is_numeric( $start_of_week ) ) { $start_of_week = get_option( 'start_of_week' ); @@ -434,18 +587,44 @@ } /** - * Unserialize value only if it was serialized. + * Serialize data, if needed. + * + * @since 2.0.5 + * + * @param string|array|object $data Data that might be serialized. + * @return mixed A scalar data. + */ +function maybe_serialize( $data ) { + if ( is_array( $data ) || is_object( $data ) ) { + return serialize( $data ); + } + + /* + * Double serialization is required for backward compatibility. + * See https://core.trac.wordpress.org/ticket/12930 + * Also the world will end. See WP 3.6.1. + */ + if ( is_serialized( $data, false ) ) { + return serialize( $data ); + } + + return $data; +} + +/** + * Unserialize data only if it was serialized. * * @since 2.0.0 * - * @param string $original Maybe unserialized original, if is needed. + * @param string $data Data that might be unserialized. * @return mixed Unserialized data can be any type. */ -function maybe_unserialize( $original ) { - if ( is_serialized( $original ) ) { // don't attempt to unserialize data that wasn't serialized going in - return @unserialize( $original ); - } - return $original; +function maybe_unserialize( $data ) { + if ( is_serialized( $data ) ) { // Don't attempt to unserialize data that wasn't serialized going in. + return @unserialize( trim( $data ) ); + } + + return $data; } /** @@ -461,12 +640,12 @@ * @return bool False if not serialized and true if it was. */ function is_serialized( $data, $strict = true ) { - // if it isn't a string, it isn't serialized. + // If it isn't a string, it isn't serialized. if ( ! is_string( $data ) ) { return false; } $data = trim( $data ); - if ( 'N;' == $data ) { + if ( 'N;' === $data ) { return true; } if ( strlen( $data ) < 4 ) { @@ -505,7 +684,7 @@ } elseif ( false === strpos( $data, '"' ) ) { return false; } - // or else fall through + // Or else fall through. case 'a': case 'O': return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data ); @@ -513,7 +692,7 @@ case 'i': case 'd': $end = $strict ? '$' : ''; - return (bool) preg_match( "/^{$token}:[0-9.E-]+;$end/", $data ); + return (bool) preg_match( "/^{$token}:[0-9.E+-]+;$end/", $data ); } return false; } @@ -538,7 +717,7 @@ return false; } elseif ( ';' !== substr( $data, -1 ) ) { return false; - } elseif ( $data[0] !== 's' ) { + } elseif ( 's' !== $data[0] ) { return false; } elseif ( '"' !== substr( $data, -2, 1 ) ) { return false; @@ -548,29 +727,6 @@ } /** - * Serialize data, if needed. - * - * @since 2.0.5 - * - * @param string|array|object $data Data that might be serialized. - * @return mixed A scalar data - */ -function maybe_serialize( $data ) { - if ( is_array( $data ) || is_object( $data ) ) { - return serialize( $data ); - } - - // Double serialization is required for backward compatibility. - // See https://core.trac.wordpress.org/ticket/12930 - // Also the world will end. See WP 3.6.1. - if ( is_serialized( $data, false ) ) { - return serialize( $data ); - } - - return $data; -} - -/** * Retrieve post title from XMLRPC XML. * * If the title element is not part of the XML, then the default post title from @@ -639,7 +795,7 @@ * @since 3.7.0 * * @param string $content Content to extract URLs from. - * @return array URLs found in passed string. + * @return string[] Array of URLs found in passed string. */ function wp_extract_urls( $content ) { preg_match_all( @@ -672,27 +828,40 @@ * pingbacks and trackbacks. * * @since 1.5.0 + * @since 5.3.0 The `$content` parameter was made optional, and the `$post` parameter was + * updated to accept a post ID or a WP_Post object. * * @global wpdb $wpdb WordPress database abstraction object. * - * @param string $content Post Content. - * @param int $post_ID Post ID. - */ -function do_enclose( $content, $post_ID ) { + * @param string $content Post content. If `null`, the `post_content` field from `$post` is used. + * @param int|WP_Post $post Post ID or post object. + * @return null|bool Returns false if post is not found. + */ +function do_enclose( $content = null, $post ) { global $wpdb; - //TODO: Tidy this ghetto code up and make the debug code optional - include_once( ABSPATH . WPINC . '/class-IXR.php' ); + // @todo Tidy this code and make the debug code optional. + include_once ABSPATH . WPINC . '/class-IXR.php'; + + $post = get_post( $post ); + if ( ! $post ) { + return false; + } + + if ( null === $content ) { + $content = $post->post_content; + } $post_links = array(); - $pung = get_enclosed( $post_ID ); + $pung = get_enclosed( $post->ID ); $post_links_temp = wp_extract_urls( $content ); foreach ( $pung as $link_test ) { - if ( ! in_array( $link_test, $post_links_temp ) ) { // link no longer in post - $mids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post_ID, $wpdb->esc_like( $link_test ) . '%' ) ); + // Link is no longer in post. + if ( ! in_array( $link_test, $post_links_temp, true ) ) { + $mids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post->ID, $wpdb->esc_like( $link_test ) . '%' ) ); foreach ( $mids as $mid ) { delete_metadata_by_mid( 'post', $mid ); } @@ -700,14 +869,15 @@ } foreach ( (array) $post_links_temp as $link_test ) { - if ( ! in_array( $link_test, $pung ) ) { // If we haven't pung it already - $test = @parse_url( $link_test ); + // If we haven't pung it already. + if ( ! in_array( $link_test, $pung, true ) ) { + $test = parse_url( $link_test ); if ( false === $test ) { continue; } if ( isset( $test['query'] ) ) { $post_links[] = $link_test; - } elseif ( isset( $test['path'] ) && ( $test['path'] != '/' ) && ( $test['path'] != '' ) ) { + } elseif ( isset( $test['path'] ) && ( '/' !== $test['path'] ) && ( '' !== $test['path'] ) ) { $post_links[] = $link_test; } } @@ -721,23 +891,23 @@ * * @since 4.4.0 * - * @param array $post_links An array of enclosure links. - * @param int $post_ID Post ID. + * @param string[] $post_links An array of enclosure links. + * @param int $post_ID Post ID. */ - $post_links = apply_filters( 'enclosure_links', $post_links, $post_ID ); + $post_links = apply_filters( 'enclosure_links', $post_links, $post->ID ); foreach ( (array) $post_links as $url ) { - if ( $url != '' && ! $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post_ID, $wpdb->esc_like( $url ) . '%' ) ) ) { - - if ( $headers = wp_get_http_headers( $url ) ) { + if ( '' !== $url && ! $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post->ID, $wpdb->esc_like( $url ) . '%' ) ) ) { + + $headers = wp_get_http_headers( $url ); + if ( $headers ) { $len = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0; $type = isset( $headers['content-type'] ) ? $headers['content-type'] : ''; $allowed_types = array( 'video', 'audio' ); - // Check to see if we can figure out the mime type from - // the extension - $url_parts = @parse_url( $url ); - if ( false !== $url_parts ) { + // Check to see if we can figure out the mime type from the extension. + $url_parts = parse_url( $url ); + if ( false !== $url_parts && ! empty( $url_parts['path'] ) ) { $extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION ); if ( ! empty( $extension ) ) { foreach ( wp_get_mime_types() as $exts => $mime ) { @@ -749,8 +919,8 @@ } } - if ( in_array( substr( $type, 0, strpos( $type, '/' ) ), $allowed_types ) ) { - add_post_meta( $post_ID, 'enclosure', "$url\n$len\n$mime\n" ); + if ( in_array( substr( $type, 0, strpos( $type, '/' ) ), $allowed_types, true ) ) { + add_post_meta( $post->ID, 'enclosure', "$url\n$len\n$mime\n" ); } } } @@ -797,7 +967,8 @@ */ function is_new_day() { global $currentday, $previousday; - if ( $currentday != $previousday ) { + + if ( $currentday !== $previousday ) { return 1; } else { return 0; @@ -813,7 +984,7 @@ * @since 2.3.0 * * @see _http_build_query() Used to build the query - * @link https://secure.php.net/manual/en/function.http-build-query.php for more on what + * @link https://www.php.net/manual/en/function.http-build-query.php for more on what * http_build_query() does. * * @param array $data URL-encode key/value pairs. @@ -829,16 +1000,15 @@ * @since 3.2.0 * @access private * - * @see https://secure.php.net/manual/en/function.http-build-query.php - * - * @param array|object $data An array or object of data. Converted to array. - * @param string $prefix Optional. Numeric index. If set, start parameter numbering with it. - * Default null. - * @param string $sep Optional. Argument separator; defaults to 'arg_separator.output'. - * Default null. - * @param string $key Optional. Used to prefix key name. Default empty. - * @param bool $urlencode Optional. Whether to use urlencode() in the result. Default true. - * + * @see https://www.php.net/manual/en/function.http-build-query.php + * + * @param array|object $data An array or object of data. Converted to array. + * @param string $prefix Optional. Numeric index. If set, start parameter numbering with it. + * Default null. + * @param string $sep Optional. Argument separator; defaults to 'arg_separator.output'. + * Default null. + * @param string $key Optional. Used to prefix key name. Default empty. + * @param bool $urlencode Optional. Whether to use urlencode() in the result. Default true. * @return string The query string. */ function _http_build_query( $data, $prefix = null, $sep = null, $key = '', $urlencode = true ) { @@ -848,15 +1018,15 @@ if ( $urlencode ) { $k = urlencode( $k ); } - if ( is_int( $k ) && $prefix != null ) { + if ( is_int( $k ) && null != $prefix ) { $k = $prefix . $k; } if ( ! empty( $key ) ) { $k = $key . '%5B' . $k . '%5D'; } - if ( $v === null ) { + if ( null === $v ) { continue; - } elseif ( $v === false ) { + } elseif ( false === $v ) { $v = '0'; } @@ -905,14 +1075,15 @@ * (XSS) attacks. * * @since 1.5.0 + * @since 5.3.0 Formalized the existing and already documented parameters + * by adding `...$args` to the function signature. * * @param string|array $key Either a query variable key, or an associative array of query variables. * @param string $value Optional. Either a query variable value, or a URL to act upon. * @param string $url Optional. A URL to act upon. * @return string New URL query string (unescaped). */ -function add_query_arg() { - $args = func_get_args(); +function add_query_arg( ...$args ) { if ( is_array( $args[0] ) ) { if ( count( $args ) < 2 || false === $args[1] ) { $uri = $_SERVER['REQUEST_URI']; @@ -927,7 +1098,8 @@ } } - if ( $frag = strstr( $uri, '#' ) ) { + $frag = strstr( $uri, '#' ); + if ( $frag ) { $uri = substr( $uri, 0, -strlen( $frag ) ); } else { $frag = ''; @@ -955,7 +1127,7 @@ } wp_parse_str( $query, $qs ); - $qs = urlencode_deep( $qs ); // this re-URL-encodes things that were already in the query string + $qs = urlencode_deep( $qs ); // This re-URL-encodes things that were already in the query string. if ( is_array( $args[0] ) ) { foreach ( $args[0] as $k => $v ) { $qs[ $k ] = $v; @@ -965,7 +1137,7 @@ } foreach ( $qs as $k => $v ) { - if ( $v === false ) { + if ( false === $v ) { unset( $qs[ $k ] ); } } @@ -988,7 +1160,7 @@ * @return string New URL query string. */ function remove_query_arg( $key, $query = false ) { - if ( is_array( $key ) ) { // removing multiple keys + if ( is_array( $key ) ) { // Removing multiple keys. foreach ( $key as $k ) { $query = add_query_arg( $k, false, $query ); } @@ -1002,16 +1174,19 @@ * * @since 4.4.0 * - * @return array An array of parameters to remove from the URL. + * @return string[] An array of parameters to remove from the URL. */ function wp_removable_query_args() { $removable_query_args = array( 'activate', 'activated', + 'admin_email_remind_later', 'approved', 'deactivate', + 'delete_count', 'deleted', 'disabled', + 'doing_wp_cron', 'enabled', 'error', 'hotkeys_highlight_first', @@ -1036,7 +1211,7 @@ * * @since 4.2.0 * - * @param array $removable_query_args An array of query variables to remove from a URL. + * @param string[] $removable_query_args An array of query variables to remove from a URL. */ return apply_filters( 'removable_query_args', $removable_query_args ); } @@ -1045,6 +1220,7 @@ * Walks the array while sanitizing the contents. * * @since 0.71 + * @since 5.5.0 Non-string values are left untouched. * * @param array $array Array to walk while sanitizing contents. * @return array Sanitized $array. @@ -1053,10 +1229,13 @@ foreach ( (array) $array as $k => $v ) { if ( is_array( $v ) ) { $array[ $k ] = add_magic_quotes( $v ); - } else { + } elseif ( is_string( $v ) ) { $array[ $k ] = addslashes( $v ); + } else { + continue; } } + return $array; } @@ -1068,10 +1247,10 @@ * @see wp_safe_remote_get() * * @param string $uri URI/URL of web page to retrieve. - * @return false|string HTTP content. False on failure. + * @return string|false HTTP content. False on failure. */ function wp_remote_fopen( $uri ) { - $parsed_url = @parse_url( $uri ); + $parsed_url = parse_url( $uri ); if ( ! $parsed_url || ! is_array( $parsed_url ) ) { return false; @@ -1094,14 +1273,15 @@ * * @since 2.0.0 * - * @global WP $wp_locale - * @global WP_Query $wp_query - * @global WP_Query $wp_the_query + * @global WP $wp Current WordPress environment instance. + * @global WP_Query $wp_query WordPress Query object. + * @global WP_Query $wp_the_query Copy of the WordPress Query object. * * @param string|array $query_vars Default WP_Query arguments. */ function wp( $query_vars = '' ) { global $wp, $wp_query, $wp_the_query; + $wp->main( $query_vars ); if ( ! isset( $wp_the_query ) ) { @@ -1120,7 +1300,7 @@ * @global array $wp_header_to_desc * * @param int $code HTTP status code. - * @return string Empty string if not found, or description if found. + * @return string Status description if found, an empty string otherwise. */ function get_status_header_desc( $code ) { global $wp_header_to_desc; @@ -1240,7 +1420,9 @@ $status_header = apply_filters( 'status_header', $status_header, $code, $description, $protocol ); } - @header( $status_header, true, $code ); + if ( ! headers_sent() ) { + header( $status_header, true, $code ); + } } /** @@ -1292,26 +1474,18 @@ * @see wp_get_nocache_headers() */ function nocache_headers() { + if ( headers_sent() ) { + return; + } + $headers = wp_get_nocache_headers(); unset( $headers['Last-Modified'] ); - // In PHP 5.3+, make sure we are not sending a Last-Modified header. - if ( function_exists( 'header_remove' ) ) { - @header_remove( 'Last-Modified' ); - } else { - // In PHP 5.2, send an empty Last-Modified header, but only as a - // last resort to override a header already sent. #WP23021 - foreach ( headers_list() as $header ) { - if ( 0 === stripos( $header, 'Last-Modified' ) ) { - $headers['Last-Modified'] = ''; - break; - } - } - } + header_remove( 'Last-Modified' ); foreach ( $headers as $name => $field_value ) { - @header( "{$name}: {$field_value}" ); + header( "{$name}: {$field_value}" ); } } @@ -1324,7 +1498,7 @@ $expiresOffset = 10 * DAY_IN_SECONDS; header( 'Content-Type: text/javascript; charset=' . get_bloginfo( 'charset' ) ); - header( 'Vary: Accept-Encoding' ); // Handle proxies + header( 'Vary: Accept-Encoding' ); // Handle proxies. header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + $expiresOffset ) . ' GMT' ); } @@ -1353,7 +1527,7 @@ * @return bool True if yes, false on anything else. */ function bool_from_yn( $yn ) { - return ( strtolower( $yn ) == 'y' ); + return ( 'y' === strtolower( $yn ) ); } /** @@ -1366,7 +1540,7 @@ * * @since 2.1.0 * - * @global WP_Query $wp_query Used to tell if the use a comment feed. + * @global WP_Query $wp_query WordPress Query object. */ function do_feed() { global $wp_query; @@ -1376,12 +1550,12 @@ // Remove the pad, if present. $feed = preg_replace( '/^_+/', '', $feed ); - if ( $feed == '' || $feed == 'feed' ) { + if ( '' === $feed || 'feed' === $feed ) { $feed = get_default_feed(); } 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 ) ); } /** @@ -1456,12 +1630,11 @@ } /** - * Display the robots.txt file content. - * - * The echo content should be with usage of the permalinks or for creating the - * robots.txt file. + * Displays the default robots.txt file content. * * @since 2.1.0 + * @since 5.3.0 Remove the "Disallow: /" output if search engine visiblity is + * discouraged in favor of robots meta HTML tag in wp_no_robots(). */ function do_robots() { header( 'Content-Type: text/plain; charset=utf-8' ); @@ -1475,27 +1648,41 @@ $output = "User-agent: *\n"; $public = get_option( 'blog_public' ); - if ( '0' == $public ) { - $output .= "Disallow: /\n"; - } else { - $site_url = parse_url( site_url() ); - $path = ( ! empty( $site_url['path'] ) ) ? $site_url['path'] : ''; - $output .= "Disallow: $path/wp-admin/\n"; - $output .= "Allow: $path/wp-admin/admin-ajax.php\n"; - } + + $site_url = parse_url( site_url() ); + $path = ( ! empty( $site_url['path'] ) ) ? $site_url['path'] : ''; + $output .= "Disallow: $path/wp-admin/\n"; + $output .= "Allow: $path/wp-admin/admin-ajax.php\n"; /** * Filters the robots.txt output. * * @since 3.0.0 * - * @param string $output Robots.txt output. + * @param string $output The robots.txt output. * @param bool $public Whether the site is considered "public". */ echo apply_filters( 'robots_txt', $output, $public ); } /** + * Display the favicon.ico file content. + * + * @since 5.4.0 + */ +function do_favicon() { + /** + * Fires when serving the favicon.ico file. + * + * @since 5.4.0 + */ + do_action( 'do_faviconico' ); + + wp_redirect( get_site_icon_url( 32, includes_url( 'images/w-logo-blue-white-bg.png' ) ) ); + exit; +} + +/** * Determines whether WordPress is already installed. * * The cache will be checked first. If you have a cache plugin, which saves @@ -1529,7 +1716,7 @@ if ( ! wp_installing() ) { $alloptions = wp_load_alloptions(); } - // If siteurl is not set to autoload, check it specifically + // If siteurl is not set to autoload, check it specifically. if ( ! isset( $alloptions['siteurl'] ) ) { $installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" ); } else { @@ -1576,7 +1763,7 @@ // Die with a DB error. $wpdb->error = sprintf( - /* translators: %s: database repair URL */ + /* translators: %s: Database repair URL. */ __( 'One or more database tables are unavailable. The database may need to be repaired.' ), 'maint/repair.php?referrer=is_blog_installed' ); @@ -1664,6 +1851,7 @@ if ( $echo ) { echo $referer_field; } + return $referer_field; } @@ -1682,13 +1870,18 @@ * @return string Original referer field. */ function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) { - if ( ! $ref = wp_get_original_referer() ) { - $ref = 'previous' == $jump_back_to ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] ); - } + $ref = wp_get_original_referer(); + + if ( ! $ref ) { + $ref = ( 'previous' === $jump_back_to ) ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] ); + } + $orig_referer_field = ''; + if ( $echo ) { echo $orig_referer_field; } + return $orig_referer_field; } @@ -1699,7 +1892,7 @@ * * @since 2.0.4 * - * @return false|string False on failure. Referer URL on success. + * @return string|false Referer URL on success, false on failure. */ function wp_get_referer() { if ( ! function_exists( 'wp_validate_redirect' ) ) { @@ -1708,7 +1901,7 @@ $ref = wp_get_raw_referer(); - if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) && $ref !== home_url() . wp_unslash( $_SERVER['REQUEST_URI'] ) ) { + if ( $ref && wp_unslash( $_SERVER['REQUEST_URI'] ) !== $ref && home_url() . wp_unslash( $_SERVER['REQUEST_URI'] ) !== $ref ) { return wp_validate_redirect( $ref, false ); } @@ -1739,12 +1932,13 @@ * * @since 2.0.4 * - * @return string|false False if no original referer or original referer if set. + * @return string|false Original referer URL on success, false on failure. */ function wp_get_original_referer() { if ( ! empty( $_REQUEST['_wp_original_http_referer'] ) && function_exists( 'wp_validate_redirect' ) ) { return wp_validate_redirect( wp_unslash( $_REQUEST['_wp_original_http_referer'] ), false ); } + return false; } @@ -1770,7 +1964,7 @@ $target = str_replace( '//', '/', $target ); // Put the wrapper back on the target. - if ( $wrapper !== null ) { + if ( null !== $wrapper ) { $target = $wrapper . '://' . $target; } @@ -1794,12 +1988,13 @@ // We need to find the permissions of the parent folder that exists and inherit that. $target_parent = dirname( $target ); - while ( '.' != $target_parent && ! is_dir( $target_parent ) && dirname( $target_parent ) !== $target_parent ) { + while ( '.' !== $target_parent && ! is_dir( $target_parent ) && dirname( $target_parent ) !== $target_parent ) { $target_parent = dirname( $target_parent ); } // Get the permission bits. - if ( $stat = @stat( $target_parent ) ) { + $stat = @stat( $target_parent ); + if ( $stat ) { $dir_perms = $stat['mode'] & 0007777; } else { $dir_perms = 0777; @@ -1811,10 +2006,10 @@ * If a umask is set that modifies $dir_perms, we'll have to re-set * the $dir_perms correctly with chmod() */ - if ( $dir_perms != ( $dir_perms & ~umask() ) ) { + if ( ( $dir_perms & ~umask() ) != $dir_perms ) { $folder_parts = explode( '/', substr( $target, strlen( $target_parent ) + 1 ) ); for ( $i = 1, $c = count( $folder_parts ); $i <= $c; $i++ ) { - @chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms ); + chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms ); } } @@ -1851,7 +2046,7 @@ return true; } - if ( strlen( $path ) == 0 || $path[0] == '.' ) { + if ( strlen( $path ) == 0 || '.' === $path[0] ) { return false; } @@ -1861,7 +2056,7 @@ } // A path starting with / or \ is absolute; anything else is relative. - return ( $path[0] == '/' || $path[0] == '\\' ); + return ( '/' === $path[0] || '\\' === $path[0] ); } /** @@ -1902,18 +2097,20 @@ */ function wp_normalize_path( $path ) { $wrapper = ''; + if ( wp_is_stream( $path ) ) { list( $wrapper, $path ) = explode( '://', $path, 2 ); - $wrapper .= '://'; - } - - // Standardise all paths to use / + + $wrapper .= '://'; + } + + // Standardise all paths to use '/'. $path = str_replace( '\\', '/', $path ); // Replace multiple slashes down to a singular, allowing for network shares having two slashes. $path = preg_replace( '|(?<=.)/+|', '/', $path ); - // Windows paths should uppercase the drive letter + // Windows paths should uppercase the drive letter. if ( ':' === substr( $path, 1, 1 ) ) { $path = ucfirst( $path ); } @@ -1933,8 +2130,6 @@ * * @since 2.5.0 * - * @staticvar string $temp - * * @return string Writable temporary directory. */ function get_temp_dir() { @@ -2005,22 +2200,27 @@ * @return bool Whether the path is writable. */ function win_is_writable( $path ) { - - if ( $path[ strlen( $path ) - 1 ] == '/' ) { // if it looks like a directory, check a random file within the directory + if ( '/' === $path[ strlen( $path ) - 1 ] ) { + // If it looks like a directory, check a random file within the directory. return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp' ); - } elseif ( is_dir( $path ) ) { // If it's a directory (and not a file) check a random file within the directory + } elseif ( is_dir( $path ) ) { + // If it's a directory (and not a file), check a random file within the directory. return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' ); } - // check tmp file for read/write capabilities + + // Check tmp file for read/write capabilities. $should_delete_tmp_file = ! file_exists( $path ); - $f = @fopen( $path, 'a' ); - if ( $f === false ) { + + $f = @fopen( $path, 'a' ); + if ( false === $f ) { return false; } fclose( $f ); + if ( $should_delete_tmp_file ) { unlink( $path ); } + return true; } @@ -2042,7 +2242,7 @@ } /** - * Get an array containing the current upload directory's path and url. + * Returns an array containing the current upload directory's path and URL. * * Checks the 'upload_path' option, which should be from the web root folder, * and if it isn't empty it will be used. If it is empty, then the path will be @@ -2060,25 +2260,23 @@ * 'error' containing the error message. The error suggests that the parent * directory is not writable by the server. * - * On success, the returned array will have many indices: - * 'path' - base directory and sub directory or full path to upload directory. - * 'url' - base url and sub directory or absolute URL to upload directory. - * 'subdir' - sub directory if uploads use year/month folders option is on. - * 'basedir' - path without subdir. - * 'baseurl' - URL path without subdir. - * 'error' - false or error message. - * * @since 2.0.0 * @uses _wp_upload_dir() * - * @staticvar array $cache - * @staticvar array $tested_paths - * * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null. * @param bool $create_dir Optional. Whether to check and create the uploads directory. * Default true for backward compatibility. * @param bool $refresh_cache Optional. Whether to refresh the cache. Default false. - * @return array See above for description. + * @return array { + * Array of information about the upload directory. + * + * @type string $path Base directory and subdirectory or full path to upload directory. + * @type string $url Base URL and subdirectory or absolute URL to upload directory. + * @type string $subdir Subdirectory if uploads use year/month folders option is on. + * @type string $basedir Path without subdir. + * @type string $baseurl URL path without subdir. + * @type string|false $error False or error message. + * } */ function wp_upload_dir( $time = null, $create_dir = true, $refresh_cache = false ) { static $cache = array(), $tested_paths = array(); @@ -2094,8 +2292,16 @@ * * @since 2.0.0 * - * @param array $uploads Array of upload directory data with keys of 'path', - * 'url', 'subdir, 'basedir', and 'error'. + * @param array $uploads { + * Array of information about the upload directory. + * + * @type string $path Base directory and subdirectory or full path to upload directory. + * @type string $url Base URL and subdirectory or absolute URL to upload directory. + * @type string $subdir Subdirectory if uploads use year/month folders option is on. + * @type string $basedir Path without subdir. + * @type string $baseurl URL path without subdir. + * @type string|false $error False or error message. + * } */ $uploads = apply_filters( 'upload_dir', $cache[ $key ] ); @@ -2113,7 +2319,7 @@ } $uploads['error'] = sprintf( - /* translators: %s: directory path */ + /* translators: %s: Directory path. */ __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), esc_html( $error_path ) ); @@ -2139,17 +2345,18 @@ $siteurl = get_option( 'siteurl' ); $upload_path = trim( get_option( 'upload_path' ) ); - if ( empty( $upload_path ) || 'wp-content/uploads' == $upload_path ) { + if ( empty( $upload_path ) || 'wp-content/uploads' === $upload_path ) { $dir = WP_CONTENT_DIR . '/uploads'; } elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) { - // $dir is absolute, $upload_path is (maybe) relative to ABSPATH + // $dir is absolute, $upload_path is (maybe) relative to ABSPATH. $dir = path_join( ABSPATH, $upload_path ); } else { $dir = $upload_path; } - if ( ! $url = get_option( 'upload_url_path' ) ) { - if ( empty( $upload_path ) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) ) { + $url = get_option( 'upload_url_path' ); + if ( ! $url ) { + if ( empty( $upload_path ) || ( 'wp-content/uploads' === $upload_path ) || ( $upload_path == $dir ) ) { $url = WP_CONTENT_URL . '/uploads'; } else { $url = trailingslashit( $siteurl ) . $upload_path; @@ -2165,7 +2372,7 @@ $url = trailingslashit( $siteurl ) . UPLOADS; } - // If multisite (and if not the main site in a post-MU network) + // If multisite (and if not the main site in a post-MU network). if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) { if ( ! get_site_option( 'ms_files_rewriting' ) ) { @@ -2216,7 +2423,7 @@ $subdir = ''; if ( get_option( 'uploads_use_yearmonth_folders' ) ) { - // Generate the yearly and monthly dirs + // Generate the yearly and monthly directories. if ( ! $time ) { $time = current_time( 'mysql' ); } @@ -2242,11 +2449,12 @@ * Get a filename that is sanitized and unique for the given directory. * * If the filename is not unique, then a number will be added to the filename - * before the extension, and will continue adding numbers until the filename is - * unique. - * - * The callback is passed three parameters, the first one is the directory, the - * second is the filename, and the third is the extension. + * before the extension, and will continue adding numbers until the filename + * is unique. + * + * The callback function allows the caller to use their own method to create + * unique file names. If defined, the callback should take three arguments: + * - directory, base filename, and extension - and return a unique filename. * * @since 2.5.0 * @@ -2258,10 +2466,12 @@ function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) { // Sanitize the file name before we begin processing. $filename = sanitize_file_name( $filename ); + $ext2 = null; // Separate the filename into a name and extension. $ext = pathinfo( $filename, PATHINFO_EXTENSION ); $name = pathinfo( $filename, PATHINFO_BASENAME ); + if ( $ext ) { $ext = '.' . $ext; } @@ -2279,6 +2489,15 @@ $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext ); } else { $number = ''; + $fname = pathinfo( $filename, PATHINFO_FILENAME ); + + // Always append a number to file names that can potentially match image sub-size file names. + if ( $fname && preg_match( '/-(?:\d+x\d+|scaled|rotated)$/', $fname ) ) { + $number = 1; + + // At this point the file name may not be unique. This is tested below and the $number is incremented. + $filename = str_replace( "{$fname}{$ext}", "{$fname}-{$number}{$ext}", $filename ); + } // Change '.ext' to lower case. if ( $ext && strtolower( $ext ) != $ext ) { @@ -2286,42 +2505,126 @@ $filename2 = preg_replace( '|' . preg_quote( $ext ) . '$|', $ext2, $filename ); // Check for both lower and upper case extension or image sub-sizes may be overwritten. - while ( file_exists( $dir . "/$filename" ) || file_exists( $dir . "/$filename2" ) ) { + while ( file_exists( $dir . "/{$filename}" ) || file_exists( $dir . "/{$filename2}" ) ) { $new_number = (int) $number + 1; - $filename = str_replace( array( "-$number$ext", "$number$ext" ), "-$new_number$ext", $filename ); - $filename2 = str_replace( array( "-$number$ext2", "$number$ext2" ), "-$new_number$ext2", $filename2 ); + $filename = str_replace( array( "-{$number}{$ext}", "{$number}{$ext}" ), "-{$new_number}{$ext}", $filename ); + $filename2 = str_replace( array( "-{$number}{$ext2}", "{$number}{$ext2}" ), "-{$new_number}{$ext2}", $filename2 ); $number = $new_number; } - /** - * Filters the result when generating a unique file name. - * - * @since 4.5.0 - * - * @param string $filename Unique file name. - * @param string $ext File extension, eg. ".png". - * @param string $dir Directory path. - * @param callable|null $unique_filename_callback Callback function that generates the unique file name. - */ - return apply_filters( 'wp_unique_filename', $filename2, $ext, $dir, $unique_filename_callback ); + $filename = $filename2; + } else { + while ( file_exists( $dir . "/{$filename}" ) ) { + $new_number = (int) $number + 1; + + if ( '' === "{$number}{$ext}" ) { + $filename = "{$filename}-{$new_number}"; + } else { + $filename = str_replace( array( "-{$number}{$ext}", "{$number}{$ext}" ), "-{$new_number}{$ext}", $filename ); + } + + $number = $new_number; + } } - while ( file_exists( $dir . "/$filename" ) ) { - $new_number = (int) $number + 1; - if ( '' == "$number$ext" ) { - $filename = "$filename-" . $new_number; - } else { - $filename = str_replace( array( "-$number$ext", "$number$ext" ), '-' . $new_number . $ext, $filename ); + // Prevent collisions with existing file names that contain dimension-like strings + // (whether they are subsizes or originals uploaded prior to #42437). + $upload_dir = wp_get_upload_dir(); + + // The (resized) image files would have name and extension, and will be in the uploads dir. + if ( $name && $ext && @is_dir( $dir ) && false !== strpos( $dir, $upload_dir['basedir'] ) ) { + /** + * Filters the file list used for calculating a unique filename for a newly added file. + * + * Returning an array from the filter will effectively short-circuit retrieval + * from the filesystem and return the passed value instead. + * + * @since 5.5.0 + * + * @param array|null $files The list of files to use for filename comparisons. + * Default null (to retrieve the list from the filesystem). + * @param string $dir The directory for the new file. + * @param string $filename The proposed filename for the new file. + */ + $files = apply_filters( 'pre_wp_unique_filename_file_list', null, $dir, $filename ); + + if ( null === $files ) { + // List of all files and directories contained in $dir. + $files = @scandir( $dir ); + } + + if ( ! empty( $files ) ) { + // Remove "dot" dirs. + $files = array_diff( $files, array( '.', '..' ) ); + } + + if ( ! empty( $files ) ) { + // The extension case may have changed above. + $new_ext = ! empty( $ext2 ) ? $ext2 : $ext; + + // Ensure this never goes into infinite loop + // as it uses pathinfo() and regex in the check, but string replacement for the changes. + $count = count( $files ); + $i = 0; + + while ( $i <= $count && _wp_check_existing_file_names( $filename, $files ) ) { + $new_number = (int) $number + 1; + $filename = str_replace( array( "-{$number}{$new_ext}", "{$number}{$new_ext}" ), "-{$new_number}{$new_ext}", $filename ); + $number = $new_number; + $i++; + } } - $number = $new_number; } } - /** This filter is documented in wp-includes/functions.php */ + /** + * Filters the result when generating a unique file name. + * + * @since 4.5.0 + * + * @param string $filename Unique file name. + * @param string $ext File extension, eg. ".png". + * @param string $dir Directory path. + * @param callable|null $unique_filename_callback Callback function that generates the unique file name. + */ return apply_filters( 'wp_unique_filename', $filename, $ext, $dir, $unique_filename_callback ); } /** + * Helper function to check if a file name could match an existing image sub-size file name. + * + * @since 5.3.1 + * @access private + * + * @param string $filename The file name to check. + * @param array $files An array of existing files in the directory. + * @return bool True if the tested file name could match an existing file, false otherwise. + */ +function _wp_check_existing_file_names( $filename, $files ) { + $fname = pathinfo( $filename, PATHINFO_FILENAME ); + $ext = pathinfo( $filename, PATHINFO_EXTENSION ); + + // Edge case, file names like `.ext`. + if ( empty( $fname ) ) { + return false; + } + + if ( $ext ) { + $ext = ".$ext"; + } + + $regex = '/^' . preg_quote( $fname ) . '-(?:\d+x\d+|scaled|rotated)' . preg_quote( $ext ) . '$/i'; + + foreach ( $files as $file ) { + if ( preg_match( $regex, $file ) ) { + return true; + } + } + + return false; +} + +/** * Create a file in the upload folder with given content. * * If there is an error, then the key 'error' will exist with the error message. @@ -2338,11 +2641,18 @@ * * @since 2.0.0 * - * @param string $name Filename. - * @param null|string $deprecated Never used. Set to null. - * @param mixed $bits File content - * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null. - * @return array + * @param string $name Filename. + * @param null|string $deprecated Never used. Set to null. + * @param string $bits File content + * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null. + * @return array { + * Information about the newly-uploaded file. + * + * @type string $file Filename of the newly-uploaded file. + * @type string $url URL of the uploaded file. + * @type string $type File type. + * @type string|false $error Error message, if there has been an error. + * } */ function wp_upload_bits( $name, $deprecated, $bits, $time = null ) { if ( ! empty( $deprecated ) ) { @@ -2360,19 +2670,19 @@ $upload = wp_upload_dir( $time ); - if ( $upload['error'] !== false ) { + if ( false !== $upload['error'] ) { return $upload; } /** * Filters whether to treat the upload bits as an error. * - * Passing a non-array to the filter will effectively short-circuit preparing - * the upload bits, returning that value instead. + * Returning a non-array from the filter will effectively short-circuit preparing the upload bits + * and return that value instead. An error message should be returned as a string. * * @since 3.0.0 * - * @param mixed $upload_bits_error An array of upload bits data, or a non-array error to return. + * @param array|string $upload_bits_error An array of upload bits data, or error message to return. */ $upload_bits_error = apply_filters( 'wp_upload_bits', @@ -2398,30 +2708,33 @@ } $message = sprintf( - /* translators: %s: directory path */ + /* translators: %s: Directory path. */ __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path ); return array( 'error' => $message ); } - $ifp = @ fopen( $new_file, 'wb' ); + $ifp = @fopen( $new_file, 'wb' ); if ( ! $ifp ) { - return array( 'error' => sprintf( __( 'Could not write file %s' ), $new_file ) ); - } - - @fwrite( $ifp, $bits ); + return array( + /* translators: %s: File name. */ + 'error' => sprintf( __( 'Could not write file %s' ), $new_file ), + ); + } + + fwrite( $ifp, $bits ); fclose( $ifp ); clearstatcache(); - // Set correct file permissions + // Set correct file permissions. $stat = @ stat( dirname( $new_file ) ); $perms = $stat['mode'] & 0007777; $perms = $perms & 0000666; - @ chmod( $new_file, $perms ); + chmod( $new_file, $perms ); clearstatcache(); - // Compute the URL + // Compute the URL. $url = $upload['url'] . "/$filename"; /** This filter is documented in wp-admin/includes/file.php */ @@ -2450,7 +2763,7 @@ $ext2type = wp_get_ext_types(); foreach ( $ext2type as $type => $exts ) { - if ( in_array( $ext, $exts ) ) { + if ( in_array( $ext, $exts, true ) ) { return $type; } } @@ -2463,9 +2776,14 @@ * * @since 2.0.4 * - * @param string $filename File name or path. - * @param array $mimes Optional. Key is the file extension with value as the mime type. - * @return array Values with extension first and mime type. + * @param string $filename File name or path. + * @param string[] $mimes Optional. Array of mime types keyed by their file extension regex. + * @return array { + * Values for the extension and mime type. + * + * @type string|false $ext File extension, or false if the file doesn't match a mime type. + * @type string|false $type File mime type, or false if the file doesn't match a mime type. + * } */ function wp_check_filetype( $filename, $mimes = null ) { if ( empty( $mimes ) ) { @@ -2498,22 +2816,27 @@ * * @since 3.0.0 * - * @param string $file Full path to the file. - * @param string $filename The name of the file (may differ from $file due to $file being - * in a tmp directory). - * @param array $mimes Optional. Key is the file extension with value as the mime type. - * @return array Values for the extension, MIME, and either a corrected filename or false - * if original $filename is valid. + * @param string $file Full path to the file. + * @param string $filename The name of the file (may differ from $file due to $file being + * in a tmp directory). + * @param string[] $mimes Optional. Array of mime types keyed by their file extension regex. + * @return array { + * Values for the extension, mime type, and corrected filename. + * + * @type string|false $ext File extension, or false if the file doesn't match a mime type. + * @type string|false $type File mime type, or false if the file doesn't match a mime type. + * @type string|false $proper_filename File name with its correct extension, or false if it cannot be determined. + * } */ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) { $proper_filename = false; - // Do basic extension validation and MIME mapping + // Do basic extension validation and MIME mapping. $wp_filetype = wp_check_filetype( $filename, $mimes ); $ext = $wp_filetype['ext']; $type = $wp_filetype['type']; - // We can't do any further validation without a file to work with + // We can't do any further validation without a file to work with. if ( ! file_exists( $file ) ) { return compact( 'ext', 'type', 'proper_filename' ); } @@ -2523,7 +2846,7 @@ // Validate image types. if ( $type && 0 === strpos( $type, 'image/' ) ) { - // Attempt to figure out what type of image it actually is + // Attempt to figure out what type of image it actually is. $real_mime = wp_get_image_mime( $file ); if ( $real_mime && $real_mime != $type ) { @@ -2532,7 +2855,7 @@ * * @since 3.0.0 * - * @param array $mime_to_ext Array of image mime types and their matching extensions. + * @param array $mime_to_ext Array of image mime types and their matching extensions. */ $mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', @@ -2545,7 +2868,7 @@ ) ); - // Replace whatever is after the last period in the filename with the correct extension + // 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 ); @@ -2553,9 +2876,9 @@ $new_filename = implode( '.', $filename_parts ); if ( $new_filename != $filename ) { - $proper_filename = $new_filename; // Mark that it changed + $proper_filename = $new_filename; // Mark that it changed. } - // Redefine the extension / MIME + // Redefine the extension / MIME. $wp_filetype = wp_check_filetype( $new_filename, $mimes ); $ext = $wp_filetype['ext']; $type = $wp_filetype['type']; @@ -2572,7 +2895,7 @@ $real_mime = finfo_file( $finfo, $file ); finfo_close( $finfo ); - // fileinfo often misidentifies obscure files as one of these types + // fileinfo often misidentifies obscure files as one of these types. $nonspecific_types = array( 'application/octet-stream', 'application/encrypted', @@ -2587,8 +2910,9 @@ */ if ( in_array( $real_mime, $nonspecific_types, true ) ) { // File is a non-specific binary type. That's ok if it's a type that generally tends to be binary. - if ( ! in_array( substr( $type, 0, strcspn( $type, '/' ) ), array( 'application', 'video', 'audio' ) ) ) { - $type = $ext = false; + if ( ! in_array( substr( $type, 0, strcspn( $type, '/' ) ), array( 'application', 'video', 'audio' ), true ) ) { + $type = false; + $ext = false; } } elseif ( 0 === strpos( $real_mime, 'video/' ) || 0 === strpos( $real_mime, 'audio/' ) ) { /* @@ -2597,7 +2921,8 @@ * and some media files are commonly named with the wrong extension (.mov instead of .mp4) */ if ( substr( $real_mime, 0, strcspn( $real_mime, '/' ) ) !== substr( $type, 0, strcspn( $type, '/' ) ) ) { - $type = $ext = false; + $type = false; + $ext = false; } } elseif ( 'text/plain' === $real_mime ) { // A few common file types are occasionally detected as text/plain; allow those. @@ -2609,10 +2934,12 @@ 'text/richtext', 'text/tsv', 'text/vtt', - ) + ), + true ) ) { - $type = $ext = false; + $type = false; + $ext = false; } } elseif ( 'text/rtf' === $real_mime ) { // Special casing for RTF files. @@ -2622,10 +2949,12 @@ 'text/rtf', 'text/plain', 'application/rtf', - ) + ), + true ) ) { - $type = $ext = false; + $type = false; + $ext = false; } } else { if ( $type !== $real_mime ) { @@ -2633,17 +2962,19 @@ * Everything else including image/* and application/*: * If the real content type doesn't match the file extension, assume it's dangerous. */ - $type = $ext = false; + $type = false; + $ext = false; } } } - // The mime type must be allowed + // The mime type must be allowed. if ( $type ) { $allowed = get_allowed_mime_types(); - if ( ! in_array( $type, $allowed ) ) { - $type = $ext = false; + if ( ! in_array( $type, $allowed, true ) ) { + $type = false; + $ext = false; } } @@ -2653,12 +2984,17 @@ * @since 3.0.0 * @since 5.1.0 The $real_mime parameter was added. * - * @param array $wp_check_filetype_and_ext File data array containing 'ext', 'type', and - * 'proper_filename' keys. + * @param array $wp_check_filetype_and_ext { + * Values for the extension, mime type, and corrected filename. + * + * @type string|false $ext File extension, or false if the file doesn't match a mime type. + * @type string|false $type File mime type, or false if the file doesn't match a mime type. + * @type string|false $proper_filename File name with its correct extension, or false if it cannot be determined. + * } * @param string $file Full path to the file. * @param string $filename The name of the file (may differ from $file due to * $file being in a tmp directory). - * @param array $mimes Key is the file extension with value as the mime type. + * @param string[] $mimes Array of mime types keyed by their file extension regex. * @param string|bool $real_mime The actual mime type or false if the type cannot be determined. */ return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes, $real_mime ); @@ -2685,7 +3021,7 @@ $imagetype = exif_imagetype( $file ); $mime = ( $imagetype ) ? image_type_to_mime_type( $imagetype ) : false; } elseif ( function_exists( 'getimagesize' ) ) { - $imagesize = getimagesize( $file ); + $imagesize = @getimagesize( $file ); $mime = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false; } else { $mime = false; @@ -2701,9 +3037,11 @@ * Retrieve list of mime types and file extensions. * * @since 3.5.0 - * @since 4.2.0 Support was added for GIMP (xcf) files. - * - * @return array Array of mime types keyed by the file extension regex corresponding to those types. + * @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. + * + * @return string[] Array of mime types keyed by the file extension regex corresponding to those types. */ function wp_get_mime_types() { /** @@ -2714,7 +3052,7 @@ * * @since 3.5.0 * - * @param array $wp_get_mime_types Mime types keyed by the file extension regex + * @param string[] $wp_get_mime_types Mime types keyed by the file extension regex * corresponding to those types. */ return apply_filters( @@ -2727,6 +3065,7 @@ 'bmp' => 'image/bmp', 'tiff|tif' => 'image/tiff', 'ico' => 'image/x-icon', + 'heic' => 'image/heic', // Video formats. 'asf|asx' => 'video/x-ms-asf', 'wmv' => 'video/x-ms-wmv', @@ -2741,8 +3080,8 @@ 'ogv' => 'video/ogg', 'webm' => 'video/webm', 'mkv' => 'video/x-matroska', - '3gp|3gpp' => 'video/3gpp', // Can also be audio - '3g2|3gp2' => 'video/3gpp2', // Can also be audio + '3gp|3gpp' => 'video/3gpp', // Can also be audio. + '3g2|3gp2' => 'video/3gpp2', // Can also be audio. // Text formats. 'txt|asc|c|cc|h|srt' => 'text/plain', 'csv' => 'text/csv', @@ -2830,7 +3169,7 @@ * * @since 4.6.0 * - * @return array Array of file extensions types keyed by the type of file. + * @return array[] Multi-dimensional array of file extensions types keyed by the type of file. */ function wp_get_ext_types() { @@ -2841,13 +3180,12 @@ * * @see wp_ext2type() * - * @param array $ext2type Multi-dimensional array with extensions for a default set - * of file types. + * @param array[] $ext2type Multi-dimensional array of file extensions types keyed by the type of file. */ return apply_filters( 'ext2type', array( - 'image' => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico' ), + 'image' => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico', 'heic' ), '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' ), @@ -2866,8 +3204,8 @@ * @since 2.8.6 * * @param int|WP_User $user Optional. User to check. Defaults to current user. - * @return array Array of mime types keyed by the file extension regex corresponding - * to those types. + * @return string[] Array of mime types keyed by the file extension regex corresponding + * to those types. */ function get_allowed_mime_types( $user = null ) { $t = wp_get_mime_types(); @@ -2886,9 +3224,7 @@ * * @since 2.0.0 * - * @param array $t Mime types keyed by the file extension regex corresponding to - * those types. 'swf' and 'exe' removed from full list. 'htm|html' also - * removed depending on '$user' capabilities. + * @param array $t Mime types keyed by the file extension regex corresponding to those types. * @param int|WP_User|null $user User ID, User object or null if not provided (indicates current user). */ return apply_filters( 'upload_mimes', $t, $user ); @@ -2905,16 +3241,16 @@ * @param string $action The nonce action. */ function wp_nonce_ays( $action ) { - if ( 'log-out' == $action ) { + if ( 'log-out' === $action ) { $html = sprintf( - /* translators: %s: site name */ + /* translators: %s: Site title. */ __( 'You are attempting to log out of %s' ), get_bloginfo( 'name' ) ); $html .= '
'; $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : ''; $html .= sprintf( - /* translators: %s: logout URL */ + /* translators: %s: Logout URL. */ __( 'Do you really want to log out?' ), wp_logout_url( $redirect_to ) ); @@ -2949,8 +3285,11 @@ * @since 4.1.0 The `$title` and `$args` parameters were changed to optionally accept * an integer to be used as the response code. * @since 5.1.0 The `$link_url`, `$link_text`, and `$exit` arguments were added. - * - * @global WP_Query $wp_query Global WP_Query instance. + * @since 5.3.0 The `$charset` argument was added. + * @since 5.5.0 The `$text_direction` argument has a priority over get_language_attributes() + * in the default handler. + * + * @global WP_Query $wp_query WordPress Query object. * * @param string|WP_Error $message Optional. Error message. If this is a WP_Error object, * and not an Ajax or XML-RPC request, the error's messages are used. @@ -2969,9 +3308,10 @@ * @type string $link_text A label for the link to include. Only works in combination with $link_url. * Default empty string. * @type bool $back_link Whether to include a link to go back. Default false. - * @type string $text_direction The text direction. This is only useful internally, when WordPress - * is still loading and the site's locale is not set up yet. Accepts 'rtl'. + * @type string $text_direction The text direction. This is only useful internally, when WordPress is still + * loading and the site's locale is not set up yet. Accepts 'rtl' and 'ltr'. * Default is the value of is_rtl(). + * @type string $charset Character set of the HTML output. Default 'utf-8'. * @type string $code Error code to use. Default is 'wp_die', or the main error code if $message * is a WP_Error. * @type bool $exit Whether to exit the process after completion. Default true. @@ -3064,54 +3404,61 @@ * @param string|array $args Optional. Arguments to control behavior. Default empty array. */ function _default_wp_die_handler( $message, $title = '', $args = array() ) { - list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args ); + list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args ); if ( is_string( $message ) ) { - if ( ! empty( $r['additional_errors'] ) ) { + if ( ! empty( $parsed_args['additional_errors'] ) ) { $message = array_merge( array( $message ), - wp_list_pluck( $r['additional_errors'], 'message' ) + wp_list_pluck( $parsed_args['additional_errors'], 'message' ) ); $message = "
$message
"; } + + $message = sprintf( + ' ', + $message + ); } $have_gettext = function_exists( '__' ); - if ( ! empty( $r['link_url'] ) && ! empty( $r['link_text'] ) ) { - $link_url = $r['link_url']; + if ( ! empty( $parsed_args['link_url'] ) && ! empty( $parsed_args['link_text'] ) ) { + $link_url = $parsed_args['link_url']; if ( function_exists( 'esc_url' ) ) { $link_url = esc_url( $link_url ); } - $link_text = $r['link_text']; + $link_text = $parsed_args['link_text']; $message .= "\n"; } - if ( isset( $r['back_link'] ) && $r['back_link'] ) { + if ( isset( $parsed_args['back_link'] ) && $parsed_args['back_link'] ) { $back_text = $have_gettext ? __( '« Back' ) : '« Back'; $message .= "\n"; } if ( ! did_action( 'admin_head' ) ) : if ( ! headers_sent() ) { - header( 'Content-Type: text/html; charset=utf-8' ); - status_header( $r['response'] ); + header( "Content-Type: text/html; charset={$parsed_args['charset']}" ); + status_header( $parsed_args['response'] ); nocache_headers(); } - $text_direction = $r['text_direction']; - if ( function_exists( 'language_attributes' ) && function_exists( 'is_rtl' ) ) { + $text_direction = $parsed_args['text_direction']; + $dir_attr = "dir='$text_direction'"; + + // If `text_direction` was not explicitly passed, + // use get_language_attributes() if available. + if ( empty( $args['text_direction'] ) + && function_exists( 'language_attributes' ) && function_exists( 'is_rtl' ) + ) { $dir_attr = get_language_attributes(); - } else { - $dir_attr = "dir='$text_direction'"; } ?> -> +> - + @@ -3242,7 +3587,7 @@ 200 ) ); - list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args ); + list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args ); if ( ! headers_sent() ) { // This is intentional. For backward-compatibility, support passing null here. if ( null !== $args['response'] ) { - status_header( $r['response'] ); + status_header( $parsed_args['response'] ); } nocache_headers(); } @@ -3282,7 +3627,7 @@ $message = '0'; } - if ( $r['exit'] ) { + if ( $parsed_args['exit'] ) { die( $message ); } @@ -3302,27 +3647,27 @@ * @param string|array $args Optional. Arguments to control behavior. Default empty array. */ function _json_wp_die_handler( $message, $title = '', $args = array() ) { - list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args ); + list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args ); $data = array( - 'code' => $r['code'], + 'code' => $parsed_args['code'], 'message' => $message, 'data' => array( - 'status' => $r['response'], + 'status' => $parsed_args['response'], ), - 'additional_errors' => $r['additional_errors'], + 'additional_errors' => $parsed_args['additional_errors'], ); if ( ! headers_sent() ) { - header( 'Content-Type: application/json; charset=utf-8' ); - if ( null !== $r['response'] ) { - status_header( $r['response'] ); + header( "Content-Type: application/json; charset={$parsed_args['charset']}" ); + if ( null !== $parsed_args['response'] ) { + status_header( $parsed_args['response'] ); } nocache_headers(); } echo wp_json_encode( $data ); - if ( $r['exit'] ) { + if ( $parsed_args['exit'] ) { die(); } } @@ -3340,23 +3685,23 @@ * @param string|array $args Optional. Arguments to control behavior. Default empty array. */ function _jsonp_wp_die_handler( $message, $title = '', $args = array() ) { - list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args ); + list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args ); $data = array( - 'code' => $r['code'], + 'code' => $parsed_args['code'], 'message' => $message, 'data' => array( - 'status' => $r['response'], + 'status' => $parsed_args['response'], ), - 'additional_errors' => $r['additional_errors'], + 'additional_errors' => $parsed_args['additional_errors'], ); if ( ! headers_sent() ) { - header( 'Content-Type: application/javascript; charset=utf-8' ); + header( "Content-Type: application/javascript; charset={$parsed_args['charset']}" ); header( 'X-Content-Type-Options: nosniff' ); header( 'X-Robots-Tag: noindex' ); - if ( null !== $r['response'] ) { - status_header( $r['response'] ); + if ( null !== $parsed_args['response'] ) { + status_header( $parsed_args['response'] ); } nocache_headers(); } @@ -3364,7 +3709,7 @@ $result = wp_json_encode( $data ); $jsonp_callback = $_GET['_jsonp']; echo '/**/' . $jsonp_callback . '(' . $result . ')'; - if ( $r['exit'] ) { + if ( $parsed_args['exit'] ) { die(); } } @@ -3386,17 +3731,17 @@ function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) { global $wp_xmlrpc_server; - list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args ); + list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args ); if ( ! headers_sent() ) { nocache_headers(); } if ( $wp_xmlrpc_server ) { - $error = new IXR_Error( $r['response'], $message ); + $error = new IXR_Error( $parsed_args['response'], $message ); $wp_xmlrpc_server->output( $error->getXml() ); } - if ( $r['exit'] ) { + if ( $parsed_args['exit'] ) { die(); } } @@ -3414,33 +3759,33 @@ * @param string|array $args Optional. Arguments to control behavior. Default empty array. */ function _xml_wp_die_handler( $message, $title = '', $args = array() ) { - list( $message, $title, $r ) = _wp_die_process_input( $message, $title, $args ); + list( $message, $title, $parsed_args ) = _wp_die_process_input( $message, $title, $args ); $message = htmlspecialchars( $message ); $title = htmlspecialchars( $title ); $xml = <<{$r['code']}
+ {$parsed_args['code']}
__construct()' - ) + '
__construct()
'
+ ),
+ E_USER_DEPRECATED
);
} else {
- /* translators: 1: PHP class name, 2: version number, 3: __construct() method */
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.' ),
$class,
$version,
- '__construct()' - ) + '
__construct()
'
+ ),
+ E_USER_DEPRECATED
);
}
} else {
- if ( ! empty( $parent_class ) ) {
+ 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.',
$class,
$parent_class,
$version,
- '__construct()' - ) + '
__construct()
'
+ ),
+ E_USER_DEPRECATED
);
} else {
trigger_error(
@@ -4536,8 +4895,9 @@
'The called constructor method for %1$s is deprecated since version %2$s! Use %3$s instead.',
$class,
$version,
- '__construct()' - ) + '
__construct()
'
+ ),
+ E_USER_DEPRECATED
);
}
}
@@ -4557,15 +4917,16 @@
* This function is to be used in every file that is deprecated.
*
* @since 2.5.0
- * @access private
+ * @since 5.4.0 This function is no longer marked as "private".
+ * @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
*
* @param string $file The file that was included.
* @param string $version The version of WordPress that deprecated the file.
* @param string $replacement Optional. The file that should have been included based on ABSPATH.
- * Default null.
+ * Default empty.
* @param string $message Optional. A message regarding the change. Default empty.
*/
-function _deprecated_file( $file, $version, $replacement = null, $message = '' ) {
+function _deprecated_file( $file, $version, $replacement = '', $message = '' ) {
/**
* Fires when a deprecated file is called.
@@ -4588,19 +4949,50 @@
*/
if ( WP_DEBUG && apply_filters( 'deprecated_file_trigger_error', true ) ) {
$message = empty( $message ) ? '' : ' ' . $message;
+
if ( function_exists( '__' ) ) {
- if ( ! is_null( $replacement ) ) {
- /* translators: 1: PHP file name, 2: version number, 3: alternative file name */
- trigger_error( sprintf( __( '%1$s is deprecated since version %2$s! Use %3$s instead.' ), $file, $version, $replacement ) . $message );
+ if ( $replacement ) {
+ 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,
+ $version,
+ $replacement
+ ) . $message,
+ E_USER_DEPRECATED
+ );
} else {
- /* translators: 1: PHP file name, 2: version number */
- trigger_error( sprintf( __( '%1$s is deprecated since version %2$s with no alternative available.' ), $file, $version ) . $message );
+ trigger_error(
+ sprintf(
+ /* translators: 1: PHP file name, 2: Version number. */
+ __( '%1$s is deprecated since version %2$s with no alternative available.' ),
+ $file,
+ $version
+ ) . $message,
+ E_USER_DEPRECATED
+ );
}
} else {
- if ( ! is_null( $replacement ) ) {
- trigger_error( sprintf( '%1$s is deprecated since version %2$s! Use %3$s instead.', $file, $version, $replacement ) . $message );
+ if ( $replacement ) {
+ trigger_error(
+ sprintf(
+ '%1$s is deprecated since version %2$s! Use %3$s instead.',
+ $file,
+ $version,
+ $replacement
+ ) . $message,
+ E_USER_DEPRECATED
+ );
} else {
- trigger_error( sprintf( '%1$s is deprecated since version %2$s with no alternative available.', $file, $version ) . $message );
+ trigger_error(
+ sprintf(
+ '%1$s is deprecated since version %2$s with no alternative available.',
+ $file,
+ $version
+ ) . $message,
+ E_USER_DEPRECATED
+ );
}
}
}
@@ -4624,13 +5016,14 @@
* The current behavior is to trigger a user error if WP_DEBUG is true.
*
* @since 3.0.0
- * @access private
+ * @since 5.4.0 This function is no longer marked as "private".
+ * @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
*
* @param string $function The function that was called.
* @param string $version The version of WordPress that deprecated the argument used.
- * @param string $message Optional. A message regarding the change. Default null.
- */
-function _deprecated_argument( $function, $version, $message = null ) {
+ * @param string $message Optional. A message regarding the change. Default empty.
+ */
+function _deprecated_argument( $function, $version, $message = '' ) {
/**
* Fires when a deprecated argument is called.
@@ -4652,18 +5045,48 @@
*/
if ( WP_DEBUG && apply_filters( 'deprecated_argument_trigger_error', true ) ) {
if ( function_exists( '__' ) ) {
- if ( ! is_null( $message ) ) {
- /* translators: 1: PHP function name, 2: version number, 3: optional message regarding the change */
- trigger_error( sprintf( __( '%1$s was called with an argument that is deprecated since version %2$s! %3$s' ), $function, $version, $message ) );
+ if ( $message ) {
+ 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,
+ $version,
+ $message
+ ),
+ E_USER_DEPRECATED
+ );
} else {
- /* translators: 1: PHP function name, 2: version number */
- trigger_error( sprintf( __( '%1$s was called with an argument that is deprecated since version %2$s with no alternative available.' ), $function, $version ) );
+ 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,
+ $version
+ ),
+ E_USER_DEPRECATED
+ );
}
} else {
- if ( ! is_null( $message ) ) {
- trigger_error( sprintf( '%1$s was called with an argument that is deprecated since version %2$s! %3$s', $function, $version, $message ) );
+ if ( $message ) {
+ trigger_error(
+ sprintf(
+ '%1$s was called with an argument that is deprecated since version %2$s! %3$s',
+ $function,
+ $version,
+ $message
+ ),
+ E_USER_DEPRECATED
+ );
} else {
- trigger_error( sprintf( '%1$s was called with an argument that is deprecated since version %2$s with no alternative available.', $function, $version ) );
+ trigger_error(
+ sprintf(
+ '%1$s was called with an argument that is deprecated since version %2$s with no alternative available.',
+ $function,
+ $version
+ ),
+ E_USER_DEPRECATED
+ );
}
}
}
@@ -4681,14 +5104,15 @@
* functions, and so generally does not need to be called directly.
*
* @since 4.6.0
+ * @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
* @access private
*
* @param string $hook The hook that was used.
* @param string $version The version of WordPress that deprecated the hook.
- * @param string $replacement Optional. The hook that should have been used.
- * @param string $message Optional. A message regarding the change.
- */
-function _deprecated_hook( $hook, $version, $replacement = null, $message = null ) {
+ * @param string $replacement Optional. The hook that should have been used. Default empty.
+ * @param string $message Optional. A message regarding the change. Default empty.
+ */
+function _deprecated_hook( $hook, $version, $replacement = '', $message = '' ) {
/**
* Fires when a deprecated hook is called.
*
@@ -4711,12 +5135,28 @@
*/
if ( WP_DEBUG && apply_filters( 'deprecated_hook_trigger_error', true ) ) {
$message = empty( $message ) ? '' : ' ' . $message;
- if ( ! is_null( $replacement ) ) {
- /* translators: 1: WordPress hook name, 2: version number, 3: alternative hook name */
- trigger_error( sprintf( __( '%1$s is deprecated since version %2$s! Use %3$s instead.' ), $hook, $version, $replacement ) . $message );
+
+ if ( $replacement ) {
+ 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,
+ $version,
+ $replacement
+ ) . $message,
+ E_USER_DEPRECATED
+ );
} else {
- /* translators: 1: WordPress hook name, 2: version number */
- trigger_error( sprintf( __( '%1$s is deprecated since version %2$s with no alternative available.' ), $hook, $version ) . $message );
+ trigger_error(
+ sprintf(
+ /* translators: 1: WordPress hook name, 2: Version number. */
+ __( '%1$s is deprecated since version %2$s with no alternative available.' ),
+ $hook,
+ $version
+ ) . $message,
+ E_USER_DEPRECATED
+ );
}
}
}
@@ -4731,7 +5171,7 @@
* The current behavior is to trigger a user error if `WP_DEBUG` is true.
*
* @since 3.1.0
- * @access private
+ * @since 5.4.0 This function is no longer marked as "private".
*
* @param string $function The function that was called.
* @param string $message A message explaining what has been done incorrectly.
@@ -4763,30 +5203,46 @@
*/
if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true, $function, $message, $version ) ) {
if ( function_exists( '__' ) ) {
- if ( is_null( $version ) ) {
- $version = '';
- } else {
- /* translators: %s: version number */
+ if ( $version ) {
+ /* translators: %s: Version number. */
$version = sprintf( __( '(This message was added in version %s.)' ), $version );
}
- /* translators: %s: Codex URL */
+
$message .= ' ' . sprintf(
+ /* translators: %s: Documentation URL. */
__( 'Please see Debugging in WordPress for more information.' ),
- __( 'https://codex.wordpress.org/Debugging_in_WordPress' )
+ __( 'https://wordpress.org/support/article/debugging-in-wordpress/' )
);
- /* translators: Developer debugging message. 1: PHP function name, 2: Explanatory message, 3: Version information message */
- trigger_error( sprintf( __( '%1$s was called incorrectly. %2$s %3$s' ), $function, $message, $version ) );
+
+ 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,
+ $message,
+ $version
+ ),
+ E_USER_NOTICE
+ );
} else {
- if ( is_null( $version ) ) {
- $version = '';
- } else {
+ if ( $version ) {
$version = sprintf( '(This message was added in version %s.)', $version );
}
+
$message .= sprintf(
' Please see Debugging in WordPress for more information.',
- 'https://codex.wordpress.org/Debugging_in_WordPress'
+ 'https://wordpress.org/support/article/debugging-in-wordpress/'
);
- trigger_error( sprintf( '%1$s was called incorrectly. %2$s %3$s', $function, $message, $version ) );
+
+ trigger_error(
+ sprintf(
+ '%1$s was called incorrectly. %2$s %3$s',
+ $function,
+ $message,
+ $version
+ ),
+ E_USER_NOTICE
+ );
}
}
}
@@ -4801,7 +5257,8 @@
function is_lighttpd_before_150() {
$server_parts = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : '' );
$server_parts[1] = isset( $server_parts[1] ) ? $server_parts[1] : '';
- return 'lighttpd' == $server_parts[0] && -1 == version_compare( $server_parts[1], '1.5.0' );
+
+ return ( 'lighttpd' === $server_parts[0] && -1 == version_compare( $server_parts[1], '1.5.0' ) );
}
/**
@@ -4824,7 +5281,7 @@
if ( function_exists( 'apache_get_modules' ) ) {
$mods = apache_get_modules();
- if ( in_array( $mod, $mods ) ) {
+ if ( in_array( $mod, $mods, true ) ) {
return true;
}
} elseif ( function_exists( 'phpinfo' ) && false === strpos( ini_get( 'disable_functions' ), 'phpinfo' ) ) {
@@ -4835,6 +5292,7 @@
return true;
}
}
+
return $default;
}
@@ -4861,7 +5319,7 @@
* Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
* via ISAPI then pretty permalinks will not work.
*/
- $supports_permalinks = class_exists( 'DOMDocument', false ) && isset( $_SERVER['IIS_UrlRewriteModule'] ) && ( PHP_SAPI == 'cgi-fcgi' );
+ $supports_permalinks = class_exists( 'DOMDocument', false ) && isset( $_SERVER['IIS_UrlRewriteModule'] ) && ( 'cgi-fcgi' === PHP_SAPI );
}
/**
@@ -4885,8 +5343,8 @@
*
* @since 1.2.0
*
- * @param string $file File path.
- * @param array $allowed_files Optional. List of allowed files.
+ * @param string $file File path.
+ * @param string[] $allowed_files Optional. Array of allowed files.
* @return int 0 means nothing is wrong, greater than 0 means something was wrong.
*/
function validate_file( $file, $allowed_files = array() ) {
@@ -4906,12 +5364,12 @@
}
// Files not in the allowed file list are not allowed:
- if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) ) {
+ if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files, true ) ) {
return 3;
}
// Absolute Windows drive paths are not allowed:
- if ( ':' == substr( $file, 1, 1 ) ) {
+ if ( ':' === substr( $file, 1, 1 ) ) {
return 2;
}
@@ -4923,8 +5381,6 @@
*
* @since 2.6.0
*
- * @staticvar bool $forced
- *
* @param string|bool $force Optional. Whether to force SSL in admin screens. Default null.
* @return bool True if forced, false if not forced.
*/
@@ -4951,38 +5407,38 @@
* @return string The guessed URL.
*/
function wp_guess_url() {
- if ( defined( 'WP_SITEURL' ) && '' != WP_SITEURL ) {
+ if ( defined( 'WP_SITEURL' ) && '' !== WP_SITEURL ) {
$url = WP_SITEURL;
} else {
$abspath_fix = str_replace( '\\', '/', ABSPATH );
$script_filename_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
- // The request is for the admin
+ // The request is for the admin.
if ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false || strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ) {
$path = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $_SERVER['REQUEST_URI'] );
- // The request is for a file in ABSPATH
- } elseif ( $script_filename_dir . '/' == $abspath_fix ) {
- // Strip off any file/query params in the path
+ // The request is for a file in ABSPATH.
+ } elseif ( $script_filename_dir . '/' === $abspath_fix ) {
+ // Strip off any file/query params in the path.
$path = preg_replace( '#/[^/]*$#i', '', $_SERVER['PHP_SELF'] );
} else {
if ( false !== strpos( $_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
- // Request is hitting a file inside ABSPATH
+ // Request is hitting a file inside ABSPATH.
$directory = str_replace( ABSPATH, '', $script_filename_dir );
- // Strip off the sub directory, and any file/query params
+ // Strip off the subdirectory, and any file/query params.
$path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '', $_SERVER['REQUEST_URI'] );
} elseif ( false !== strpos( $abspath_fix, $script_filename_dir ) ) {
- // Request is hitting a file above ABSPATH
+ // Request is hitting a file above ABSPATH.
$subdirectory = substr( $abspath_fix, strpos( $abspath_fix, $script_filename_dir ) + strlen( $script_filename_dir ) );
- // Strip off any file/query params from the path, appending the sub directory to the installation
+ // Strip off any file/query params from the path, appending the subdirectory to the installation.
$path = preg_replace( '#/[^/]*$#i', '', $_SERVER['REQUEST_URI'] ) . $subdirectory;
} else {
$path = $_SERVER['REQUEST_URI'];
}
}
- $schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet
+ $schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet.
$url = $schema . $_SERVER['HTTP_HOST'] . $path;
}
@@ -5001,8 +5457,6 @@
*
* @since 3.3.0
*
- * @staticvar bool $_suspend
- *
* @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
* @return bool The current suspend setting
*/
@@ -5061,7 +5515,7 @@
$site_id = (int) $site_id;
- return $site_id === get_main_site_id( $network_id );
+ return get_main_site_id( $network_id ) === $site_id;
}
/**
@@ -5105,7 +5559,7 @@
$network_id = (int) $network_id;
- return ( $network_id === get_main_network_id() );
+ return ( get_main_network_id() === $network_id );
}
/**
@@ -5152,8 +5606,6 @@
*
* @since 3.0.0
*
- * @staticvar bool $global_terms
- *
* @return bool True if multisite and global terms enabled.
*/
function global_terms_enabled() {
@@ -5167,8 +5619,8 @@
/**
* Filters whether global terms are enabled.
*
- * Passing a non-null value to the filter will effectively short-circuit the function,
- * returning the value of the 'global_terms_enabled' site option instead.
+ * Returning a non-null value from the filter will effectively short-circuit the function
+ * and return the value of the 'global_terms_enabled' site option instead.
*
* @since 3.0.0
*
@@ -5226,7 +5678,8 @@
* @return float|false Timezone GMT offset, false otherwise.
*/
function wp_timezone_override_offset() {
- if ( ! $timezone_string = get_option( 'timezone_string' ) ) {
+ $timezone_string = get_option( 'timezone_string' );
+ if ( ! $timezone_string ) {
return false;
}
@@ -5249,9 +5702,9 @@
* @return int
*/
function _wp_timezone_choice_usort_callback( $a, $b ) {
- // Don't use translated versions of Etc
+ // Don't use translated versions of Etc.
if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
- // Make the order of these more like the old dropdown
+ // Make the order of these more like the old dropdown.
if ( 'GMT+' === substr( $a['city'], 0, 4 ) && 'GMT+' === substr( $b['city'], 0, 4 ) ) {
return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
}
@@ -5275,7 +5728,7 @@
}
return strnatcasecmp( $a['t_city'], $b['t_city'] );
} else {
- // Force Etc to the bottom of the list
+ // Force Etc to the bottom of the list.
if ( 'Etc' === $a['continent'] ) {
return 1;
}
@@ -5292,9 +5745,6 @@
* @since 2.9.0
* @since 4.7.0 Added the `$locale` parameter.
*
- * @staticvar bool $mo_loaded
- * @staticvar string $locale_loaded
- *
* @param string $selected_zone Selected timezone.
* @param string $locale Optional. Locale to load the timezones in. Default current site locale.
* @return string
@@ -5316,11 +5766,11 @@
$zonen = array();
foreach ( timezone_identifiers_list() as $zone ) {
$zone = explode( '/', $zone );
- if ( ! in_array( $zone[0], $continents ) ) {
+ if ( ! in_array( $zone[0], $continents, true ) ) {
continue;
}
- // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
+ // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later.
$exists = array(
0 => ( isset( $zone[0] ) && $zone[0] ),
1 => ( isset( $zone[1] ) && $zone[1] ),
@@ -5350,33 +5800,33 @@
}
foreach ( $zonen as $key => $zone ) {
- // Build value in an array to join later
+ // Build value in an array to join later.
$value = array( $zone['continent'] );
if ( empty( $zone['city'] ) ) {
- // It's at the continent level (generally won't happen)
+ // It's at the continent level (generally won't happen).
$display = $zone['t_continent'];
} else {
- // It's inside a continent group
-
- // Continent optgroup
+ // It's inside a continent group.
+
+ // Continent optgroup.
if ( ! isset( $zonen[ $key - 1 ] ) || $zonen[ $key - 1 ]['continent'] !== $zone['continent'] ) {
$label = $zone['t_continent'];
$structure[] = '';
}
}
- // Do UTC
+ // Do UTC.
$structure[] = '';
- // Do manual UTC offsets
+ // Do manual UTC offsets.
$structure[] = '