X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/a6f44f0edcda2471c5a33e4156c1c9488c7f3210..5d244c8fd9a27c9f89dd08da2af6fbc67d4fce63:/wp-includes/functions.php diff --git a/wp-includes/functions.php b/wp-includes/functions.php index ea774868..d903349c 100644 --- a/wp-includes/functions.php +++ b/wp-includes/functions.php @@ -8,7 +8,7 @@ require( ABSPATH . WPINC . '/option.php' ); /** - * Converts given date string into a different format. + * 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. @@ -18,10 +18,10 @@ require( ABSPATH . WPINC . '/option.php' ); * * @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 is true. - * @return string|int Formatted date string, or Unix timestamp. + * @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. */ function mysql2date( $format, $date, $translate = true ) { if ( empty( $date ) ) @@ -46,24 +46,26 @@ function mysql2date( $format, $date, $translate = true ) { * * The 'mysql' type will return the time in the format for MySQL DATETIME field. * The 'timestamp' type will return the current timestamp. + * Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d'). * * If $gmt is set to either '1' or 'true', then both types will use GMT time. * if $gmt is false, the output is adjusted with the GMT offset in the WordPress option. * * @since 1.0.0 * - * @param string $type Either 'mysql' or 'timestamp'. - * @param int|bool $gmt Optional. Whether to use GMT timezone. Default is false. - * @return int|string String if $type is 'gmt', int if $type is 'timestamp'. + * @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 ) ) ); - break; case 'timestamp': return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ); - break; + default: + return ( $gmt ) ? date( $type ) : date( $type, time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ); } } @@ -76,9 +78,10 @@ function current_time( $type, $gmt = 0 ) { * * @since 0.71 * - * @param string $dateformatstring Format to display the date. - * @param int $unixtimestamp Optional. Unix timestamp. - * @param bool $gmt Optional, default is false. Whether to convert to GMT for time. + * @param string $dateformatstring Format to display the date. + * @param bool|int $unixtimestamp Optional. Unix timestamp. Default false. + * @param bool $gmt Optional. Whether to use GMT timezone. Default false. + * * @return string The date, translated if locale specifies it. */ function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) { @@ -95,8 +98,10 @@ function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) { $gmt = true; } - // store original value for language with untypical grammars - // see http://core.trac.wordpress.org/ticket/9396 + /* + * Store original value for language with untypical grammars. + * See https://core.trac.wordpress.org/ticket/9396 + */ $req_format = $dateformatstring; $datefunc = $gmt? 'gmdate' : 'date'; @@ -136,8 +141,18 @@ function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) { } } $j = @$datefunc( $dateformatstring, $i ); - // allow plugins to redo this entirely for languages with untypical grammars - $j = apply_filters('date_i18n', $j, $req_format, $i, $gmt); + + /** + * Filter 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 Unix timestamp. + * @param bool $gmt Whether to convert to GMT for time. Default false. + */ + $j = apply_filters( 'date_i18n', $j, $req_format, $i, $gmt ); return $j; } @@ -146,13 +161,21 @@ function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) { * * @since 2.3.0 * - * @param int $number The number to convert based on locale. - * @param int $decimals Precision of the number of decimal places. + * @param int $number The number to convert based on locale. + * @param int $decimals Optional. Precision of the number of decimal places. Default 0. * @return string Converted number in string format. */ function number_format_i18n( $number, $decimals = 0 ) { global $wp_locale; $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] ); + + /** + * Filter the number formatted based on the locale. + * + * @since 2.8.0 + * + * @param string $formatted Converted number in string format. + */ return apply_filters( 'number_format_i18n', $formatted ); } @@ -169,13 +192,12 @@ function number_format_i18n( $number, $decimals = 0 ) { * be converted to a double, which should always have 64 bit length. * * Technically the correct unit names for powers of 1024 are KiB, MiB etc. - * @link http://en.wikipedia.org/wiki/Byte * * @since 2.3.0 * - * @param int|string $bytes Number of bytes. Note max integer size for integers. - * @param int $decimals Precision of number of decimal places. Deprecated. - * @return bool|string False on failure. Number string on success. + * @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. */ function size_format( $bytes, $decimals = 0 ) { $quant = array( @@ -194,28 +216,41 @@ function size_format( $bytes, $decimals = 0 ) { } /** - * Get the week start and end from the datetime or date string from mysql. + * Get the week start and end from the datetime or date string from MySQL. * * @since 0.71 * - * @param string $mysqlstring Date or datetime field type from mysql. - * @param int $start_of_week Optional. Start of the week as an integer. + * @param string $mysqlstring Date or datetime field type from MySQL. + * @param int|string $start_of_week Optional. Start of the week as an integer. Default empty string. * @return array Keys are 'start' and 'end'. */ function get_weekstartend( $mysqlstring, $start_of_week = '' ) { - $my = substr( $mysqlstring, 0, 4 ); // Mysql string Year - $mm = substr( $mysqlstring, 8, 2 ); // Mysql string Month - $md = substr( $mysqlstring, 5, 2 ); // Mysql string day - $day = mktime( 0, 0, 0, $md, $mm, $my ); // The timestamp for mysqlstring day. - $weekday = date( 'w', $day ); // The day of the week from the timestamp + // MySQL string year. + $my = substr( $mysqlstring, 0, 4 ); + + // MySQL string month. + $mm = substr( $mysqlstring, 8, 2 ); + + // MySQL string day. + $md = substr( $mysqlstring, 5, 2 ); + + // The timestamp for MySQL string day. + $day = mktime( 0, 0, 0, $md, $mm, $my ); + + // The day of the week from the timestamp. + $weekday = date( 'w', $day ); + if ( !is_numeric($start_of_week) ) $start_of_week = get_option( 'start_of_week' ); if ( $weekday < $start_of_week ) $weekday += 7; - $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week ); // The most recent week start day on or before $day - $end = $start + 7 * DAY_IN_SECONDS - 1; // $start + 7 days - 1 second + // The most recent week start day on or before $day. + $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week ); + + // $start + 7 days - 1 second. + $end = $start + 7 * DAY_IN_SECONDS - 1; return compact( 'start', 'end' ); } @@ -241,26 +276,30 @@ function maybe_unserialize( $original ) { * * @since 2.0.5 * - * @param mixed $data Value to check to see if was serialized. - * @param bool $strict Optional. Whether to be strict about the end of the string. Defaults true. + * @param string $data Value to check to see if was serialized. + * @param bool $strict Optional. Whether to be strict about the end of the string. Default true. * @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 ( ! is_string( $data ) ) + // 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; - $length = strlen( $data ); - if ( $length < 4 ) + } + if ( strlen( $data ) < 4 ) { return false; - if ( ':' !== $data[1] ) + } + if ( ':' !== $data[1] ) { return false; + } if ( $strict ) { - $lastc = $data[ $length - 1 ]; - if ( ';' !== $lastc && '}' !== $lastc ) + $lastc = substr( $data, -1 ); + if ( ';' !== $lastc && '}' !== $lastc ) { return false; + } } else { $semicolon = strpos( $data, ';' ); $brace = strpos( $data, '}' ); @@ -277,11 +316,13 @@ function is_serialized( $data, $strict = true ) { switch ( $token ) { case 's' : if ( $strict ) { - if ( '"' !== $data[ $length - 2 ] ) + if ( '"' !== substr( $data, -2, 1 ) ) { return false; + } } elseif ( false === strpos( $data, '"' ) ) { return false; } + // or else fall through case 'a' : case 'O' : return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data ); @@ -299,27 +340,28 @@ function is_serialized( $data, $strict = true ) { * * @since 2.0.5 * - * @param mixed $data Serialized data + * @param string $data Serialized data. * @return bool False if not a serialized string, true if it is. */ function is_serialized_string( $data ) { - // if it isn't a string, it isn't a serialized string - if ( !is_string( $data ) ) + // if it isn't a string, it isn't a serialized string. + if ( ! is_string( $data ) ) { return false; + } $data = trim( $data ); - $length = strlen( $data ); - if ( $length < 4 ) + if ( strlen( $data ) < 4 ) { return false; - elseif ( ':' !== $data[1] ) + } elseif ( ':' !== $data[1] ) { return false; - elseif ( ';' !== $data[$length-1] ) + } elseif ( ';' !== substr( $data, -1 ) ) { return false; - elseif ( $data[0] !== 's' ) + } elseif ( $data[0] !== 's' ) { return false; - elseif ( '"' !== $data[$length-2] ) + } elseif ( '"' !== substr( $data, -2, 1 ) ) { return false; - else + } else { return true; + } } /** @@ -327,7 +369,7 @@ function is_serialized_string( $data ) { * * @since 2.0.5 * - * @param mixed $data Data that might be serialized. + * @param string|array|object $data Data that might be serialized. * @return mixed A scalar data */ function maybe_serialize( $data ) { @@ -335,7 +377,7 @@ function maybe_serialize( $data ) { return serialize( $data ); // Double serialization is required for backward compatibility. - // See http://core.trac.wordpress.org/ticket/12930 + // See https://core.trac.wordpress.org/ticket/12930 if ( is_serialized( $data, false ) ) return serialize( $data ); @@ -348,11 +390,9 @@ function maybe_serialize( $data ) { * If the title element is not part of the XML, then the default post title from * the $post_default_title will be used instead. * - * @package WordPress - * @subpackage XMLRPC * @since 0.71 * - * @global string $post_default_title Default XMLRPC post title. + * @global string $post_default_title Default XML-RPC post title. * * @param string $content XMLRPC XML Request content * @return string Post title @@ -374,11 +414,9 @@ function xmlrpc_getposttitle( $content ) { * used. The return type then would be what $post_default_category. If the * category is found, then it will always be an array. * - * @package WordPress - * @subpackage XMLRPC * @since 0.71 * - * @global string $post_default_category Default XMLRPC post category. + * @global string $post_default_category Default XML-RPC post category. * * @param string $content XMLRPC XML Request content * @return string|array List of categories or category name. @@ -397,11 +435,9 @@ function xmlrpc_getpostcategory( $content ) { /** * XMLRPC XML content without title and category elements. * - * @package WordPress - * @subpackage XMLRPC * @since 0.71 * - * @param string $content XMLRPC XML Request content + * @param string $content XML-RPC XML Request content. * @return string XMLRPC XML Request content without title and category elements. */ function xmlrpc_removepostdata( $content ) { @@ -411,6 +447,37 @@ function xmlrpc_removepostdata( $content ) { return $content; } +/** + * Use RegEx to extract URLs from arbitrary content. + * + * @since 3.7.0 + * + * @param string $content Content to extract URLs from. + * @return array URLs found in passed string. + */ +function wp_extract_urls( $content ) { + preg_match_all( + "#([\"']?)(" + . "(?:([\w-]+:)?//?)" + . "[^\s()<>]+" + . "[.]" + . "(?:" + . "\([\w\d]+\)|" + . "(?:" + . "[^`!()\[\]{};:'\".,<>«»“”‘’\s]|" + . "(?:[:]\d+)?/?" + . ")+" + . ")" + . ")\\1#", + $content, + $post_links + ); + + $post_links = array_unique( array_map( 'html_entity_decode', $post_links[2] ) ); + + return array_values( $post_links ); +} + /** * Check content for video and audio links to add as enclosures. * @@ -418,13 +485,12 @@ function xmlrpc_removepostdata( $content ) { * remove enclosures that are no longer in the post. This is called as * pingbacks and trackbacks. * - * @package WordPress * @since 1.5.0 * - * @uses $wpdb + * @see $wpdb * - * @param string $content Post Content - * @param int $post_ID Post ID + * @param string $content Post Content. + * @param int $post_ID Post ID. */ function do_enclose( $content, $post_ID ) { global $wpdb; @@ -436,22 +502,17 @@ function do_enclose( $content, $post_ID ) { $pung = get_enclosed( $post_ID ); - $ltrs = '\w'; - $gunk = '/#~:.?+=&%@!\-'; - $punc = '.:?\-'; - $any = $ltrs . $gunk . $punc; - - preg_match_all( "{\b http : [$any] +? (?= [$punc] * [^$any] | $)}x", $content, $post_links_temp ); + $post_links_temp = wp_extract_urls( $content ); foreach ( $pung as $link_test ) { - if ( !in_array( $link_test, $post_links_temp[0] ) ) { // 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, like_escape( $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 ) . '%') ); foreach ( $mids as $mid ) delete_metadata_by_mid( 'post', $mid ); } } - foreach ( (array) $post_links_temp[0] as $link_test ) { + 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 ( false === $test ) @@ -464,7 +525,7 @@ function do_enclose( $content, $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, like_escape( $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) ) { $len = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0; @@ -502,9 +563,10 @@ function do_enclose( $content, $post_ID ) { * * @since 2.5.0 * - * @param string $url URL to fetch. - * @param string|bool $file_path Optional. File path to write request to. - * @param int $red (private) The number of Redirects followed, Upon 5 being hit, returns false. + * @param string $url URL to fetch. + * @param string|bool $file_path Optional. File path to write request to. Default false. + * @param int $red Optional. The number of Redirects followed, Upon 5 being hit, + * returns false. Default 1. * @return bool|string False on failure and string of headers if HEAD request. */ function wp_get_http( $url, $file_path = false, $red = 1 ) { @@ -554,8 +616,8 @@ function wp_get_http( $url, $file_path = false, $red = 1 ) { * * @since 1.5.1 * - * @param string $url - * @param bool $deprecated Not Used. + * @param string $url URL to retrieve HTTP headers from. + * @param bool $deprecated Not Used. * @return bool|string False on failure, headers on success. */ function wp_get_http_headers( $url, $deprecated = false ) { @@ -571,11 +633,13 @@ function wp_get_http_headers( $url, $deprecated = false ) { } /** - * Whether today is a new day. + * Whether the publish date of the current post in the loop is different from the + * publish date of the previous post in the loop. * * @since 0.71 - * @uses $day Today - * @uses $previousday Previous day + * + * @global string $currentday The day of the current post in the loop. + * @global string $previousday The day of the previous post in the loop. * * @return int 1 when new day, 0 if not a new day. */ @@ -593,21 +657,38 @@ function is_new_day() { * This is a convenient function for easily building url queries. It sets the * separator to '&' and uses _http_build_query() function. * + * @since 2.3.0 + * * @see _http_build_query() Used to build the query - * @link http://us2.php.net/manual/en/function.http-build-query.php more on what + * @see http://us2.php.net/manual/en/function.http-build-query.php for more on what * http_build_query() does. * - * @since 2.3.0 - * * @param array $data URL-encode key/value pairs. - * @return string URL encoded string + * @return string URL-encoded string. */ function build_query( $data ) { return _http_build_query( $data, null, '&', '', false ); } -// from php.net (modified by Mark Jaquith to behave like the native PHP5 function) -function _http_build_query($data, $prefix=null, $sep=null, $key='', $urlencode=true) { +/** + * From php.net (modified by Mark Jaquith to behave like the native PHP5 function). + * + * @since 3.2.0 + * @access private + * + * @see http://us1.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 ) { $ret = array(); foreach ( (array) $data as $k => $v ) { @@ -649,13 +730,12 @@ function _http_build_query($data, $prefix=null, $sep=null, $key='', $urlencode=t * * @since 1.5.0 * - * @param mixed $param1 Either newkey or an associative_array - * @param mixed $param2 Either newvalue or oldquery or uri - * @param mixed $param3 Optional. Old query or uri + * @param string|array $param1 Either newkey or an associative_array. + * @param string $param2 Either newvalue or oldquery or URI. + * @param string $param3 Optional. Old query or URI. * @return string New URL query string. */ function add_query_arg() { - $ret = ''; $args = func_get_args(); if ( is_array( $args[0] ) ) { if ( count( $args ) < 2 || false === $args[1] ) @@ -685,14 +765,8 @@ function add_query_arg() { } if ( strpos( $uri, '?' ) !== false ) { - $parts = explode( '?', $uri, 2 ); - if ( 1 == count( $parts ) ) { - $base = '?'; - $query = $parts[0]; - } else { - $base = $parts[0] . '?'; - $query = $parts[1]; - } + list( $base, $query ) = explode( '?', $uri, 2 ); + $base .= '?'; } elseif ( $protocol || strpos( $uri, '=' ) === false ) { $base = $uri . '?'; $query = ''; @@ -728,11 +802,11 @@ function add_query_arg() { * * @since 1.5.0 * - * @param string|array $key Query key or keys to remove. - * @param bool $query When false uses the $_SERVER value. + * @param string|array $key Query key or keys to remove. + * @param bool|string $query Optional. When false uses the $_SERVER value. Default false. * @return string New URL query string. */ -function remove_query_arg( $key, $query=false ) { +function remove_query_arg( $key, $query = false ) { if ( is_array( $key ) ) { // removing multiple keys foreach ( $key as $k ) $query = add_query_arg( $k, false, $query ); @@ -764,10 +838,11 @@ function add_magic_quotes( $array ) { * HTTP request for URI to retrieve content. * * @since 1.5.1 - * @uses wp_remote_get() + * + * @see wp_safe_remote_get() * * @param string $uri URI/URL of web page to retrieve. - * @return bool|string HTTP content. False on failure. + * @return false|string HTTP content. False on failure. */ function wp_remote_fopen( $uri ) { $parsed_url = @parse_url( $uri ); @@ -857,10 +932,14 @@ function get_status_header_desc( $code ) { 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', + 418 => 'I\'m a teapot', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 426 => 'Upgrade Required', + 428 => 'Precondition Required', + 429 => 'Too Many Requests', + 431 => 'Request Header Fields Too Large', 500 => 'Internal Server Error', 501 => 'Not Implemented', @@ -870,7 +949,8 @@ function get_status_header_desc( $code ) { 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', - 510 => 'Not Extended' + 510 => 'Not Extended', + 511 => 'Network Authentication Required', ); } @@ -884,38 +964,46 @@ function get_status_header_desc( $code ) { * Set HTTP status header. * * @since 2.0.0 - * @uses apply_filters() Calls 'status_header' on status header string, HTTP - * HTTP code, HTTP code description, and protocol string as separate - * parameters. * - * @param int $header HTTP status code - * @return unknown + * @see get_status_header_desc() + * + * @param int $code HTTP status code. */ -function status_header( $header ) { - $text = get_status_header_desc( $header ); +function status_header( $code ) { + $description = get_status_header_desc( $code ); - if ( empty( $text ) ) - return false; + if ( empty( $description ) ) + return; - $protocol = $_SERVER["SERVER_PROTOCOL"]; + $protocol = $_SERVER['SERVER_PROTOCOL']; if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol ) $protocol = 'HTTP/1.0'; - $status_header = "$protocol $header $text"; + $status_header = "$protocol $code $description"; if ( function_exists( 'apply_filters' ) ) - $status_header = apply_filters( 'status_header', $status_header, $header, $text, $protocol ); - return @header( $status_header, true, $header ); + /** + * Filter an HTTP status header. + * + * @since 2.2.0 + * + * @param string $status_header HTTP status header. + * @param int $code HTTP status code. + * @param string $description Description for the status code. + * @param string $protocol Server protocol. + */ + $status_header = apply_filters( 'status_header', $status_header, $code, $description, $protocol ); + + @header( $status_header, true, $code ); } /** - * Gets the header information to prevent caching. + * Get the header information to prevent caching. * - * The several different headers cover the different ways cache prevention is handled - * by different browsers + * The several different headers cover the different ways cache prevention + * is handled by different browsers * * @since 2.8.0 * - * @uses apply_filters() * @return array The associative array of header names and field values. */ function wp_get_nocache_headers() { @@ -926,20 +1014,37 @@ function wp_get_nocache_headers() { ); if ( function_exists('apply_filters') ) { - $headers = (array) apply_filters('nocache_headers', $headers); + /** + * Filter the cache-controlling headers. + * + * @since 2.8.0 + * + * @see wp_get_nocache_headers() + * + * @param array $headers { + * Header names and field values. + * + * @type string $Expires Expires header. + * @type string $Cache-Control Cache-Control header. + * @type string $Pragma Pragma header. + * } + */ + $headers = (array) apply_filters( 'nocache_headers', $headers ); } $headers['Last-Modified'] = false; return $headers; } /** - * Sets the headers to prevent caching for the different browsers. + * Set the headers to prevent caching for the different browsers. * - * Different browsers support different nocache headers, so several headers must - * be sent so that all of them get the point that no caching should occur. + * Different browsers support different nocache headers, so several + * headers must be sent so that all of them get the point that no + * caching should occur. * * @since 2.0.0 - * @uses wp_get_nocache_headers() + * + * @see wp_get_nocache_headers() */ function nocache_headers() { $headers = wp_get_nocache_headers(); @@ -971,6 +1076,7 @@ function nocache_headers() { */ function cache_javascript_headers() { $expiresOffset = 10 * DAY_IN_SECONDS; + header( "Content-Type: text/javascript; charset=" . get_bloginfo( 'charset' ) ); header( "Vary: Accept-Encoding" ); // Handle proxies header( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $expiresOffset ) . " GMT" ); @@ -981,7 +1087,9 @@ function cache_javascript_headers() { * * @since 2.0.0 * - * @return int Number of database queries + * @global wpdb $wpdb WordPress database abstraction object. + * + * @return int Number of database queries. */ function get_num_queries() { global $wpdb; @@ -989,19 +1097,21 @@ function get_num_queries() { } /** - * Whether input is yes or no. Must be 'y' to be true. + * Whether input is yes or no. + * + * Must be 'y' to be true. * * @since 1.0.0 * - * @param string $yn Character string containing either 'y' or 'n' - * @return bool True if yes, false on anything else + * @param string $yn Character string containing either 'y' (yes) or 'n' (no). + * @return bool True if yes, false on anything else. */ function bool_from_yn( $yn ) { return ( strtolower( $yn ) == 'y' ); } /** - * Loads the feed template from the use of an action hook. + * Load the feed template from the use of an action hook. * * If the feed action does not have a hook, then the function will die with a * message telling the visitor that the feed is not valid. @@ -1009,8 +1119,8 @@ function bool_from_yn( $yn ) { * It is better to only have one hook for each feed. * * @since 2.1.0 + * * @uses $wp_query Used to tell if the use a comment feed. - * @uses do_action() Calls 'do_feed_$feed' hook, if a hook exists for the feed. */ function do_feed() { global $wp_query; @@ -1024,11 +1134,18 @@ function do_feed() { $feed = get_default_feed(); $hook = 'do_feed_' . $feed; - if ( !has_action($hook) ) { - $message = sprintf( __( 'ERROR: %s is not a valid feed template.' ), esc_html($feed)); - wp_die( $message, '', array( 'response' => 404 ) ); - } - + if ( ! has_action( $hook ) ) + wp_die( __( 'ERROR: This is not a valid feed template.' ), '', array( 'response' => 404 ) ); + + /** + * Fires once the given feed is loaded. + * + * The dynamic hook name, $hook, refers to the feed name. + * + * @since 2.1.0 + * + * @param bool $is_comment_feed Whether the feed is a comment feed. + */ do_action( $hook, $wp_query->is_comment_feed ); } @@ -1036,6 +1153,8 @@ function do_feed() { * Load the RDF RSS 0.91 Feed template. * * @since 2.1.0 + * + * @see load_template() */ function do_feed_rdf() { load_template( ABSPATH . WPINC . '/feed-rdf.php' ); @@ -1045,6 +1164,8 @@ function do_feed_rdf() { * Load the RSS 1.0 Feed Template. * * @since 2.1.0 + * + * @see load_template() */ function do_feed_rss() { load_template( ABSPATH . WPINC . '/feed-rss.php' ); @@ -1055,6 +1176,8 @@ function do_feed_rss() { * * @since 2.1.0 * + * @see load_template() + * * @param bool $for_comments True for the comment feed, false for normal feed. */ function do_feed_rss2( $for_comments ) { @@ -1069,6 +1192,8 @@ function do_feed_rss2( $for_comments ) { * * @since 2.1.0 * + * @see load_template() + * * @param bool $for_comments True for the comment feed, false for normal feed. */ function do_feed_atom( $for_comments ) { @@ -1085,11 +1210,15 @@ function do_feed_atom( $for_comments ) { * robots.txt file. * * @since 2.1.0 - * @uses do_action() Calls 'do_robotstxt' hook for displaying robots.txt rules. */ function do_robots() { header( 'Content-Type: text/plain; charset=utf-8' ); + /** + * Fires when displaying the robots.txt file. + * + * @since 2.1.0 + */ do_action( 'do_robotstxt' ); $output = "User-agent: *\n"; @@ -1100,30 +1229,41 @@ function do_robots() { $site_url = parse_url( site_url() ); $path = ( !empty( $site_url['path'] ) ) ? $site_url['path'] : ''; $output .= "Disallow: $path/wp-admin/\n"; - $output .= "Disallow: $path/wp-includes/\n"; } - echo apply_filters('robots_txt', $output, $public); + /** + * Filter the robots.txt output. + * + * @since 3.0.0 + * + * @param string $output Robots.txt output. + * @param bool $public Whether the site is considered "public". + */ + echo apply_filters( 'robots_txt', $output, $public ); } /** * Test whether blog is already installed. * - * The cache will be checked first. If you have a cache plugin, which saves the - * cache values, then this will work. If you use the default WordPress cache, - * and the database goes away, then you might have problems. + * The cache will be checked first. If you have a cache plugin, which saves + * the cache values, then this will work. If you use the default WordPress + * cache, and the database goes away, then you might have problems. * - * Checks for the option siteurl for whether WordPress is installed. + * Checks for the 'siteurl' option for whether WordPress is installed. * * @since 2.1.0 - * @uses $wpdb * - * @return bool Whether blog is already installed. + * @global wpdb $wpdb WordPress database abstraction object. + * + * @return bool Whether the blog is already installed. */ function is_blog_installed() { global $wpdb; - // Check cache first. If options table goes away and we have true cached, oh well. + /* + * Check cache first. If options table goes away and we have true + * cached, oh well. + */ if ( wp_cache_get( 'is_blog_installed' ) ) return true; @@ -1150,9 +1290,11 @@ function is_blog_installed() { $suppress = $wpdb->suppress_errors(); - // Loop over the WP tables. If none exist, then scratch install is allowed. - // If one or more exist, suggest table repair since we got here because the options - // table could not be accessed. + /* + * Loop over the WP tables. If none exist, then scratch install is allowed. + * If one or more exist, suggest table repair since we got here because the + * options table could not be accessed. + */ $wp_tables = $wpdb->tables(); foreach ( $wp_tables as $table ) { // The existence of custom user tables shouldn't suggest an insane state or prevent a clean install. @@ -1183,14 +1325,12 @@ function is_blog_installed() { /** * Retrieve URL with nonce added to URL query. * - * @package WordPress - * @subpackage Security * @since 2.0.4 * - * @param string $actionurl URL to add nonce action. - * @param string $action Optional. Nonce action name. - * @param string $name Optional. Nonce name. - * @return string URL with nonce action added. + * @param string $actionurl URL to add nonce action. + * @param int|string $action Optional. Nonce action name. Default -1. + * @param string $name Optional. Nonce name. Default '_wpnonce'. + * @return string Escaped URL with nonce action added. */ function wp_nonce_url( $actionurl, $action = -1, $name = '_wpnonce' ) { $actionurl = str_replace( '&', '&', $actionurl ); @@ -1215,15 +1355,13 @@ function wp_nonce_url( $actionurl, $action = -1, $name = '_wpnonce' ) { * The input name will be whatever $name value you gave. The input value will be * the nonce creation value. * - * @package WordPress - * @subpackage Security * @since 2.0.4 * - * @param string $action Optional. Action name. - * @param string $name Optional. Nonce name. - * @param bool $referer Optional, default true. Whether to set the referer field for validation. - * @param bool $echo Optional, default true. Whether to display or return hidden form field. - * @return string Nonce field. + * @param int|string $action Optional. Action name. Default -1. + * @param string $name Optional. Nonce name. Default '_wpnonce'. + * @param bool $referer Optional. Whether to set the referer field for validation. Default true. + * @param bool $echo Optional. Whether to display or return hidden form field. Default true. + * @return string Nonce field HTML markup. */ function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true , $echo = true ) { $name = esc_attr( $name ); @@ -1244,12 +1382,10 @@ function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true , $ec * The referer link is the current Request URI from the server super global. The * input name is '_wp_http_referer', in case you wanted to check manually. * - * @package WordPress - * @subpackage Security * @since 2.0.4 * - * @param bool $echo Whether to echo or return the referer field. - * @return string Referer field. + * @param bool $echo Optional. Whether to echo or return the referer field. Default true. + * @return string Referer field HTML markup. */ function wp_referer_field( $echo = true ) { $referer_field = ''; @@ -1263,15 +1399,14 @@ function wp_referer_field( $echo = true ) { * Retrieve or display original referer hidden field for forms. * * The input name is '_wp_original_http_referer' and will be either the same - * value of {@link wp_referer_field()}, if that was posted already or it will - * be the current page, if it doesn't exist. + * value of wp_referer_field(), if that was posted already or it will be the + * current page, if it doesn't exist. * - * @package WordPress - * @subpackage Security * @since 2.0.4 * - * @param bool $echo Whether to echo the original http referer - * @param string $jump_back_to Optional, default is 'current'. Can be 'previous' or page you want to jump back to. + * @param bool $echo Optional. Whether to echo the original http referer. Default true. + * @param string $jump_back_to Optional. Can be 'previous' or page you want to jump back to. + * Default 'current'. * @return string Original referer field. */ function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) { @@ -1285,16 +1420,17 @@ function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) { } /** - * Retrieve referer from '_wp_http_referer' or HTTP referer. If it's the same - * as the current request URL, will return false. + * Retrieve referer from '_wp_http_referer' or HTTP referer. + * + * If it's the same as the current request URL, will return false. * - * @package WordPress - * @subpackage Security * @since 2.0.4 * - * @return string|bool False on failure. Referer URL on success. + * @return false|string False on failure. Referer URL on success. */ function wp_get_referer() { + if ( ! function_exists( 'wp_validate_redirect' ) ) + return false; $ref = false; if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) $ref = wp_unslash( $_REQUEST['_wp_http_referer'] ); @@ -1309,14 +1445,12 @@ function wp_get_referer() { /** * Retrieve original referer that was posted, if it exists. * - * @package WordPress - * @subpackage Security * @since 2.0.4 * - * @return string|bool False if no original referer or original referer if set. + * @return string|false False if no original referer or original referer if set. */ function wp_get_original_referer() { - if ( !empty( $_REQUEST['_wp_original_http_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; } @@ -1334,77 +1468,101 @@ function wp_get_original_referer() { function wp_mkdir_p( $target ) { $wrapper = null; - // strip the protocol + // Strip the protocol. if( wp_is_stream( $target ) ) { list( $wrapper, $target ) = explode( '://', $target, 2 ); } - // from php.net/mkdir user contributed notes + // From php.net/mkdir user contributed notes. $target = str_replace( '//', '/', $target ); - // put the wrapper back on the target + // Put the wrapper back on the target. if( $wrapper !== null ) { $target = $wrapper . '://' . $target; } - // safe mode fails with a trailing slash under certain PHP versions. - $target = rtrim($target, '/'); // Use rtrim() instead of untrailingslashit to avoid formatting.php dependency. + /* + * Safe mode fails with a trailing slash under certain PHP versions. + * Use rtrim() instead of untrailingslashit to avoid formatting.php dependency. + */ + $target = rtrim($target, '/'); if ( empty($target) ) $target = '/'; if ( file_exists( $target ) ) return @is_dir( $target ); - // Attempting to create the directory may clutter up our display. - if ( @mkdir( $target ) ) { - $stat = @stat( dirname( $target ) ); - $dir_perms = $stat['mode'] & 0007777; // Get the permission bits. - @chmod( $target, $dir_perms ); - return true; - } elseif ( is_dir( dirname( $target ) ) ) { - return false; + // 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 ) ) { + $target_parent = dirname( $target_parent ); } - // If the above failed, attempt to create the parent node, then try again. - if ( ( $target != '/' ) && ( wp_mkdir_p( dirname( $target ) ) ) ) - return wp_mkdir_p( $target ); + // Get the permission bits. + if ( $stat = @stat( $target_parent ) ) { + $dir_perms = $stat['mode'] & 0007777; + } else { + $dir_perms = 0777; + } + + if ( @mkdir( $target, $dir_perms, true ) ) { + + /* + * 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() ) ) { + $folder_parts = explode( '/', substr( $target, strlen( $target_parent ) + 1 ) ); + for ( $i = 1; $i <= count( $folder_parts ); $i++ ) { + @chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms ); + } + } + + return true; + } return false; } /** - * Test if a give filesystem path is absolute ('/foo/bar', 'c:\windows'). + * Test if a give filesystem path is absolute. + * + * For example, '/foo/bar', or 'c:\windows'. * * @since 2.5.0 * - * @param string $path File path + * @param string $path File path. * @return bool True if path is absolute, false is not absolute. */ function path_is_absolute( $path ) { - // this is definitive if true but fails if $path does not exist or contains a symbolic link + /* + * This is definitive if true but fails if $path does not exist or contains + * a symbolic link. + */ if ( realpath($path) == $path ) return true; if ( strlen($path) == 0 || $path[0] == '.' ) return false; - // windows allows absolute paths like this + // Windows allows absolute paths like this. if ( preg_match('#^[a-zA-Z]:\\\\#', $path) ) return true; - // a path starting with / or \ is absolute; anything else is relative + // A path starting with / or \ is absolute; anything else is relative. return ( $path[0] == '/' || $path[0] == '\\' ); } /** - * Join two filesystem paths together (e.g. 'give me $path relative to $base'). + * Join two filesystem paths together. * - * If the $path is absolute, then it the full path is returned. + * For example, 'give me $path relative to $base'. If the $path is absolute, + * then it the full path is returned. * * @since 2.5.0 * - * @param string $base - * @param string $path + * @param string $base Base path. + * @param string $path Path relative to $base. * @return string The path with the base or absolute path. */ function path_join( $base, $path ) { @@ -1415,18 +1573,35 @@ function path_join( $base, $path ) { } /** - * Determines a writable directory for temporary files. - * Function's preference is the return value of sys_get_temp_dir(), + * Normalize a filesystem path. + * + * Replaces backslashes with forward slashes for Windows systems, and ensures + * no duplicate slashes exist. + * + * @since 3.9.0 + * + * @param string $path Path to normalize. + * @return string Normalized path. + */ +function wp_normalize_path( $path ) { + $path = str_replace( '\\', '/', $path ); + $path = preg_replace( '|/+|','/', $path ); + return $path; +} + +/** + * Determine a writable directory for temporary files. + * + * Function's preference is the return value of sys_get_temp_dir(), * followed by your PHP temporary upload directory, followed by WP_CONTENT_DIR, * before finally defaulting to /tmp/ * * In the event that this function does not find a writable location, - * It may be overridden by the WP_TEMP_DIR constant in - * your wp-config.php file. + * It may be overridden by the WP_TEMP_DIR constant in your wp-config.php file. * * @since 2.5.0 * - * @return string Writable temporary directory + * @return string Writable temporary directory. */ function get_temp_dir() { static $temp; @@ -1434,17 +1609,17 @@ function get_temp_dir() { return trailingslashit(WP_TEMP_DIR); if ( $temp ) - return trailingslashit( rtrim( $temp, '\\' ) ); + return trailingslashit( $temp ); if ( function_exists('sys_get_temp_dir') ) { $temp = sys_get_temp_dir(); if ( @is_dir( $temp ) && wp_is_writable( $temp ) ) - return trailingslashit( rtrim( $temp, '\\' ) ); + return trailingslashit( $temp ); } $temp = ini_get('upload_tmp_dir'); - if ( is_dir( $temp ) && wp_is_writable( $temp ) ) - return trailingslashit( rtrim( $temp, '\\' ) ); + if ( @is_dir( $temp ) && wp_is_writable( $temp ) ) + return trailingslashit( $temp ); $temp = WP_CONTENT_DIR . '/'; if ( is_dir( $temp ) && wp_is_writable( $temp ) ) @@ -1457,15 +1632,15 @@ function get_temp_dir() { /** * Determine if a directory is writable. * - * This function is used to work around certain ACL issues - * in PHP primarily affecting Windows Servers. - * - * @see win_is_writable() + * This function is used to work around certain ACL issues in PHP primarily + * affecting Windows Servers. * * @since 3.6.0 * - * @param string $path - * @return bool + * @see win_is_writable() + * + * @param string $path Path to check for write-ability. + * @return bool Whether the path is writable. */ function wp_is_writable( $path ) { if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) ) @@ -1482,13 +1657,13 @@ function wp_is_writable( $path ) { * checking the ability to open files rather than relying * upon PHP to interprate the OS ACL. * - * @link http://bugs.php.net/bug.php?id=27609 - * @link http://bugs.php.net/bug.php?id=30931 - * * @since 2.8.0 * - * @param string $path - * @return bool + * @see http://bugs.php.net/bug.php?id=27609 + * @see http://bugs.php.net/bug.php?id=30931 + * + * @param string $path Windows path to check for write-ability. + * @return bool Whether the path is writable. */ function win_is_writable( $path ) { @@ -1536,9 +1711,8 @@ function win_is_writable( $path ) { * 'error' - set to false. * * @since 2.0.0 - * @uses apply_filters() Calls 'upload_dir' on returned array. * - * @param string $time Optional. Time formatted in 'yyyy/mm'. + * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null. * @return array See above for description. */ function wp_upload_dir( $time = null ) { @@ -1561,22 +1735,27 @@ function wp_upload_dir( $time = null ) { $url = trailingslashit( $siteurl ) . $upload_path; } - // Obey the value of UPLOADS. This happens as long as ms-files rewriting is disabled. - // We also sometimes obey UPLOADS when rewriting is enabled -- see the next block. + /* + * Honor the value of UPLOADS. This happens as long as ms-files rewriting is disabled. + * We also sometimes obey UPLOADS when rewriting is enabled -- see the next block. + */ if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) { $dir = ABSPATH . UPLOADS; $url = trailingslashit( $siteurl ) . UPLOADS; } // If multisite (and if not the main site in a post-MU network) - if ( is_multisite() && ! ( is_main_site() && defined( 'MULTISITE' ) ) ) { + if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) { if ( ! get_site_option( 'ms_files_rewriting' ) ) { - // If ms-files rewriting is disabled (networks created post-3.5), it is fairly straightforward: - // Append sites/%d if we're not on the main site (for post-MU networks). (The extra directory - // prevents a four-digit ID from conflicting with a year-based directory for the main site. - // But if a MU-era network has disabled ms-files rewriting manually, they don't need the extra - // directory, as they never had wp-content/uploads for the main site.) + /* + * If ms-files rewriting is disabled (networks created post-3.5), it is fairly + * straightforward: Append sites/%d if we're not on the main site (for post-MU + * networks). (The extra directory prevents a four-digit ID from conflicting with + * a year-based directory for the main site. But if a MU-era network has disabled + * ms-files rewriting manually, they don't need the extra directory, as they never + * had wp-content/uploads for the main site.) + */ if ( defined( 'MULTISITE' ) ) $ms_dir = '/sites/' . get_current_blog_id(); @@ -1587,17 +1766,19 @@ function wp_upload_dir( $time = null ) { $url .= $ms_dir; } elseif ( defined( 'UPLOADS' ) && ! ms_is_switched() ) { - // Handle the old-form ms-files.php rewriting if the network still has that enabled. - // When ms-files rewriting is enabled, then we only listen to UPLOADS when: - // 1) we are not on the main site in a post-MU network, - // as wp-content/uploads is used there, and - // 2) we are not switched, as ms_upload_constants() hardcodes - // these constants to reflect the original blog ID. - // - // Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute. - // (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as - // as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files - // rewriting in multisite, the resulting URL is /files. (#WP22702 for background.) + /* + * Handle the old-form ms-files.php rewriting if the network still has that enabled. + * When ms-files rewriting is enabled, then we only listen to UPLOADS when: + * 1) We are not on the main site in a post-MU network, as wp-content/uploads is used + * there, and + * 2) We are not switched, as ms_upload_constants() hardcodes these constants to reflect + * the original blog ID. + * + * Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute. + * (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as + * as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files + * rewriting in multisite, the resulting URL is /files. (#WP22702 for background.) + */ if ( defined( 'BLOGUPLOADDIR' ) ) $dir = untrailingslashit( BLOGUPLOADDIR ); @@ -1623,6 +1804,14 @@ function wp_upload_dir( $time = null ) { $dir .= $subdir; $url .= $subdir; + /** + * Filter the uploads directory data. + * + * @since 2.0.0 + * + * @param array $uploads Array of upload directory data with keys of 'path', + * 'url', 'subdir, 'basedir', and 'error'. + */ $uploads = apply_filters( 'upload_dir', array( 'path' => $dir, @@ -1633,7 +1822,7 @@ function wp_upload_dir( $time = null ) { 'error' => false, ) ); - // Make sure we have an uploads dir + // Make sure we have an uploads directory. if ( ! wp_mkdir_p( $uploads['path'] ) ) { if ( 0 === strpos( $uploads['basedir'], ABSPATH ) ) $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir']; @@ -1659,36 +1848,39 @@ function wp_upload_dir( $time = null ) { * * @since 2.5.0 * - * @param string $dir - * @param string $filename - * @param mixed $unique_filename_callback Callback. + * @param string $dir Directory. + * @param string $filename File name. + * @param callback $unique_filename_callback Callback. Default null. * @return string New filename, if given wasn't unique. */ function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) { - // sanitize the file name before we begin processing + // Sanitize the file name before we begin processing. $filename = sanitize_file_name($filename); - // separate the filename into a name and extension + // Separate the filename into a name and extension. $info = pathinfo($filename); $ext = !empty($info['extension']) ? '.' . $info['extension'] : ''; $name = basename($filename, $ext); - // edge case: if file is named '.ext', treat as an empty name + // Edge case: if file is named '.ext', treat as an empty name. if ( $name === $ext ) $name = ''; - // Increment the file number until we have a unique file to save in $dir. Use callback if supplied. + /* + * Increment the file number until we have a unique file to save in $dir. + * Use callback if supplied. + */ if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) { $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext ); } else { $number = ''; - // change '.ext' to lower case + // Change '.ext' to lower case. if ( $ext && strtolower($ext) != $ext ) { $ext2 = strtolower($ext); $filename2 = preg_replace( '|' . preg_quote($ext) . '$|', $ext2, $filename ); - // check for both lower and upper case extension or image sub-sizes may be overwritten + // Check for both lower and upper case extension or image sub-sizes may be overwritten. while ( file_exists($dir . "/$filename") || file_exists($dir . "/$filename2") ) { $new_number = $number + 1; $filename = str_replace( "$number$ext", "$new_number$ext", $filename ); @@ -1726,10 +1918,10 @@ function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) * * @since 2.0.0 * - * @param string $name - * @param null $deprecated Never used. Set to null. - * @param mixed $bits File content - * @param string $time Optional. Time formatted in 'yyyy/mm'. + * @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 */ function wp_upload_bits( $name, $deprecated, $bits, $time = null ) { @@ -1748,6 +1940,16 @@ function wp_upload_bits( $name, $deprecated, $bits, $time = null ) { if ( $upload['error'] !== false ) return $upload; + /** + * Filter 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. + * + * @since 3.0.0 + * + * @param mixed $upload_bits_error An array of upload bits data, or a non-array error to return. + */ $upload_bits_error = apply_filters( 'wp_upload_bits', array( 'name' => $name, 'bits' => $bits, 'time' => $time ) ); if ( !is_array( $upload_bits_error ) ) { $upload[ 'error' ] = $upload_bits_error; @@ -1791,27 +1993,42 @@ function wp_upload_bits( $name, $deprecated, $bits, $time = null ) { /** * Retrieve the file type based on the extension name. * - * @package WordPress * @since 2.5.0 - * @uses apply_filters() Calls 'ext2type' hook on default supported types. * * @param string $ext The extension to search. - * @return string|null The file type, example: audio, video, document, spreadsheet, etc. Null if not found. + * @return string|null The file type, example: audio, video, document, spreadsheet, etc. + * Null if not found. */ function wp_ext2type( $ext ) { + $ext = strtolower( $ext ); + + /** + * Filter file type based on the extension name. + * + * @since 2.5.0 + * + * @see wp_ext2type() + * + * @param array $ext2type Multi-dimensional array with extensions for a default set + * of file types. + */ $ext2type = apply_filters( 'ext2type', array( + 'image' => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico' ), 'audio' => array( 'aac', 'ac3', 'aif', 'aiff', 'm3a', 'm4a', 'm4b', 'mka', 'mp1', 'mp2', 'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ), - 'video' => array( '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', 'rtf', 'wp', 'wpd' ), + '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' ), 'spreadsheet' => array( 'numbers', 'ods', 'xls', 'xlsx', 'xlsm', 'xlsb' ), 'interactive' => array( 'swf', 'key', 'ppt', 'pptx', 'pptm', 'pps', 'ppsx', 'ppsm', 'sldx', 'sldm', 'odp' ), 'text' => array( 'asc', 'csv', 'tsv', 'txt' ), 'archive' => array( 'bz2', 'cab', 'dmg', 'gz', 'rar', 'sea', 'sit', 'sqx', 'tar', 'tgz', 'zip', '7z' ), 'code' => array( 'css', 'htm', 'html', 'php', 'js' ), - )); + ) ); + foreach ( $ext2type as $type => $exts ) if ( in_array( $ext, $exts ) ) return $type; + + return null; } /** @@ -1822,7 +2039,7 @@ function wp_ext2type( $ext ) { * @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. + * @param array $mimes Optional. Key is the file extension with value as the mime type. * @return array Values with extension first and mime type. */ function wp_check_filetype( $filename, $mimes = null ) { @@ -1845,6 +2062,7 @@ function wp_check_filetype( $filename, $mimes = null ) { /** * Attempt to determine the real file type of a file. + * * If unable to, the file name extension will be used to determine type. * * If it's determined that the extension does not match the file's real type, @@ -1854,10 +2072,12 @@ function wp_check_filetype( $filename, $mimes = null ) { * * @since 3.0.0 * - * @param string $file Full path to the image. - * @param string $filename The filename of the image (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 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. */ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) { @@ -1865,11 +2085,13 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) { // Do basic extension validation and MIME mapping $wp_filetype = wp_check_filetype( $filename, $mimes ); - extract( $wp_filetype ); + $ext = $wp_filetype['ext']; + $type = $wp_filetype['type']; // We can't do any further validation without a file to work with - if ( ! file_exists( $file ) ) + if ( ! file_exists( $file ) ) { return compact( 'ext', 'type', 'proper_filename' ); + } // We're able to validate images using GD if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) { @@ -1879,8 +2101,13 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) { // If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) { - // This is a simplified array of MIMEs that getimagesize() can detect and their extensions - // You shouldn't need to use this filter, but it's here just in case + /** + * Filter the list mapping image mime types to their respective extensions. + * + * @since 3.0.0 + * + * @param array $mime_to_ext Array of image mime types and their matching extensions. + */ $mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array( 'image/jpeg' => 'jpg', 'image/png' => 'png', @@ -1896,18 +2123,29 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) { $filename_parts[] = $mime_to_ext[ $imgstats['mime'] ]; $new_filename = implode( '.', $filename_parts ); - if ( $new_filename != $filename ) + if ( $new_filename != $filename ) { $proper_filename = $new_filename; // Mark that it changed - + } // Redefine the extension / MIME $wp_filetype = wp_check_filetype( $new_filename, $mimes ); - extract( $wp_filetype ); + $ext = $wp_filetype['ext']; + $type = $wp_filetype['type']; } } } - // Let plugins try and validate other types of files - // Should return an array in the style of array( 'ext' => $ext, 'type' => $type, 'proper_filename' => $proper_filename ) + /** + * Filter the "real" file type of the given file. + * + * @since 3.0.0 + * + * @param array $wp_check_filetype_and_ext File data array containing 'ext', 'type', and + * 'proper_filename' keys. + * @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. + */ return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes ); } @@ -1916,22 +2154,29 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) { * * @since 3.5.0 * - * @uses apply_filters() Calls 'mime_types' on returned array. This filter should - * be used to add types, not remove them. To remove types use the upload_mimes filter. - * * @return array Array of mime types keyed by the file extension regex corresponding to those types. */ function wp_get_mime_types() { - // Accepted MIME types are set here as PCRE unless provided. + /** + * Filter the list of mime types and file extensions. + * + * This filter should be used to add, not remove, mime types. To remove + * mime types, use the 'upload_mimes' filter. + * + * @since 3.5.0 + * + * @param array $wp_get_mime_types Mime types keyed by the file extension regex + * corresponding to those types. + */ return apply_filters( 'mime_types', array( - // Image formats + // Image formats. 'jpg|jpeg|jpe' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', 'bmp' => 'image/bmp', 'tif|tiff' => 'image/tiff', 'ico' => 'image/x-icon', - // Video formats + // Video formats. 'asf|asx' => 'video/x-ms-asf', 'wmv' => 'video/x-ms-wmv', 'wmx' => 'video/x-ms-wmx', @@ -1945,15 +2190,19 @@ function wp_get_mime_types() { 'ogv' => 'video/ogg', 'webm' => 'video/webm', 'mkv' => 'video/x-matroska', - // Text formats - 'txt|asc|c|cc|h' => 'text/plain', + '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', 'tsv' => 'text/tab-separated-values', 'ics' => 'text/calendar', 'rtx' => 'text/richtext', 'css' => 'text/css', 'htm|html' => 'text/html', - // Audio formats + 'vtt' => 'text/vtt', + 'dfxp' => 'application/ttaf+xml', + // Audio formats. 'mp3|m4a|m4b' => 'audio/mpeg', 'ra|ram' => 'audio/x-realaudio', 'wav' => 'audio/wav', @@ -1962,7 +2211,7 @@ function wp_get_mime_types() { 'wma' => 'audio/x-ms-wma', 'wax' => 'audio/x-ms-wax', 'mka' => 'audio/x-matroska', - // Misc application formats + // Misc application formats. 'rtf' => 'application/rtf', 'js' => 'application/javascript', 'pdf' => 'application/pdf', @@ -1974,7 +2223,8 @@ function wp_get_mime_types() { 'rar' => 'application/rar', '7z' => 'application/x-7z-compressed', 'exe' => 'application/x-msdownload', - // MS Office formats + 'psd' => 'application/octet-stream', + // MS Office formats. 'doc' => 'application/msword', 'pot|pps|ppt' => 'application/vnd.ms-powerpoint', 'wri' => 'application/vnd.ms-write', @@ -2001,7 +2251,9 @@ function wp_get_mime_types() { 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', 'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12', 'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote', - // OpenOffice formats + 'oxps' => 'application/oxps', + 'xps' => 'application/vnd.ms-xpsdocument', + // OpenOffice formats. 'odt' => 'application/vnd.oasis.opendocument.text', 'odp' => 'application/vnd.oasis.opendocument.presentation', 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', @@ -2009,9 +2261,9 @@ function wp_get_mime_types() { 'odc' => 'application/vnd.oasis.opendocument.chart', 'odb' => 'application/vnd.oasis.opendocument.database', 'odf' => 'application/vnd.oasis.opendocument.formula', - // WordPerfect formats + // WordPerfect formats. 'wp|wpd' => 'application/wordperfect', - // iWork formats + // iWork formats. 'key' => 'application/vnd.apple.keynote', 'numbers' => 'application/vnd.apple.numbers', 'pages' => 'application/vnd.apple.pages', @@ -2022,11 +2274,9 @@ function wp_get_mime_types() { * * @since 2.8.6 * - * @uses apply_filters() Calls 'upload_mimes' on returned array - * @uses wp_get_upload_mime_types() to fetch the list of mime types - * * @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 array 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(); @@ -2038,57 +2288,113 @@ function get_allowed_mime_types( $user = null ) { if ( empty( $unfiltered ) ) unset( $t['htm|html'] ); + /** + * Filter list of allowed mime types and file extensions. + * + * @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 int|WP_User|null $user User ID, User object or null if not provided (indicates current user). + */ return apply_filters( 'upload_mimes', $t, $user ); } /** * Display "Are You Sure" message to confirm the action being taken. * - * If the action has the nonce explain message, then it will be displayed along - * with the "Are you sure?" message. + * If the action has the nonce explain message, then it will be displayed + * along with the "Are you sure?" message. * - * @package WordPress - * @subpackage Security * @since 2.0.4 * * @param string $action The nonce action. */ function wp_nonce_ays( $action ) { - $title = __( 'WordPress Failure Notice' ); if ( 'log-out' == $action ) { $html = sprintf( __( 'You are attempting to log out of %s' ), get_bloginfo( 'name' ) ) . '

