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