+/**
+ * Check if IIS 7 supports pretty permalinks.
+ *
+ * @since 2.8.0
+ *
+ * @return bool
+ */
+function iis7_supports_permalinks() {
+ global $is_iis7;
+
+ $supports_permalinks = false;
+ if ( $is_iis7 ) {
+ /* First we check if the DOMDocument class exists. If it does not exist,
+ * which is the case for PHP 4.X, then we cannot easily update the xml configuration file,
+ * hence we just bail out and tell user that pretty permalinks cannot be used.
+ * This is not a big issue because PHP 4.X is going to be deprecated and for IIS it
+ * is recommended to use PHP 5.X NTS.
+ * Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the web site. When
+ * URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
+ * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
+ * via ISAPI then pretty permalinks will not work.
+ */
+ $supports_permalinks = class_exists('DOMDocument') && isset($_SERVER['IIS_UrlRewriteModule']) && ( php_sapi_name() == 'cgi-fcgi' );
+ }
+
+ return apply_filters('iis7_supports_permalinks', $supports_permalinks);
+}
+
+/**
+ * File validates against allowed set of defined rules.
+ *
+ * A return value of '1' means that the $file contains either '..' or './'. A
+ * return value of '2' means that the $file contains ':' after the first
+ * character. A return value of '3' means that the file is not in the allowed
+ * files list.
+ *
+ * @since 1.2.0
+ *
+ * @param string $file File path.
+ * @param array $allowed_files List of allowed files.
+ * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
+ */
+function validate_file( $file, $allowed_files = '' ) {
+ if ( false !== strpos( $file, '..' ) )
+ return 1;
+
+ if ( false !== strpos( $file, './' ) )
+ return 1;
+
+ if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) )
+ return 3;
+
+ if (':' == substr( $file, 1, 1 ) )
+ return 2;
+
+ return 0;
+}
+
+/**
+ * Determine if SSL is used.
+ *
+ * @since 2.6.0
+ *
+ * @return bool True if SSL, false if not used.
+ */
+function is_ssl() {
+ if ( isset($_SERVER['HTTPS']) ) {
+ if ( 'on' == strtolower($_SERVER['HTTPS']) )
+ return true;
+ if ( '1' == $_SERVER['HTTPS'] )
+ return true;
+ } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Whether SSL login should be forced.
+ *
+ * @since 2.6.0
+ *
+ * @param string|bool $force Optional.
+ * @return bool True if forced, false if not forced.
+ */
+function force_ssl_login( $force = null ) {
+ static $forced = false;
+
+ if ( !is_null( $force ) ) {
+ $old_forced = $forced;
+ $forced = $force;
+ return $old_forced;
+ }
+
+ return $forced;
+}
+
+/**
+ * Whether to force SSL used for the Administration Screens.
+ *
+ * @since 2.6.0
+ *
+ * @param string|bool $force
+ * @return bool True if forced, false if not forced.
+ */
+function force_ssl_admin( $force = null ) {
+ static $forced = false;
+
+ if ( !is_null( $force ) ) {
+ $old_forced = $forced;
+ $forced = $force;
+ return $old_forced;
+ }
+
+ return $forced;
+}
+
+/**
+ * Guess the URL for the site.
+ *
+ * Will remove wp-admin links to retrieve only return URLs not in the wp-admin
+ * directory.
+ *
+ * @since 2.6.0
+ *
+ * @return string
+ */
+function wp_guess_url() {
+ if ( defined('WP_SITEURL') && '' != WP_SITEURL ) {
+ $url = WP_SITEURL;
+ } else {
+ $schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet
+ $url = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $schema . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
+ }
+
+ return rtrim($url, '/');
+}
+
+/**
+ * Temporarily suspend cache additions.
+ *
+ * Stops more data being added to the cache, but still allows cache retrieval.
+ * This is useful for actions, such as imports, when a lot of data would otherwise
+ * be almost uselessly added to the cache.
+ *
+ * Suspension lasts for a single page load at most. Remember to call this
+ * function again if you wish to re-enable cache adds earlier.
+ *
+ * @since 3.3.0
+ *
+ * @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
+ * @return bool The current suspend setting
+ */
+function wp_suspend_cache_addition( $suspend = null ) {
+ static $_suspend = false;
+
+ if ( is_bool( $suspend ) )
+ $_suspend = $suspend;
+
+ return $_suspend;
+}
+
+/**
+ * Suspend cache invalidation.
+ *
+ * Turns cache invalidation on and off. Useful during imports where you don't wont to do invalidations
+ * every time a post is inserted. Callers must be sure that what they are doing won't lead to an inconsistent
+ * cache when invalidation is suspended.
+ *
+ * @since 2.7.0
+ *
+ * @param bool $suspend Whether to suspend or enable cache invalidation
+ * @return bool The current suspend setting
+ */
+function wp_suspend_cache_invalidation($suspend = true) {
+ global $_wp_suspend_cache_invalidation;
+
+ $current_suspend = $_wp_suspend_cache_invalidation;
+ $_wp_suspend_cache_invalidation = $suspend;
+ return $current_suspend;
+}
+
+/**
+ * Is main site?
+ *
+ *
+ * @since 3.0.0
+ * @package WordPress
+ *
+ * @param int $blog_id optional blog id to test (default current blog)
+ * @return bool True if not multisite or $blog_id is main site
+ */
+function is_main_site( $blog_id = '' ) {
+ global $current_site;
+
+ if ( ! is_multisite() )
+ return true;
+
+ if ( ! $blog_id )
+ $blog_id = get_current_blog_id();
+
+ return $blog_id == $current_site->blog_id;
+}
+
+/**
+ * Whether global terms are enabled.
+ *
+ *
+ * @since 3.0.0
+ * @package WordPress
+ *
+ * @return bool True if multisite and global terms enabled
+ */
+function global_terms_enabled() {
+ if ( ! is_multisite() )
+ return false;
+
+ static $global_terms = null;
+ if ( is_null( $global_terms ) ) {
+ $filter = apply_filters( 'global_terms_enabled', null );
+ if ( ! is_null( $filter ) )
+ $global_terms = (bool) $filter;
+ else
+ $global_terms = (bool) get_site_option( 'global_terms_enabled', false );
+ }
+ return $global_terms;
+}
+
+/**
+ * gmt_offset modification for smart timezone handling.
+ *
+ * Overrides the gmt_offset option if we have a timezone_string available.
+ *
+ * @since 2.8.0
+ *
+ * @return float|bool
+ */
+function wp_timezone_override_offset() {
+ if ( !$timezone_string = get_option( 'timezone_string' ) ) {
+ return false;
+ }
+
+ $timezone_object = timezone_open( $timezone_string );
+ $datetime_object = date_create();
+ if ( false === $timezone_object || false === $datetime_object ) {
+ return false;
+ }
+ return round( timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS, 2 );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.9.0
+ *
+ * @param unknown_type $a
+ * @param unknown_type $b
+ * @return int
+ */
+function _wp_timezone_choice_usort_callback( $a, $b ) {
+ // Don't use translated versions of Etc
+ if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
+ // Make the order of these more like the old dropdown
+ if ( 'GMT+' === substr( $a['city'], 0, 4 ) && 'GMT+' === substr( $b['city'], 0, 4 ) ) {
+ return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
+ }
+ if ( 'UTC' === $a['city'] ) {
+ if ( 'GMT+' === substr( $b['city'], 0, 4 ) ) {
+ return 1;
+ }
+ return -1;
+ }
+ if ( 'UTC' === $b['city'] ) {
+ if ( 'GMT+' === substr( $a['city'], 0, 4 ) ) {
+ return -1;
+ }
+ return 1;
+ }
+ return strnatcasecmp( $a['city'], $b['city'] );
+ }
+ if ( $a['t_continent'] == $b['t_continent'] ) {
+ if ( $a['t_city'] == $b['t_city'] ) {
+ return strnatcasecmp( $a['t_subcity'], $b['t_subcity'] );
+ }
+ return strnatcasecmp( $a['t_city'], $b['t_city'] );
+ } else {
+ // Force Etc to the bottom of the list
+ if ( 'Etc' === $a['continent'] ) {
+ return 1;
+ }
+ if ( 'Etc' === $b['continent'] ) {
+ return -1;
+ }
+ return strnatcasecmp( $a['t_continent'], $b['t_continent'] );
+ }
+}
+
+/**
+ * Gives a nicely formatted list of timezone strings. // temporary! Not in final
+ *
+ * @since 2.9.0
+ *
+ * @param string $selected_zone Selected Zone
+ * @return string
+ */
+function wp_timezone_choice( $selected_zone ) {
+ static $mo_loaded = false;
+
+ $continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific');
+
+ // Load translations for continents and cities
+ if ( !$mo_loaded ) {
+ $locale = get_locale();
+ $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
+ load_textdomain( 'continents-cities', $mofile );
+ $mo_loaded = true;
+ }
+
+ $zonen = array();
+ foreach ( timezone_identifiers_list() as $zone ) {
+ $zone = explode( '/', $zone );
+ if ( !in_array( $zone[0], $continents ) ) {
+ continue;
+ }
+
+ // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
+ $exists = array(
+ 0 => ( isset( $zone[0] ) && $zone[0] ),
+ 1 => ( isset( $zone[1] ) && $zone[1] ),
+ 2 => ( isset( $zone[2] ) && $zone[2] ),
+ );
+ $exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
+ $exists[4] = ( $exists[1] && $exists[3] );
+ $exists[5] = ( $exists[2] && $exists[3] );
+
+ $zonen[] = array(
+ 'continent' => ( $exists[0] ? $zone[0] : '' ),
+ 'city' => ( $exists[1] ? $zone[1] : '' ),
+ 'subcity' => ( $exists[2] ? $zone[2] : '' ),
+ 't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
+ 't_city' => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
+ 't_subcity' => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' )
+ );
+ }
+ usort( $zonen, '_wp_timezone_choice_usort_callback' );
+
+ $structure = array();
+
+ if ( empty( $selected_zone ) ) {
+ $structure[] = '<option selected="selected" value="">' . __( 'Select a city' ) . '</option>';
+ }
+
+ foreach ( $zonen as $key => $zone ) {
+ // Build value in an array to join later
+ $value = array( $zone['continent'] );
+
+ if ( empty( $zone['city'] ) ) {
+ // It's at the continent level (generally won't happen)
+ $display = $zone['t_continent'];
+ } else {
+ // It's inside a continent group
+
+ // Continent optgroup
+ if ( !isset( $zonen[$key - 1] ) || $zonen[$key - 1]['continent'] !== $zone['continent'] ) {
+ $label = $zone['t_continent'];
+ $structure[] = '<optgroup label="'. esc_attr( $label ) .'">';
+ }
+
+ // Add the city to the value
+ $value[] = $zone['city'];
+
+ $display = $zone['t_city'];
+ if ( !empty( $zone['subcity'] ) ) {
+ // Add the subcity to the value
+ $value[] = $zone['subcity'];
+ $display .= ' - ' . $zone['t_subcity'];
+ }
+ }
+
+ // Build the value
+ $value = join( '/', $value );
+ $selected = '';
+ if ( $value === $selected_zone ) {
+ $selected = 'selected="selected" ';
+ }
+ $structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . "</option>";
+
+ // Close continent optgroup
+ if ( !empty( $zone['city'] ) && ( !isset($zonen[$key + 1]) || (isset( $zonen[$key + 1] ) && $zonen[$key + 1]['continent'] !== $zone['continent']) ) ) {
+ $structure[] = '</optgroup>';
+ }
+ }
+
+ // Do UTC
+ $structure[] = '<optgroup label="'. esc_attr__( 'UTC' ) .'">';
+ $selected = '';
+ if ( 'UTC' === $selected_zone )
+ $selected = 'selected="selected" ';
+ $structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __('UTC') . '</option>';
+ $structure[] = '</optgroup>';
+
+ // Do manual UTC offsets
+ $structure[] = '<optgroup label="'. esc_attr__( 'Manual Offsets' ) .'">';
+ $offset_range = array (-12, -11.5, -11, -10.5, -10, -9.5, -9, -8.5, -8, -7.5, -7, -6.5, -6, -5.5, -5, -4.5, -4, -3.5, -3, -2.5, -2, -1.5, -1, -0.5,
+ 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 5.75, 6, 6.5, 7, 7.5, 8, 8.5, 8.75, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 13.75, 14);
+ foreach ( $offset_range as $offset ) {
+ if ( 0 <= $offset )
+ $offset_name = '+' . $offset;
+ else
+ $offset_name = (string) $offset;
+
+ $offset_value = $offset_name;
+ $offset_name = str_replace(array('.25','.5','.75'), array(':15',':30',':45'), $offset_name);
+ $offset_name = 'UTC' . $offset_name;
+ $offset_value = 'UTC' . $offset_value;
+ $selected = '';
+ if ( $offset_value === $selected_zone )
+ $selected = 'selected="selected" ';
+ $structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . "</option>";
+
+ }
+ $structure[] = '</optgroup>';
+
+ return join( "\n", $structure );
+}
+
+/**
+ * Strip close comment and close php tags from file headers used by WP.
+ * See http://core.trac.wordpress.org/ticket/8497
+ *
+ * @since 2.8.0
+ *
+ * @param string $str
+ * @return string
+ */
+function _cleanup_header_comment($str) {
+ return trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $str));
+}
+
+/**
+ * Permanently deletes posts, pages, attachments, and comments which have been in the trash for EMPTY_TRASH_DAYS.
+ *
+ * @since 2.9.0
+ */
+function wp_scheduled_delete() {
+ global $wpdb;
+
+ $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
+
+ $posts_to_delete = $wpdb->get_results($wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < '%d'", $delete_timestamp), ARRAY_A);
+
+ foreach ( (array) $posts_to_delete as $post ) {
+ $post_id = (int) $post['post_id'];
+ if ( !$post_id )
+ continue;
+
+ $del_post = get_post($post_id);
+
+ if ( !$del_post || 'trash' != $del_post->post_status ) {
+ delete_post_meta($post_id, '_wp_trash_meta_status');
+ delete_post_meta($post_id, '_wp_trash_meta_time');
+ } else {
+ wp_delete_post($post_id);
+ }
+ }
+
+ $comments_to_delete = $wpdb->get_results($wpdb->prepare("SELECT comment_id FROM $wpdb->commentmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < '%d'", $delete_timestamp), ARRAY_A);
+
+ foreach ( (array) $comments_to_delete as $comment ) {
+ $comment_id = (int) $comment['comment_id'];
+ if ( !$comment_id )
+ continue;
+
+ $del_comment = get_comment($comment_id);
+
+ if ( !$del_comment || 'trash' != $del_comment->comment_approved ) {
+ delete_comment_meta($comment_id, '_wp_trash_meta_time');
+ delete_comment_meta($comment_id, '_wp_trash_meta_status');
+ } else {
+ wp_delete_comment($comment_id);
+ }
+ }
+}
+
+/**
+ * Retrieve metadata from a file.
+ *
+ * Searches for metadata in the first 8kiB of a file, such as a plugin or theme.
+ * Each piece of metadata must be on its own line. Fields can not span multiple
+ * lines, the value will get cut at the end of the first line.
+ *
+ * If the file data is not within that first 8kiB, then the author should correct
+ * their plugin file and move the data headers to the top.
+ *
+ * @see http://codex.wordpress.org/File_Header
+ *
+ * @since 2.9.0
+ * @param string $file Path to the file
+ * @param array $default_headers List of headers, in the format array('HeaderKey' => 'Header Name')
+ * @param string $context If specified adds filter hook "extra_{$context}_headers"
+ */
+function get_file_data( $file, $default_headers, $context = '' ) {
+ // We don't need to write to the file, so just open for reading.
+ $fp = fopen( $file, 'r' );
+
+ // Pull only the first 8kiB of the file in.
+ $file_data = fread( $fp, 8192 );
+
+ // PHP will close file handle, but we are good citizens.
+ fclose( $fp );
+
+ // Make sure we catch CR-only line endings.
+ $file_data = str_replace( "\r", "\n", $file_data );
+
+ if ( $context && $extra_headers = apply_filters( "extra_{$context}_headers", array() ) ) {
+ $extra_headers = array_combine( $extra_headers, $extra_headers ); // keys equal values
+ $all_headers = array_merge( $extra_headers, (array) $default_headers );
+ } else {
+ $all_headers = $default_headers;
+ }
+
+ foreach ( $all_headers as $field => $regex ) {
+ if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] )
+ $all_headers[ $field ] = _cleanup_header_comment( $match[1] );
+ else
+ $all_headers[ $field ] = '';
+ }
+
+ return $all_headers;
+}
+
+/**
+ * Used internally to tidy up the search terms.
+ *
+ * @access private
+ * @since 2.9.0
+ *
+ * @param string $t
+ * @return string
+ */
+function _search_terms_tidy($t) {
+ return trim($t, "\"'\n\r ");
+}
+
+/**
+ * Returns true.
+ *
+ * Useful for returning true to filters easily.
+ *
+ * @since 3.0.0
+ * @see __return_false()
+ * @return bool true
+ */
+function __return_true() {
+ return true;
+}
+
+/**
+ * Returns false.
+ *
+ * Useful for returning false to filters easily.
+ *
+ * @since 3.0.0
+ * @see __return_true()
+ * @return bool false
+ */
+function __return_false() {
+ return false;
+}
+
+/**
+ * Returns 0.
+ *
+ * Useful for returning 0 to filters easily.
+ *
+ * @since 3.0.0
+ * @see __return_zero()
+ * @return int 0
+ */
+function __return_zero() {
+ return 0;
+}
+
+/**
+ * Returns an empty array.
+ *
+ * Useful for returning an empty array to filters easily.
+ *
+ * @since 3.0.0
+ * @see __return_zero()
+ * @return array Empty array
+ */
+function __return_empty_array() {
+ return array();
+}
+
+/**
+ * Returns null.
+ *
+ * Useful for returning null to filters easily.
+ *
+ * @since 3.4.0
+ * @return null
+ */
+function __return_null() {
+ return null;
+}
+
+/**
+ * Send a HTTP header to disable content type sniffing in browsers which support it.
+ *
+ * @link http://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
+ * @link http://src.chromium.org/viewvc/chrome?view=rev&revision=6985
+ *
+ * @since 3.0.0
+ * @return none
+ */
+function send_nosniff_header() {
+ @header( 'X-Content-Type-Options: nosniff' );
+}
+
+/**
+ * Returns a MySQL expression for selecting the week number based on the start_of_week option.
+ *
+ * @internal
+ * @since 3.0.0
+ * @param string $column
+ * @return string
+ */
+function _wp_mysql_week( $column ) {
+ switch ( $start_of_week = (int) get_option( 'start_of_week' ) ) {
+ default :
+ case 0 :
+ return "WEEK( $column, 0 )";
+ case 1 :
+ return "WEEK( $column, 1 )";
+ case 2 :
+ case 3 :
+ case 4 :
+ case 5 :
+ case 6 :
+ return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
+ }
+}
+
+/**
+ * Finds hierarchy loops using a callback function that maps object IDs to parent IDs.
+ *
+ * @since 3.1.0
+ * @access private
+ *
+ * @param callback $callback function that accepts ( ID, $callback_args ) and outputs parent_ID
+ * @param int $start The ID to start the loop check at
+ * @param int $start_parent the parent_ID of $start to use instead of calling $callback( $start ). Use null to always use $callback
+ * @param array $callback_args optional additional arguments to send to $callback
+ * @return array IDs of all members of loop
+ */
+function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_args = array() ) {
+ $override = is_null( $start_parent ) ? array() : array( $start => $start_parent );
+
+ if ( !$arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args ) )
+ return array();
+
+ return wp_find_hierarchy_loop_tortoise_hare( $callback, $arbitrary_loop_member, $override, $callback_args, true );
+}
+
+/**
+ * Uses the "The Tortoise and the Hare" algorithm to detect loops.
+ *
+ * For every step of the algorithm, the hare takes two steps and the tortoise one.
+ * If the hare ever laps the tortoise, there must be a loop.
+ *
+ * @since 3.1.0
+ * @access private
+ *
+ * @param callback $callback function that accepts ( ID, callback_arg, ... ) and outputs parent_ID
+ * @param int $start The ID to start the loop check at
+ * @param array $override an array of ( ID => parent_ID, ... ) to use instead of $callback
+ * @param array $callback_args optional additional arguments to send to $callback
+ * @param bool $_return_loop Return loop members or just detect presence of loop?
+ * Only set to true if you already know the given $start is part of a loop
+ * (otherwise the returned array might include branches)
+ * @return mixed scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if $_return_loop
+ */
+function wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override = array(), $callback_args = array(), $_return_loop = false ) {
+ $tortoise = $hare = $evanescent_hare = $start;
+ $return = array();
+
+ // Set evanescent_hare to one past hare
+ // Increment hare two steps
+ while (
+ $tortoise
+ &&
+ ( $evanescent_hare = isset( $override[$hare] ) ? $override[$hare] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
+ &&
+ ( $hare = isset( $override[$evanescent_hare] ) ? $override[$evanescent_hare] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
+ ) {
+ if ( $_return_loop )
+ $return[$tortoise] = $return[$evanescent_hare] = $return[$hare] = true;
+
+ // tortoise got lapped - must be a loop
+ if ( $tortoise == $evanescent_hare || $tortoise == $hare )
+ return $_return_loop ? $return : $tortoise;
+
+ // Increment tortoise by one step
+ $tortoise = isset( $override[$tortoise] ) ? $override[$tortoise] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
+ }
+
+ return false;
+}
+
+/**
+ * Send a HTTP header to limit rendering of pages to same origin iframes.
+ *
+ * @link https://developer.mozilla.org/en/the_x-frame-options_response_header
+ *
+ * @since 3.1.3
+ * @return none
+ */
+function send_frame_options_header() {
+ @header( 'X-Frame-Options: SAMEORIGIN' );
+}
+
+/**
+ * Retrieve a list of protocols to allow in HTML attributes.
+ *
+ * @since 3.3.0
+ * @see wp_kses()
+ * @see esc_url()
+ *
+ * @return array Array of allowed protocols
+ */
+function wp_allowed_protocols() {
+ static $protocols;
+
+ if ( empty( $protocols ) ) {
+ $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp' );
+ $protocols = apply_filters( 'kses_allowed_protocols', $protocols );
+ }
+
+ return $protocols;
+}
+
+/**
+ * Return a comma separated string of functions that have been called to get to the current point in code.
+ *
+ * @link http://core.trac.wordpress.org/ticket/19589
+ * @since 3.4
+ *
+ * @param string $ignore_class A class to ignore all function calls within - useful when you want to just give info about the callee
+ * @param int $skip_frames A number of stack frames to skip - useful for unwinding back to the source of the issue
+ * @param bool $pretty Whether or not you want a comma separated string or raw array returned
+ * @return string|array Either a string containing a reversed comma separated trace or an array of individual calls.
+ */
+function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
+ if ( version_compare( PHP_VERSION, '5.2.5', '>=' ) )
+ $trace = debug_backtrace( false );
+ else
+ $trace = debug_backtrace();
+
+ $caller = array();
+ $check_class = ! is_null( $ignore_class );
+ $skip_frames++; // skip this function
+
+ foreach ( $trace as $call ) {
+ if ( $skip_frames > 0 ) {
+ $skip_frames--;
+ } elseif ( isset( $call['class'] ) ) {
+ if ( $check_class && $ignore_class == $call['class'] )
+ continue; // Filter out calls
+
+ $caller[] = "{$call['class']}{$call['type']}{$call['function']}";
+ } else {
+ if ( in_array( $call['function'], array( 'do_action', 'apply_filters' ) ) ) {
+ $caller[] = "{$call['function']}('{$call['args'][0]}')";
+ } elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ) ) ) {
+ $caller[] = $call['function'] . "('" . str_replace( array( WP_CONTENT_DIR, ABSPATH ) , '', $call['args'][0] ) . "')";
+ } else {
+ $caller[] = $call['function'];
+ }
+ }
+ }
+ if ( $pretty )
+ return join( ', ', array_reverse( $caller ) );
+ else
+ return $caller;
+}
+
+/**
+ * Retrieve ids that are not already present in the cache
+ *
+ * @since 3.4.0
+ *
+ * @param array $object_ids ID list
+ * @param string $cache_key The cache bucket to check against
+ *
+ * @return array
+ */
+function _get_non_cached_ids( $object_ids, $cache_key ) {
+ $clean = array();
+ foreach ( $object_ids as $id ) {
+ $id = (int) $id;
+ if ( !wp_cache_get( $id, $cache_key ) ) {
+ $clean[] = $id;
+ }
+ }
+
+ return $clean;
+}
+
+/**
+ * Test if the current device has the capability to upload files.
+ *
+ * @since 3.4.0
+ * @access private
+ *
+ * @return bool true|false
+ */
+function _device_can_upload() {
+ if ( ! wp_is_mobile() )
+ return true;
+
+ $ua = $_SERVER['HTTP_USER_AGENT'];
+
+ if ( strpos($ua, 'iPhone') !== false
+ || strpos($ua, 'iPad') !== false
+ || strpos($ua, 'iPod') !== false ) {
+ return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
+ }
+
+ return true;
+}
+
+/**
+ * Test if a given path is a stream URL
+ *
+ * @param string $path The resource path or URL
+ * @return bool True if the path is a stream URL
+ */
+function wp_is_stream( $path ) {
+ $wrappers = stream_get_wrappers();
+ $wrappers_re = '(' . join('|', $wrappers) . ')';
+
+ return preg_match( "!^$wrappers_re://!", $path ) === 1;
+}
+
+/**
+ * Test if the supplied date is valid for the Gregorian calendar
+ *
+ * @since 3.5.0
+ *
+ * @return bool true|false
+ */
+function wp_checkdate( $month, $day, $year, $source_date ) {
+ return apply_filters( 'wp_checkdate', checkdate( $month, $day, $year ), $source_date );
+}