'; - $html .= sprintf( __( "Do you really want to log out?"), wp_logout_url() ); + $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : ''; + $html .= sprintf( __( "Do you really want to log out?"), wp_logout_url( $redirect_to ) ); } else { $html = __( 'Are you sure you want to do this?' ); if ( wp_get_referer() ) $html .= "

" . __( 'Please try again.' ) . ""; } - wp_die( $html, $title, array('response' => 403) ); + wp_die( $html, __( 'WordPress Failure Notice' ), 403 ); } /** * Kill WordPress execution and display HTML message with error message. * - * This function complements the die() PHP function. The difference is that + * This function complements the `die()` PHP function. The difference is that * HTML will be displayed to the user. It is recommended to use this function - * only, when the execution should not continue any further. It is not - * recommended to call this function very often and try to handle as many errors - * as possible silently. + * only when the execution should not continue any further. It is not recommended + * to call this function very often, and try to handle as many errors as possible + * silently or more gracefully. * - * @since 2.0.4 + * As a shorthand, the desired HTTP response code may be passed as an integer to + * the `$title` parameter (the default title would apply) or the `$args` parameter. * - * @param string $message Error message. - * @param string $title Error title. - * @param string|array $args Optional arguments to control behavior. + * @since 2.0.4 + * @since 4.1.0 The `$title` and `$args` parameters were changed to optionally accept + * an integer to be used as the response code. + * + * @param string|WP_Error $message Optional. Error message. If this is a {@see WP_Error} object, + * the error's messages are used. Default empty. + * @param string|int $title Optional. Error title. If `$message` is a `WP_Error` object, + * error data with the key 'title' may be used to specify the title. + * If `$title` is an integer, then it is treated as the response + * code. Default empty. + * @param string|array|int $args { + * Optional. Arguments to control behavior. If `$args` is an integer, then it is treated + * as the response code. Default empty array. + * + * @type int $response The HTTP response code. Default 500. + * @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'. + * Default is the value of {@see is_rtl()}. + * } */ function wp_die( $message = '', $title = '', $args = array() ) { - if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) + + if ( is_int( $args ) ) { + $args = array( 'response' => $args ); + } elseif ( is_int( $title ) ) { + $args = array( 'response' => $title ); + $title = ''; + } + + if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { + /** + * Filter callback for killing WordPress execution for AJAX requests. + * + * @since 3.4.0 + * + * @param callback $function Callback function name. + */ $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' ); - elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) + } elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) { + /** + * Filter callback for killing WordPress execution for XML-RPC requests. + * + * @since 3.4.0 + * + * @param callback $function Callback function name. + */ $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' ); - else + } else { + /** + * Filter callback for killing WordPress execution for all non-AJAX, non-XML-RPC requests. + * + * @since 3.0.0 + * + * @param callback $function Callback function name. + */ $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' ); + } call_user_func( $function, $message, $title, $args ); } @@ -2102,9 +2408,9 @@ function wp_die( $message = '', $title = '', $args = array() ) { * @since 3.0.0 * @access private * - * @param string $message Error message. - * @param string $title Error title. - * @param string|array $args Optional arguments to control behavior. + * @param string $message Error message. + * @param string $title Optional. Error title. Default empty. + * @param string|array $args Optional. Arguments to control behavior. Default empty array. */ function _default_wp_die_handler( $message, $title = '', $args = array() ) { $defaults = array( 'response' => 500 ); @@ -2119,7 +2425,7 @@ function _default_wp_die_handler( $message, $title = '', $args = array() ) { $title = $error_data['title']; } $errors = $message->get_error_messages(); - switch ( count( $errors ) ) : + switch ( count( $errors ) ) { case 0 : $message = ''; break; @@ -2129,7 +2435,7 @@ function _default_wp_die_handler( $message, $title = '', $args = array() ) { default : $message = "

"; break; - endswitch; + } } elseif ( is_string( $message ) ) { $message = "

$message

"; } @@ -2164,24 +2470,23 @@ function _default_wp_die_handler( $message, $title = '', $args = array() ) { <?php echo $title ?>