Make WordPress Core

Ticket #33852: functions.php

File functions.php, 150.7 KB (added by LukasNeptun, 10 years ago)

Added line 2526

Line 
1<?php
2/**
3 * Main WordPress API
4 *
5 * @package WordPress
6 */
7
8require( ABSPATH . WPINC . '/option.php' );
9
10/**
11 * Convert given date string into a different format.
12 *
13 * $format should be either a PHP date format string, e.g. 'U' for a Unix
14 * timestamp, or 'G' for a Unix timestamp assuming that $date is GMT.
15 *
16 * If $translate is true then the given date and format string will
17 * be passed to date_i18n() for translation.
18 *
19 * @since 0.71
20 *
21 * @param string $format    Format of the date to return.
22 * @param string $date      Date string to convert.
23 * @param bool   $translate Whether the return date should be translated. Default true.
24 * @return string|int|bool Formatted date string or Unix timestamp. False if $date is empty.
25 */
26function mysql2date( $format, $date, $translate = true ) {
27        if ( empty( $date ) )
28                return false;
29
30        if ( 'G' == $format )
31                return strtotime( $date . ' +0000' );
32
33        $i = strtotime( $date );
34
35        if ( 'U' == $format )
36                return $i;
37
38        if ( $translate )
39                return date_i18n( $format, $i );
40        else
41                return date( $format, $i );
42}
43
44/**
45 * Retrieve the current time based on specified type.
46 *
47 * The 'mysql' type will return the time in the format for MySQL DATETIME field.
48 * The 'timestamp' type will return the current timestamp.
49 * Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d').
50 *
51 * If $gmt is set to either '1' or 'true', then both types will use GMT time.
52 * if $gmt is false, the output is adjusted with the GMT offset in the WordPress option.
53 *
54 * @since 1.0.0
55 *
56 * @param string   $type Type of time to retrieve. Accepts 'mysql', 'timestamp', or PHP date
57 *                       format string (e.g. 'Y-m-d').
58 * @param int|bool $gmt  Optional. Whether to use GMT timezone. Default false.
59 * @return int|string Integer if $type is 'timestamp', string otherwise.
60 */
61function current_time( $type, $gmt = 0 ) {
62        switch ( $type ) {
63                case 'mysql':
64                        return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', ( time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ) );
65                case 'timestamp':
66                        return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
67                default:
68                        return ( $gmt ) ? date( $type ) : date( $type, time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) );
69        }
70}
71
72/**
73 * Retrieve the date in localized format, based on timestamp.
74 *
75 * If the locale specifies the locale month and weekday, then the locale will
76 * take over the format for the date. If it isn't, then the date format string
77 * will be used instead.
78 *
79 * @since 0.71
80 *
81 * @global WP_Locale $wp_locale
82 *
83 * @param string   $dateformatstring Format to display the date.
84 * @param bool|int $unixtimestamp    Optional. Unix timestamp. Default false.
85 * @param bool     $gmt              Optional. Whether to use GMT timezone. Default false.
86 *
87 * @return string The date, translated if locale specifies it.
88 */
89function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
90        global $wp_locale;
91        $i = $unixtimestamp;
92
93        if ( false === $i ) {
94                if ( ! $gmt )
95                        $i = current_time( 'timestamp' );
96                else
97                        $i = time();
98                // we should not let date() interfere with our
99                // specially computed timestamp
100                $gmt = true;
101        }
102
103        /*
104         * Store original value for language with untypical grammars.
105         * See https://core.trac.wordpress.org/ticket/9396
106         */
107        $req_format = $dateformatstring;
108
109        $datefunc = $gmt? 'gmdate' : 'date';
110
111        if ( ( !empty( $wp_locale->month ) ) && ( !empty( $wp_locale->weekday ) ) ) {
112                $datemonth = $wp_locale->get_month( $datefunc( 'm', $i ) );
113                $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth );
114                $dateweekday = $wp_locale->get_weekday( $datefunc( 'w', $i ) );
115                $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday );
116                $datemeridiem = $wp_locale->get_meridiem( $datefunc( 'a', $i ) );
117                $datemeridiem_capital = $wp_locale->get_meridiem( $datefunc( 'A', $i ) );
118                $dateformatstring = ' '.$dateformatstring;
119                $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
120                $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . backslashit( $datemonth ), $dateformatstring );
121                $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . backslashit( $dateweekday ), $dateformatstring );
122                $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring );
123                $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . backslashit( $datemeridiem ), $dateformatstring );
124                $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring );
125
126                $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
127        }
128        $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' );
129        $timezone_formats_re = implode( '|', $timezone_formats );
130        if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) {
131                $timezone_string = get_option( 'timezone_string' );
132                if ( $timezone_string ) {
133                        $timezone_object = timezone_open( $timezone_string );
134                        $date_object = date_create( null, $timezone_object );
135                        foreach ( $timezone_formats as $timezone_format ) {
136                                if ( false !== strpos( $dateformatstring, $timezone_format ) ) {
137                                        $formatted = date_format( $date_object, $timezone_format );
138                                        $dateformatstring = ' '.$dateformatstring;
139                                        $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring );
140                                        $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
141                                }
142                        }
143                }
144        }
145        $j = @$datefunc( $dateformatstring, $i );
146
147        /**
148         * Filter the date formatted based on the locale.
149         *
150         * @since 2.8.0
151         *
152         * @param string $j          Formatted date string.
153         * @param string $req_format Format to display the date.
154         * @param int    $i          Unix timestamp.
155         * @param bool   $gmt        Whether to convert to GMT for time. Default false.
156         */
157        $j = apply_filters( 'date_i18n', $j, $req_format, $i, $gmt );
158        return $j;
159}
160
161/**
162 * Convert integer number to format based on the locale.
163 *
164 * @since 2.3.0
165 *
166 * @global WP_Locale $wp_locale
167 *
168 * @param int $number   The number to convert based on locale.
169 * @param int $decimals Optional. Precision of the number of decimal places. Default 0.
170 * @return string Converted number in string format.
171 */
172function number_format_i18n( $number, $decimals = 0 ) {
173        global $wp_locale;
174        $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
175
176        /**
177         * Filter the number formatted based on the locale.
178         *
179         * @since  2.8.0
180         *
181         * @param string $formatted Converted number in string format.
182         */
183        return apply_filters( 'number_format_i18n', $formatted );
184}
185
186/**
187 * Convert number of bytes largest unit bytes will fit into.
188 *
189 * It is easier to read 1 kB than 1024 bytes and 1 MB than 1048576 bytes. Converts
190 * number of bytes to human readable number by taking the number of that unit
191 * that the bytes will go into it. Supports TB value.
192 *
193 * Please note that integers in PHP are limited to 32 bits, unless they are on
194 * 64 bit architecture, then they have 64 bit size. If you need to place the
195 * larger size then what PHP integer type will hold, then use a string. It will
196 * be converted to a double, which should always have 64 bit length.
197 *
198 * Technically the correct unit names for powers of 1024 are KiB, MiB etc.
199 *
200 * @since 2.3.0
201 *
202 * @param int|string $bytes    Number of bytes. Note max integer size for integers.
203 * @param int        $decimals Optional. Precision of number of decimal places. Default 0.
204 * @return string|false False on failure. Number string on success.
205 */
206function size_format( $bytes, $decimals = 0 ) {
207        $quant = array(
208                // ========================= Origin ====
209                'TB' => 1099511627776,  // pow( 1024, 4)
210                'GB' => 1073741824,     // pow( 1024, 3)
211                'MB' => 1048576,        // pow( 1024, 2)
212                'kB' => 1024,           // pow( 1024, 1)
213                'B'  => 1,              // pow( 1024, 0)
214        );
215
216        foreach ( $quant as $unit => $mag ) {
217                if ( doubleval( $bytes ) >= $mag ) {
218                        return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
219                }
220        }
221
222        return false;
223}
224
225/**
226 * Get the week start and end from the datetime or date string from MySQL.
227 *
228 * @since 0.71
229 *
230 * @param string     $mysqlstring   Date or datetime field type from MySQL.
231 * @param int|string $start_of_week Optional. Start of the week as an integer. Default empty string.
232 * @return array Keys are 'start' and 'end'.
233 */
234function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
235        // MySQL string year.
236        $my = substr( $mysqlstring, 0, 4 );
237
238        // MySQL string month.
239        $mm = substr( $mysqlstring, 8, 2 );
240
241        // MySQL string day.
242        $md = substr( $mysqlstring, 5, 2 );
243
244        // The timestamp for MySQL string day.
245        $day = mktime( 0, 0, 0, $md, $mm, $my );
246
247        // The day of the week from the timestamp.
248        $weekday = date( 'w', $day );
249
250        if ( !is_numeric($start_of_week) )
251                $start_of_week = get_option( 'start_of_week' );
252
253        if ( $weekday < $start_of_week )
254                $weekday += 7;
255
256        // The most recent week start day on or before $day.
257        $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week );
258
259        // $start + 7 days - 1 second.
260        $end = $start + 7 * DAY_IN_SECONDS - 1;
261        return compact( 'start', 'end' );
262}
263
264/**
265 * Unserialize value only if it was serialized.
266 *
267 * @since 2.0.0
268 *
269 * @param string $original Maybe unserialized original, if is needed.
270 * @return mixed Unserialized data can be any type.
271 */
272function maybe_unserialize( $original ) {
273        if ( is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in
274                return @unserialize( $original );
275        return $original;
276}
277
278/**
279 * Check value to find if it was serialized.
280 *
281 * If $data is not an string, then returned value will always be false.
282 * Serialized data is always a string.
283 *
284 * @since 2.0.5
285 *
286 * @param string $data   Value to check to see if was serialized.
287 * @param bool   $strict Optional. Whether to be strict about the end of the string. Default true.
288 * @return bool False if not serialized and true if it was.
289 */
290function is_serialized( $data, $strict = true ) {
291        // if it isn't a string, it isn't serialized.
292        if ( ! is_string( $data ) ) {
293                return false;
294        }
295        $data = trim( $data );
296        if ( 'N;' == $data ) {
297                return true;
298        }
299        if ( strlen( $data ) < 4 ) {
300                return false;
301        }
302        if ( ':' !== $data[1] ) {
303                return false;
304        }
305        if ( $strict ) {
306                $lastc = substr( $data, -1 );
307                if ( ';' !== $lastc && '}' !== $lastc ) {
308                        return false;
309                }
310        } else {
311                $semicolon = strpos( $data, ';' );
312                $brace     = strpos( $data, '}' );
313                // Either ; or } must exist.
314                if ( false === $semicolon && false === $brace )
315                        return false;
316                // But neither must be in the first X characters.
317                if ( false !== $semicolon && $semicolon < 3 )
318                        return false;
319                if ( false !== $brace && $brace < 4 )
320                        return false;
321        }
322        $token = $data[0];
323        switch ( $token ) {
324                case 's' :
325                        if ( $strict ) {
326                                if ( '"' !== substr( $data, -2, 1 ) ) {
327                                        return false;
328                                }
329                        } elseif ( false === strpos( $data, '"' ) ) {
330                                return false;
331                        }
332                        // or else fall through
333                case 'a' :
334                case 'O' :
335                        return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
336                case 'b' :
337                case 'i' :
338                case 'd' :
339                        $end = $strict ? '$' : '';
340                        return (bool) preg_match( "/^{$token}:[0-9.E-]+;$end/", $data );
341        }
342        return false;
343}
344
345/**
346 * Check whether serialized data is of string type.
347 *
348 * @since 2.0.5
349 *
350 * @param string $data Serialized data.
351 * @return bool False if not a serialized string, true if it is.
352 */
353function is_serialized_string( $data ) {
354        // if it isn't a string, it isn't a serialized string.
355        if ( ! is_string( $data ) ) {
356                return false;
357        }
358        $data = trim( $data );
359        if ( strlen( $data ) < 4 ) {
360                return false;
361        } elseif ( ':' !== $data[1] ) {
362                return false;
363        } elseif ( ';' !== substr( $data, -1 ) ) {
364                return false;
365        } elseif ( $data[0] !== 's' ) {
366                return false;
367        } elseif ( '"' !== substr( $data, -2, 1 ) ) {
368                return false;
369        } else {
370                return true;
371        }
372}
373
374/**
375 * Serialize data, if needed.
376 *
377 * @since 2.0.5
378 *
379 * @param string|array|object $data Data that might be serialized.
380 * @return mixed A scalar data
381 */
382function maybe_serialize( $data ) {
383        if ( is_array( $data ) || is_object( $data ) )
384                return serialize( $data );
385
386        // Double serialization is required for backward compatibility.
387        // See https://core.trac.wordpress.org/ticket/12930
388        // Also the world will end. See WP 3.6.1.
389        if ( is_serialized( $data, false ) )
390                return serialize( $data );
391
392        return $data;
393}
394
395/**
396 * Retrieve post title from XMLRPC XML.
397 *
398 * If the title element is not part of the XML, then the default post title from
399 * the $post_default_title will be used instead.
400 *
401 * @since 0.71
402 *
403 * @global string $post_default_title Default XML-RPC post title.
404 *
405 * @param string $content XMLRPC XML Request content
406 * @return string Post title
407 */
408function xmlrpc_getposttitle( $content ) {
409        global $post_default_title;
410        if ( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) ) {
411                $post_title = $matchtitle[1];
412        } else {
413                $post_title = $post_default_title;
414        }
415        return $post_title;
416}
417
418/**
419 * Retrieve the post category or categories from XMLRPC XML.
420 *
421 * If the category element is not found, then the default post category will be
422 * used. The return type then would be what $post_default_category. If the
423 * category is found, then it will always be an array.
424 *
425 * @since 0.71
426 *
427 * @global string $post_default_category Default XML-RPC post category.
428 *
429 * @param string $content XMLRPC XML Request content
430 * @return string|array List of categories or category name.
431 */
432function xmlrpc_getpostcategory( $content ) {
433        global $post_default_category;
434        if ( preg_match( '/<category>(.+?)<\/category>/is', $content, $matchcat ) ) {
435                $post_category = trim( $matchcat[1], ',' );
436                $post_category = explode( ',', $post_category );
437        } else {
438                $post_category = $post_default_category;
439        }
440        return $post_category;
441}
442
443/**
444 * XMLRPC XML content without title and category elements.
445 *
446 * @since 0.71
447 *
448 * @param string $content XML-RPC XML Request content.
449 * @return string XMLRPC XML Request content without title and category elements.
450 */
451function xmlrpc_removepostdata( $content ) {
452        $content = preg_replace( '/<title>(.+?)<\/title>/si', '', $content );
453        $content = preg_replace( '/<category>(.+?)<\/category>/si', '', $content );
454        $content = trim( $content );
455        return $content;
456}
457
458/**
459 * Use RegEx to extract URLs from arbitrary content.
460 *
461 * @since 3.7.0
462 *
463 * @param string $content Content to extract URLs from.
464 * @return array URLs found in passed string.
465 */
466function wp_extract_urls( $content ) {
467        preg_match_all(
468                "#([\"']?)("
469                        . "(?:([\w-]+:)?//?)"
470                        . "[^\s()<>]+"
471                        . "[.]"
472                        . "(?:"
473                                . "\([\w\d]+\)|"
474                                . "(?:"
475                                        . "[^`!()\[\]{};:'\".,<>«»“”‘’\s]|"
476                                        . "(?:[:]\d+)?/?"
477                                . ")+"
478                        . ")"
479                . ")\\1#",
480                $content,
481                $post_links
482        );
483
484        $post_links = array_unique( array_map( 'html_entity_decode', $post_links[2] ) );
485
486        return array_values( $post_links );
487}
488
489/**
490 * Check content for video and audio links to add as enclosures.
491 *
492 * Will not add enclosures that have already been added and will
493 * remove enclosures that are no longer in the post. This is called as
494 * pingbacks and trackbacks.
495 *
496 * @since 1.5.0
497 *
498 * @global wpdb $wpdb
499 *
500 * @param string $content Post Content.
501 * @param int    $post_ID Post ID.
502 */
503function do_enclose( $content, $post_ID ) {
504        global $wpdb;
505
506        //TODO: Tidy this ghetto code up and make the debug code optional
507        include_once( ABSPATH . WPINC . '/class-IXR.php' );
508
509        $post_links = array();
510
511        $pung = get_enclosed( $post_ID );
512
513        $post_links_temp = wp_extract_urls( $content );
514
515        foreach ( $pung as $link_test ) {
516                if ( ! in_array( $link_test, $post_links_temp ) ) { // link no longer in post
517                        $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 ) . '%') );
518                        foreach ( $mids as $mid )
519                                delete_metadata_by_mid( 'post', $mid );
520                }
521        }
522
523        foreach ( (array) $post_links_temp as $link_test ) {
524                if ( !in_array( $link_test, $pung ) ) { // If we haven't pung it already
525                        $test = @parse_url( $link_test );
526                        if ( false === $test )
527                                continue;
528                        if ( isset( $test['query'] ) )
529                                $post_links[] = $link_test;
530                        elseif ( isset($test['path']) && ( $test['path'] != '/' ) &&  ($test['path'] != '' ) )
531                                $post_links[] = $link_test;
532                }
533        }
534
535        foreach ( (array) $post_links as $url ) {
536                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 ) . '%' ) ) ) {
537
538                        if ( $headers = wp_get_http_headers( $url) ) {
539                                $len = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0;
540                                $type = isset( $headers['content-type'] ) ? $headers['content-type'] : '';
541                                $allowed_types = array( 'video', 'audio' );
542
543                                // Check to see if we can figure out the mime type from
544                                // the extension
545                                $url_parts = @parse_url( $url );
546                                if ( false !== $url_parts ) {
547                                        $extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION );
548                                        if ( !empty( $extension ) ) {
549                                                foreach ( wp_get_mime_types() as $exts => $mime ) {
550                                                        if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
551                                                                $type = $mime;
552                                                                break;
553                                                        }
554                                                }
555                                        }
556                                }
557
558                                if ( in_array( substr( $type, 0, strpos( $type, "/" ) ), $allowed_types ) ) {
559                                        add_post_meta( $post_ID, 'enclosure', "$url\n$len\n$mime\n" );
560                                }
561                        }
562                }
563        }
564}
565
566/**
567 * Perform a HTTP HEAD or GET request.
568 *
569 * If $file_path is a writable filename, this will do a GET request and write
570 * the file to that path.
571 *
572 * @since 2.5.0
573 *
574 * @param string      $url       URL to fetch.
575 * @param string|bool $file_path Optional. File path to write request to. Default false.
576 * @param int         $red       Optional. The number of Redirects followed, Upon 5 being hit,
577 *                               returns false. Default 1.
578 * @return bool|string False on failure and string of headers if HEAD request.
579 */
580function wp_get_http( $url, $file_path = false, $red = 1 ) {
581        @set_time_limit( 60 );
582
583        if ( $red > 5 )
584                return false;
585
586        $options = array();
587        $options['redirection'] = 5;
588
589        if ( false == $file_path )
590                $options['method'] = 'HEAD';
591        else
592                $options['method'] = 'GET';
593
594        $response = wp_safe_remote_request( $url, $options );
595
596        if ( is_wp_error( $response ) )
597                return false;
598
599        $headers = wp_remote_retrieve_headers( $response );
600        $headers['response'] = wp_remote_retrieve_response_code( $response );
601
602        // WP_HTTP no longer follows redirects for HEAD requests.
603        if ( 'HEAD' == $options['method'] && in_array($headers['response'], array(301, 302)) && isset( $headers['location'] ) ) {
604                return wp_get_http( $headers['location'], $file_path, ++$red );
605        }
606
607        if ( false == $file_path )
608                return $headers;
609
610        // GET request - write it to the supplied filename
611        $out_fp = fopen($file_path, 'w');
612        if ( !$out_fp )
613                return $headers;
614
615        fwrite( $out_fp,  wp_remote_retrieve_body( $response ) );
616        fclose($out_fp);
617        clearstatcache();
618
619        return $headers;
620}
621
622/**
623 * Retrieve HTTP Headers from URL.
624 *
625 * @since 1.5.1
626 *
627 * @param string $url        URL to retrieve HTTP headers from.
628 * @param bool   $deprecated Not Used.
629 * @return bool|string False on failure, headers on success.
630 */
631function wp_get_http_headers( $url, $deprecated = false ) {
632        if ( !empty( $deprecated ) )
633                _deprecated_argument( __FUNCTION__, '2.7' );
634
635        $response = wp_safe_remote_head( $url );
636
637        if ( is_wp_error( $response ) )
638                return false;
639
640        return wp_remote_retrieve_headers( $response );
641}
642
643/**
644 * Whether the publish date of the current post in the loop is different from the
645 * publish date of the previous post in the loop.
646 *
647 * @since 0.71
648 *
649 * @global string $currentday  The day of the current post in the loop.
650 * @global string $previousday The day of the previous post in the loop.
651 *
652 * @return int 1 when new day, 0 if not a new day.
653 */
654function is_new_day() {
655        global $currentday, $previousday;
656        if ( $currentday != $previousday )
657                return 1;
658        else
659                return 0;
660}
661
662/**
663 * Build URL query based on an associative and, or indexed array.
664 *
665 * This is a convenient function for easily building url queries. It sets the
666 * separator to '&' and uses _http_build_query() function.
667 *
668 * @since 2.3.0
669 *
670 * @see _http_build_query() Used to build the query
671 * @see http://us2.php.net/manual/en/function.http-build-query.php for more on what
672 *              http_build_query() does.
673 *
674 * @param array $data URL-encode key/value pairs.
675 * @return string URL-encoded string.
676 */
677function build_query( $data ) {
678        return _http_build_query( $data, null, '&', '', false );
679}
680
681/**
682 * From php.net (modified by Mark Jaquith to behave like the native PHP5 function).
683 *
684 * @since 3.2.0
685 * @access private
686 *
687 * @see http://us1.php.net/manual/en/function.http-build-query.php
688 *
689 * @param array|object  $data       An array or object of data. Converted to array.
690 * @param string        $prefix     Optional. Numeric index. If set, start parameter numbering with it.
691 *                                  Default null.
692 * @param string        $sep        Optional. Argument separator; defaults to 'arg_separator.output'.
693 *                                  Default null.
694 * @param string        $key        Optional. Used to prefix key name. Default empty.
695 * @param bool          $urlencode  Optional. Whether to use urlencode() in the result. Default true.
696 *
697 * @return string The query string.
698 */
699function _http_build_query( $data, $prefix = null, $sep = null, $key = '', $urlencode = true ) {
700        $ret = array();
701
702        foreach ( (array) $data as $k => $v ) {
703                if ( $urlencode)
704                        $k = urlencode($k);
705                if ( is_int($k) && $prefix != null )
706                        $k = $prefix.$k;
707                if ( !empty($key) )
708                        $k = $key . '%5B' . $k . '%5D';
709                if ( $v === null )
710                        continue;
711                elseif ( $v === false )
712                        $v = '0';
713
714                if ( is_array($v) || is_object($v) )
715                        array_push($ret,_http_build_query($v, '', $sep, $k, $urlencode));
716                elseif ( $urlencode )
717                        array_push($ret, $k.'='.urlencode($v));
718                else
719                        array_push($ret, $k.'='.$v);
720        }
721
722        if ( null === $sep )
723                $sep = ini_get('arg_separator.output');
724
725        return implode($sep, $ret);
726}
727
728/**
729 * Retrieve a modified URL query string.
730 *
731 * You can rebuild the URL and append a new query variable to the URL query by
732 * using this function. You can also retrieve the full URL with query data.
733 *
734 * Adding a single key & value or an associative array. Setting a key value to
735 * an empty string removes the key. Omitting oldquery_or_uri uses the $_SERVER
736 * value. Additional values provided are expected to be encoded appropriately
737 * with urlencode() or rawurlencode().
738 *
739 * @since 1.5.0
740 *
741 * @param string|array $param1 Either newkey or an associative_array.
742 * @param string       $param2 Either newvalue or oldquery or URI.
743 * @param string       $param3 Optional. Old query or URI.
744 * @return string New URL query string.
745 */
746function add_query_arg() {
747        $args = func_get_args();
748        if ( is_array( $args[0] ) ) {
749                if ( count( $args ) < 2 || false === $args[1] )
750                        $uri = $_SERVER['REQUEST_URI'];
751                else
752                        $uri = $args[1];
753        } else {
754                if ( count( $args ) < 3 || false === $args[2] )
755                        $uri = $_SERVER['REQUEST_URI'];
756                else
757                        $uri = $args[2];
758        }
759
760        if ( $frag = strstr( $uri, '#' ) )
761                $uri = substr( $uri, 0, -strlen( $frag ) );
762        else
763                $frag = '';
764
765        if ( 0 === stripos( $uri, 'http://' ) ) {
766                $protocol = 'http://';
767                $uri = substr( $uri, 7 );
768        } elseif ( 0 === stripos( $uri, 'https://' ) ) {
769                $protocol = 'https://';
770                $uri = substr( $uri, 8 );
771        } else {
772                $protocol = '';
773        }
774
775        if ( strpos( $uri, '?' ) !== false ) {
776                list( $base, $query ) = explode( '?', $uri, 2 );
777                $base .= '?';
778        } elseif ( $protocol || strpos( $uri, '=' ) === false ) {
779                $base = $uri . '?';
780                $query = '';
781        } else {
782                $base = '';
783                $query = $uri;
784        }
785
786        wp_parse_str( $query, $qs );
787        $qs = urlencode_deep( $qs ); // this re-URL-encodes things that were already in the query string
788        if ( is_array( $args[0] ) ) {
789                foreach ( $args[0] as $k => $v ) {
790                        $qs[ $k ] = $v;
791                }
792        } else {
793                $qs[ $args[0] ] = $args[1];
794        }
795
796        foreach ( $qs as $k => $v ) {
797                if ( $v === false )
798                        unset( $qs[$k] );
799        }
800
801        $ret = build_query( $qs );
802        $ret = trim( $ret, '?' );
803        $ret = preg_replace( '#=(&|$)#', '$1', $ret );
804        $ret = $protocol . $base . $ret . $frag;
805        $ret = rtrim( $ret, '?' );
806        return $ret;
807}
808
809/**
810 * Removes an item or list from the query string.
811 *
812 * @since 1.5.0
813 *
814 * @param string|array $key   Query key or keys to remove.
815 * @param bool|string  $query Optional. When false uses the $_SERVER value. Default false.
816 * @return string New URL query string.
817 */
818function remove_query_arg( $key, $query = false ) {
819        if ( is_array( $key ) ) { // removing multiple keys
820                foreach ( $key as $k )
821                        $query = add_query_arg( $k, false, $query );
822                return $query;
823        }
824        return add_query_arg( $key, false, $query );
825}
826
827/**
828 * Returns an array of single-use query variable names that can be removed from a URL.
829 *
830 * @since 4.4.0
831 *
832 * @return array An array of parameters to remove from the URL.
833 */
834function wp_removable_query_args() {
835        $removable_query_args = array(
836                'activate',
837                'activated',
838                'approved',
839                'deactivate',
840                'deleted',
841                'disabled',
842                'enabled',
843                'error',
844                'locked',
845                'message',
846                'same',
847                'saved',
848                'settings-updated',
849                'skipped',
850                'spammed',
851                'trashed',
852                'unspammed',
853                'untrashed',
854                'update',
855                'updated',
856        );
857
858        /**
859         * Filter the list of query variables to remove.
860         *
861         * @since 4.2.0
862         *
863         * @param array $removable_query_args An array of query variables to remove from a URL.
864         */
865        return apply_filters( 'removable_query_args', $removable_query_args );
866}
867
868/**
869 * Walks the array while sanitizing the contents.
870 *
871 * @since 0.71
872 *
873 * @param array $array Array to walk while sanitizing contents.
874 * @return array Sanitized $array.
875 */
876function add_magic_quotes( $array ) {
877        foreach ( (array) $array as $k => $v ) {
878                if ( is_array( $v ) ) {
879                        $array[$k] = add_magic_quotes( $v );
880                } else {
881                        $array[$k] = addslashes( $v );
882                }
883        }
884        return $array;
885}
886
887/**
888 * HTTP request for URI to retrieve content.
889 *
890 * @since 1.5.1
891 *
892 * @see wp_safe_remote_get()
893 *
894 * @param string $uri URI/URL of web page to retrieve.
895 * @return false|string HTTP content. False on failure.
896 */
897function wp_remote_fopen( $uri ) {
898        $parsed_url = @parse_url( $uri );
899
900        if ( !$parsed_url || !is_array( $parsed_url ) )
901                return false;
902
903        $options = array();
904        $options['timeout'] = 10;
905
906        $response = wp_safe_remote_get( $uri, $options );
907
908        if ( is_wp_error( $response ) )
909                return false;
910
911        return wp_remote_retrieve_body( $response );
912}
913
914/**
915 * Set up the WordPress query.
916 *
917 * @since 2.0.0
918 *
919 * @global WP       $wp_locale
920 * @global WP_Query $wp_query
921 * @global WP_Query $wp_the_query
922 *
923 * @param string|array $query_vars Default WP_Query arguments.
924 */
925function wp( $query_vars = '' ) {
926        global $wp, $wp_query, $wp_the_query;
927        $wp->main( $query_vars );
928
929        if ( !isset($wp_the_query) )
930                $wp_the_query = $wp_query;
931}
932
933/**
934 * Retrieve the description for the HTTP status.
935 *
936 * @since 2.3.0
937 *
938 * @global array $wp_header_to_desc
939 *
940 * @param int $code HTTP status code.
941 * @return string Empty string if not found, or description if found.
942 */
943function get_status_header_desc( $code ) {
944        global $wp_header_to_desc;
945
946        $code = absint( $code );
947
948        if ( !isset( $wp_header_to_desc ) ) {
949                $wp_header_to_desc = array(
950                        100 => 'Continue',
951                        101 => 'Switching Protocols',
952                        102 => 'Processing',
953
954                        200 => 'OK',
955                        201 => 'Created',
956                        202 => 'Accepted',
957                        203 => 'Non-Authoritative Information',
958                        204 => 'No Content',
959                        205 => 'Reset Content',
960                        206 => 'Partial Content',
961                        207 => 'Multi-Status',
962                        226 => 'IM Used',
963
964                        300 => 'Multiple Choices',
965                        301 => 'Moved Permanently',
966                        302 => 'Found',
967                        303 => 'See Other',
968                        304 => 'Not Modified',
969                        305 => 'Use Proxy',
970                        306 => 'Reserved',
971                        307 => 'Temporary Redirect',
972
973                        400 => 'Bad Request',
974                        401 => 'Unauthorized',
975                        402 => 'Payment Required',
976                        403 => 'Forbidden',
977                        404 => 'Not Found',
978                        405 => 'Method Not Allowed',
979                        406 => 'Not Acceptable',
980                        407 => 'Proxy Authentication Required',
981                        408 => 'Request Timeout',
982                        409 => 'Conflict',
983                        410 => 'Gone',
984                        411 => 'Length Required',
985                        412 => 'Precondition Failed',
986                        413 => 'Request Entity Too Large',
987                        414 => 'Request-URI Too Long',
988                        415 => 'Unsupported Media Type',
989                        416 => 'Requested Range Not Satisfiable',
990                        417 => 'Expectation Failed',
991                        418 => 'I\'m a teapot',
992                        422 => 'Unprocessable Entity',
993                        423 => 'Locked',
994                        424 => 'Failed Dependency',
995                        426 => 'Upgrade Required',
996                        428 => 'Precondition Required',
997                        429 => 'Too Many Requests',
998                        431 => 'Request Header Fields Too Large',
999
1000                        500 => 'Internal Server Error',
1001                        501 => 'Not Implemented',
1002                        502 => 'Bad Gateway',
1003                        503 => 'Service Unavailable',
1004                        504 => 'Gateway Timeout',
1005                        505 => 'HTTP Version Not Supported',
1006                        506 => 'Variant Also Negotiates',
1007                        507 => 'Insufficient Storage',
1008                        510 => 'Not Extended',
1009                        511 => 'Network Authentication Required',
1010                );
1011        }
1012
1013        if ( isset( $wp_header_to_desc[$code] ) )
1014                return $wp_header_to_desc[$code];
1015        else
1016                return '';
1017}
1018
1019/**
1020 * Set HTTP status header.
1021 *
1022 * @since 2.0.0
1023 *
1024 * @see get_status_header_desc()
1025 *
1026 * @param int $code HTTP status code.
1027 */
1028function status_header( $code ) {
1029        $description = get_status_header_desc( $code );
1030
1031        if ( empty( $description ) )
1032                return;
1033
1034        $protocol = $_SERVER['SERVER_PROTOCOL'];
1035        if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol )
1036                $protocol = 'HTTP/1.0';
1037        $status_header = "$protocol $code $description";
1038        if ( function_exists( 'apply_filters' ) )
1039
1040                /**
1041                 * Filter an HTTP status header.
1042                 *
1043                 * @since 2.2.0
1044                 *
1045                 * @param string $status_header HTTP status header.
1046                 * @param int    $code          HTTP status code.
1047                 * @param string $description   Description for the status code.
1048                 * @param string $protocol      Server protocol.
1049                 */
1050                $status_header = apply_filters( 'status_header', $status_header, $code, $description, $protocol );
1051
1052        @header( $status_header, true, $code );
1053}
1054
1055/**
1056 * Get the header information to prevent caching.
1057 *
1058 * The several different headers cover the different ways cache prevention
1059 * is handled by different browsers
1060 *
1061 * @since 2.8.0
1062 *
1063 * @return array The associative array of header names and field values.
1064 */
1065function wp_get_nocache_headers() {
1066        $headers = array(
1067                'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
1068                'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
1069                'Pragma' => 'no-cache',
1070        );
1071
1072        if ( function_exists('apply_filters') ) {
1073                /**
1074                 * Filter the cache-controlling headers.
1075                 *
1076                 * @since 2.8.0
1077                 *
1078                 * @see wp_get_nocache_headers()
1079                 *
1080                 * @param array $headers {
1081                 *     Header names and field values.
1082                 *
1083                 *     @type string $Expires       Expires header.
1084                 *     @type string $Cache-Control Cache-Control header.
1085                 *     @type string $Pragma        Pragma header.
1086                 * }
1087                 */
1088                $headers = (array) apply_filters( 'nocache_headers', $headers );
1089        }
1090        $headers['Last-Modified'] = false;
1091        return $headers;
1092}
1093
1094/**
1095 * Set the headers to prevent caching for the different browsers.
1096 *
1097 * Different browsers support different nocache headers, so several
1098 * headers must be sent so that all of them get the point that no
1099 * caching should occur.
1100 *
1101 * @since 2.0.0
1102 *
1103 * @see wp_get_nocache_headers()
1104 */
1105function nocache_headers() {
1106        $headers = wp_get_nocache_headers();
1107
1108        unset( $headers['Last-Modified'] );
1109
1110        // In PHP 5.3+, make sure we are not sending a Last-Modified header.
1111        if ( function_exists( 'header_remove' ) ) {
1112                @header_remove( 'Last-Modified' );
1113        } else {
1114                // In PHP 5.2, send an empty Last-Modified header, but only as a
1115                // last resort to override a header already sent. #WP23021
1116                foreach ( headers_list() as $header ) {
1117                        if ( 0 === stripos( $header, 'Last-Modified' ) ) {
1118                                $headers['Last-Modified'] = '';
1119                                break;
1120                        }
1121                }
1122        }
1123
1124        foreach ( $headers as $name => $field_value )
1125                @header("{$name}: {$field_value}");
1126}
1127
1128/**
1129 * Set the headers for caching for 10 days with JavaScript content type.
1130 *
1131 * @since 2.1.0
1132 */
1133function cache_javascript_headers() {
1134        $expiresOffset = 10 * DAY_IN_SECONDS;
1135
1136        header( "Content-Type: text/javascript; charset=" . get_bloginfo( 'charset' ) );
1137        header( "Vary: Accept-Encoding" ); // Handle proxies
1138        header( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $expiresOffset ) . " GMT" );
1139}
1140
1141/**
1142 * Retrieve the number of database queries during the WordPress execution.
1143 *
1144 * @since 2.0.0
1145 *
1146 * @global wpdb $wpdb WordPress database abstraction object.
1147 *
1148 * @return int Number of database queries.
1149 */
1150function get_num_queries() {
1151        global $wpdb;
1152        return $wpdb->num_queries;
1153}
1154
1155/**
1156 * Whether input is yes or no.
1157 *
1158 * Must be 'y' to be true.
1159 *
1160 * @since 1.0.0
1161 *
1162 * @param string $yn Character string containing either 'y' (yes) or 'n' (no).
1163 * @return bool True if yes, false on anything else.
1164 */
1165function bool_from_yn( $yn ) {
1166        return ( strtolower( $yn ) == 'y' );
1167}
1168
1169/**
1170 * Load the feed template from the use of an action hook.
1171 *
1172 * If the feed action does not have a hook, then the function will die with a
1173 * message telling the visitor that the feed is not valid.
1174 *
1175 * It is better to only have one hook for each feed.
1176 *
1177 * @since 2.1.0
1178 *
1179 * @global WP_Query $wp_query Used to tell if the use a comment feed.
1180 */
1181function do_feed() {
1182        global $wp_query;
1183
1184        $feed = get_query_var( 'feed' );
1185
1186        // Remove the pad, if present.
1187        $feed = preg_replace( '/^_+/', '', $feed );
1188
1189        if ( $feed == '' || $feed == 'feed' )
1190                $feed = get_default_feed();
1191
1192        $hook = 'do_feed_' . $feed;
1193        if ( ! has_action( $hook ) )
1194                wp_die( __( 'ERROR: This is not a valid feed template.' ), '', array( 'response' => 404 ) );
1195
1196        /**
1197         * Fires once the given feed is loaded.
1198         *
1199         * The dynamic hook name, $hook, refers to the feed name.
1200         *
1201         * @since 2.1.0
1202         *
1203         * @param bool $is_comment_feed Whether the feed is a comment feed.
1204         */
1205        do_action( $hook, $wp_query->is_comment_feed );
1206}
1207
1208/**
1209 * Load the RDF RSS 0.91 Feed template.
1210 *
1211 * @since 2.1.0
1212 *
1213 * @see load_template()
1214 */
1215function do_feed_rdf() {
1216        load_template( ABSPATH . WPINC . '/feed-rdf.php' );
1217}
1218
1219/**
1220 * Load the RSS 1.0 Feed Template.
1221 *
1222 * @since 2.1.0
1223 *
1224 * @see load_template()
1225 */
1226function do_feed_rss() {
1227        load_template( ABSPATH . WPINC . '/feed-rss.php' );
1228}
1229
1230/**
1231 * Load either the RSS2 comment feed or the RSS2 posts feed.
1232 *
1233 * @since 2.1.0
1234 *
1235 * @see load_template()
1236 *
1237 * @param bool $for_comments True for the comment feed, false for normal feed.
1238 */
1239function do_feed_rss2( $for_comments ) {
1240        if ( $for_comments )
1241                load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' );
1242        else
1243                load_template( ABSPATH . WPINC . '/feed-rss2.php' );
1244}
1245
1246/**
1247 * Load either Atom comment feed or Atom posts feed.
1248 *
1249 * @since 2.1.0
1250 *
1251 * @see load_template()
1252 *
1253 * @param bool $for_comments True for the comment feed, false for normal feed.
1254 */
1255function do_feed_atom( $for_comments ) {
1256        if ($for_comments)
1257                load_template( ABSPATH . WPINC . '/feed-atom-comments.php');
1258        else
1259                load_template( ABSPATH . WPINC . '/feed-atom.php' );
1260}
1261
1262/**
1263 * Display the robots.txt file content.
1264 *
1265 * The echo content should be with usage of the permalinks or for creating the
1266 * robots.txt file.
1267 *
1268 * @since 2.1.0
1269 */
1270function do_robots() {
1271        header( 'Content-Type: text/plain; charset=utf-8' );
1272
1273        /**
1274         * Fires when displaying the robots.txt file.
1275         *
1276         * @since 2.1.0
1277         */
1278        do_action( 'do_robotstxt' );
1279
1280        $output = "User-agent: *\n";
1281        $public = get_option( 'blog_public' );
1282        if ( '0' == $public ) {
1283                $output .= "Disallow: /\n";
1284        } else {
1285                $site_url = parse_url( site_url() );
1286                $path = ( !empty( $site_url['path'] ) ) ? $site_url['path'] : '';
1287                $output .= "Disallow: $path/wp-admin/\n";
1288        }
1289
1290        /**
1291         * Filter the robots.txt output.
1292         *
1293         * @since 3.0.0
1294         *
1295         * @param string $output Robots.txt output.
1296         * @param bool   $public Whether the site is considered "public".
1297         */
1298        echo apply_filters( 'robots_txt', $output, $public );
1299}
1300
1301/**
1302 * Test whether blog is already installed.
1303 *
1304 * The cache will be checked first. If you have a cache plugin, which saves
1305 * the cache values, then this will work. If you use the default WordPress
1306 * cache, and the database goes away, then you might have problems.
1307 *
1308 * Checks for the 'siteurl' option for whether WordPress is installed.
1309 *
1310 * @since 2.1.0
1311 *
1312 * @global wpdb $wpdb WordPress database abstraction object.
1313 *
1314 * @return bool Whether the blog is already installed.
1315 */
1316function is_blog_installed() {
1317        global $wpdb;
1318
1319        /*
1320         * Check cache first. If options table goes away and we have true
1321         * cached, oh well.
1322         */
1323        if ( wp_cache_get( 'is_blog_installed' ) )
1324                return true;
1325
1326        $suppress = $wpdb->suppress_errors();
1327        if ( ! defined( 'WP_INSTALLING' ) ) {
1328                $alloptions = wp_load_alloptions();
1329        }
1330        // If siteurl is not set to autoload, check it specifically
1331        if ( !isset( $alloptions['siteurl'] ) )
1332                $installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" );
1333        else
1334                $installed = $alloptions['siteurl'];
1335        $wpdb->suppress_errors( $suppress );
1336
1337        $installed = !empty( $installed );
1338        wp_cache_set( 'is_blog_installed', $installed );
1339
1340        if ( $installed )
1341                return true;
1342
1343        // If visiting repair.php, return true and let it take over.
1344        if ( defined( 'WP_REPAIRING' ) )
1345                return true;
1346
1347        $suppress = $wpdb->suppress_errors();
1348
1349        /*
1350         * Loop over the WP tables. If none exist, then scratch install is allowed.
1351         * If one or more exist, suggest table repair since we got here because the
1352         * options table could not be accessed.
1353         */
1354        $wp_tables = $wpdb->tables();
1355        foreach ( $wp_tables as $table ) {
1356                // The existence of custom user tables shouldn't suggest an insane state or prevent a clean install.
1357                if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table )
1358                        continue;
1359                if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE == $table )
1360                        continue;
1361
1362                if ( ! $wpdb->get_results( "DESCRIBE $table;" ) )
1363                        continue;
1364
1365                // One or more tables exist. We are insane.
1366
1367                wp_load_translations_early();
1368
1369                // Die with a DB error.
1370                $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' );
1371                dead_db();
1372        }
1373
1374        $wpdb->suppress_errors( $suppress );
1375
1376        wp_cache_set( 'is_blog_installed', false );
1377
1378        return false;
1379}
1380
1381/**
1382 * Retrieve URL with nonce added to URL query.
1383 *
1384 * @since 2.0.4
1385 *
1386 * @param string     $actionurl URL to add nonce action.
1387 * @param int|string $action    Optional. Nonce action name. Default -1.
1388 * @param string     $name      Optional. Nonce name. Default '_wpnonce'.
1389 * @return string Escaped URL with nonce action added.
1390 */
1391function wp_nonce_url( $actionurl, $action = -1, $name = '_wpnonce' ) {
1392        $actionurl = str_replace( '&amp;', '&', $actionurl );
1393        return esc_html( add_query_arg( $name, wp_create_nonce( $action ), $actionurl ) );
1394}
1395
1396/**
1397 * Retrieve or display nonce hidden field for forms.
1398 *
1399 * The nonce field is used to validate that the contents of the form came from
1400 * the location on the current site and not somewhere else. The nonce does not
1401 * offer absolute protection, but should protect against most cases. It is very
1402 * important to use nonce field in forms.
1403 *
1404 * The $action and $name are optional, but if you want to have better security,
1405 * it is strongly suggested to set those two parameters. It is easier to just
1406 * call the function without any parameters, because validation of the nonce
1407 * doesn't require any parameters, but since crackers know what the default is
1408 * it won't be difficult for them to find a way around your nonce and cause
1409 * damage.
1410 *
1411 * The input name will be whatever $name value you gave. The input value will be
1412 * the nonce creation value.
1413 *
1414 * @since 2.0.4
1415 *
1416 * @param int|string $action  Optional. Action name. Default -1.
1417 * @param string     $name    Optional. Nonce name. Default '_wpnonce'.
1418 * @param bool       $referer Optional. Whether to set the referer field for validation. Default true.
1419 * @param bool       $echo    Optional. Whether to display or return hidden form field. Default true.
1420 * @return string Nonce field HTML markup.
1421 */
1422function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true , $echo = true ) {
1423        $name = esc_attr( $name );
1424        $nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />';
1425
1426        if ( $referer )
1427                $nonce_field .= wp_referer_field( false );
1428
1429        if ( $echo )
1430                echo $nonce_field;
1431
1432        return $nonce_field;
1433}
1434
1435/**
1436 * Retrieve or display referer hidden field for forms.
1437 *
1438 * The referer link is the current Request URI from the server super global. The
1439 * input name is '_wp_http_referer', in case you wanted to check manually.
1440 *
1441 * @since 2.0.4
1442 *
1443 * @param bool $echo Optional. Whether to echo or return the referer field. Default true.
1444 * @return string Referer field HTML markup.
1445 */
1446function wp_referer_field( $echo = true ) {
1447        $referer_field = '<input type="hidden" name="_wp_http_referer" value="'. esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
1448
1449        if ( $echo )
1450                echo $referer_field;
1451        return $referer_field;
1452}
1453
1454/**
1455 * Retrieve or display original referer hidden field for forms.
1456 *
1457 * The input name is '_wp_original_http_referer' and will be either the same
1458 * value of wp_referer_field(), if that was posted already or it will be the
1459 * current page, if it doesn't exist.
1460 *
1461 * @since 2.0.4
1462 *
1463 * @param bool   $echo         Optional. Whether to echo the original http referer. Default true.
1464 * @param string $jump_back_to Optional. Can be 'previous' or page you want to jump back to.
1465 *                             Default 'current'.
1466 * @return string Original referer field.
1467 */
1468function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) {
1469        if ( ! $ref = wp_get_original_referer() ) {
1470                $ref = 'previous' == $jump_back_to ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] );
1471        }
1472        $orig_referer_field = '<input type="hidden" name="_wp_original_http_referer" value="' . esc_attr( $ref ) . '" />';
1473        if ( $echo )
1474                echo $orig_referer_field;
1475        return $orig_referer_field;
1476}
1477
1478/**
1479 * Retrieve referer from '_wp_http_referer' or HTTP referer.
1480 *
1481 * If it's the same as the current request URL, will return false.
1482 *
1483 * @since 2.0.4
1484 *
1485 * @return false|string False on failure. Referer URL on success.
1486 */
1487function wp_get_referer() {
1488        if ( ! function_exists( 'wp_validate_redirect' ) )
1489                return false;
1490        $ref = false;
1491        if ( ! empty( $_REQUEST['_wp_http_referer'] ) )
1492                $ref = wp_unslash( $_REQUEST['_wp_http_referer'] );
1493        elseif ( ! empty( $_SERVER['HTTP_REFERER'] ) )
1494                $ref = wp_unslash( $_SERVER['HTTP_REFERER'] );
1495
1496        if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) )
1497                return wp_validate_redirect( $ref, false );
1498        return false;
1499}
1500
1501/**
1502 * Retrieve original referer that was posted, if it exists.
1503 *
1504 * @since 2.0.4
1505 *
1506 * @return string|false False if no original referer or original referer if set.
1507 */
1508function wp_get_original_referer() {
1509        if ( ! empty( $_REQUEST['_wp_original_http_referer'] ) && function_exists( 'wp_validate_redirect' ) )
1510                return wp_validate_redirect( wp_unslash( $_REQUEST['_wp_original_http_referer'] ), false );
1511        return false;
1512}
1513
1514/**
1515 * Recursive directory creation based on full path.
1516 *
1517 * Will attempt to set permissions on folders.
1518 *
1519 * @since 2.0.1
1520 *
1521 * @param string $target Full path to attempt to create.
1522 * @return bool Whether the path was created. True if path already exists.
1523 */
1524function wp_mkdir_p( $target ) {
1525        $wrapper = null;
1526
1527        // Strip the protocol.
1528        if ( wp_is_stream( $target ) ) {
1529                list( $wrapper, $target ) = explode( '://', $target, 2 );
1530        }
1531
1532        // From php.net/mkdir user contributed notes.
1533        $target = str_replace( '//', '/', $target );
1534
1535        // Put the wrapper back on the target.
1536        if ( $wrapper !== null ) {
1537                $target = $wrapper . '://' . $target;
1538        }
1539
1540        /*
1541         * Safe mode fails with a trailing slash under certain PHP versions.
1542         * Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
1543         */
1544        $target = rtrim($target, '/');
1545        if ( empty($target) )
1546                $target = '/';
1547
1548        if ( file_exists( $target ) )
1549                return @is_dir( $target );
1550
1551        // We need to find the permissions of the parent folder that exists and inherit that.
1552        $target_parent = dirname( $target );
1553        while ( '.' != $target_parent && ! is_dir( $target_parent ) ) {
1554                $target_parent = dirname( $target_parent );
1555        }
1556
1557        // Get the permission bits.
1558        if ( $stat = @stat( $target_parent ) ) {
1559                $dir_perms = $stat['mode'] & 0007777;
1560        } else {
1561                $dir_perms = 0777;
1562        }
1563
1564        if ( @mkdir( $target, $dir_perms, true ) ) {
1565
1566                /*
1567                 * If a umask is set that modifies $dir_perms, we'll have to re-set
1568                 * the $dir_perms correctly with chmod()
1569                 */
1570                if ( $dir_perms != ( $dir_perms & ~umask() ) ) {
1571                        $folder_parts = explode( '/', substr( $target, strlen( $target_parent ) + 1 ) );
1572                        for ( $i = 1, $c = count( $folder_parts ); $i <= $c; $i++ ) {
1573                                @chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms );
1574                        }
1575                }
1576
1577                return true;
1578        }
1579
1580        return false;
1581}
1582
1583/**
1584 * Test if a give filesystem path is absolute.
1585 *
1586 * For example, '/foo/bar', or 'c:\windows'.
1587 *
1588 * @since 2.5.0
1589 *
1590 * @param string $path File path.
1591 * @return bool True if path is absolute, false is not absolute.
1592 */
1593function path_is_absolute( $path ) {
1594        /*
1595         * This is definitive if true but fails if $path does not exist or contains
1596         * a symbolic link.
1597         */
1598        if ( realpath($path) == $path )
1599                return true;
1600
1601        if ( strlen($path) == 0 || $path[0] == '.' )
1602                return false;
1603
1604        // Windows allows absolute paths like this.
1605        if ( preg_match('#^[a-zA-Z]:\\\\#', $path) )
1606                return true;
1607
1608        // A path starting with / or \ is absolute; anything else is relative.
1609        return ( $path[0] == '/' || $path[0] == '\\' );
1610}
1611
1612/**
1613 * Join two filesystem paths together.
1614 *
1615 * For example, 'give me $path relative to $base'. If the $path is absolute,
1616 * then it the full path is returned.
1617 *
1618 * @since 2.5.0
1619 *
1620 * @param string $base Base path.
1621 * @param string $path Path relative to $base.
1622 * @return string The path with the base or absolute path.
1623 */
1624function path_join( $base, $path ) {
1625        if ( path_is_absolute($path) )
1626                return $path;
1627
1628        return rtrim($base, '/') . '/' . ltrim($path, '/');
1629}
1630
1631/**
1632 * Normalize a filesystem path.
1633 *
1634 * Replaces backslashes with forward slashes for Windows systems, and ensures
1635 * no duplicate slashes exist.
1636 *
1637 * @since 3.9.0
1638 *
1639 * @param string $path Path to normalize.
1640 * @return string Normalized path.
1641 */
1642function wp_normalize_path( $path ) {
1643        $path = str_replace( '\\', '/', $path );
1644        $path = preg_replace( '|/+|','/', $path );
1645        return $path;
1646}
1647
1648/**
1649 * Determine a writable directory for temporary files.
1650 *
1651 * Function's preference is the return value of sys_get_temp_dir(),
1652 * followed by your PHP temporary upload directory, followed by WP_CONTENT_DIR,
1653 * before finally defaulting to /tmp/
1654 *
1655 * In the event that this function does not find a writable location,
1656 * It may be overridden by the WP_TEMP_DIR constant in your wp-config.php file.
1657 *
1658 * @since 2.5.0
1659 *
1660 * @staticvar string $temp
1661 *
1662 * @return string Writable temporary directory.
1663 */
1664function get_temp_dir() {
1665        static $temp = '';
1666        if ( defined('WP_TEMP_DIR') )
1667                return trailingslashit(WP_TEMP_DIR);
1668
1669        if ( $temp )
1670                return trailingslashit( $temp );
1671
1672        if ( function_exists('sys_get_temp_dir') ) {
1673                $temp = sys_get_temp_dir();
1674                if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
1675                        return trailingslashit( $temp );
1676        }
1677
1678        $temp = ini_get('upload_tmp_dir');
1679        if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
1680                return trailingslashit( $temp );
1681
1682        $temp = WP_CONTENT_DIR . '/';
1683        if ( is_dir( $temp ) && wp_is_writable( $temp ) )
1684                return $temp;
1685
1686        return '/tmp/';
1687}
1688
1689/**
1690 * Determine if a directory is writable.
1691 *
1692 * This function is used to work around certain ACL issues in PHP primarily
1693 * affecting Windows Servers.
1694 *
1695 * @since 3.6.0
1696 *
1697 * @see win_is_writable()
1698 *
1699 * @param string $path Path to check for write-ability.
1700 * @return bool Whether the path is writable.
1701 */
1702function wp_is_writable( $path ) {
1703        if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) )
1704                return win_is_writable( $path );
1705        else
1706                return @is_writable( $path );
1707}
1708
1709/**
1710 * Workaround for Windows bug in is_writable() function
1711 *
1712 * PHP has issues with Windows ACL's for determine if a
1713 * directory is writable or not, this works around them by
1714 * checking the ability to open files rather than relying
1715 * upon PHP to interprate the OS ACL.
1716 *
1717 * @since 2.8.0
1718 *
1719 * @see http://bugs.php.net/bug.php?id=27609
1720 * @see http://bugs.php.net/bug.php?id=30931
1721 *
1722 * @param string $path Windows path to check for write-ability.
1723 * @return bool Whether the path is writable.
1724 */
1725function win_is_writable( $path ) {
1726
1727        if ( $path[strlen( $path ) - 1] == '/' ) { // if it looks like a directory, check a random file within the directory
1728                return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp');
1729        } elseif ( is_dir( $path ) ) { // If it's a directory (and not a file) check a random file within the directory
1730                return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' );
1731        }
1732        // check tmp file for read/write capabilities
1733        $should_delete_tmp_file = !file_exists( $path );
1734        $f = @fopen( $path, 'a' );
1735        if ( $f === false )
1736                return false;
1737        fclose( $f );
1738        if ( $should_delete_tmp_file )
1739                unlink( $path );
1740        return true;
1741}
1742
1743/**
1744 * Get an array containing the current upload directory's path and url.
1745 *
1746 * Checks the 'upload_path' option, which should be from the web root folder,
1747 * and if it isn't empty it will be used. If it is empty, then the path will be
1748 * 'WP_CONTENT_DIR/uploads'. If the 'UPLOADS' constant is defined, then it will
1749 * override the 'upload_path' option and 'WP_CONTENT_DIR/uploads' path.
1750 *
1751 * The upload URL path is set either by the 'upload_url_path' option or by using
1752 * the 'WP_CONTENT_URL' constant and appending '/uploads' to the path.
1753 *
1754 * If the 'uploads_use_yearmonth_folders' is set to true (checkbox if checked in
1755 * the administration settings panel), then the time will be used. The format
1756 * will be year first and then month.
1757 *
1758 * If the path couldn't be created, then an error will be returned with the key
1759 * 'error' containing the error message. The error suggests that the parent
1760 * directory is not writable by the server.
1761 *
1762 * On success, the returned array will have many indices:
1763 * 'path' - base directory and sub directory or full path to upload directory.
1764 * 'url' - base url and sub directory or absolute URL to upload directory.
1765 * 'subdir' - sub directory if uploads use year/month folders option is on.
1766 * 'basedir' - path without subdir.
1767 * 'baseurl' - URL path without subdir.
1768 * 'error' - set to false.
1769 *
1770 * @since 2.0.0
1771 *
1772 * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
1773 * @return array See above for description.
1774 */
1775function wp_upload_dir( $time = null ) {
1776        $siteurl = get_option( 'siteurl' );
1777        $upload_path = trim( get_option( 'upload_path' ) );
1778
1779        if ( empty( $upload_path ) || 'wp-content/uploads' == $upload_path ) {
1780                $dir = WP_CONTENT_DIR . '/uploads';
1781        } elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) {
1782                // $dir is absolute, $upload_path is (maybe) relative to ABSPATH
1783                $dir = path_join( ABSPATH, $upload_path );
1784        } else {
1785                $dir = $upload_path;
1786        }
1787
1788        if ( !$url = get_option( 'upload_url_path' ) ) {
1789                if ( empty($upload_path) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) )
1790                        $url = WP_CONTENT_URL . '/uploads';
1791                else
1792                        $url = trailingslashit( $siteurl ) . $upload_path;
1793        }
1794
1795        /*
1796         * Honor the value of UPLOADS. This happens as long as ms-files rewriting is disabled.
1797         * We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
1798         */
1799        if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
1800                $dir = ABSPATH . UPLOADS;
1801                $url = trailingslashit( $siteurl ) . UPLOADS;
1802        }
1803
1804        // If multisite (and if not the main site in a post-MU network)
1805        if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) {
1806
1807                if ( ! get_site_option( 'ms_files_rewriting' ) ) {
1808                        /*
1809                         * If ms-files rewriting is disabled (networks created post-3.5), it is fairly
1810                         * straightforward: Append sites/%d if we're not on the main site (for post-MU
1811                         * networks). (The extra directory prevents a four-digit ID from conflicting with
1812                         * a year-based directory for the main site. But if a MU-era network has disabled
1813                         * ms-files rewriting manually, they don't need the extra directory, as they never
1814                         * had wp-content/uploads for the main site.)
1815                         */
1816
1817                        if ( defined( 'MULTISITE' ) )
1818                                $ms_dir = '/sites/' . get_current_blog_id();
1819                        else
1820                                $ms_dir = '/' . get_current_blog_id();
1821
1822                        $dir .= $ms_dir;
1823                        $url .= $ms_dir;
1824
1825                } elseif ( defined( 'UPLOADS' ) && ! ms_is_switched() ) {
1826                        /*
1827                         * Handle the old-form ms-files.php rewriting if the network still has that enabled.
1828                         * When ms-files rewriting is enabled, then we only listen to UPLOADS when:
1829                         * 1) We are not on the main site in a post-MU network, as wp-content/uploads is used
1830                         *    there, and
1831                         * 2) We are not switched, as ms_upload_constants() hardcodes these constants to reflect
1832                         *    the original blog ID.
1833                         *
1834                         * Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute.
1835                         * (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as
1836                         * as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files
1837                         * rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
1838                         */
1839
1840                        if ( defined( 'BLOGUPLOADDIR' ) )
1841                                $dir = untrailingslashit( BLOGUPLOADDIR );
1842                        else
1843                                $dir = ABSPATH . UPLOADS;
1844                        $url = trailingslashit( $siteurl ) . 'files';
1845                }
1846        }
1847
1848        $basedir = $dir;
1849        $baseurl = $url;
1850
1851        $subdir = '';
1852        if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
1853                // Generate the yearly and monthly dirs
1854                if ( !$time )
1855                        $time = current_time( 'mysql' );
1856                $y = substr( $time, 0, 4 );
1857                $m = substr( $time, 5, 2 );
1858                $subdir = "/$y/$m";
1859        }
1860
1861        $dir .= $subdir;
1862        $url .= $subdir;
1863
1864        /**
1865         * Filter the uploads directory data.
1866         *
1867         * @since 2.0.0
1868         *
1869         * @param array $uploads Array of upload directory data with keys of 'path',
1870         *                       'url', 'subdir, 'basedir', and 'error'.
1871         */
1872        $uploads = apply_filters( 'upload_dir',
1873                array(
1874                        'path'    => $dir,
1875                        'url'     => $url,
1876                        'subdir'  => $subdir,
1877                        'basedir' => $basedir,
1878                        'baseurl' => $baseurl,
1879                        'error'   => false,
1880                ) );
1881
1882        // Make sure we have an uploads directory.
1883        if ( ! wp_mkdir_p( $uploads['path'] ) ) {
1884                if ( 0 === strpos( $uploads['basedir'], ABSPATH ) )
1885                        $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
1886                else
1887                        $error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
1888
1889                $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
1890                $uploads['error'] = $message;
1891        }
1892
1893        return $uploads;
1894}
1895
1896/**
1897 * Get a filename that is sanitized and unique for the given directory.
1898 *
1899 * If the filename is not unique, then a number will be added to the filename
1900 * before the extension, and will continue adding numbers until the filename is
1901 * unique.
1902 *
1903 * The callback is passed three parameters, the first one is the directory, the
1904 * second is the filename, and the third is the extension.
1905 *
1906 * @since 2.5.0
1907 *
1908 * @param string   $dir                      Directory.
1909 * @param string   $filename                 File name.
1910 * @param callback $unique_filename_callback Callback. Default null.
1911 * @return string New filename, if given wasn't unique.
1912 */
1913function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) {
1914        // Sanitize the file name before we begin processing.
1915        $filename = sanitize_file_name($filename);
1916
1917        // Separate the filename into a name and extension.
1918        $info = pathinfo($filename);
1919        $ext = !empty($info['extension']) ? '.' . $info['extension'] : '';
1920        $name = basename($filename, $ext);
1921
1922        // Edge case: if file is named '.ext', treat as an empty name.
1923        if ( $name === $ext )
1924                $name = '';
1925
1926        /*
1927         * Increment the file number until we have a unique file to save in $dir.
1928         * Use callback if supplied.
1929         */
1930        if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) {
1931                $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext );
1932        } else {
1933                $number = '';
1934
1935                // Change '.ext' to lower case.
1936                if ( $ext && strtolower($ext) != $ext ) {
1937                        $ext2 = strtolower($ext);
1938                        $filename2 = preg_replace( '|' . preg_quote($ext) . '$|', $ext2, $filename );
1939
1940                        // Check for both lower and upper case extension or image sub-sizes may be overwritten.
1941                        while ( file_exists($dir . "/$filename") || file_exists($dir . "/$filename2") ) {
1942                                $new_number = $number + 1;
1943                                $filename = str_replace( "$number$ext", "$new_number$ext", $filename );
1944                                $filename2 = str_replace( "$number$ext2", "$new_number$ext2", $filename2 );
1945                                $number = $new_number;
1946                        }
1947                        return $filename2;
1948                }
1949
1950                while ( file_exists( $dir . "/$filename" ) ) {
1951                        if ( '' == "$number$ext" )
1952                                $filename = $filename . ++$number . $ext;
1953                        else
1954                                $filename = str_replace( "$number$ext", ++$number . $ext, $filename );
1955                }
1956        }
1957
1958        return $filename;
1959}
1960
1961/**
1962 * Create a file in the upload folder with given content.
1963 *
1964 * If there is an error, then the key 'error' will exist with the error message.
1965 * If success, then the key 'file' will have the unique file path, the 'url' key
1966 * will have the link to the new file. and the 'error' key will be set to false.
1967 *
1968 * This function will not move an uploaded file to the upload folder. It will
1969 * create a new file with the content in $bits parameter. If you move the upload
1970 * file, read the content of the uploaded file, and then you can give the
1971 * filename and content to this function, which will add it to the upload
1972 * folder.
1973 *
1974 * The permissions will be set on the new file automatically by this function.
1975 *
1976 * @since 2.0.0
1977 *
1978 * @param string       $name       Filename.
1979 * @param null|string  $deprecated Never used. Set to null.
1980 * @param mixed        $bits       File content
1981 * @param string       $time       Optional. Time formatted in 'yyyy/mm'. Default null.
1982 * @return array
1983 */
1984function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
1985        if ( !empty( $deprecated ) )
1986                _deprecated_argument( __FUNCTION__, '2.0' );
1987
1988        if ( empty( $name ) )
1989                return array( 'error' => __( 'Empty filename' ) );
1990
1991        $wp_filetype = wp_check_filetype( $name );
1992        if ( ! $wp_filetype['ext'] && ! current_user_can( 'unfiltered_upload' ) )
1993                return array( 'error' => __( 'Invalid file type' ) );
1994
1995        $upload = wp_upload_dir( $time );
1996
1997        if ( $upload['error'] !== false )
1998                return $upload;
1999
2000        /**
2001         * Filter whether to treat the upload bits as an error.
2002         *
2003         * Passing a non-array to the filter will effectively short-circuit preparing
2004         * the upload bits, returning that value instead.
2005         *
2006         * @since 3.0.0
2007         *
2008         * @param mixed $upload_bits_error An array of upload bits data, or a non-array error to return.
2009         */
2010        $upload_bits_error = apply_filters( 'wp_upload_bits', array( 'name' => $name, 'bits' => $bits, 'time' => $time ) );
2011        if ( !is_array( $upload_bits_error ) ) {
2012                $upload[ 'error' ] = $upload_bits_error;
2013                return $upload;
2014        }
2015
2016        $filename = wp_unique_filename( $upload['path'], $name );
2017
2018        $new_file = $upload['path'] . "/$filename";
2019        if ( ! wp_mkdir_p( dirname( $new_file ) ) ) {
2020                if ( 0 === strpos( $upload['basedir'], ABSPATH ) )
2021                        $error_path = str_replace( ABSPATH, '', $upload['basedir'] ) . $upload['subdir'];
2022                else
2023                        $error_path = basename( $upload['basedir'] ) . $upload['subdir'];
2024
2025                $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
2026                return array( 'error' => $message );
2027        }
2028
2029        $ifp = @ fopen( $new_file, 'wb' );
2030        if ( ! $ifp )
2031                return array( 'error' => sprintf( __( 'Could not write file %s' ), $new_file ) );
2032
2033        @fwrite( $ifp, $bits );
2034        fclose( $ifp );
2035        clearstatcache();
2036
2037        // Set correct file permissions
2038        $stat = @ stat( dirname( $new_file ) );
2039        $perms = $stat['mode'] & 0007777;
2040        $perms = $perms & 0000666;
2041        @ chmod( $new_file, $perms );
2042        clearstatcache();
2043
2044        // Compute the URL
2045        $url = $upload['url'] . "/$filename";
2046
2047        return array( 'file' => $new_file, 'url' => $url, 'error' => false );
2048}
2049
2050/**
2051 * Retrieve the file type based on the extension name.
2052 *
2053 * @since 2.5.0
2054 *
2055 * @param string $ext The extension to search.
2056 * @return string|void The file type, example: audio, video, document, spreadsheet, etc.
2057 */
2058function wp_ext2type( $ext ) {
2059        $ext = strtolower( $ext );
2060
2061        /**
2062         * Filter file type based on the extension name.
2063         *
2064         * @since 2.5.0
2065         *
2066         * @see wp_ext2type()
2067         *
2068         * @param array $ext2type Multi-dimensional array with extensions for a default set
2069         *                        of file types.
2070         */
2071        $ext2type = apply_filters( 'ext2type', array(
2072                'image'       => array( 'jpg', 'jpeg', 'jpe',  'gif',  'png',  'bmp',   'tif',  'tiff', 'ico' ),
2073                'audio'       => array( 'aac', 'ac3',  'aif',  'aiff', 'm3a',  'm4a',   'm4b',  'mka',  'mp1',  'mp2',  'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
2074                'video'       => array( '3g2',  '3gp', '3gpp', 'asf', 'avi',  'divx', 'dv',   'flv',  'm4v',   'mkv',  'mov',  'mp4',  'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt',  'rm', 'vob', 'wmv' ),
2075                'document'    => array( 'doc', 'docx', 'docm', 'dotm', 'odt',  'pages', 'pdf',  'xps',  'oxps', 'rtf',  'wp', 'wpd', 'psd', 'xcf' ),
2076                'spreadsheet' => array( 'numbers',     'ods',  'xls',  'xlsx', 'xlsm',  'xlsb' ),
2077                'interactive' => array( 'swf', 'key',  'ppt',  'pptx', 'pptm', 'pps',   'ppsx', 'ppsm', 'sldx', 'sldm', 'odp' ),
2078                'text'        => array( 'asc', 'csv',  'tsv',  'txt' ),
2079                'archive'     => array( 'bz2', 'cab',  'dmg',  'gz',   'rar',  'sea',   'sit',  'sqx',  'tar',  'tgz',  'zip', '7z' ),
2080                'code'        => array( 'css', 'htm',  'html', 'php',  'js' ),
2081        ) );
2082
2083        foreach ( $ext2type as $type => $exts )
2084                if ( in_array( $ext, $exts ) )
2085                        return $type;
2086}
2087
2088/**
2089 * Retrieve the file type from the file name.
2090 *
2091 * You can optionally define the mime array, if needed.
2092 *
2093 * @since 2.0.4
2094 *
2095 * @param string $filename File name or path.
2096 * @param array  $mimes    Optional. Key is the file extension with value as the mime type.
2097 * @return array Values with extension first and mime type.
2098 */
2099function wp_check_filetype( $filename, $mimes = null ) {
2100        if ( empty($mimes) )
2101                $mimes = get_allowed_mime_types();
2102        $type = false;
2103        $ext = false;
2104
2105        foreach ( $mimes as $ext_preg => $mime_match ) {
2106                $ext_preg = '!\.(' . $ext_preg . ')$!i';
2107                if ( preg_match( $ext_preg, $filename, $ext_matches ) ) {
2108                        $type = $mime_match;
2109                        $ext = $ext_matches[1];
2110                        break;
2111                }
2112        }
2113
2114        return compact( 'ext', 'type' );
2115}
2116
2117/**
2118 * Attempt to determine the real file type of a file.
2119 *
2120 * If unable to, the file name extension will be used to determine type.
2121 *
2122 * If it's determined that the extension does not match the file's real type,
2123 * then the "proper_filename" value will be set with a proper filename and extension.
2124 *
2125 * Currently this function only supports validating images known to getimagesize().
2126 *
2127 * @since 3.0.0
2128 *
2129 * @param string $file     Full path to the file.
2130 * @param string $filename The name of the file (may differ from $file due to $file being
2131 *                         in a tmp directory).
2132 * @param array   $mimes   Optional. Key is the file extension with value as the mime type.
2133 * @return array Values for the extension, MIME, and either a corrected filename or false
2134 *               if original $filename is valid.
2135 */
2136function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
2137        $proper_filename = false;
2138
2139        // Do basic extension validation and MIME mapping
2140        $wp_filetype = wp_check_filetype( $filename, $mimes );
2141        $ext = $wp_filetype['ext'];
2142        $type = $wp_filetype['type'];
2143
2144        // We can't do any further validation without a file to work with
2145        if ( ! file_exists( $file ) ) {
2146                return compact( 'ext', 'type', 'proper_filename' );
2147        }
2148
2149        // We're able to validate images using GD
2150        if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) {
2151
2152                // Attempt to figure out what type of image it actually is
2153                $imgstats = @getimagesize( $file );
2154
2155                // If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME
2156                if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) {
2157                        /**
2158                         * Filter the list mapping image mime types to their respective extensions.
2159                         *
2160                         * @since 3.0.0
2161                         *
2162                         * @param  array $mime_to_ext Array of image mime types and their matching extensions.
2163                         */
2164                        $mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array(
2165                                'image/jpeg' => 'jpg',
2166                                'image/png'  => 'png',
2167                                'image/gif'  => 'gif',
2168                                'image/bmp'  => 'bmp',
2169                                'image/tiff' => 'tif',
2170                        ) );
2171
2172                        // Replace whatever is after the last period in the filename with the correct extension
2173                        if ( ! empty( $mime_to_ext[ $imgstats['mime'] ] ) ) {
2174                                $filename_parts = explode( '.', $filename );
2175                                array_pop( $filename_parts );
2176                                $filename_parts[] = $mime_to_ext[ $imgstats['mime'] ];
2177                                $new_filename = implode( '.', $filename_parts );
2178
2179                                if ( $new_filename != $filename ) {
2180                                        $proper_filename = $new_filename; // Mark that it changed
2181                                }
2182                                // Redefine the extension / MIME
2183                                $wp_filetype = wp_check_filetype( $new_filename, $mimes );
2184                                $ext = $wp_filetype['ext'];
2185                                $type = $wp_filetype['type'];
2186                        }
2187                }
2188        }
2189
2190        /**
2191         * Filter the "real" file type of the given file.
2192         *
2193         * @since 3.0.0
2194         *
2195         * @param array  $wp_check_filetype_and_ext File data array containing 'ext', 'type', and
2196         *                                          'proper_filename' keys.
2197         * @param string $file                      Full path to the file.
2198         * @param string $filename                  The name of the file (may differ from $file due to
2199         *                                          $file being in a tmp directory).
2200         * @param array  $mimes                     Key is the file extension with value as the mime type.
2201         */
2202        return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes );
2203}
2204
2205/**
2206 * Retrieve list of mime types and file extensions.
2207 *
2208 * @since 3.5.0
2209 * @since 4.2.0 Support was added for GIMP (xcf) files.
2210 *
2211 * @return array Array of mime types keyed by the file extension regex corresponding to those types.
2212 */
2213function wp_get_mime_types() {
2214        /**
2215         * Filter the list of mime types and file extensions.
2216         *
2217         * This filter should be used to add, not remove, mime types. To remove
2218         * mime types, use the 'upload_mimes' filter.
2219         *
2220         * @since 3.5.0
2221         *
2222         * @param array $wp_get_mime_types Mime types keyed by the file extension regex
2223         *                                 corresponding to those types.
2224         */
2225        return apply_filters( 'mime_types', array(
2226        // Image formats.
2227        'jpg|jpeg|jpe' => 'image/jpeg',
2228        'gif' => 'image/gif',
2229        'png' => 'image/png',
2230        'bmp' => 'image/bmp',
2231        'tiff|tif' => 'image/tiff',
2232        'ico' => 'image/x-icon',
2233        // Video formats.
2234        'asf|asx' => 'video/x-ms-asf',
2235        'wmv' => 'video/x-ms-wmv',
2236        'wmx' => 'video/x-ms-wmx',
2237        'wm' => 'video/x-ms-wm',
2238        'avi' => 'video/avi',
2239        'divx' => 'video/divx',
2240        'flv' => 'video/x-flv',
2241        'mov|qt' => 'video/quicktime',
2242        'mpeg|mpg|mpe' => 'video/mpeg',
2243        'mp4|m4v' => 'video/mp4',
2244        'ogv' => 'video/ogg',
2245        'webm' => 'video/webm',
2246        'mkv' => 'video/x-matroska',
2247        '3gp|3gpp' => 'video/3gpp', // Can also be audio
2248        '3g2|3gp2' => 'video/3gpp2', // Can also be audio
2249        // Text formats.
2250        'txt|asc|c|cc|h|srt' => 'text/plain',
2251        'csv' => 'text/csv',
2252        'tsv' => 'text/tab-separated-values',
2253        'ics' => 'text/calendar',
2254        'rtx' => 'text/richtext',
2255        'css' => 'text/css',
2256        'htm|html' => 'text/html',
2257        'vtt' => 'text/vtt',
2258        'dfxp' => 'application/ttaf+xml',
2259        // Audio formats.
2260        'mp3|m4a|m4b' => 'audio/mpeg',
2261        'ra|ram' => 'audio/x-realaudio',
2262        'wav' => 'audio/wav',
2263        'ogg|oga' => 'audio/ogg',
2264        'mid|midi' => 'audio/midi',
2265        'wma' => 'audio/x-ms-wma',
2266        'wax' => 'audio/x-ms-wax',
2267        'mka' => 'audio/x-matroska',
2268        // Misc application formats.
2269        'rtf' => 'application/rtf',
2270        'js' => 'application/javascript',
2271        'pdf' => 'application/pdf',
2272        'swf' => 'application/x-shockwave-flash',
2273        'class' => 'application/java',
2274        'tar' => 'application/x-tar',
2275        'zip' => 'application/zip',
2276        'gz|gzip' => 'application/x-gzip',
2277        'rar' => 'application/rar',
2278        '7z' => 'application/x-7z-compressed',
2279        'exe' => 'application/x-msdownload',
2280        'psd' => 'application/octet-stream',
2281        'xcf' => 'application/octet-stream',
2282        // MS Office formats.
2283        'doc' => 'application/msword',
2284        'pot|pps|ppt' => 'application/vnd.ms-powerpoint',
2285        'wri' => 'application/vnd.ms-write',
2286        'xla|xls|xlt|xlw' => 'application/vnd.ms-excel',
2287        'mdb' => 'application/vnd.ms-access',
2288        'mpp' => 'application/vnd.ms-project',
2289        'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
2290        'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
2291        'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
2292        'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
2293        'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
2294        'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
2295        'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
2296        'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
2297        'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
2298        'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
2299        'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
2300        'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
2301        'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
2302        'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
2303        'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
2304        'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
2305        'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
2306        'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
2307        'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
2308        'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
2309        'oxps' => 'application/oxps',
2310        'xps' => 'application/vnd.ms-xpsdocument',
2311        // OpenOffice formats.
2312        'odt' => 'application/vnd.oasis.opendocument.text',
2313        'odp' => 'application/vnd.oasis.opendocument.presentation',
2314        'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
2315        'odg' => 'application/vnd.oasis.opendocument.graphics',
2316        'odc' => 'application/vnd.oasis.opendocument.chart',
2317        'odb' => 'application/vnd.oasis.opendocument.database',
2318        'odf' => 'application/vnd.oasis.opendocument.formula',
2319        // WordPerfect formats.
2320        'wp|wpd' => 'application/wordperfect',
2321        // iWork formats.
2322        'key' => 'application/vnd.apple.keynote',
2323        'numbers' => 'application/vnd.apple.numbers',
2324        'pages' => 'application/vnd.apple.pages',
2325        ) );
2326}
2327/**
2328 * Retrieve list of allowed mime types and file extensions.
2329 *
2330 * @since 2.8.6
2331 *
2332 * @param int|WP_User $user Optional. User to check. Defaults to current user.
2333 * @return array Array of mime types keyed by the file extension regex corresponding
2334 *               to those types.
2335 */
2336function get_allowed_mime_types( $user = null ) {
2337        $t = wp_get_mime_types();
2338
2339        unset( $t['swf'], $t['exe'] );
2340        if ( function_exists( 'current_user_can' ) )
2341                $unfiltered = $user ? user_can( $user, 'unfiltered_html' ) : current_user_can( 'unfiltered_html' );
2342
2343        if ( empty( $unfiltered ) )
2344                unset( $t['htm|html'] );
2345
2346        /**
2347         * Filter list of allowed mime types and file extensions.
2348         *
2349         * @since 2.0.0
2350         *
2351         * @param array            $t    Mime types keyed by the file extension regex corresponding to
2352         *                               those types. 'swf' and 'exe' removed from full list. 'htm|html' also
2353         *                               removed depending on '$user' capabilities.
2354         * @param int|WP_User|null $user User ID, User object or null if not provided (indicates current user).
2355         */
2356        return apply_filters( 'upload_mimes', $t, $user );
2357}
2358
2359/**
2360 * Display "Are You Sure" message to confirm the action being taken.
2361 *
2362 * If the action has the nonce explain message, then it will be displayed
2363 * along with the "Are you sure?" message.
2364 *
2365 * @since 2.0.4
2366 *
2367 * @param string $action The nonce action.
2368 */
2369function wp_nonce_ays( $action ) {
2370        if ( 'log-out' == $action ) {
2371                $html = sprintf( __( 'You are attempting to log out of %s' ), get_bloginfo( 'name' ) ) . '</p><p>';
2372                $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
2373                $html .= sprintf( __( "Do you really want to <a href='%s'>log out</a>?"), wp_logout_url( $redirect_to ) );
2374        } else {
2375                $html = __( 'Are you sure you want to do this?' );
2376                if ( wp_get_referer() )
2377                        $html .= "</p><p><a href='" . esc_url( remove_query_arg( 'updated', wp_get_referer() ) ) . "'>" . __( 'Please try again.' ) . "</a>";
2378        }
2379
2380        wp_die( $html, __( 'WordPress Failure Notice' ), 403 );
2381}
2382
2383/**
2384 * Kill WordPress execution and display HTML message with error message.
2385 *
2386 * This function complements the `die()` PHP function. The difference is that
2387 * HTML will be displayed to the user. It is recommended to use this function
2388 * only when the execution should not continue any further. It is not recommended
2389 * to call this function very often, and try to handle as many errors as possible
2390 * silently or more gracefully.
2391 *
2392 * As a shorthand, the desired HTTP response code may be passed as an integer to
2393 * the `$title` parameter (the default title would apply) or the `$args` parameter.
2394 *
2395 * @since 2.0.4
2396 * @since 4.1.0 The `$title` and `$args` parameters were changed to optionally accept
2397 *              an integer to be used as the response code.
2398 *
2399 * @param string|WP_Error  $message Optional. Error message. If this is a {@see WP_Error} object,
2400 *                                  the error's messages are used. Default empty.
2401 * @param string|int       $title   Optional. Error title. If `$message` is a `WP_Error` object,
2402 *                                  error data with the key 'title' may be used to specify the title.
2403 *                                  If `$title` is an integer, then it is treated as the response
2404 *                                  code. Default empty.
2405 * @param string|array|int $args {
2406 *     Optional. Arguments to control behavior. If `$args` is an integer, then it is treated
2407 *     as the response code. Default empty array.
2408 *
2409 *     @type int    $response       The HTTP response code. Default 500.
2410 *     @type bool   $back_link      Whether to include a link to go back. Default false.
2411 *     @type string $text_direction The text direction. This is only useful internally, when WordPress
2412 *                                  is still loading and the site's locale is not set up yet. Accepts 'rtl'.
2413 *                                  Default is the value of {@see is_rtl()}.
2414 * }
2415 */
2416function wp_die( $message = '', $title = '', $args = array() ) {
2417
2418        if ( is_int( $args ) ) {
2419                $args = array( 'response' => $args );
2420        } elseif ( is_int( $title ) ) {
2421                $args  = array( 'response' => $title );
2422                $title = '';
2423        }
2424
2425        if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
2426                /**
2427                 * Filter callback for killing WordPress execution for AJAX requests.
2428                 *
2429                 * @since 3.4.0
2430                 *
2431                 * @param callback $function Callback function name.
2432                 */
2433                $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
2434        } elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
2435                /**
2436                 * Filter callback for killing WordPress execution for XML-RPC requests.
2437                 *
2438                 * @since 3.4.0
2439                 *
2440                 * @param callback $function Callback function name.
2441                 */
2442                $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
2443        } else {
2444                /**
2445                 * Filter callback for killing WordPress execution for all non-AJAX, non-XML-RPC requests.
2446                 *
2447                 * @since 3.0.0
2448                 *
2449                 * @param callback $function Callback function name.
2450                 */
2451                $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
2452        }
2453
2454        call_user_func( $function, $message, $title, $args );
2455}
2456
2457/**
2458 * Kill WordPress execution and display HTML message with error message.
2459 *
2460 * This is the default handler for wp_die if you want a custom one for your
2461 * site then you can overload using the wp_die_handler filter in wp_die
2462 *
2463 * @since 3.0.0
2464 * @access private
2465 *
2466 * @param string       $message Error message.
2467 * @param string       $title   Optional. Error title. Default empty.
2468 * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
2469 */
2470function _default_wp_die_handler( $message, $title = '', $args = array() ) {
2471        $defaults = array( 'response' => 500 );
2472        $r = wp_parse_args($args, $defaults);
2473
2474        $have_gettext = function_exists('__');
2475
2476        if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) {
2477                if ( empty( $title ) ) {
2478                        $error_data = $message->get_error_data();
2479                        if ( is_array( $error_data ) && isset( $error_data['title'] ) )
2480                                $title = $error_data['title'];
2481                }
2482                $errors = $message->get_error_messages();
2483                switch ( count( $errors ) ) {
2484                case 0 :
2485                        $message = '';
2486                        break;
2487                case 1 :
2488                        $message = "<p>{$errors[0]}</p>";
2489                        break;
2490                default :
2491                        $message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $errors ) . "</li>\n\t</ul>";
2492                        break;
2493                }
2494        } elseif ( is_string( $message ) ) {
2495                $message = "<p>$message</p>";
2496        }
2497
2498        if ( isset( $r['back_link'] ) && $r['back_link'] ) {
2499                $back_text = $have_gettext? __('&laquo; Back') : '&laquo; Back';
2500                $message .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
2501        }
2502
2503        if ( ! did_action( 'admin_head' ) ) :
2504                if ( !headers_sent() ) {
2505                        status_header( $r['response'] );
2506                        nocache_headers();
2507                        header( 'Content-Type: text/html; charset=utf-8' );
2508                }
2509
2510                if ( empty($title) )
2511                        $title = $have_gettext ? __('WordPress &rsaquo; Error') : 'WordPress &rsaquo; Error';
2512
2513                $text_direction = 'ltr';
2514                if ( isset($r['text_direction']) && 'rtl' == $r['text_direction'] )
2515                        $text_direction = 'rtl';
2516                elseif ( function_exists( 'is_rtl' ) && is_rtl() )
2517                        $text_direction = 'rtl';
2518?>
2519<!DOCTYPE html>
2520<!-- Ticket #11289, IE bug fix: always pad the error page with enough characters such that it is greater than 512 bytes, even after gzip compression abcdefghijklmnopqrstuvwxyz1234567890aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz11223344556677889900abacbcbdcdcededfefegfgfhghgihihjijikjkjlklkmlmlnmnmononpopoqpqprqrqsrsrtstsubcbcdcdedefefgfabcadefbghicjkldmnoepqrfstugvwxhyz1i234j567k890laabmbccnddeoeffpgghqhiirjjksklltmmnunoovppqwqrrxsstytuuzvvw0wxx1yyz2z113223434455666777889890091abc2def3ghi4jkl5mno6pqr7stu8vwx9yz11aab2bcc3dd4ee5ff6gg7hh8ii9j0jk1kl2lmm3nnoo4p5pq6qrr7ss8tt9uuvv0wwx1x2yyzz13aba4cbcb5dcdc6dedfef8egf9gfh0ghg1ihi2hji3jik4jkj5lkl6kml7mln8mnm9ono
2521-->
2522<html xmlns="http://www.w3.org/1999/xhtml" <?php if ( function_exists( 'language_attributes' ) && function_exists( 'is_rtl' ) ) language_attributes(); else echo "dir='$text_direction'"; ?>>
2523<head>
2524        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2525        <meta name="viewport" content="width=device-width">
2526        <meta name="robots" content="noindex,nofollow" />
2527        <title><?php echo $title ?></title>
2528        <style type="text/css">
2529                html {
2530                        background: #f1f1f1;
2531                }
2532                body {
2533                        background: #fff;
2534                        color: #444;
2535                        font-family: "Open Sans", sans-serif;
2536                        margin: 2em auto;
2537                        padding: 1em 2em;
2538                        max-width: 700px;
2539                        -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2540                        box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2541                }
2542                h1 {
2543                        border-bottom: 1px solid #dadada;
2544                        clear: both;
2545                        color: #666;
2546                        font: 24px "Open Sans", sans-serif;
2547                        margin: 30px 0 0 0;
2548                        padding: 0;
2549                        padding-bottom: 7px;
2550                }
2551                #error-page {
2552                        margin-top: 50px;
2553                }
2554                #error-page p {
2555                        font-size: 14px;
2556                        line-height: 1.5;
2557                        margin: 25px 0 20px;
2558                }
2559                #error-page code {
2560                        font-family: Consolas, Monaco, monospace;
2561                }
2562                ul li {
2563                        margin-bottom: 10px;
2564                        font-size: 14px ;
2565                }
2566                a {
2567                        color: #21759B;
2568                        text-decoration: none;
2569                }
2570                a:hover {
2571                        color: #D54E21;
2572                }
2573                .button {
2574                        background: #f7f7f7;
2575                        border: 1px solid #cccccc;
2576                        color: #555;
2577                        display: inline-block;
2578                        text-decoration: none;
2579                        font-size: 13px;
2580                        line-height: 26px;
2581                        height: 28px;
2582                        margin: 0;
2583                        padding: 0 10px 1px;
2584                        cursor: pointer;
2585                        -webkit-border-radius: 3px;
2586                        -webkit-appearance: none;
2587                        border-radius: 3px;
2588                        white-space: nowrap;
2589                        -webkit-box-sizing: border-box;
2590                        -moz-box-sizing:    border-box;
2591                        box-sizing:         border-box;
2592
2593                        -webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0,0,0,.08);
2594                        box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0,0,0,.08);
2595                        vertical-align: top;
2596                }
2597
2598                .button.button-large {
2599                        height: 29px;
2600                        line-height: 28px;
2601                        padding: 0 12px;
2602                }
2603
2604                .button:hover,
2605                .button:focus {
2606                        background: #fafafa;
2607                        border-color: #999;
2608                        color: #222;
2609                }
2610
2611                .button:focus  {
2612                        -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,.2);
2613                        box-shadow: 1px 1px 1px rgba(0,0,0,.2);
2614                }
2615
2616                .button:active {
2617                        background: #eee;
2618                        border-color: #999;
2619                        color: #333;
2620                        -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2621                        box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2622                }
2623
2624                <?php if ( 'rtl' == $text_direction ) : ?>
2625                body { font-family: Tahoma, Arial; }
2626                <?php endif; ?>
2627        </style>
2628</head>
2629<body id="error-page">
2630<?php endif; // ! did_action( 'admin_head' ) ?>
2631        <?php echo $message; ?>
2632</body>
2633</html>
2634<?php
2635        die();
2636}
2637
2638/**
2639 * Kill WordPress execution and display XML message with error message.
2640 *
2641 * This is the handler for wp_die when processing XMLRPC requests.
2642 *
2643 * @since 3.2.0
2644 * @access private
2645 *
2646 * @global wp_xmlrpc_server $wp_xmlrpc_server
2647 *
2648 * @param string       $message Error message.
2649 * @param string       $title   Optional. Error title. Default empty.
2650 * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
2651 */
2652function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) {
2653        global $wp_xmlrpc_server;
2654        $defaults = array( 'response' => 500 );
2655
2656        $r = wp_parse_args($args, $defaults);
2657
2658        if ( $wp_xmlrpc_server ) {
2659                $error = new IXR_Error( $r['response'] , $message);
2660                $wp_xmlrpc_server->output( $error->getXml() );
2661        }
2662        die();
2663}
2664
2665/**
2666 * Kill WordPress ajax execution.
2667 *
2668 * This is the handler for wp_die when processing Ajax requests.
2669 *
2670 * @since 3.4.0
2671 * @access private
2672 *
2673 * @param string $message Optional. Response to print. Default empty.
2674 */
2675function _ajax_wp_die_handler( $message = '' ) {
2676        if ( is_scalar( $message ) )
2677                die( (string) $message );
2678        die( '0' );
2679}
2680
2681/**
2682 * Kill WordPress execution.
2683 *
2684 * This is the handler for wp_die when processing APP requests.
2685 *
2686 * @since 3.4.0
2687 * @access private
2688 *
2689 * @param string $message Optional. Response to print. Default empty.
2690 */
2691function _scalar_wp_die_handler( $message = '' ) {
2692        if ( is_scalar( $message ) )
2693                die( (string) $message );
2694        die();
2695}
2696
2697/**
2698 * Encode a variable into JSON, with some sanity checks.
2699 *
2700 * @since 4.1.0
2701 *
2702 * @param mixed $data    Variable (usually an array or object) to encode as JSON.
2703 * @param int   $options Optional. Options to be passed to json_encode(). Default 0.
2704 * @param int   $depth   Optional. Maximum depth to walk through $data. Must be
2705 *                       greater than 0. Default 512.
2706 * @return string|false The JSON encoded string, or false if it cannot be encoded.
2707 */
2708function wp_json_encode( $data, $options = 0, $depth = 512 ) {
2709        /*
2710         * json_encode() has had extra params added over the years.
2711         * $options was added in 5.3, and $depth in 5.5.
2712         * We need to make sure we call it with the correct arguments.
2713         */
2714        if ( version_compare( PHP_VERSION, '5.5', '>=' ) ) {
2715                $args = array( $data, $options, $depth );
2716        } elseif ( version_compare( PHP_VERSION, '5.3', '>=' ) ) {
2717                $args = array( $data, $options );
2718        } else {
2719                $args = array( $data );
2720        }
2721
2722        $json = @call_user_func_array( 'json_encode', $args );
2723
2724        // If json_encode() was successful, no need to do more sanity checking.
2725        // ... unless we're in an old version of PHP, and json_encode() returned
2726        // a string containing 'null'. Then we need to do more sanity checking.
2727        if ( false !== $json && ( version_compare( PHP_VERSION, '5.5', '>=' ) || false === strpos( $json, 'null' ) ) )  {
2728                return $json;
2729        }
2730
2731        try {
2732                $args[0] = _wp_json_sanity_check( $data, $depth );
2733        } catch ( Exception $e ) {
2734                return false;
2735        }
2736
2737        return call_user_func_array( 'json_encode', $args );
2738}
2739
2740/**
2741 * Perform sanity checks on data that shall be encoded to JSON.
2742 *
2743 * @ignore
2744 * @since 4.1.0
2745 * @access private
2746 *
2747 * @see wp_json_encode()
2748 *
2749 * @param mixed $data  Variable (usually an array or object) to encode as JSON.
2750 * @param int   $depth Maximum depth to walk through $data. Must be greater than 0.
2751 * @return mixed The sanitized data that shall be encoded to JSON.
2752 */
2753function _wp_json_sanity_check( $data, $depth ) {
2754        if ( $depth < 0 ) {
2755                throw new Exception( 'Reached depth limit' );
2756        }
2757
2758        if ( is_array( $data ) ) {
2759                $output = array();
2760                foreach ( $data as $id => $el ) {
2761                        // Don't forget to sanitize the ID!
2762                        if ( is_string( $id ) ) {
2763                                $clean_id = _wp_json_convert_string( $id );
2764                        } else {
2765                                $clean_id = $id;
2766                        }
2767
2768                        // Check the element type, so that we're only recursing if we really have to.
2769                        if ( is_array( $el ) || is_object( $el ) ) {
2770                                $output[ $clean_id ] = _wp_json_sanity_check( $el, $depth - 1 );
2771                        } elseif ( is_string( $el ) ) {
2772                                $output[ $clean_id ] = _wp_json_convert_string( $el );
2773                        } else {
2774                                $output[ $clean_id ] = $el;
2775                        }
2776                }
2777        } elseif ( is_object( $data ) ) {
2778                $output = new stdClass;
2779                foreach ( $data as $id => $el ) {
2780                        if ( is_string( $id ) ) {
2781                                $clean_id = _wp_json_convert_string( $id );
2782                        } else {
2783                                $clean_id = $id;
2784                        }
2785
2786                        if ( is_array( $el ) || is_object( $el ) ) {
2787                                $output->$clean_id = _wp_json_sanity_check( $el, $depth - 1 );
2788                        } elseif ( is_string( $el ) ) {
2789                                $output->$clean_id = _wp_json_convert_string( $el );
2790                        } else {
2791                                $output->$clean_id = $el;
2792                        }
2793                }
2794        } elseif ( is_string( $data ) ) {
2795                return _wp_json_convert_string( $data );
2796        } else {
2797                return $data;
2798        }
2799
2800        return $output;
2801}
2802
2803/**
2804 * Convert a string to UTF-8, so that it can be safely encoded to JSON.
2805 *
2806 * @ignore
2807 * @since 4.1.0
2808 * @access private
2809 *
2810 * @see _wp_json_sanity_check()
2811 *
2812 * @staticvar bool $use_mb
2813 *
2814 * @param string $string The string which is to be converted.
2815 * @return string The checked string.
2816 */
2817function _wp_json_convert_string( $string ) {
2818        static $use_mb = null;
2819        if ( is_null( $use_mb ) ) {
2820                $use_mb = function_exists( 'mb_convert_encoding' );
2821        }
2822
2823        if ( $use_mb ) {
2824                $encoding = mb_detect_encoding( $string, mb_detect_order(), true );
2825                if ( $encoding ) {
2826                        return mb_convert_encoding( $string, 'UTF-8', $encoding );
2827                } else {
2828                        return mb_convert_encoding( $string, 'UTF-8', 'UTF-8' );
2829                }
2830        } else {
2831                return wp_check_invalid_utf8( $string, true );
2832        }
2833}
2834
2835/**
2836 * Send a JSON response back to an Ajax request.
2837 *
2838 * @since 3.5.0
2839 *
2840 * @param mixed $response Variable (usually an array or object) to encode as JSON,
2841 *                        then print and die.
2842 */
2843function wp_send_json( $response ) {
2844        @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
2845        echo wp_json_encode( $response );
2846        if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
2847                wp_die();
2848        else
2849                die;
2850}
2851
2852/**
2853 * Send a JSON response back to an Ajax request, indicating success.
2854 *
2855 * @since 3.5.0
2856 *
2857 * @param mixed $data Data to encode as JSON, then print and die.
2858 */
2859function wp_send_json_success( $data = null ) {
2860        $response = array( 'success' => true );
2861
2862        if ( isset( $data ) )
2863                $response['data'] = $data;
2864
2865        wp_send_json( $response );
2866}
2867
2868/**
2869 * Send a JSON response back to an Ajax request, indicating failure.
2870 *
2871 * If the `$data` parameter is a {@see WP_Error} object, the errors
2872 * within the object are processed and output as an array of error
2873 * codes and corresponding messages. All other types are output
2874 * without further processing.
2875 *
2876 * @since 3.5.0
2877 * @since 4.1.0 The `$data` parameter is now processed if a {@see WP_Error}
2878 *              object is passed in.
2879 *
2880 * @param mixed $data Data to encode as JSON, then print and die.
2881 */
2882function wp_send_json_error( $data = null ) {
2883        $response = array( 'success' => false );
2884
2885        if ( isset( $data ) ) {
2886                if ( is_wp_error( $data ) ) {
2887                        $result = array();
2888                        foreach ( $data->errors as $code => $messages ) {
2889                                foreach ( $messages as $message ) {
2890                                        $result[] = array( 'code' => $code, 'message' => $message );
2891                                }
2892                        }
2893
2894                        $response['data'] = $result;
2895                } else {
2896                        $response['data'] = $data;
2897                }
2898        }
2899
2900        wp_send_json( $response );
2901}
2902
2903/**
2904 * Retrieve the WordPress home page URL.
2905 *
2906 * If the constant named 'WP_HOME' exists, then it will be used and returned
2907 * by the function. This can be used to counter the redirection on your local
2908 * development environment.
2909 *
2910 * @since 2.2.0
2911 * @access private
2912 *
2913 * @see WP_HOME
2914 *
2915 * @param string $url URL for the home location.
2916 * @return string Homepage location.
2917 */
2918function _config_wp_home( $url = '' ) {
2919        if ( defined( 'WP_HOME' ) )
2920                return untrailingslashit( WP_HOME );
2921        return $url;
2922}
2923
2924/**
2925 * Retrieve the WordPress site URL.
2926 *
2927 * If the constant named 'WP_SITEURL' is defined, then the value in that
2928 * constant will always be returned. This can be used for debugging a site
2929 * on your localhost while not having to change the database to your URL.
2930 *
2931 * @since 2.2.0
2932 * @access private
2933 *
2934 * @see WP_SITEURL
2935 *
2936 * @param string $url URL to set the WordPress site location.
2937 * @return string The WordPress Site URL.
2938 */
2939function _config_wp_siteurl( $url = '' ) {
2940        if ( defined( 'WP_SITEURL' ) )
2941                return untrailingslashit( WP_SITEURL );
2942        return $url;
2943}
2944
2945/**
2946 * Set the localized direction for MCE plugin.
2947 *
2948 * Will only set the direction to 'rtl', if the WordPress locale has
2949 * the text direction set to 'rtl'.
2950 *
2951 * Fills in the 'directionality' setting, enables the 'directionality'
2952 * plugin, and adds the 'ltr' button to 'toolbar1', formerly
2953 * 'theme_advanced_buttons1' array keys. These keys are then returned
2954 * in the $input (TinyMCE settings) array.
2955 *
2956 * @since 2.1.0
2957 * @access private
2958 *
2959 * @param array $input MCE settings array.
2960 * @return array Direction set for 'rtl', if needed by locale.
2961 */
2962function _mce_set_direction( $input ) {
2963        if ( is_rtl() ) {
2964                $input['directionality'] = 'rtl';
2965
2966                if ( ! empty( $input['plugins'] ) && strpos( $input['plugins'], 'directionality' ) === false ) {
2967                        $input['plugins'] .= ',directionality';
2968                }
2969
2970                if ( ! empty( $input['toolbar1'] ) && ! preg_match( '/\bltr\b/', $input['toolbar1'] ) ) {
2971                        $input['toolbar1'] .= ',ltr';
2972                }
2973        }
2974
2975        return $input;
2976}
2977
2978
2979/**
2980 * Convert smiley code to the icon graphic file equivalent.
2981 *
2982 * You can turn off smilies, by going to the write setting screen and unchecking
2983 * the box, or by setting 'use_smilies' option to false or removing the option.
2984 *
2985 * Plugins may override the default smiley list by setting the $wpsmiliestrans
2986 * to an array, with the key the code the blogger types in and the value the
2987 * image file.
2988 *
2989 * The $wp_smiliessearch global is for the regular expression and is set each
2990 * time the function is called.
2991 *
2992 * The full list of smilies can be found in the function and won't be listed in
2993 * the description. Probably should create a Codex page for it, so that it is
2994 * available.
2995 *
2996 * @global array $wpsmiliestrans
2997 * @global array $wp_smiliessearch
2998 *
2999 * @since 2.2.0
3000 */
3001function smilies_init() {
3002        global $wpsmiliestrans, $wp_smiliessearch;
3003
3004        // don't bother setting up smilies if they are disabled
3005        if ( !get_option( 'use_smilies' ) )
3006                return;
3007
3008        if ( !isset( $wpsmiliestrans ) ) {
3009                $wpsmiliestrans = array(
3010                ':mrgreen:' => 'mrgreen.png',
3011                ':neutral:' => "\xf0\x9f\x98\x90",
3012                ':twisted:' => "\xf0\x9f\x98\x88",
3013                  ':arrow:' => "\xe2\x9e\xa1",
3014                  ':shock:' => "\xf0\x9f\x98\xaf",
3015                  ':smile:' => 'simple-smile.png',
3016                    ':???:' => "\xf0\x9f\x98\x95",
3017                   ':cool:' => "\xf0\x9f\x98\x8e",
3018                   ':evil:' => "\xf0\x9f\x91\xbf",
3019                   ':grin:' => "\xf0\x9f\x98\x80",
3020                   ':idea:' => "\xf0\x9f\x92\xa1",
3021                   ':oops:' => "\xf0\x9f\x98\xb3",
3022                   ':razz:' => "\xf0\x9f\x98\x9b",
3023                   ':roll:' => 'rolleyes.png',
3024                   ':wink:' => "\xf0\x9f\x98\x89",
3025                    ':cry:' => "\xf0\x9f\x98\xa5",
3026                    ':eek:' => "\xf0\x9f\x98\xae",
3027                    ':lol:' => "\xf0\x9f\x98\x86",
3028                    ':mad:' => "\xf0\x9f\x98\xa1",
3029                    ':sad:' => 'frownie.png',
3030                      '8-)' => "\xf0\x9f\x98\x8e",
3031                      '8-O' => "\xf0\x9f\x98\xaf",
3032                      ':-(' => 'frownie.png',
3033                      ':-)' => 'simple-smile.png',
3034                      ':-?' => "\xf0\x9f\x98\x95",
3035                      ':-D' => "\xf0\x9f\x98\x80",
3036                      ':-P' => "\xf0\x9f\x98\x9b",
3037                      ':-o' => "\xf0\x9f\x98\xae",
3038                      ':-x' => "\xf0\x9f\x98\xa1",
3039                      ':-|' => "\xf0\x9f\x98\x90",
3040                      ';-)' => "\xf0\x9f\x98\x89",
3041                // This one transformation breaks regular text with frequency.
3042                //     '8)' => "\xf0\x9f\x98\x8e",
3043                       '8O' => "\xf0\x9f\x98\xaf",
3044                       ':(' => 'frownie.png',
3045                       ':)' => 'simple-smile.png',
3046                       ':?' => "\xf0\x9f\x98\x95",
3047                       ':D' => "\xf0\x9f\x98\x80",
3048                       ':P' => "\xf0\x9f\x98\x9b",
3049                       ':o' => "\xf0\x9f\x98\xae",
3050                       ':x' => "\xf0\x9f\x98\xa1",
3051                       ':|' => "\xf0\x9f\x98\x90",
3052                       ';)' => "\xf0\x9f\x98\x89",
3053                      ':!:' => "\xe2\x9d\x97",
3054                      ':?:' => "\xe2\x9d\x93",
3055                );
3056        }
3057
3058        if (count($wpsmiliestrans) == 0) {
3059                return;
3060        }
3061
3062        /*
3063         * NOTE: we sort the smilies in reverse key order. This is to make sure
3064         * we match the longest possible smilie (:???: vs :?) as the regular
3065         * expression used below is first-match
3066         */
3067        krsort($wpsmiliestrans);
3068
3069        $spaces = wp_spaces_regexp();
3070
3071        // Begin first "subpattern"
3072        $wp_smiliessearch = '/(?<=' . $spaces . '|^)';
3073
3074        $subchar = '';
3075        foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
3076                $firstchar = substr($smiley, 0, 1);
3077                $rest = substr($smiley, 1);
3078
3079                // new subpattern?
3080                if ($firstchar != $subchar) {
3081                        if ($subchar != '') {
3082                                $wp_smiliessearch .= ')(?=' . $spaces . '|$)';  // End previous "subpattern"
3083                                $wp_smiliessearch .= '|(?<=' . $spaces . '|^)'; // Begin another "subpattern"
3084                        }
3085                        $subchar = $firstchar;
3086                        $wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:';
3087                } else {
3088                        $wp_smiliessearch .= '|';
3089                }
3090                $wp_smiliessearch .= preg_quote($rest, '/');
3091        }
3092
3093        $wp_smiliessearch .= ')(?=' . $spaces . '|$)/m';
3094
3095}
3096
3097/**
3098 * Merge user defined arguments into defaults array.
3099 *
3100 * This function is used throughout WordPress to allow for both string or array
3101 * to be merged into another array.
3102 *
3103 * @since 2.2.0
3104 *
3105 * @param string|array $args     Value to merge with $defaults
3106 * @param array        $defaults Optional. Array that serves as the defaults. Default empty.
3107 * @return array Merged user defined values with defaults.
3108 */
3109function wp_parse_args( $args, $defaults = '' ) {
3110        if ( is_object( $args ) )
3111                $r = get_object_vars( $args );
3112        elseif ( is_array( $args ) )
3113                $r =& $args;
3114        else
3115                wp_parse_str( $args, $r );
3116
3117        if ( is_array( $defaults ) )
3118                return array_merge( $defaults, $r );
3119        return $r;
3120}
3121
3122/**
3123 * Clean up an array, comma- or space-separated list of IDs.
3124 *
3125 * @since 3.0.0
3126 *
3127 * @param array|string $list List of ids.
3128 * @return array Sanitized array of IDs.
3129 */
3130function wp_parse_id_list( $list ) {
3131        if ( !is_array($list) )
3132                $list = preg_split('/[\s,]+/', $list);
3133
3134        return array_unique(array_map('absint', $list));
3135}
3136
3137/**
3138 * Extract a slice of an array, given a list of keys.
3139 *
3140 * @since 3.1.0
3141 *
3142 * @param array $array The original array.
3143 * @param array $keys  The list of keys.
3144 * @return array The array slice.
3145 */
3146function wp_array_slice_assoc( $array, $keys ) {
3147        $slice = array();
3148        foreach ( $keys as $key )
3149                if ( isset( $array[ $key ] ) )
3150                        $slice[ $key ] = $array[ $key ];
3151
3152        return $slice;
3153}
3154
3155/**
3156 * Filters a list of objects, based on a set of key => value arguments.
3157 *
3158 * @since 3.0.0
3159 *
3160 * @param array       $list     An array of objects to filter
3161 * @param array       $args     Optional. An array of key => value arguments to match
3162 *                              against each object. Default empty array.
3163 * @param string      $operator Optional. The logical operation to perform. 'or' means
3164 *                              only one element from the array needs to match; 'and'
3165 *                              means all elements must match. Default 'and'.
3166 * @param bool|string $field    A field from the object to place instead of the entire object.
3167 *                              Default false.
3168 * @return array A list of objects or object fields.
3169 */
3170function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) {
3171        if ( ! is_array( $list ) )
3172                return array();
3173
3174        $list = wp_list_filter( $list, $args, $operator );
3175
3176        if ( $field )
3177                $list = wp_list_pluck( $list, $field );
3178
3179        return $list;
3180}
3181
3182/**
3183 * Filters a list of objects, based on a set of key => value arguments.
3184 *
3185 * @since 3.1.0
3186 *
3187 * @param array  $list     An array of objects to filter.
3188 * @param array  $args     Optional. An array of key => value arguments to match
3189 *                         against each object. Default empty array.
3190 * @param string $operator Optional. The logical operation to perform. 'AND' means
3191 *                         all elements from the array must match. 'OR' means only
3192 *                         one element needs to match. 'NOT' means no elements may
3193 *                         match. Default 'AND'.
3194 * @return array Array of found values.
3195 */
3196function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
3197        if ( ! is_array( $list ) )
3198                return array();
3199
3200        if ( empty( $args ) )
3201                return $list;
3202
3203        $operator = strtoupper( $operator );
3204        $count = count( $args );
3205        $filtered = array();
3206
3207        foreach ( $list as $key => $obj ) {
3208                $to_match = (array) $obj;
3209
3210                $matched = 0;
3211                foreach ( $args as $m_key => $m_value ) {
3212                        if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] )
3213                                $matched++;
3214                }
3215
3216                if ( ( 'AND' == $operator && $matched == $count )
3217                  || ( 'OR' == $operator && $matched > 0 )
3218                  || ( 'NOT' == $operator && 0 == $matched ) ) {
3219                        $filtered[$key] = $obj;
3220                }
3221        }
3222
3223        return $filtered;
3224}
3225
3226/**
3227 * Pluck a certain field out of each object in a list.
3228 *
3229 * This has the same functionality and prototype of
3230 * array_column() (PHP 5.5) but also supports objects.
3231 *
3232 * @since 3.1.0
3233 * @since 4.0.0 $index_key parameter added.
3234 *
3235 * @param array      $list      List of objects or arrays
3236 * @param int|string $field     Field from the object to place instead of the entire object
3237 * @param int|string $index_key Optional. Field from the object to use as keys for the new array.
3238 *                              Default null.
3239 * @return array Array of found values. If `$index_key` is set, an array of found values with keys
3240 *               corresponding to `$index_key`. If `$index_key` is null, array keys from the original
3241 *               `$list` will be preserved in the results.
3242 */
3243function wp_list_pluck( $list, $field, $index_key = null ) {
3244        if ( ! $index_key ) {
3245                /*
3246                 * This is simple. Could at some point wrap array_column()
3247                 * if we knew we had an array of arrays.
3248                 */
3249                foreach ( $list as $key => $value ) {
3250                        if ( is_object( $value ) ) {
3251                                $list[ $key ] = $value->$field;
3252                        } else {
3253                                $list[ $key ] = $value[ $field ];
3254                        }
3255                }
3256                return $list;
3257        }
3258
3259        /*
3260         * When index_key is not set for a particular item, push the value
3261         * to the end of the stack. This is how array_column() behaves.
3262         */
3263        $newlist = array();
3264        foreach ( $list as $value ) {
3265                if ( is_object( $value ) ) {
3266                        if ( isset( $value->$index_key ) ) {
3267                                $newlist[ $value->$index_key ] = $value->$field;
3268                        } else {
3269                                $newlist[] = $value->$field;
3270                        }
3271                } else {
3272                        if ( isset( $value[ $index_key ] ) ) {
3273                                $newlist[ $value[ $index_key ] ] = $value[ $field ];
3274                        } else {
3275                                $newlist[] = $value[ $field ];
3276                        }
3277                }
3278        }
3279
3280        return $newlist;
3281}
3282
3283/**
3284 * Determines if Widgets library should be loaded.
3285 *
3286 * Checks to make sure that the widgets library hasn't already been loaded.
3287 * If it hasn't, then it will load the widgets library and run an action hook.
3288 *
3289 * @since 2.2.0
3290 */
3291function wp_maybe_load_widgets() {
3292        /**
3293         * Filter whether to load the Widgets library.
3294         *
3295         * Passing a falsey value to the filter will effectively short-circuit
3296         * the Widgets library from loading.
3297         *
3298         * @since 2.8.0
3299         *
3300         * @param bool $wp_maybe_load_widgets Whether to load the Widgets library.
3301         *                                    Default true.
3302         */
3303        if ( ! apply_filters( 'load_default_widgets', true ) ) {
3304                return;
3305        }
3306
3307        require_once( ABSPATH . WPINC . '/default-widgets.php' );
3308
3309        add_action( '_admin_menu', 'wp_widgets_add_menu' );
3310}
3311
3312/**
3313 * Append the Widgets menu to the themes main menu.
3314 *
3315 * @since 2.2.0
3316 *
3317 * @global array $submenu
3318 */
3319function wp_widgets_add_menu() {
3320        global $submenu;
3321
3322        if ( ! current_theme_supports( 'widgets' ) )
3323                return;
3324
3325        $submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' );
3326        ksort( $submenu['themes.php'], SORT_NUMERIC );
3327}
3328
3329/**
3330 * Flush all output buffers for PHP 5.2.
3331 *
3332 * Make sure all output buffers are flushed before our singletons are destroyed.
3333 *
3334 * @since 2.2.0
3335 */
3336function wp_ob_end_flush_all() {
3337        $levels = ob_get_level();
3338        for ($i=0; $i<$levels; $i++)
3339                ob_end_flush();
3340}
3341
3342/**
3343 * Load custom DB error or display WordPress DB error.
3344 *
3345 * If a file exists in the wp-content directory named db-error.php, then it will
3346 * be loaded instead of displaying the WordPress DB error. If it is not found,
3347 * then the WordPress DB error will be displayed instead.
3348 *
3349 * The WordPress DB error sets the HTTP status header to 500 to try to prevent
3350 * search engines from caching the message. Custom DB messages should do the
3351 * same.
3352 *
3353 * This function was backported to WordPress 2.3.2, but originally was added
3354 * in WordPress 2.5.0.
3355 *
3356 * @since 2.3.2
3357 *
3358 * @global wpdb $wpdb WordPress database abstraction object.
3359 */
3360function dead_db() {
3361        global $wpdb;
3362
3363        wp_load_translations_early();
3364
3365        // Load custom DB error template, if present.
3366        if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
3367                require_once( WP_CONTENT_DIR . '/db-error.php' );
3368                die();
3369        }
3370
3371        // If installing or in the admin, provide the verbose message.
3372        if ( defined('WP_INSTALLING') || defined('WP_ADMIN') )
3373                wp_die($wpdb->error);
3374
3375        // Otherwise, be terse.
3376        status_header( 500 );
3377        nocache_headers();
3378        header( 'Content-Type: text/html; charset=utf-8' );
3379?>
3380<!DOCTYPE html>
3381<html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
3382<head>
3383<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
3384        <title><?php _e( 'Database Error' ); ?></title>
3385
3386</head>
3387<body>
3388        <h1><?php _e( 'Error establishing a database connection' ); ?></h1>
3389</body>
3390</html>
3391<?php
3392        die();
3393}
3394
3395/**
3396 * Convert a value to non-negative integer.
3397 *
3398 * @since 2.5.0
3399 *
3400 * @param mixed $maybeint Data you wish to have converted to a non-negative integer.
3401 * @return int A non-negative integer.
3402 */
3403function absint( $maybeint ) {
3404        return abs( intval( $maybeint ) );
3405}
3406
3407/**
3408 * Mark a function as deprecated and inform when it has been used.
3409 *
3410 * There is a hook deprecated_function_run that will be called that can be used
3411 * to get the backtrace up to what file and function called the deprecated
3412 * function.
3413 *
3414 * The current behavior is to trigger a user error if WP_DEBUG is true.
3415 *
3416 * This function is to be used in every function that is deprecated.
3417 *
3418 * @since 2.5.0
3419 * @access private
3420 *
3421 * @param string $function    The function that was called.
3422 * @param string $version     The version of WordPress that deprecated the function.
3423 * @param string $replacement Optional. The function that should have been called. Default null.
3424 */
3425function _deprecated_function( $function, $version, $replacement = null ) {
3426
3427        /**
3428         * Fires when a deprecated function is called.
3429         *
3430         * @since 2.5.0
3431         *
3432         * @param string $function    The function that was called.
3433         * @param string $replacement The function that should have been called.
3434         * @param string $version     The version of WordPress that deprecated the function.
3435         */
3436        do_action( 'deprecated_function_run', $function, $replacement, $version );
3437
3438        /**
3439         * Filter whether to trigger an error for deprecated functions.
3440         *
3441         * @since 2.5.0
3442         *
3443         * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
3444         */
3445        if ( WP_DEBUG && apply_filters( 'deprecated_function_trigger_error', true ) ) {
3446                if ( function_exists( '__' ) ) {
3447                        if ( ! is_null( $replacement ) )
3448                                trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) );
3449                        else
3450                                trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
3451                } else {
3452                        if ( ! is_null( $replacement ) )
3453                                trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $function, $version, $replacement ) );
3454                        else
3455                                trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
3456                }
3457        }
3458}
3459
3460/**
3461 * Marks a constructor as deprecated and informs when it has been used.
3462 *
3463 * Similar to _deprecated_function(), but with different strings. Used to
3464 * remove PHP4 style constructors.
3465 *
3466 * The current behavior is to trigger a user error if `WP_DEBUG` is true.
3467 *
3468 * This function is to be used in every PHP4 style constructor method that is deprecated.
3469 *
3470 * @since 4.3.0
3471 * @access private
3472 *
3473 * @param string $class   The class containing the deprecated constructor.
3474 * @param string $version The version of WordPress that deprecated the function.
3475 */
3476function _deprecated_constructor( $class, $version ) {
3477
3478        /**
3479         * Fires when a deprecated constructor is called.
3480         *
3481         * @since 4.3.0
3482         *
3483         * @param string $class   The class containing the deprecated constructor.
3484         * @param string $version The version of WordPress that deprecated the function.
3485         */
3486        do_action( 'deprecated_constructor_run', $class, $version );
3487
3488        /**
3489         * Filter whether to trigger an error for deprecated functions.
3490         *
3491         * `WP_DEBUG` must be true in addition to the filter evaluating to true.
3492         *
3493         * @since 4.3.0
3494         *
3495         * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
3496         */
3497        if ( WP_DEBUG && apply_filters( 'deprecated_constructor_trigger_error', true ) ) {
3498                if ( function_exists( '__' ) ) {
3499                        trigger_error( sprintf( __( 'The called constructor method for %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ), $class, $version, '<pre>__construct()</pre>' ) );
3500                } else {
3501                        trigger_error( sprintf( 'The called constructor method for %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $class, $version, '<pre>__construct()</pre>' ) );
3502                }
3503        }
3504
3505}
3506
3507/**
3508 * Mark a file as deprecated and inform when it has been used.
3509 *
3510 * There is a hook deprecated_file_included that will be called that can be used
3511 * to get the backtrace up to what file and function included the deprecated
3512 * file.
3513 *
3514 * The current behavior is to trigger a user error if WP_DEBUG is true.
3515 *
3516 * This function is to be used in every file that is deprecated.
3517 *
3518 * @since 2.5.0
3519 * @access private
3520 *
3521 * @param string $file        The file that was included.
3522 * @param string $version     The version of WordPress that deprecated the file.
3523 * @param string $replacement Optional. The file that should have been included based on ABSPATH.
3524 *                            Default null.
3525 * @param string $message     Optional. A message regarding the change. Default empty.
3526 */
3527function _deprecated_file( $file, $version, $replacement = null, $message = '' ) {
3528
3529        /**
3530         * Fires when a deprecated file is called.
3531         *
3532         * @since 2.5.0
3533         *
3534         * @param string $file        The file that was called.
3535         * @param string $replacement The file that should have been included based on ABSPATH.
3536         * @param string $version     The version of WordPress that deprecated the file.
3537         * @param string $message     A message regarding the change.
3538         */
3539        do_action( 'deprecated_file_included', $file, $replacement, $version, $message );
3540
3541        /**
3542         * Filter whether to trigger an error for deprecated files.
3543         *
3544         * @since 2.5.0
3545         *
3546         * @param bool $trigger Whether to trigger the error for deprecated files. Default true.
3547         */
3548        if ( WP_DEBUG && apply_filters( 'deprecated_file_trigger_error', true ) ) {
3549                $message = empty( $message ) ? '' : ' ' . $message;
3550                if ( function_exists( '__' ) ) {
3551                        if ( ! is_null( $replacement ) )
3552                                trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $file, $version, $replacement ) . $message );
3553                        else
3554                                trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $file, $version ) . $message );
3555                } else {
3556                        if ( ! is_null( $replacement ) )
3557                                trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $file, $version, $replacement ) . $message );
3558                        else
3559                                trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $file, $version ) . $message );
3560                }
3561        }
3562}
3563/**
3564 * Mark a function argument as deprecated and inform when it has been used.
3565 *
3566 * This function is to be used whenever a deprecated function argument is used.
3567 * Before this function is called, the argument must be checked for whether it was
3568 * used by comparing it to its default value or evaluating whether it is empty.
3569 * For example:
3570 *
3571 *     if ( ! empty( $deprecated ) ) {
3572 *         _deprecated_argument( __FUNCTION__, '3.0' );
3573 *     }
3574 *
3575 *
3576 * There is a hook deprecated_argument_run that will be called that can be used
3577 * to get the backtrace up to what file and function used the deprecated
3578 * argument.
3579 *
3580 * The current behavior is to trigger a user error if WP_DEBUG is true.
3581 *
3582 * @since 3.0.0
3583 * @access private
3584 *
3585 * @param string $function The function that was called.
3586 * @param string $version  The version of WordPress that deprecated the argument used.
3587 * @param string $message  Optional. A message regarding the change. Default null.
3588 */
3589function _deprecated_argument( $function, $version, $message = null ) {
3590
3591        /**
3592         * Fires when a deprecated argument is called.
3593         *
3594         * @since 3.0.0
3595         *
3596         * @param string $function The function that was called.
3597         * @param string $message  A message regarding the change.
3598         * @param string $version  The version of WordPress that deprecated the argument used.
3599         */
3600        do_action( 'deprecated_argument_run', $function, $message, $version );
3601
3602        /**
3603         * Filter whether to trigger an error for deprecated arguments.
3604         *
3605         * @since 3.0.0
3606         *
3607         * @param bool $trigger Whether to trigger the error for deprecated arguments. Default true.
3608         */
3609        if ( WP_DEBUG && apply_filters( 'deprecated_argument_trigger_error', true ) ) {
3610                if ( function_exists( '__' ) ) {
3611                        if ( ! is_null( $message ) )
3612                                trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s'), $function, $version, $message ) );
3613                        else
3614                                trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
3615                } else {
3616                        if ( ! is_null( $message ) )
3617                                trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s', $function, $version, $message ) );
3618                        else
3619                                trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
3620                }
3621        }
3622}
3623
3624/**
3625 * Mark something as being incorrectly called.
3626 *
3627 * There is a hook doing_it_wrong_run that will be called that can be used
3628 * to get the backtrace up to what file and function called the deprecated
3629 * function.
3630 *
3631 * The current behavior is to trigger a user error if WP_DEBUG is true.
3632 *
3633 * @since 3.1.0
3634 * @access private
3635 *
3636 * @param string $function The function that was called.
3637 * @param string $message  A message explaining what has been done incorrectly.
3638 * @param string $version  The version of WordPress where the message was added.
3639 */
3640function _doing_it_wrong( $function, $message, $version ) {
3641
3642        /**
3643         * Fires when the given function is being used incorrectly.
3644         *
3645         * @since 3.1.0
3646         *
3647         * @param string $function The function that was called.
3648         * @param string $message  A message explaining what has been done incorrectly.
3649         * @param string $version  The version of WordPress where the message was added.
3650         */
3651        do_action( 'doing_it_wrong_run', $function, $message, $version );
3652
3653        /**
3654         * Filter whether to trigger an error for _doing_it_wrong() calls.
3655         *
3656         * @since 3.1.0
3657         *
3658         * @param bool $trigger Whether to trigger the error for _doing_it_wrong() calls. Default true.
3659         */
3660        if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
3661                if ( function_exists( '__' ) ) {
3662                        $version = is_null( $version ) ? '' : sprintf( __( '(This message was added in version %s.)' ), $version );
3663                        $message .= ' ' . __( 'Please see <a href="https://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.' );
3664                        trigger_error( sprintf( __( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s' ), $function, $message, $version ) );
3665                } else {
3666                        $version = is_null( $version ) ? '' : sprintf( '(This message was added in version %s.)', $version );
3667                        $message .= ' Please see <a href="https://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.';
3668                        trigger_error( sprintf( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s', $function, $message, $version ) );
3669                }
3670        }
3671}
3672
3673/**
3674 * Is the server running earlier than 1.5.0 version of lighttpd?
3675 *
3676 * @since 2.5.0
3677 *
3678 * @return bool Whether the server is running lighttpd < 1.5.0.
3679 */
3680function is_lighttpd_before_150() {
3681        $server_parts = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] )? $_SERVER['SERVER_SOFTWARE'] : '' );
3682        $server_parts[1] = isset( $server_parts[1] )? $server_parts[1] : '';
3683        return  'lighttpd' == $server_parts[0] && -1 == version_compare( $server_parts[1], '1.5.0' );
3684}
3685
3686/**
3687 * Does the specified module exist in the Apache config?
3688 *
3689 * @since 2.5.0
3690 *
3691 * @global bool $is_apache
3692 *
3693 * @param string $mod     The module, e.g. mod_rewrite.
3694 * @param bool   $default Optional. The default return value if the module is not found. Default false.
3695 * @return bool Whether the specified module is loaded.
3696 */
3697function apache_mod_loaded($mod, $default = false) {
3698        global $is_apache;
3699
3700        if ( !$is_apache )
3701                return false;
3702
3703        if ( function_exists( 'apache_get_modules' ) ) {
3704                $mods = apache_get_modules();
3705                if ( in_array($mod, $mods) )
3706                        return true;
3707        } elseif ( function_exists( 'phpinfo' ) && false === strpos( ini_get( 'disable_functions' ), 'phpinfo' ) ) {
3708                        ob_start();
3709                        phpinfo(8);
3710                        $phpinfo = ob_get_clean();
3711                        if ( false !== strpos($phpinfo, $mod) )
3712                                return true;
3713        }
3714        return $default;
3715}
3716
3717/**
3718 * Check if IIS 7+ supports pretty permalinks.
3719 *
3720 * @since 2.8.0
3721 *
3722 * @global bool $is_iis7
3723 *
3724 * @return bool Whether IIS7 supports permalinks.
3725 */
3726function iis7_supports_permalinks() {
3727        global $is_iis7;
3728
3729        $supports_permalinks = false;
3730        if ( $is_iis7 ) {
3731                /* First we check if the DOMDocument class exists. If it does not exist, then we cannot
3732                 * easily update the xml configuration file, hence we just bail out and tell user that
3733                 * pretty permalinks cannot be used.
3734                 *
3735                 * Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the web site. When
3736                 * URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
3737                 * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
3738                 * via ISAPI then pretty permalinks will not work.
3739                 */
3740                $supports_permalinks = class_exists('DOMDocument') && isset($_SERVER['IIS_UrlRewriteModule']) && ( PHP_SAPI == 'cgi-fcgi' );
3741        }
3742
3743        /**
3744         * Filter whether IIS 7+ supports pretty permalinks.
3745         *
3746         * @since 2.8.0
3747         *
3748         * @param bool $supports_permalinks Whether IIS7 supports permalinks. Default false.
3749         */
3750        return apply_filters( 'iis7_supports_permalinks', $supports_permalinks );
3751}
3752
3753/**
3754 * File validates against allowed set of defined rules.
3755 *
3756 * A return value of '1' means that the $file contains either '..' or './'. A
3757 * return value of '2' means that the $file contains ':' after the first
3758 * character. A return value of '3' means that the file is not in the allowed
3759 * files list.
3760 *
3761 * @since 1.2.0
3762 *
3763 * @param string $file File path.
3764 * @param array  $allowed_files List of allowed files.
3765 * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
3766 */
3767function validate_file( $file, $allowed_files = '' ) {
3768        if ( false !== strpos( $file, '..' ) )
3769                return 1;
3770
3771        if ( false !== strpos( $file, './' ) )
3772                return 1;
3773
3774        if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) )
3775                return 3;
3776
3777        if (':' == substr( $file, 1, 1 ) )
3778                return 2;
3779
3780        return 0;
3781}
3782
3783/**
3784 * Determine if SSL is used.
3785 *
3786 * @since 2.6.0
3787 *
3788 * @return bool True if SSL, false if not used.
3789 */
3790function is_ssl() {
3791        if ( isset($_SERVER['HTTPS']) ) {
3792                if ( 'on' == strtolower($_SERVER['HTTPS']) )
3793                        return true;
3794                if ( '1' == $_SERVER['HTTPS'] )
3795                        return true;
3796        } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
3797                return true;
3798        }
3799        return false;
3800}
3801
3802/**
3803 * Whether SSL login should be forced.
3804 *
3805 * @since 2.6.0
3806 *
3807 * @see force_ssl_admin()
3808 *
3809 * @param string|bool $force Optional Whether to force SSL login. Default null.
3810 * @return bool True if forced, false if not forced.
3811 */
3812function force_ssl_login( $force = null ) {
3813        return force_ssl_admin( $force );
3814}
3815
3816/**
3817 * Whether to force SSL used for the Administration Screens.
3818 *
3819 * @since 2.6.0
3820 *
3821 * @staticvar bool $forced
3822 *
3823 * @param string|bool $force Optional. Whether to force SSL in admin screens. Default null.
3824 * @return bool True if forced, false if not forced.
3825 */
3826function force_ssl_admin( $force = null ) {
3827        static $forced = false;
3828
3829        if ( !is_null( $force ) ) {
3830                $old_forced = $forced;
3831                $forced = $force;
3832                return $old_forced;
3833        }
3834
3835        return $forced;
3836}
3837
3838/**
3839 * Guess the URL for the site.
3840 *
3841 * Will remove wp-admin links to retrieve only return URLs not in the wp-admin
3842 * directory.
3843 *
3844 * @since 2.6.0
3845 *
3846 * @return string The guessed URL.
3847 */
3848function wp_guess_url() {
3849        if ( defined('WP_SITEURL') && '' != WP_SITEURL ) {
3850                $url = WP_SITEURL;
3851        } else {
3852                $abspath_fix = str_replace( '\\', '/', ABSPATH );
3853                $script_filename_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
3854
3855                // The request is for the admin
3856                if ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false || strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ) {
3857                        $path = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $_SERVER['REQUEST_URI'] );
3858
3859                // The request is for a file in ABSPATH
3860                } elseif ( $script_filename_dir . '/' == $abspath_fix ) {
3861                        // Strip off any file/query params in the path
3862                        $path = preg_replace( '#/[^/]*$#i', '', $_SERVER['PHP_SELF'] );
3863
3864                } else {
3865                        if ( false !== strpos( $_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
3866                                // Request is hitting a file inside ABSPATH
3867                                $directory = str_replace( ABSPATH, '', $script_filename_dir );
3868                                // Strip off the sub directory, and any file/query params
3869                                $path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] );
3870                        } elseif ( false !== strpos( $abspath_fix, $script_filename_dir ) ) {
3871                                // Request is hitting a file above ABSPATH
3872                                $subdirectory = substr( $abspath_fix, strpos( $abspath_fix, $script_filename_dir ) + strlen( $script_filename_dir ) );
3873                                // Strip off any file/query params from the path, appending the sub directory to the install
3874                                $path = preg_replace( '#/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] ) . $subdirectory;
3875                        } else {
3876                                $path = $_SERVER['REQUEST_URI'];
3877                        }
3878                }
3879
3880                $schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet
3881                $url = $schema . $_SERVER['HTTP_HOST'] . $path;
3882        }
3883
3884        return rtrim($url, '/');
3885}
3886
3887/**
3888 * Temporarily suspend cache additions.
3889 *
3890 * Stops more data being added to the cache, but still allows cache retrieval.
3891 * This is useful for actions, such as imports, when a lot of data would otherwise
3892 * be almost uselessly added to the cache.
3893 *
3894 * Suspension lasts for a single page load at most. Remember to call this
3895 * function again if you wish to re-enable cache adds earlier.
3896 *
3897 * @since 3.3.0
3898 *
3899 * @staticvar bool $_suspend
3900 *
3901 * @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
3902 * @return bool The current suspend setting
3903 */
3904function wp_suspend_cache_addition( $suspend = null ) {
3905        static $_suspend = false;
3906
3907        if ( is_bool( $suspend ) )
3908                $_suspend = $suspend;
3909
3910        return $_suspend;
3911}
3912
3913/**
3914 * Suspend cache invalidation.
3915 *
3916 * Turns cache invalidation on and off. Useful during imports where you don't wont to do
3917 * invalidations every time a post is inserted. Callers must be sure that what they are
3918 * doing won't lead to an inconsistent cache when invalidation is suspended.
3919 *
3920 * @since 2.7.0
3921 *
3922 * @global bool $_wp_suspend_cache_invalidation
3923 *
3924 * @param bool $suspend Optional. Whether to suspend or enable cache invalidation. Default true.
3925 * @return bool The current suspend setting.
3926 */
3927function wp_suspend_cache_invalidation( $suspend = true ) {
3928        global $_wp_suspend_cache_invalidation;
3929
3930        $current_suspend = $_wp_suspend_cache_invalidation;
3931        $_wp_suspend_cache_invalidation = $suspend;
3932        return $current_suspend;
3933}
3934
3935/**
3936 * Determine whether a site is the main site of the current network.
3937 *
3938 * @since 3.0.0
3939 *
3940 * @global object $current_site
3941 *
3942 * @param int $site_id Optional. Site ID to test. Defaults to current site.
3943 *                     Defaults to current site.
3944 * @return bool True if $site_id is the main site of the network, or if not
3945 *              running Multisite.
3946 */
3947function is_main_site( $site_id = null ) {
3948        // This is the current network's information; 'site' is old terminology.
3949        global $current_site;
3950
3951        if ( ! is_multisite() )
3952                return true;
3953
3954        if ( ! $site_id )
3955                $site_id = get_current_blog_id();
3956
3957        return (int) $site_id === (int) $current_site->blog_id;
3958}
3959
3960/**
3961 * Determine whether a network is the main network of the Multisite install.
3962 *
3963 * @since 3.7.0
3964 *
3965 * @param int $network_id Optional. Network ID to test. Defaults to current network.
3966 * @return bool True if $network_id is the main network, or if not running Multisite.
3967 */
3968function is_main_network( $network_id = null ) {
3969        if ( ! is_multisite() ) {
3970                return true;
3971        }
3972
3973        $current_network_id = (int) get_current_site()->id;
3974
3975        if ( null === $network_id ) {
3976                $network_id = $current_network_id;
3977        }
3978
3979        $network_id = (int) $network_id;
3980
3981        return ( $network_id === get_main_network_id() );
3982}
3983
3984/**
3985 * Get the main network ID.
3986 *
3987 * @since 4.3.0
3988 *
3989 * @global wpdb $wpdb WordPress database abstraction object.
3990 *
3991 * @return int The ID of the main network.
3992 */
3993function get_main_network_id() {
3994        global $wpdb;
3995
3996        if ( ! is_multisite() ) {
3997                return 1;
3998        }
3999
4000        if ( defined( 'PRIMARY_NETWORK_ID' ) ) {
4001                $main_network_id = PRIMARY_NETWORK_ID;
4002        } elseif ( 1 === (int) get_current_site()->id ) {
4003                // If the current network has an ID of 1, assume it is the main network.
4004                $main_network_id = 1;
4005        } else {
4006                $main_network_id = wp_cache_get( 'primary_network_id', 'site-options' );
4007
4008                if ( false === $main_network_id ) {
4009                        $main_network_id = (int) $wpdb->get_var( "SELECT id FROM {$wpdb->site} ORDER BY id LIMIT 1" );
4010                        wp_cache_add( 'primary_network_id', $main_network_id, 'site-options' );
4011                }
4012        }
4013
4014        /**
4015         * Filter the main network ID.
4016         *
4017         * @since 4.3.0
4018         *
4019         * @param int $main_network_id The ID of the main network.
4020         */
4021        return (int) apply_filters( 'get_main_network_id', $main_network_id );
4022}
4023
4024/**
4025 * Determine whether global terms are enabled.
4026 *
4027 * @since 3.0.0
4028 *
4029 * @staticvar bool $global_terms
4030 *
4031 * @return bool True if multisite and global terms enabled.
4032 */
4033function global_terms_enabled() {
4034        if ( ! is_multisite() )
4035                return false;
4036
4037        static $global_terms = null;
4038        if ( is_null( $global_terms ) ) {
4039
4040                /**
4041                 * Filter whether global terms are enabled.
4042                 *
4043                 * Passing a non-null value to the filter will effectively short-circuit the function,
4044                 * returning the value of the 'global_terms_enabled' site option instead.
4045                 *
4046                 * @since 3.0.0
4047                 *
4048                 * @param null $enabled Whether global terms are enabled.
4049                 */
4050                $filter = apply_filters( 'global_terms_enabled', null );
4051                if ( ! is_null( $filter ) )
4052                        $global_terms = (bool) $filter;
4053                else
4054                        $global_terms = (bool) get_site_option( 'global_terms_enabled', false );
4055        }
4056        return $global_terms;
4057}
4058
4059/**
4060 * gmt_offset modification for smart timezone handling.
4061 *
4062 * Overrides the gmt_offset option if we have a timezone_string available.
4063 *
4064 * @since 2.8.0
4065 *
4066 * @return float|false Timezone GMT offset, false otherwise.
4067 */
4068function wp_timezone_override_offset() {
4069        if ( !$timezone_string = get_option( 'timezone_string' ) ) {
4070                return false;
4071        }
4072
4073        $timezone_object = timezone_open( $timezone_string );
4074        $datetime_object = date_create();
4075        if ( false === $timezone_object || false === $datetime_object ) {
4076                return false;
4077        }
4078        return round( timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS, 2 );
4079}
4080
4081/**
4082 * Sort-helper for timezones.
4083 *
4084 * @since 2.9.0
4085 * @access private
4086 *
4087 * @param array $a
4088 * @param array $b
4089 * @return int
4090 */
4091function _wp_timezone_choice_usort_callback( $a, $b ) {
4092        // Don't use translated versions of Etc
4093        if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
4094                // Make the order of these more like the old dropdown
4095                if ( 'GMT+' === substr( $a['city'], 0, 4 ) && 'GMT+' === substr( $b['city'], 0, 4 ) ) {
4096                        return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
4097                }
4098                if ( 'UTC' === $a['city'] ) {
4099                        if ( 'GMT+' === substr( $b['city'], 0, 4 ) ) {
4100                                return 1;
4101                        }
4102                        return -1;
4103                }
4104                if ( 'UTC' === $b['city'] ) {
4105                        if ( 'GMT+' === substr( $a['city'], 0, 4 ) ) {
4106                                return -1;
4107                        }
4108                        return 1;
4109                }
4110                return strnatcasecmp( $a['city'], $b['city'] );
4111        }
4112        if ( $a['t_continent'] == $b['t_continent'] ) {
4113                if ( $a['t_city'] == $b['t_city'] ) {
4114                        return strnatcasecmp( $a['t_subcity'], $b['t_subcity'] );
4115                }
4116                return strnatcasecmp( $a['t_city'], $b['t_city'] );
4117        } else {
4118                // Force Etc to the bottom of the list
4119                if ( 'Etc' === $a['continent'] ) {
4120                        return 1;
4121                }
4122                if ( 'Etc' === $b['continent'] ) {
4123                        return -1;
4124                }
4125                return strnatcasecmp( $a['t_continent'], $b['t_continent'] );
4126        }
4127}
4128
4129/**
4130 * Gives a nicely-formatted list of timezone strings.
4131 *
4132 * @since 2.9.0
4133 *
4134 * @staticvar bool $mo_loaded
4135 *
4136 * @param string $selected_zone Selected timezone.
4137 * @return string
4138 */
4139function wp_timezone_choice( $selected_zone ) {
4140        static $mo_loaded = false;
4141
4142        $continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific');
4143
4144        // Load translations for continents and cities
4145        if ( !$mo_loaded ) {
4146                $locale = get_locale();
4147                $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
4148                load_textdomain( 'continents-cities', $mofile );
4149                $mo_loaded = true;
4150        }
4151
4152        $zonen = array();
4153        foreach ( timezone_identifiers_list() as $zone ) {
4154                $zone = explode( '/', $zone );
4155                if ( !in_array( $zone[0], $continents ) ) {
4156                        continue;
4157                }
4158
4159                // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
4160                $exists = array(
4161                        0 => ( isset( $zone[0] ) && $zone[0] ),
4162                        1 => ( isset( $zone[1] ) && $zone[1] ),
4163                        2 => ( isset( $zone[2] ) && $zone[2] ),
4164                );
4165                $exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
4166                $exists[4] = ( $exists[1] && $exists[3] );
4167                $exists[5] = ( $exists[2] && $exists[3] );
4168
4169                $zonen[] = array(
4170                        'continent'   => ( $exists[0] ? $zone[0] : '' ),
4171                        'city'        => ( $exists[1] ? $zone[1] : '' ),
4172                        'subcity'     => ( $exists[2] ? $zone[2] : '' ),
4173                        't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
4174                        't_city'      => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
4175                        't_subcity'   => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' )
4176                );
4177        }
4178        usort( $zonen, '_wp_timezone_choice_usort_callback' );
4179
4180        $structure = array();
4181
4182        if ( empty( $selected_zone ) ) {
4183                $structure[] = '<option selected="selected" value="">' . __( 'Select a city' ) . '</option>';
4184        }
4185
4186        foreach ( $zonen as $key => $zone ) {
4187                // Build value in an array to join later
4188                $value = array( $zone['continent'] );
4189
4190                if ( empty( $zone['city'] ) ) {
4191                        // It's at the continent level (generally won't happen)
4192                        $display = $zone['t_continent'];
4193                } else {
4194                        // It's inside a continent group
4195
4196                        // Continent optgroup
4197                        if ( !isset( $zonen[$key - 1] ) || $zonen[$key - 1]['continent'] !== $zone['continent'] ) {
4198                                $label = $zone['t_continent'];
4199                                $structure[] = '<optgroup label="'. esc_attr( $label ) .'">';
4200                        }
4201
4202                        // Add the city to the value
4203                        $value[] = $zone['city'];
4204
4205                        $display = $zone['t_city'];
4206                        if ( !empty( $zone['subcity'] ) ) {
4207                                // Add the subcity to the value
4208                                $value[] = $zone['subcity'];
4209                                $display .= ' - ' . $zone['t_subcity'];
4210                        }
4211                }
4212
4213                // Build the value
4214                $value = join( '/', $value );
4215                $selected = '';
4216                if ( $value === $selected_zone ) {
4217                        $selected = 'selected="selected" ';
4218                }
4219                $structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . "</option>";
4220
4221                // Close continent optgroup
4222                if ( !empty( $zone['city'] ) && ( !isset($zonen[$key + 1]) || (isset( $zonen[$key + 1] ) && $zonen[$key + 1]['continent'] !== $zone['continent']) ) ) {
4223                        $structure[] = '</optgroup>';
4224                }
4225        }
4226
4227        // Do UTC
4228        $structure[] = '<optgroup label="'. esc_attr__( 'UTC' ) .'">';
4229        $selected = '';
4230        if ( 'UTC' === $selected_zone )
4231                $selected = 'selected="selected" ';
4232        $structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __('UTC') . '</option>';
4233        $structure[] = '</optgroup>';
4234
4235        // Do manual UTC offsets
4236        $structure[] = '<optgroup label="'. esc_attr__( 'Manual Offsets' ) .'">';
4237        $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,
4238                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);
4239        foreach ( $offset_range as $offset ) {
4240                if ( 0 <= $offset )
4241                        $offset_name = '+' . $offset;
4242                else
4243                        $offset_name = (string) $offset;
4244
4245                $offset_value = $offset_name;
4246                $offset_name = str_replace(array('.25','.5','.75'), array(':15',':30',':45'), $offset_name);
4247                $offset_name = 'UTC' . $offset_name;
4248                $offset_value = 'UTC' . $offset_value;
4249                $selected = '';
4250                if ( $offset_value === $selected_zone )
4251                        $selected = 'selected="selected" ';
4252                $structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . "</option>";
4253
4254        }
4255        $structure[] = '</optgroup>';
4256
4257        return join( "\n", $structure );
4258}
4259
4260/**
4261 * Strip close comment and close php tags from file headers used by WP.
4262 *
4263 * @since 2.8.0
4264 * @access private
4265 *
4266 * @see https://core.trac.wordpress.org/ticket/8497
4267 *
4268 * @param string $str Header comment to clean up.
4269 * @return string
4270 */
4271function _cleanup_header_comment( $str ) {
4272        return trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $str));
4273}
4274
4275/**
4276 * Permanently delete comments or posts of any type that have held a status
4277 * of 'trash' for the number of days defined in EMPTY_TRASH_DAYS.
4278 *
4279 * The default value of `EMPTY_TRASH_DAYS` is 30 (days).
4280 *
4281 * @since 2.9.0
4282 *
4283 * @global wpdb $wpdb
4284 */
4285function wp_scheduled_delete() {
4286        global $wpdb;
4287
4288        $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
4289
4290        $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);
4291
4292        foreach ( (array) $posts_to_delete as $post ) {
4293                $post_id = (int) $post['post_id'];
4294                if ( !$post_id )
4295                        continue;
4296
4297                $del_post = get_post($post_id);
4298
4299                if ( !$del_post || 'trash' != $del_post->post_status ) {
4300                        delete_post_meta($post_id, '_wp_trash_meta_status');
4301                        delete_post_meta($post_id, '_wp_trash_meta_time');
4302                } else {
4303                        wp_delete_post($post_id);
4304                }
4305        }
4306
4307        $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);
4308
4309        foreach ( (array) $comments_to_delete as $comment ) {
4310                $comment_id = (int) $comment['comment_id'];
4311                if ( !$comment_id )
4312                        continue;
4313
4314                $del_comment = get_comment($comment_id);
4315
4316                if ( !$del_comment || 'trash' != $del_comment->comment_approved ) {
4317                        delete_comment_meta($comment_id, '_wp_trash_meta_time');
4318                        delete_comment_meta($comment_id, '_wp_trash_meta_status');
4319                } else {
4320                        wp_delete_comment($comment_id);
4321                }
4322        }
4323}
4324
4325/**
4326 * Retrieve metadata from a file.
4327 *
4328 * Searches for metadata in the first 8kiB of a file, such as a plugin or theme.
4329 * Each piece of metadata must be on its own line. Fields can not span multiple
4330 * lines, the value will get cut at the end of the first line.
4331 *
4332 * If the file data is not within that first 8kiB, then the author should correct
4333 * their plugin file and move the data headers to the top.
4334 *
4335 * @link https://codex.wordpress.org/File_Header
4336 *
4337 * @since 2.9.0
4338 *
4339 * @param string $file            Path to the file.
4340 * @param array  $default_headers List of headers, in the format array('HeaderKey' => 'Header Name').
4341 * @param string $context         Optional. If specified adds filter hook "extra_{$context}_headers".
4342 *                                Default empty.
4343 * @return array Array of file headers in `HeaderKey => Header Value` format.
4344 */
4345function get_file_data( $file, $default_headers, $context = '' ) {
4346        // We don't need to write to the file, so just open for reading.
4347        $fp = fopen( $file, 'r' );
4348
4349        // Pull only the first 8kiB of the file in.
4350        $file_data = fread( $fp, 8192 );
4351
4352        // PHP will close file handle, but we are good citizens.
4353        fclose( $fp );
4354
4355        // Make sure we catch CR-only line endings.
4356        $file_data = str_replace( "\r", "\n", $file_data );
4357
4358        /**
4359         * Filter extra file headers by context.
4360         *
4361         * The dynamic portion of the hook name, `$context`, refers to
4362         * the context where extra headers might be loaded.
4363         *
4364         * @since 2.9.0
4365         *
4366         * @param array $extra_context_headers Empty array by default.
4367         */
4368        if ( $context && $extra_headers = apply_filters( "extra_{$context}_headers", array() ) ) {
4369                $extra_headers = array_combine( $extra_headers, $extra_headers ); // keys equal values
4370                $all_headers = array_merge( $extra_headers, (array) $default_headers );
4371        } else {
4372                $all_headers = $default_headers;
4373        }
4374
4375        foreach ( $all_headers as $field => $regex ) {
4376                if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] )
4377                        $all_headers[ $field ] = _cleanup_header_comment( $match[1] );
4378                else
4379                        $all_headers[ $field ] = '';
4380        }
4381
4382        return $all_headers;
4383}
4384
4385/**
4386 * Returns true.
4387 *
4388 * Useful for returning true to filters easily.
4389 *
4390 * @since 3.0.0
4391 *
4392 * @see __return_false()
4393 *
4394 * @return true True.
4395 */
4396function __return_true() {
4397        return true;
4398}
4399
4400/**
4401 * Returns false.
4402 *
4403 * Useful for returning false to filters easily.
4404 *
4405 * @since 3.0.0
4406 *
4407 * @see __return_true()
4408 *
4409 * @return false False.
4410 */
4411function __return_false() {
4412        return false;
4413}
4414
4415/**
4416 * Returns 0.
4417 *
4418 * Useful for returning 0 to filters easily.
4419 *
4420 * @since 3.0.0
4421 *
4422 * @return int 0.
4423 */
4424function __return_zero() {
4425        return 0;
4426}
4427
4428/**
4429 * Returns an empty array.
4430 *
4431 * Useful for returning an empty array to filters easily.
4432 *
4433 * @since 3.0.0
4434 *
4435 * @return array Empty array.
4436 */
4437function __return_empty_array() {
4438        return array();
4439}
4440
4441/**
4442 * Returns null.
4443 *
4444 * Useful for returning null to filters easily.
4445 *
4446 * @since 3.4.0
4447 *
4448 * @return null Null value.
4449 */
4450function __return_null() {
4451        return null;
4452}
4453
4454/**
4455 * Returns an empty string.
4456 *
4457 * Useful for returning an empty string to filters easily.
4458 *
4459 * @since 3.7.0
4460 *
4461 * @see __return_null()
4462 *
4463 * @return string Empty string.
4464 */
4465function __return_empty_string() {
4466        return '';
4467}
4468
4469/**
4470 * Send a HTTP header to disable content type sniffing in browsers which support it.
4471 *
4472 * @since 3.0.0
4473 *
4474 * @see http://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
4475 * @see http://src.chromium.org/viewvc/chrome?view=rev&revision=6985
4476 */
4477function send_nosniff_header() {
4478        @header( 'X-Content-Type-Options: nosniff' );
4479}
4480
4481/**
4482 * Return a MySQL expression for selecting the week number based on the start_of_week option.
4483 *
4484 * @ignore
4485 * @since 3.0.0
4486 *
4487 * @param string $column Database column.
4488 * @return string SQL clause.
4489 */
4490function _wp_mysql_week( $column ) {
4491        switch ( $start_of_week = (int) get_option( 'start_of_week' ) ) {
4492        case 1 :
4493                return "WEEK( $column, 1 )";
4494        case 2 :
4495        case 3 :
4496        case 4 :
4497        case 5 :
4498        case 6 :
4499                return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
4500        case 0 :
4501        default :
4502                return "WEEK( $column, 0 )";
4503        }
4504}
4505
4506/**
4507 * Find hierarchy loops using a callback function that maps object IDs to parent IDs.
4508 *
4509 * @since 3.1.0
4510 * @access private
4511 *
4512 * @param callback $callback      Function that accepts ( ID, $callback_args ) and outputs parent_ID.
4513 * @param int      $start         The ID to start the loop check at.
4514 * @param int      $start_parent  The parent_ID of $start to use instead of calling $callback( $start ).
4515 *                                Use null to always use $callback
4516 * @param array    $callback_args Optional. Additional arguments to send to $callback.
4517 * @return array IDs of all members of loop.
4518 */
4519function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_args = array() ) {
4520        $override = is_null( $start_parent ) ? array() : array( $start => $start_parent );
4521
4522        if ( !$arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args ) )
4523                return array();
4524
4525        return wp_find_hierarchy_loop_tortoise_hare( $callback, $arbitrary_loop_member, $override, $callback_args, true );
4526}
4527
4528/**
4529 * Use the "The Tortoise and the Hare" algorithm to detect loops.
4530 *
4531 * For every step of the algorithm, the hare takes two steps and the tortoise one.
4532 * If the hare ever laps the tortoise, there must be a loop.
4533 *
4534 * @since 3.1.0
4535 * @access private
4536 *
4537 * @param callback $callback      Function that accepts ( ID, callback_arg, ... ) and outputs parent_ID.
4538 * @param int      $start         The ID to start the loop check at.
4539 * @param array    $override      Optional. An array of ( ID => parent_ID, ... ) to use instead of $callback.
4540 *                                Default empty array.
4541 * @param array    $callback_args Optional. Additional arguments to send to $callback. Default empty array.
4542 * @param bool     $_return_loop  Optional. Return loop members or just detect presence of loop? Only set
4543 *                                to true if you already know the given $start is part of a loop (otherwise
4544 *                                the returned array might include branches). Default false.
4545 * @return mixed Scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if
4546 *               $_return_loop
4547 */
4548function wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override = array(), $callback_args = array(), $_return_loop = false ) {
4549        $tortoise = $hare = $evanescent_hare = $start;
4550        $return = array();
4551
4552        // Set evanescent_hare to one past hare
4553        // Increment hare two steps
4554        while (
4555                $tortoise
4556        &&
4557                ( $evanescent_hare = isset( $override[$hare] ) ? $override[$hare] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
4558        &&
4559                ( $hare = isset( $override[$evanescent_hare] ) ? $override[$evanescent_hare] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
4560        ) {
4561                if ( $_return_loop )
4562                        $return[$tortoise] = $return[$evanescent_hare] = $return[$hare] = true;
4563
4564                // tortoise got lapped - must be a loop
4565                if ( $tortoise == $evanescent_hare || $tortoise == $hare )
4566                        return $_return_loop ? $return : $tortoise;
4567
4568                // Increment tortoise by one step
4569                $tortoise = isset( $override[$tortoise] ) ? $override[$tortoise] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
4570        }
4571
4572        return false;
4573}
4574
4575/**
4576 * Send a HTTP header to limit rendering of pages to same origin iframes.
4577 *
4578 * @since 3.1.3
4579 *
4580 * @see https://developer.mozilla.org/en/the_x-frame-options_response_header
4581 */
4582function send_frame_options_header() {
4583        @header( 'X-Frame-Options: SAMEORIGIN' );
4584}
4585
4586/**
4587 * Retrieve a list of protocols to allow in HTML attributes.
4588 *
4589 * @since 3.3.0
4590 * @since 4.3.0 Added 'webcal' to the protocols array.
4591 *
4592 * @see wp_kses()
4593 * @see esc_url()
4594 *
4595 * @staticvar array $protocols
4596 *
4597 * @return array Array of allowed protocols. Defaults to an array containing 'http', 'https',
4598 *               'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet',
4599 *               'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', and 'webcal'.
4600 */
4601function wp_allowed_protocols() {
4602        static $protocols = array();
4603
4604        if ( empty( $protocols ) ) {
4605                $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal' );
4606
4607                /**
4608                 * Filter the list of protocols allowed in HTML attributes.
4609                 *
4610                 * @since 3.0.0
4611                 *
4612                 * @param array $protocols Array of allowed protocols e.g. 'http', 'ftp', 'tel', and more.
4613                 */
4614                $protocols = apply_filters( 'kses_allowed_protocols', $protocols );
4615        }
4616
4617        return $protocols;
4618}
4619
4620/**
4621 * Return a comma-separated string of functions that have been called to get
4622 * to the current point in code.
4623 *
4624 * @since 3.4.0
4625 *
4626 * @see https://core.trac.wordpress.org/ticket/19589
4627 *
4628 * @param string $ignore_class Optional. A class to ignore all function calls within - useful
4629 *                             when you want to just give info about the callee. Default null.
4630 * @param int    $skip_frames  Optional. A number of stack frames to skip - useful for unwinding
4631 *                             back to the source of the issue. Default 0.
4632 * @param bool   $pretty       Optional. Whether or not you want a comma separated string or raw
4633 *                             array returned. Default true.
4634 * @return string|array Either a string containing a reversed comma separated trace or an array
4635 *                      of individual calls.
4636 */
4637function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
4638        if ( version_compare( PHP_VERSION, '5.2.5', '>=' ) )
4639                $trace = debug_backtrace( false );
4640        else
4641                $trace = debug_backtrace();
4642
4643        $caller = array();
4644        $check_class = ! is_null( $ignore_class );
4645        $skip_frames++; // skip this function
4646
4647        foreach ( $trace as $call ) {
4648                if ( $skip_frames > 0 ) {
4649                        $skip_frames--;
4650                } elseif ( isset( $call['class'] ) ) {
4651                        if ( $check_class && $ignore_class == $call['class'] )
4652                                continue; // Filter out calls
4653
4654                        $caller[] = "{$call['class']}{$call['type']}{$call['function']}";
4655                } else {
4656                        if ( in_array( $call['function'], array( 'do_action', 'apply_filters' ) ) ) {
4657                                $caller[] = "{$call['function']}('{$call['args'][0]}')";
4658                        } elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ) ) ) {
4659                                $caller[] = $call['function'] . "('" . str_replace( array( WP_CONTENT_DIR, ABSPATH ) , '', $call['args'][0] ) . "')";
4660                        } else {
4661                                $caller[] = $call['function'];
4662                        }
4663                }
4664        }
4665        if ( $pretty )
4666                return join( ', ', array_reverse( $caller ) );
4667        else
4668                return $caller;
4669}
4670
4671/**
4672 * Retrieve ids that are not already present in the cache.
4673 *
4674 * @since 3.4.0
4675 * @access private
4676 *
4677 * @param array  $object_ids ID list.
4678 * @param string $cache_key  The cache bucket to check against.
4679 *
4680 * @return array List of ids not present in the cache.
4681 */
4682function _get_non_cached_ids( $object_ids, $cache_key ) {
4683        $clean = array();
4684        foreach ( $object_ids as $id ) {
4685                $id = (int) $id;
4686                if ( !wp_cache_get( $id, $cache_key ) ) {
4687                        $clean[] = $id;
4688                }
4689        }
4690
4691        return $clean;
4692}
4693
4694/**
4695 * Test if the current device has the capability to upload files.
4696 *
4697 * @since 3.4.0
4698 * @access private
4699 *
4700 * @return bool Whether the device is able to upload files.
4701 */
4702function _device_can_upload() {
4703        if ( ! wp_is_mobile() )
4704                return true;
4705
4706        $ua = $_SERVER['HTTP_USER_AGENT'];
4707
4708        if ( strpos($ua, 'iPhone') !== false
4709                || strpos($ua, 'iPad') !== false
4710                || strpos($ua, 'iPod') !== false ) {
4711                        return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
4712        }
4713
4714        return true;
4715}
4716
4717/**
4718 * Test if a given path is a stream URL
4719 *
4720 * @param string $path The resource path or URL.
4721 * @return bool True if the path is a stream URL.
4722 */
4723function wp_is_stream( $path ) {
4724        $wrappers = stream_get_wrappers();
4725        $wrappers_re = '(' . join('|', $wrappers) . ')';
4726
4727        return preg_match( "!^$wrappers_re://!", $path ) === 1;
4728}
4729
4730/**
4731 * Test if the supplied date is valid for the Gregorian calendar.
4732 *
4733 * @since 3.5.0
4734 *
4735 * @see checkdate()
4736 *
4737 * @param  int    $month       Month number.
4738 * @param  int    $day         Day number.
4739 * @param  int    $year        Year number.
4740 * @param  string $source_date The date to filter.
4741 * @return bool True if valid date, false if not valid date.
4742 */
4743function wp_checkdate( $month, $day, $year, $source_date ) {
4744        /**
4745         * Filter whether the given date is valid for the Gregorian calendar.
4746         *
4747         * @since 3.5.0
4748         *
4749         * @param bool   $checkdate   Whether the given date is valid.
4750         * @param string $source_date Date to check.
4751         */
4752        return apply_filters( 'wp_checkdate', checkdate( $month, $day, $year ), $source_date );
4753}
4754
4755/**
4756 * Load the auth check for monitoring whether the user is still logged in.
4757 *
4758 * Can be disabled with remove_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
4759 *
4760 * This is disabled for certain screens where a login screen could cause an
4761 * inconvenient interruption. A filter called wp_auth_check_load can be used
4762 * for fine-grained control.
4763 *
4764 * @since 3.6.0
4765 */
4766function wp_auth_check_load() {
4767        if ( ! is_admin() && ! is_user_logged_in() )
4768                return;
4769
4770        if ( defined( 'IFRAME_REQUEST' ) )
4771                return;
4772
4773        $screen = get_current_screen();
4774        $hidden = array( 'update', 'update-network', 'update-core', 'update-core-network', 'upgrade', 'upgrade-network', 'network' );
4775        $show = ! in_array( $screen->id, $hidden );
4776
4777        /**
4778         * Filter whether to load the authentication check.
4779         *
4780         * Passing a falsey value to the filter will effectively short-circuit
4781         * loading the authentication check.
4782         *
4783         * @since 3.6.0
4784         *
4785         * @param bool      $show   Whether to load the authentication check.
4786         * @param WP_Screen $screen The current screen object.
4787         */
4788        if ( apply_filters( 'wp_auth_check_load', $show, $screen ) ) {
4789                wp_enqueue_style( 'wp-auth-check' );
4790                wp_enqueue_script( 'wp-auth-check' );
4791
4792                add_action( 'admin_print_footer_scripts', 'wp_auth_check_html', 5 );
4793                add_action( 'wp_print_footer_scripts', 'wp_auth_check_html', 5 );
4794        }
4795}
4796
4797/**
4798 * Output the HTML that shows the wp-login dialog when the user is no longer logged in.
4799 *
4800 * @since 3.6.0
4801 */
4802function wp_auth_check_html() {
4803        $login_url = wp_login_url();
4804        $current_domain = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
4805        $same_domain = ( strpos( $login_url, $current_domain ) === 0 );
4806
4807        /**
4808         * Filter whether the authentication check originated at the same domain.
4809         *
4810         * @since 3.6.0
4811         *
4812         * @param bool $same_domain Whether the authentication check originated at the same domain.
4813         */
4814        $same_domain = apply_filters( 'wp_auth_check_same_domain', $same_domain );
4815        $wrap_class = $same_domain ? 'hidden' : 'hidden fallback';
4816
4817        ?>
4818        <div id="wp-auth-check-wrap" class="<?php echo $wrap_class; ?>">
4819        <div id="wp-auth-check-bg"></div>
4820        <div id="wp-auth-check">
4821        <div class="wp-auth-check-close" tabindex="0" title="<?php esc_attr_e('Close'); ?>"></div>
4822        <?php
4823
4824        if ( $same_domain ) {
4825                ?>
4826                <div id="wp-auth-check-form" data-src="<?php echo esc_url( add_query_arg( array( 'interim-login' => 1 ), $login_url ) ); ?>"></div>
4827                <?php
4828        }
4829
4830        ?>
4831        <div class="wp-auth-fallback">
4832                <p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e('Session expired'); ?></b></p>
4833                <p><a href="<?php echo esc_url( $login_url ); ?>" target="_blank"><?php _e('Please log in again.'); ?></a>
4834                <?php _e('The login page will open in a new window. After logging in you can close it and return to this page.'); ?></p>
4835        </div>
4836        </div>
4837        </div>
4838        <?php
4839}
4840
4841/**
4842 * Check whether a user is still logged in, for the heartbeat.
4843 *
4844 * Send a result that shows a log-in box if the user is no longer logged in,
4845 * or if their cookie is within the grace period.
4846 *
4847 * @since 3.6.0
4848 *
4849 * @global int $login_grace_period
4850 *
4851 * @param array $response  The Heartbeat response.
4852 * @return array $response The Heartbeat response with 'wp-auth-check' value set.
4853 */
4854function wp_auth_check( $response ) {
4855        $response['wp-auth-check'] = is_user_logged_in() && empty( $GLOBALS['login_grace_period'] );
4856        return $response;
4857}
4858
4859/**
4860 * Return RegEx body to liberally match an opening HTML tag.
4861 *
4862 * Matches an opening HTML tag that:
4863 * 1. Is self-closing or
4864 * 2. Has no body but has a closing tag of the same name or
4865 * 3. Contains a body and a closing tag of the same name
4866 *
4867 * Note: this RegEx does not balance inner tags and does not attempt
4868 * to produce valid HTML
4869 *
4870 * @since 3.6.0
4871 *
4872 * @param string $tag An HTML tag name. Example: 'video'.
4873 * @return string Tag RegEx.
4874 */
4875function get_tag_regex( $tag ) {
4876        if ( empty( $tag ) )
4877                return;
4878        return sprintf( '<%1$s[^<]*(?:>[\s\S]*<\/%1$s>|\s*\/>)', tag_escape( $tag ) );
4879}
4880
4881/**
4882 * Retrieve a canonical form of the provided charset appropriate for passing to PHP
4883 * functions such as htmlspecialchars() and charset html attributes.
4884 *
4885 * @since 3.6.0
4886 * @access private
4887 *
4888 * @see https://core.trac.wordpress.org/ticket/23688
4889 *
4890 * @param string $charset A charset name.
4891 * @return string The canonical form of the charset.
4892 */
4893function _canonical_charset( $charset ) {
4894        if ( 'UTF-8' === $charset || 'utf-8' === $charset || 'utf8' === $charset ||
4895                'UTF8' === $charset )
4896                return 'UTF-8';
4897
4898        if ( 'ISO-8859-1' === $charset || 'iso-8859-1' === $charset ||
4899                'iso8859-1' === $charset || 'ISO8859-1' === $charset )
4900                return 'ISO-8859-1';
4901
4902        return $charset;
4903}
4904
4905/**
4906 * Set the mbstring internal encoding to a binary safe encoding when func_overload
4907 * is enabled.
4908 *
4909 * When mbstring.func_overload is in use for multi-byte encodings, the results from
4910 * strlen() and similar functions respect the utf8 characters, causing binary data
4911 * to return incorrect lengths.
4912 *
4913 * This function overrides the mbstring encoding to a binary-safe encoding, and
4914 * resets it to the users expected encoding afterwards through the
4915 * `reset_mbstring_encoding` function.
4916 *
4917 * It is safe to recursively call this function, however each
4918 * `mbstring_binary_safe_encoding()` call must be followed up with an equal number
4919 * of `reset_mbstring_encoding()` calls.
4920 *
4921 * @since 3.7.0
4922 *
4923 * @see reset_mbstring_encoding()
4924 *
4925 * @staticvar array $encodings
4926 * @staticvar bool  $overloaded
4927 *
4928 * @param bool $reset Optional. Whether to reset the encoding back to a previously-set encoding.
4929 *                    Default false.
4930 */
4931function mbstring_binary_safe_encoding( $reset = false ) {
4932        static $encodings = array();
4933        static $overloaded = null;
4934
4935        if ( is_null( $overloaded ) )
4936                $overloaded = function_exists( 'mb_internal_encoding' ) && ( ini_get( 'mbstring.func_overload' ) & 2 );
4937
4938        if ( false === $overloaded )
4939                return;
4940
4941        if ( ! $reset ) {
4942                $encoding = mb_internal_encoding();
4943                array_push( $encodings, $encoding );
4944                mb_internal_encoding( 'ISO-8859-1' );
4945        }
4946
4947        if ( $reset && $encodings ) {
4948                $encoding = array_pop( $encodings );
4949                mb_internal_encoding( $encoding );
4950        }
4951}
4952
4953/**
4954 * Reset the mbstring internal encoding to a users previously set encoding.
4955 *
4956 * @see mbstring_binary_safe_encoding()
4957 *
4958 * @since 3.7.0
4959 */
4960function reset_mbstring_encoding() {
4961        mbstring_binary_safe_encoding( true );
4962}
4963
4964/**
4965 * Filter/validate a variable as a boolean.
4966 *
4967 * Alternative to `filter_var( $var, FILTER_VALIDATE_BOOLEAN )`.
4968 *
4969 * @since 4.0.0
4970 *
4971 * @param mixed $var Boolean value to validate.
4972 * @return bool Whether the value is validated.
4973 */
4974function wp_validate_boolean( $var ) {
4975        if ( is_bool( $var ) ) {
4976                return $var;
4977        }
4978
4979        if ( is_string( $var ) && 'false' === strtolower( $var ) ) {
4980                return false;
4981        }
4982
4983        return (bool) $var;
4984}
4985
4986/**
4987 * Delete a file
4988 *
4989 * @since 4.2.0
4990 *
4991 * @param string $file The path to the file to delete.
4992 */
4993function wp_delete_file( $file ) {
4994        /**
4995         * Filter the path of the file to delete.
4996         *
4997         * @since 2.1.0
4998         *
4999         * @param string $medium Path to the file to delete.
5000         */
5001        $delete = apply_filters( 'wp_delete_file', $file );
5002        if ( ! empty( $delete ) ) {
5003                @unlink( $delete );
5004        }
5005}
5006
5007/**
5008 * Outputs a small JS snippet on preview tabs/windows to remove `window.name` on unload.
5009 *
5010 * This prevents reusing the same tab for a preview when the user has navigated away.
5011 *
5012 * @since 4.3.0
5013 */
5014function wp_post_preview_js() {
5015        global $post;
5016
5017        if ( ! is_preview() || empty( $post ) ) {
5018                return;
5019        }
5020
5021        // Has to match the window name used in post_submit_meta_box()
5022        $name = 'wp-preview-' . (int) $post->ID;
5023
5024        ?>
5025        <script>
5026        ( function() {
5027                var query = document.location.search;
5028
5029                if ( query && query.indexOf( 'preview=true' ) !== -1 ) {
5030                        window.name = '<?php echo $name; ?>';
5031                }
5032
5033                if ( window.addEventListener ) {
5034                        window.addEventListener( 'unload', function() { window.name = ''; }, false );
5035                }
5036        }());
5037        </script>
5038        <?php
5039}