Make WordPress Core

Ticket #43366: functions.php

File functions.php, 175.9 KB (added by ravipatel, 7 years ago)

I have added a filter function code

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