+/**
+ * Build URL query based on an associative and, or indexed array.
+ *
+ * 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
+ * @see http://us2.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.
+ * @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).
+ *
+ * @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 ) {
+ if ( $urlencode)
+ $k = urlencode($k);
+ if ( is_int($k) && $prefix != null )
+ $k = $prefix.$k;
+ if ( !empty($key) )
+ $k = $key . '%5B' . $k . '%5D';
+ if ( $v === null )
+ continue;
+ elseif ( $v === false )
+ $v = '0';
+
+ if ( is_array($v) || is_object($v) )
+ array_push($ret,_http_build_query($v, '', $sep, $k, $urlencode));
+ elseif ( $urlencode )
+ array_push($ret, $k.'='.urlencode($v));
+ else
+ array_push($ret, $k.'='.$v);
+ }
+
+ if ( null === $sep )
+ $sep = ini_get('arg_separator.output');
+
+ return implode($sep, $ret);
+}
+
+/**
+ * Retrieve a modified URL query string.
+ *
+ * You can rebuild the URL and append a new query variable to the URL query by
+ * using this function. You can also retrieve the full URL with query data.
+ *
+ * Adding a single key & value or an associative array. Setting a key value to
+ * an empty string removes the key. Omitting oldquery_or_uri uses the $_SERVER
+ * value. Additional values provided are expected to be encoded appropriately
+ * with urlencode() or rawurlencode().
+ *
+ * @since 1.5.0
+ *
+ * @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() {
+ $args = func_get_args();
+ if ( is_array( $args[0] ) ) {
+ if ( count( $args ) < 2 || false === $args[1] )
+ $uri = $_SERVER['REQUEST_URI'];
+ else
+ $uri = $args[1];
+ } else {
+ if ( count( $args ) < 3 || false === $args[2] )
+ $uri = $_SERVER['REQUEST_URI'];
+ else
+ $uri = $args[2];
+ }
+
+ if ( $frag = strstr( $uri, '#' ) )
+ $uri = substr( $uri, 0, -strlen( $frag ) );
+ else
+ $frag = '';
+
+ if ( 0 === stripos( $uri, 'http://' ) ) {
+ $protocol = 'http://';
+ $uri = substr( $uri, 7 );
+ } elseif ( 0 === stripos( $uri, 'https://' ) ) {
+ $protocol = 'https://';
+ $uri = substr( $uri, 8 );
+ } else {
+ $protocol = '';
+ }
+
+ if ( strpos( $uri, '?' ) !== false ) {
+ list( $base, $query ) = explode( '?', $uri, 2 );
+ $base .= '?';
+ } elseif ( $protocol || strpos( $uri, '=' ) === false ) {
+ $base = $uri . '?';
+ $query = '';
+ } else {
+ $base = '';
+ $query = $uri;
+ }
+
+ wp_parse_str( $query, $qs );
+ $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;
+ }
+ } else {
+ $qs[ $args[0] ] = $args[1];
+ }
+
+ foreach ( $qs as $k => $v ) {
+ if ( $v === false )
+ unset( $qs[$k] );
+ }
+
+ $ret = build_query( $qs );
+ $ret = trim( $ret, '?' );
+ $ret = preg_replace( '#=(&|$)#', '$1', $ret );
+ $ret = $protocol . $base . $ret . $frag;
+ $ret = rtrim( $ret, '?' );
+ return $ret;
+}
+
+/**
+ * Removes an item or list from the query string.
+ *
+ * @since 1.5.0
+ *
+ * @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 ) {
+ if ( is_array( $key ) ) { // removing multiple keys
+ foreach ( $key as $k )
+ $query = add_query_arg( $k, false, $query );
+ return $query;
+ }
+ return add_query_arg( $key, false, $query );
+}
+
+/**
+ * Walks the array while sanitizing the contents.
+ *
+ * @since 0.71
+ *
+ * @param array $array Array to walk while sanitizing contents.
+ * @return array Sanitized $array.
+ */
+function add_magic_quotes( $array ) {
+ foreach ( (array) $array as $k => $v ) {
+ if ( is_array( $v ) ) {
+ $array[$k] = add_magic_quotes( $v );
+ } else {
+ $array[$k] = addslashes( $v );
+ }
+ }
+ return $array;
+}
+
+/**
+ * HTTP request for URI to retrieve content.
+ *
+ * @since 1.5.1
+ *
+ * @see wp_safe_remote_get()
+ *
+ * @param string $uri URI/URL of web page to retrieve.
+ * @return false|string HTTP content. False on failure.
+ */
+function wp_remote_fopen( $uri ) {
+ $parsed_url = @parse_url( $uri );
+
+ if ( !$parsed_url || !is_array( $parsed_url ) )
+ return false;
+
+ $options = array();
+ $options['timeout'] = 10;
+
+ $response = wp_safe_remote_get( $uri, $options );
+
+ if ( is_wp_error( $response ) )
+ return false;
+
+ return wp_remote_retrieve_body( $response );
+}
+
+/**
+ * Set up the WordPress query.
+ *
+ * @since 2.0.0
+ *
+ * @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) )
+ $wp_the_query = $wp_query;
+}
+
+/**
+ * Retrieve the description for the HTTP status.
+ *
+ * @since 2.3.0
+ *
+ * @param int $code HTTP status code.
+ * @return string Empty string if not found, or description if found.
+ */
+function get_status_header_desc( $code ) {
+ global $wp_header_to_desc;
+
+ $code = absint( $code );
+
+ if ( !isset( $wp_header_to_desc ) ) {
+ $wp_header_to_desc = array(
+ 100 => 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing',
+
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-Status',
+ 226 => 'IM Used',
+
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 306 => 'Reserved',
+ 307 => 'Temporary Redirect',
+
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Timeout',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Long',
+ 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',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version Not Supported',
+ 506 => 'Variant Also Negotiates',
+ 507 => 'Insufficient Storage',
+ 510 => 'Not Extended',
+ 511 => 'Network Authentication Required',
+ );
+ }
+
+ if ( isset( $wp_header_to_desc[$code] ) )
+ return $wp_header_to_desc[$code];
+ else
+ return '';
+}
+
+/**
+ * Set HTTP status header.
+ *
+ * @since 2.0.0
+ *
+ * @see get_status_header_desc()
+ *
+ * @param int $code HTTP status code.
+ */
+function status_header( $code ) {
+ $description = get_status_header_desc( $code );
+
+ if ( empty( $description ) )
+ return;
+
+ $protocol = $_SERVER['SERVER_PROTOCOL'];
+ if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol )
+ $protocol = 'HTTP/1.0';
+ $status_header = "$protocol $code $description";
+ if ( function_exists( 'apply_filters' ) )
+
+ /**
+ * 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 );
+}
+
+/**
+ * Get the header information to prevent caching.
+ *
+ * The several different headers cover the different ways cache prevention
+ * is handled by different browsers
+ *
+ * @since 2.8.0
+ *
+ * @return array The associative array of header names and field values.
+ */
+function wp_get_nocache_headers() {
+ $headers = array(
+ 'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
+ 'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
+ 'Pragma' => 'no-cache',
+ );
+
+ if ( function_exists('apply_filters') ) {
+ /**
+ * 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;
+}
+
+/**
+ * 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.
+ *
+ * @since 2.0.0
+ *
+ * @see wp_get_nocache_headers()
+ */
+function nocache_headers() {
+ $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;
+ }
+ }
+ }
+
+ foreach( $headers as $name => $field_value )
+ @header("{$name}: {$field_value}");
+}
+
+/**
+ * Set the headers for caching for 10 days with JavaScript content type.
+ *
+ * @since 2.1.0
+ */
+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" );
+}
+
+/**
+ * Retrieve the number of database queries during the WordPress execution.
+ *
+ * @since 2.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @return int Number of database queries.
+ */
+function get_num_queries() {
+ global $wpdb;
+ return $wpdb->num_queries;
+}
+
+/**
+ * Whether input is yes or no.
+ *
+ * Must be 'y' to be true.
+ *
+ * @since 1.0.0
+ *
+ * @param string $yn Character string containing either 'y' (yes) or 'n' (no).
+ * @return bool True if yes, false on anything else.
+ */
+function bool_from_yn( $yn ) {
+ return ( strtolower( $yn ) == 'y' );
+}
+
+/**
+ * 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.
+ *
+ * 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.
+ */
+function do_feed() {
+ global $wp_query;
+
+ $feed = get_query_var( 'feed' );
+
+ // Remove the pad, if present.
+ $feed = preg_replace( '/^_+/', '', $feed );
+
+ if ( $feed == '' || $feed == 'feed' )
+ $feed = get_default_feed();
+
+ $hook = 'do_feed_' . $feed;
+ 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 );
+}
+
+/**
+ * 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' );
+}
+
+/**
+ * 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' );
+}
+
+/**
+ * Load either the RSS2 comment feed or the RSS2 posts feed.
+ *
+ * @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 ) {
+ if ( $for_comments )
+ load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' );
+ else
+ load_template( ABSPATH . WPINC . '/feed-rss2.php' );
+}
+
+/**
+ * Load either Atom comment feed or Atom posts feed.
+ *
+ * @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 ) {
+ if ($for_comments)
+ load_template( ABSPATH . WPINC . '/feed-atom-comments.php');
+ else
+ load_template( ABSPATH . WPINC . '/feed-atom.php' );
+}
+
+/**
+ * Display the robots.txt file content.
+ *
+ * The echo content should be with usage of the permalinks or for creating the
+ * robots.txt file.
+ *
+ * @since 2.1.0
+ */
+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";
+ $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";
+ }
+
+ /**
+ * 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.
+ *
+ * Checks for the 'siteurl' option for whether WordPress is installed.
+ *
+ * @since 2.1.0
+ *
+ * @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.
+ */
+ if ( wp_cache_get( 'is_blog_installed' ) )
+ return true;
+
+ $suppress = $wpdb->suppress_errors();
+ if ( ! defined( 'WP_INSTALLING' ) ) {
+ $alloptions = wp_load_alloptions();
+ }
+ // 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
+ $installed = $alloptions['siteurl'];
+ $wpdb->suppress_errors( $suppress );
+
+ $installed = !empty( $installed );
+ wp_cache_set( 'is_blog_installed', $installed );
+
+ if ( $installed )
+ return true;
+
+ // If visiting repair.php, return true and let it take over.
+ if ( defined( 'WP_REPAIRING' ) )
+ return true;
+
+ $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.
+ */
+ $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.
+ if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table )
+ continue;
+ if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE == $table )
+ continue;
+
+ if ( ! $wpdb->get_results( "DESCRIBE $table;" ) )
+ continue;
+
+ // One or more tables exist. We are insane.
+
+ wp_load_translations_early();
+
+ // Die with a DB error.
+ $wpdb->error = sprintf( __( 'One or more database tables are unavailable. The database may need to be <a href="%s">repaired</a>.' ), 'maint/repair.php?referrer=is_blog_installed' );
+ dead_db();
+ }
+
+ $wpdb->suppress_errors( $suppress );
+
+ wp_cache_set( 'is_blog_installed', false );
+
+ return false;
+}
+
+/**
+ * Retrieve URL with nonce added to URL query.
+ *
+ * @since 2.0.4
+ *
+ * @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 );
+ return esc_html( add_query_arg( $name, wp_create_nonce( $action ), $actionurl ) );
+}
+
+/**
+ * Retrieve or display nonce hidden field for forms.
+ *
+ * The nonce field is used to validate that the contents of the form came from
+ * the location on the current site and not somewhere else. The nonce does not
+ * offer absolute protection, but should protect against most cases. It is very
+ * important to use nonce field in forms.
+ *
+ * The $action and $name are optional, but if you want to have better security,
+ * it is strongly suggested to set those two parameters. It is easier to just
+ * call the function without any parameters, because validation of the nonce
+ * doesn't require any parameters, but since crackers know what the default is
+ * it won't be difficult for them to find a way around your nonce and cause
+ * damage.
+ *
+ * The input name will be whatever $name value you gave. The input value will be
+ * the nonce creation value.
+ *
+ * @since 2.0.4
+ *
+ * @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 );
+ $nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />';
+
+ if ( $referer )
+ $nonce_field .= wp_referer_field( false );
+
+ if ( $echo )
+ echo $nonce_field;
+
+ return $nonce_field;
+}
+
+/**
+ * Retrieve or display referer hidden field for forms.
+ *
+ * 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.
+ *
+ * @since 2.0.4
+ *
+ * @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 = '<input type="hidden" name="_wp_http_referer" value="'. esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
+
+ if ( $echo )
+ echo $referer_field;
+ return $referer_field;
+}
+
+/**
+ * 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 wp_referer_field(), if that was posted already or it will be the
+ * current page, if it doesn't exist.
+ *
+ * @since 2.0.4
+ *
+ * @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' ) {
+ if ( ! $ref = wp_get_original_referer() ) {
+ $ref = 'previous' == $jump_back_to ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] );
+ }
+ $orig_referer_field = '<input type="hidden" name="_wp_original_http_referer" value="' . esc_attr( $ref ) . '" />';
+ if ( $echo )
+ echo $orig_referer_field;
+ return $orig_referer_field;
+}
+
+/**
+ * Retrieve referer from '_wp_http_referer' or HTTP referer.
+ *
+ * If it's the same as the current request URL, will return false.
+ *
+ * @since 2.0.4
+ *
+ * @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'] );
+ elseif ( ! empty( $_SERVER['HTTP_REFERER'] ) )
+ $ref = wp_unslash( $_SERVER['HTTP_REFERER'] );
+
+ if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) )
+ return wp_validate_redirect( $ref, false );
+ return false;
+}
+
+/**
+ * Retrieve original referer that was posted, if it exists.
+ *
+ * @since 2.0.4
+ *
+ * @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'] ) && function_exists( 'wp_validate_redirect' ) )
+ return wp_validate_redirect( wp_unslash( $_REQUEST['_wp_original_http_referer'] ), false );
+ return false;
+}
+
+/**
+ * Recursive directory creation based on full path.
+ *
+ * Will attempt to set permissions on folders.
+ *
+ * @since 2.0.1
+ *
+ * @param string $target Full path to attempt to create.
+ * @return bool Whether the path was created. True if path already exists.
+ */
+function wp_mkdir_p( $target ) {
+ $wrapper = null;
+
+ // Strip the protocol.
+ if( wp_is_stream( $target ) ) {
+ list( $wrapper, $target ) = explode( '://', $target, 2 );
+ }
+
+ // From php.net/mkdir user contributed notes.
+ $target = str_replace( '//', '/', $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.
+ * 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 );
+
+ // 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 );
+ }
+
+ // 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, $c = count( $folder_parts ); $i <= $c; $i++ ) {
+ @chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms );
+ }