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