]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/functions.php
WordPress 4.0-scripts
[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 http://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 bool|string 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 http://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                 . ")#",
472                 $content,
473                 $post_links
474         );
475
476         $post_links = array_unique( array_map( 'html_entity_decode', $post_links[0] ) );
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|bool 1|true when new day, 0|false 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         $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 bool|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 access 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 access 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 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 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 string|bool 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|bool 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   $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' ),
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         // MS Office formats.
2227         'doc' => 'application/msword',
2228         'pot|pps|ppt' => 'application/vnd.ms-powerpoint',
2229         'wri' => 'application/vnd.ms-write',
2230         'xla|xls|xlt|xlw' => 'application/vnd.ms-excel',
2231         'mdb' => 'application/vnd.ms-access',
2232         'mpp' => 'application/vnd.ms-project',
2233         'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
2234         'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
2235         'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
2236         'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
2237         'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
2238         'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
2239         'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
2240         'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
2241         'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
2242         'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
2243         'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
2244         'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
2245         'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
2246         'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
2247         'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
2248         'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
2249         'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
2250         'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
2251         'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
2252         'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
2253         'oxps' => 'application/oxps',
2254         'xps' => 'application/vnd.ms-xpsdocument',
2255         // OpenOffice formats.
2256         'odt' => 'application/vnd.oasis.opendocument.text',
2257         'odp' => 'application/vnd.oasis.opendocument.presentation',
2258         'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
2259         'odg' => 'application/vnd.oasis.opendocument.graphics',
2260         'odc' => 'application/vnd.oasis.opendocument.chart',
2261         'odb' => 'application/vnd.oasis.opendocument.database',
2262         'odf' => 'application/vnd.oasis.opendocument.formula',
2263         // WordPerfect formats.
2264         'wp|wpd' => 'application/wordperfect',
2265         // iWork formats.
2266         'key' => 'application/vnd.apple.keynote',
2267         'numbers' => 'application/vnd.apple.numbers',
2268         'pages' => 'application/vnd.apple.pages',
2269         ) );
2270 }
2271 /**
2272  * Retrieve list of allowed mime types and file extensions.
2273  *
2274  * @since 2.8.6
2275  *
2276  * @uses wp_get_upload_mime_types() to fetch the list of mime types
2277  *
2278  * @param int|WP_User $user Optional. User to check. Defaults to current user.
2279  * @return array Array of mime types keyed by the file extension regex corresponding
2280  *               to those types.
2281  */
2282 function get_allowed_mime_types( $user = null ) {
2283         $t = wp_get_mime_types();
2284
2285         unset( $t['swf'], $t['exe'] );
2286         if ( function_exists( 'current_user_can' ) )
2287                 $unfiltered = $user ? user_can( $user, 'unfiltered_html' ) : current_user_can( 'unfiltered_html' );
2288
2289         if ( empty( $unfiltered ) )
2290                 unset( $t['htm|html'] );
2291
2292         /**
2293          * Filter list of allowed mime types and file extensions.
2294          *
2295          * @since 2.0.0
2296          *
2297          * @param array            $t    Mime types keyed by the file extension regex corresponding to
2298          *                               those types. 'swf' and 'exe' removed from full list. 'htm|html' also
2299          *                               removed depending on '$user' capabilities.
2300          * @param int|WP_User|null $user User ID, User object or null if not provided (indicates current user).
2301          */
2302         return apply_filters( 'upload_mimes', $t, $user );
2303 }
2304
2305 /**
2306  * Display "Are You Sure" message to confirm the action being taken.
2307  *
2308  * If the action has the nonce explain message, then it will be displayed
2309  * along with the "Are you sure?" message.
2310  *
2311  * @since 2.0.4
2312  *
2313  * @param string $action The nonce action.
2314  */
2315 function wp_nonce_ays( $action ) {
2316         $title = __( 'WordPress Failure Notice' );
2317         if ( 'log-out' == $action ) {
2318                 $html = sprintf( __( 'You are attempting to log out of %s' ), get_bloginfo( 'name' ) ) . '</p><p>';
2319                 $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
2320                 $html .= sprintf( __( "Do you really want to <a href='%s'>log out</a>?"), wp_logout_url( $redirect_to ) );
2321         } else {
2322                 $html = __( 'Are you sure you want to do this?' );
2323                 if ( wp_get_referer() )
2324                         $html .= "</p><p><a href='" . esc_url( remove_query_arg( 'updated', wp_get_referer() ) ) . "'>" . __( 'Please try again.' ) . "</a>";
2325         }
2326
2327         wp_die( $html, $title, array('response' => 403) );
2328 }
2329
2330 /**
2331  * Kill WordPress execution and display HTML message with error message.
2332  *
2333  * This function complements the die() PHP function. The difference is that
2334  * HTML will be displayed to the user. It is recommended to use this function
2335  * only, when the execution should not continue any further. It is not
2336  * recommended to call this function very often and try to handle as many errors
2337  * as possible silently.
2338  *
2339  * @since 2.0.4
2340  *
2341  * @param string       $message Optional. Error message. Default empty.
2342  * @param string       $title   Optional. Error title. Default empty.
2343  * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
2344  */
2345 function wp_die( $message = '', $title = '', $args = array() ) {
2346         if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
2347                 /**
2348                  * Filter callback for killing WordPress execution for AJAX requests.
2349                  *
2350                  * @since 3.4.0
2351                  *
2352                  * @param callback $function Callback function name.
2353                  */
2354                 $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
2355         } elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
2356                 /**
2357                  * Filter callback for killing WordPress execution for XML-RPC requests.
2358                  *
2359                  * @since 3.4.0
2360                  *
2361                  * @param callback $function Callback function name.
2362                  */
2363                 $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
2364         } else {
2365                 /**
2366                  * Filter callback for killing WordPress execution for all non-AJAX, non-XML-RPC requests.
2367                  *
2368                  * @since 3.0.0
2369                  *
2370                  * @param callback $function Callback function name.
2371                  */
2372                 $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
2373         }
2374
2375         call_user_func( $function, $message, $title, $args );
2376 }
2377
2378 /**
2379  * Kill WordPress execution and display HTML message with error message.
2380  *
2381  * This is the default handler for wp_die if you want a custom one for your
2382  * site then you can overload using the wp_die_handler filter in wp_die
2383  *
2384  * @since 3.0.0
2385  * @access private
2386  *
2387  * @param string       $message Error message.
2388  * @param string       $title   Optional. Error title. Default empty.
2389  * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
2390  */
2391 function _default_wp_die_handler( $message, $title = '', $args = array() ) {
2392         $defaults = array( 'response' => 500 );
2393         $r = wp_parse_args($args, $defaults);
2394
2395         $have_gettext = function_exists('__');
2396
2397         if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) {
2398                 if ( empty( $title ) ) {
2399                         $error_data = $message->get_error_data();
2400                         if ( is_array( $error_data ) && isset( $error_data['title'] ) )
2401                                 $title = $error_data['title'];
2402                 }
2403                 $errors = $message->get_error_messages();
2404                 switch ( count( $errors ) ) {
2405                 case 0 :
2406                         $message = '';
2407                         break;
2408                 case 1 :
2409                         $message = "<p>{$errors[0]}</p>";
2410                         break;
2411                 default :
2412                         $message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $errors ) . "</li>\n\t</ul>";
2413                         break;
2414                 }
2415         } elseif ( is_string( $message ) ) {
2416                 $message = "<p>$message</p>";
2417         }
2418
2419         if ( isset( $r['back_link'] ) && $r['back_link'] ) {
2420                 $back_text = $have_gettext? __('&laquo; Back') : '&laquo; Back';
2421                 $message .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
2422         }
2423
2424         if ( ! did_action( 'admin_head' ) ) :
2425                 if ( !headers_sent() ) {
2426                         status_header( $r['response'] );
2427                         nocache_headers();
2428                         header( 'Content-Type: text/html; charset=utf-8' );
2429                 }
2430
2431                 if ( empty($title) )
2432                         $title = $have_gettext ? __('WordPress &rsaquo; Error') : 'WordPress &rsaquo; Error';
2433
2434                 $text_direction = 'ltr';
2435                 if ( isset($r['text_direction']) && 'rtl' == $r['text_direction'] )
2436                         $text_direction = 'rtl';
2437                 elseif ( function_exists( 'is_rtl' ) && is_rtl() )
2438                         $text_direction = 'rtl';
2439 ?>
2440 <!DOCTYPE html>
2441 <!-- 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
2442 -->
2443 <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'"; ?>>
2444 <head>
2445         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2446         <title><?php echo $title ?></title>
2447         <style type="text/css">
2448                 html {
2449                         background: #f1f1f1;
2450                 }
2451                 body {
2452                         background: #fff;
2453                         color: #444;
2454                         font-family: "Open Sans", sans-serif;
2455                         margin: 2em auto;
2456                         padding: 1em 2em;
2457                         max-width: 700px;
2458                         -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2459                         box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2460                 }
2461                 h1 {
2462                         border-bottom: 1px solid #dadada;
2463                         clear: both;
2464                         color: #666;
2465                         font: 24px "Open Sans", sans-serif;
2466                         margin: 30px 0 0 0;
2467                         padding: 0;
2468                         padding-bottom: 7px;
2469                 }
2470                 #error-page {
2471                         margin-top: 50px;
2472                 }
2473                 #error-page p {
2474                         font-size: 14px;
2475                         line-height: 1.5;
2476                         margin: 25px 0 20px;
2477                 }
2478                 #error-page code {
2479                         font-family: Consolas, Monaco, monospace;
2480                 }
2481                 ul li {
2482                         margin-bottom: 10px;
2483                         font-size: 14px ;
2484                 }
2485                 a {
2486                         color: #21759B;
2487                         text-decoration: none;
2488                 }
2489                 a:hover {
2490                         color: #D54E21;
2491                 }
2492                 .button {
2493                         background: #f7f7f7;
2494                         border: 1px solid #cccccc;
2495                         color: #555;
2496                         display: inline-block;
2497                         text-decoration: none;
2498                         font-size: 13px;
2499                         line-height: 26px;
2500                         height: 28px;
2501                         margin: 0;
2502                         padding: 0 10px 1px;
2503                         cursor: pointer;
2504                         -webkit-border-radius: 3px;
2505                         -webkit-appearance: none;
2506                         border-radius: 3px;
2507                         white-space: nowrap;
2508                         -webkit-box-sizing: border-box;
2509                         -moz-box-sizing:    border-box;
2510                         box-sizing:         border-box;
2511
2512                         -webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0,0,0,.08);
2513                         box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0,0,0,.08);
2514                         vertical-align: top;
2515                 }
2516
2517                 .button.button-large {
2518                         height: 29px;
2519                         line-height: 28px;
2520                         padding: 0 12px;
2521                 }
2522
2523                 .button:hover,
2524                 .button:focus {
2525                         background: #fafafa;
2526                         border-color: #999;
2527                         color: #222;
2528                 }
2529
2530                 .button:focus  {
2531                         -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,.2);
2532                         box-shadow: 1px 1px 1px rgba(0,0,0,.2);
2533                 }
2534
2535                 .button:active {
2536                         background: #eee;
2537                         border-color: #999;
2538                         color: #333;
2539                         -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2540                         box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2541                 }
2542
2543                 <?php if ( 'rtl' == $text_direction ) : ?>
2544                 body { font-family: Tahoma, Arial; }
2545                 <?php endif; ?>
2546         </style>
2547 </head>
2548 <body id="error-page">
2549 <?php endif; // ! did_action( 'admin_head' ) ?>
2550         <?php echo $message; ?>
2551 </body>
2552 </html>
2553 <?php
2554         die();
2555 }
2556
2557 /**
2558  * Kill WordPress execution and display XML message with error message.
2559  *
2560  * This is the handler for wp_die when processing XMLRPC requests.
2561  *
2562  * @since 3.2.0
2563  * @access private
2564  *
2565  * @param string       $message Error message.
2566  * @param string       $title   Optional. Error title. Default empty.
2567  * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
2568  */
2569 function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) {
2570         global $wp_xmlrpc_server;
2571         $defaults = array( 'response' => 500 );
2572
2573         $r = wp_parse_args($args, $defaults);
2574
2575         if ( $wp_xmlrpc_server ) {
2576                 $error = new IXR_Error( $r['response'] , $message);
2577                 $wp_xmlrpc_server->output( $error->getXml() );
2578         }
2579         die();
2580 }
2581
2582 /**
2583  * Kill WordPress ajax execution.
2584  *
2585  * This is the handler for wp_die when processing Ajax requests.
2586  *
2587  * @since 3.4.0
2588  * @access private
2589  *
2590  * @param string $message Optional. Response to print. Default empty.
2591  */
2592 function _ajax_wp_die_handler( $message = '' ) {
2593         if ( is_scalar( $message ) )
2594                 die( (string) $message );
2595         die( '0' );
2596 }
2597
2598 /**
2599  * Kill WordPress execution.
2600  *
2601  * This is the handler for wp_die when processing APP requests.
2602  *
2603  * @since 3.4.0
2604  * @access private
2605  *
2606  * @param string $message Optional. Response to print. Default empty.
2607  */
2608 function _scalar_wp_die_handler( $message = '' ) {
2609         if ( is_scalar( $message ) )
2610                 die( (string) $message );
2611         die();
2612 }
2613
2614 /**
2615  * Send a JSON response back to an Ajax request.
2616  *
2617  * @since 3.5.0
2618  *
2619  * @param mixed $response Variable (usually an array or object) to encode as JSON,
2620  *                        then print and die.
2621  */
2622 function wp_send_json( $response ) {
2623         @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
2624         echo json_encode( $response );
2625         if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
2626                 wp_die();
2627         else
2628                 die;
2629 }
2630
2631 /**
2632  * Send a JSON response back to an Ajax request, indicating success.
2633  *
2634  * @since 3.5.0
2635  *
2636  * @param mixed $data Data to encode as JSON, then print and die.
2637  */
2638 function wp_send_json_success( $data = null ) {
2639         $response = array( 'success' => true );
2640
2641         if ( isset( $data ) )
2642                 $response['data'] = $data;
2643
2644         wp_send_json( $response );
2645 }
2646
2647 /**
2648  * Send a JSON response back to an Ajax request, indicating failure.
2649  *
2650  * @since 3.5.0
2651  *
2652  * @param mixed $data Data to encode as JSON, then print and die.
2653  */
2654 function wp_send_json_error( $data = null ) {
2655         $response = array( 'success' => false );
2656
2657         if ( isset( $data ) )
2658                 $response['data'] = $data;
2659
2660         wp_send_json( $response );
2661 }
2662
2663 /**
2664  * Retrieve the WordPress home page URL.
2665  *
2666  * If the constant named 'WP_HOME' exists, then it will be used and returned
2667  * by the function. This can be used to counter the redirection on your local
2668  * development environment.
2669  *
2670  * @since 2.2.0
2671  * @access private
2672  *
2673  * @see WP_HOME
2674  *
2675  * @param string $url URL for the home location.
2676  * @return string Homepage location.
2677  */
2678 function _config_wp_home( $url = '' ) {
2679         if ( defined( 'WP_HOME' ) )
2680                 return untrailingslashit( WP_HOME );
2681         return $url;
2682 }
2683
2684 /**
2685  * Retrieve the WordPress site URL.
2686  *
2687  * If the constant named 'WP_SITEURL' is defined, then the value in that
2688  * constant will always be returned. This can be used for debugging a site
2689  * on your localhost while not having to change the database to your URL.
2690  *
2691  * @since 2.2.0
2692  * @access private
2693  *
2694  * @see WP_SITEURL
2695  *
2696  * @param string $url URL to set the WordPress site location.
2697  * @return string The WordPress Site URL.
2698  */
2699 function _config_wp_siteurl( $url = '' ) {
2700         if ( defined( 'WP_SITEURL' ) )
2701                 return untrailingslashit( WP_SITEURL );
2702         return $url;
2703 }
2704
2705 /**
2706  * Set the localized direction for MCE plugin.
2707  *
2708  * Will only set the direction to 'rtl', if the WordPress locale has
2709  * the text direction set to 'rtl'.
2710  *
2711  * Fills in the 'directionality' setting, enables the 'directionality'
2712  * plugin, and adds the 'ltr' button to 'toolbar1', formerly
2713  * 'theme_advanced_buttons1' array keys. These keys are then returned
2714  * in the $input (TinyMCE settings) array.
2715  *
2716  * @since 2.1.0
2717  * @access private
2718  *
2719  * @param array $input MCE settings array.
2720  * @return array Direction set for 'rtl', if needed by locale.
2721  */
2722 function _mce_set_direction( $input ) {
2723         if ( is_rtl() ) {
2724                 $input['directionality'] = 'rtl';
2725                 $input['plugins'] .= ',directionality';
2726                 $input['toolbar1'] .= ',ltr';
2727         }
2728
2729         return $input;
2730 }
2731
2732
2733 /**
2734  * Convert smiley code to the icon graphic file equivalent.
2735  *
2736  * You can turn off smilies, by going to the write setting screen and unchecking
2737  * the box, or by setting 'use_smilies' option to false or removing the option.
2738  *
2739  * Plugins may override the default smiley list by setting the $wpsmiliestrans
2740  * to an array, with the key the code the blogger types in and the value the
2741  * image file.
2742  *
2743  * The $wp_smiliessearch global is for the regular expression and is set each
2744  * time the function is called.
2745  *
2746  * The full list of smilies can be found in the function and won't be listed in
2747  * the description. Probably should create a Codex page for it, so that it is
2748  * available.
2749  *
2750  * @global array $wpsmiliestrans
2751  * @global array $wp_smiliessearch
2752  *
2753  * @since 2.2.0
2754  */
2755 function smilies_init() {
2756         global $wpsmiliestrans, $wp_smiliessearch;
2757
2758         // don't bother setting up smilies if they are disabled
2759         if ( !get_option( 'use_smilies' ) )
2760                 return;
2761
2762         if ( !isset( $wpsmiliestrans ) ) {
2763                 $wpsmiliestrans = array(
2764                 ':mrgreen:' => 'icon_mrgreen.gif',
2765                 ':neutral:' => 'icon_neutral.gif',
2766                 ':twisted:' => 'icon_twisted.gif',
2767                   ':arrow:' => 'icon_arrow.gif',
2768                   ':shock:' => 'icon_eek.gif',
2769                   ':smile:' => 'icon_smile.gif',
2770                     ':???:' => 'icon_confused.gif',
2771                    ':cool:' => 'icon_cool.gif',
2772                    ':evil:' => 'icon_evil.gif',
2773                    ':grin:' => 'icon_biggrin.gif',
2774                    ':idea:' => 'icon_idea.gif',
2775                    ':oops:' => 'icon_redface.gif',
2776                    ':razz:' => 'icon_razz.gif',
2777                    ':roll:' => 'icon_rolleyes.gif',
2778                    ':wink:' => 'icon_wink.gif',
2779                     ':cry:' => 'icon_cry.gif',
2780                     ':eek:' => 'icon_surprised.gif',
2781                     ':lol:' => 'icon_lol.gif',
2782                     ':mad:' => 'icon_mad.gif',
2783                     ':sad:' => 'icon_sad.gif',
2784                       '8-)' => 'icon_cool.gif',
2785                       '8-O' => 'icon_eek.gif',
2786                       ':-(' => 'icon_sad.gif',
2787                       ':-)' => 'icon_smile.gif',
2788                       ':-?' => 'icon_confused.gif',
2789                       ':-D' => 'icon_biggrin.gif',
2790                       ':-P' => 'icon_razz.gif',
2791                       ':-o' => 'icon_surprised.gif',
2792                       ':-x' => 'icon_mad.gif',
2793                       ':-|' => 'icon_neutral.gif',
2794                       ';-)' => 'icon_wink.gif',
2795                 // This one transformation breaks regular text with frequency.
2796                 //     '8)' => 'icon_cool.gif',
2797                        '8O' => 'icon_eek.gif',
2798                        ':(' => 'icon_sad.gif',
2799                        ':)' => 'icon_smile.gif',
2800                        ':?' => 'icon_confused.gif',
2801                        ':D' => 'icon_biggrin.gif',
2802                        ':P' => 'icon_razz.gif',
2803                        ':o' => 'icon_surprised.gif',
2804                        ':x' => 'icon_mad.gif',
2805                        ':|' => 'icon_neutral.gif',
2806                        ';)' => 'icon_wink.gif',
2807                       ':!:' => 'icon_exclaim.gif',
2808                       ':?:' => 'icon_question.gif',
2809                 );
2810         }
2811
2812         if (count($wpsmiliestrans) == 0) {
2813                 return;
2814         }
2815
2816         /*
2817          * NOTE: we sort the smilies in reverse key order. This is to make sure
2818          * we match the longest possible smilie (:???: vs :?) as the regular
2819          * expression used below is first-match
2820          */
2821         krsort($wpsmiliestrans);
2822
2823         $spaces = wp_spaces_regexp();
2824
2825         // Begin first "subpattern"
2826         $wp_smiliessearch = '/(?<=' . $spaces . '|^)';
2827
2828         $subchar = '';
2829         foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
2830                 $firstchar = substr($smiley, 0, 1);
2831                 $rest = substr($smiley, 1);
2832
2833                 // new subpattern?
2834                 if ($firstchar != $subchar) {
2835                         if ($subchar != '') {
2836                                 $wp_smiliessearch .= ')(?=' . $spaces . '|$)';  // End previous "subpattern"
2837                                 $wp_smiliessearch .= '|(?<=' . $spaces . '|^)'; // Begin another "subpattern"
2838                         }
2839                         $subchar = $firstchar;
2840                         $wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:';
2841                 } else {
2842                         $wp_smiliessearch .= '|';
2843                 }
2844                 $wp_smiliessearch .= preg_quote($rest, '/');
2845         }
2846
2847         $wp_smiliessearch .= ')(?=' . $spaces . '|$)/m';
2848
2849 }
2850
2851 /**
2852  * Merge user defined arguments into defaults array.
2853  *
2854  * This function is used throughout WordPress to allow for both string or array
2855  * to be merged into another array.
2856  *
2857  * @since 2.2.0
2858  *
2859  * @param string|array $args     Value to merge with $defaults
2860  * @param array        $defaults Optional. Array that serves as the defaults. Default empty.
2861  * @return array Merged user defined values with defaults.
2862  */
2863 function wp_parse_args( $args, $defaults = '' ) {
2864         if ( is_object( $args ) )
2865                 $r = get_object_vars( $args );
2866         elseif ( is_array( $args ) )
2867                 $r =& $args;
2868         else
2869                 wp_parse_str( $args, $r );
2870
2871         if ( is_array( $defaults ) )
2872                 return array_merge( $defaults, $r );
2873         return $r;
2874 }
2875
2876 /**
2877  * Clean up an array, comma- or space-separated list of IDs.
2878  *
2879  * @since 3.0.0
2880  *
2881  * @param array|string $list List of ids.
2882  * @return array Sanitized array of IDs.
2883  */
2884 function wp_parse_id_list( $list ) {
2885         if ( !is_array($list) )
2886                 $list = preg_split('/[\s,]+/', $list);
2887
2888         return array_unique(array_map('absint', $list));
2889 }
2890
2891 /**
2892  * Extract a slice of an array, given a list of keys.
2893  *
2894  * @since 3.1.0
2895  *
2896  * @param array $array The original array.
2897  * @param array $keys  The list of keys.
2898  * @return array The array slice.
2899  */
2900 function wp_array_slice_assoc( $array, $keys ) {
2901         $slice = array();
2902         foreach ( $keys as $key )
2903                 if ( isset( $array[ $key ] ) )
2904                         $slice[ $key ] = $array[ $key ];
2905
2906         return $slice;
2907 }
2908
2909 /**
2910  * Filters a list of objects, based on a set of key => value arguments.
2911  *
2912  * @since 3.0.0
2913  *
2914  * @param array       $list     An array of objects to filter
2915  * @param array       $args     Optional. An array of key => value arguments to match
2916  *                              against each object. Default empty array.
2917  * @param string      $operator Optional. The logical operation to perform. 'or' means
2918  *                              only one element from the array needs to match; 'and'
2919  *                              means all elements must match. Default 'and'.
2920  * @param bool|string $field    A field from the object to place instead of the entire object.
2921  *                              Default false.
2922  * @return array A list of objects or object fields.
2923  */
2924 function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) {
2925         if ( ! is_array( $list ) )
2926                 return array();
2927
2928         $list = wp_list_filter( $list, $args, $operator );
2929
2930         if ( $field )
2931                 $list = wp_list_pluck( $list, $field );
2932
2933         return $list;
2934 }
2935
2936 /**
2937  * Filters a list of objects, based on a set of key => value arguments.
2938  *
2939  * @since 3.1.0
2940  *
2941  * @param array  $list     An array of objects to filter.
2942  * @param array  $args     Optional. An array of key => value arguments to match
2943  *                         against each object. Default empty array.
2944  * @param string $operator Optional. The logical operation to perform. 'AND' means
2945  *                         all elements from the array must match. 'OR' means only
2946  *                         one element needs to match. 'NOT' means no elements may
2947  *                         match. Default 'AND'.
2948  * @return array Array of found values.
2949  */
2950 function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
2951         if ( ! is_array( $list ) )
2952                 return array();
2953
2954         if ( empty( $args ) )
2955                 return $list;
2956
2957         $operator = strtoupper( $operator );
2958         $count = count( $args );
2959         $filtered = array();
2960
2961         foreach ( $list as $key => $obj ) {
2962                 $to_match = (array) $obj;
2963
2964                 $matched = 0;
2965                 foreach ( $args as $m_key => $m_value ) {
2966                         if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] )
2967                                 $matched++;
2968                 }
2969
2970                 if ( ( 'AND' == $operator && $matched == $count )
2971                   || ( 'OR' == $operator && $matched > 0 )
2972                   || ( 'NOT' == $operator && 0 == $matched ) ) {
2973                         $filtered[$key] = $obj;
2974                 }
2975         }
2976
2977         return $filtered;
2978 }
2979
2980 /**
2981  * Pluck a certain field out of each object in a list.
2982  *
2983  * This has the same functionality and prototype of
2984  * array_column() (PHP 5.5) but also supports objects.
2985  *
2986  * @since 3.1.0
2987  * @since 4.0.0 $index_key parameter added.
2988  *
2989  * @param array      $list      List of objects or arrays
2990  * @param int|string $field     Field from the object to place instead of the entire object
2991  * @param int|string $index_key Optional. Field from the object to use as keys for the new array.
2992  *                              Default null.
2993  * @return array Array of found values. If $index_key is set, an array of found values with keys
2994  *               corresponding to $index_key.
2995  */
2996 function wp_list_pluck( $list, $field, $index_key = null ) {
2997         if ( ! $index_key ) {
2998                 /*
2999                  * This is simple. Could at some point wrap array_column()
3000                  * if we knew we had an array of arrays.
3001                  */
3002                 foreach ( $list as $key => $value ) {
3003                         if ( is_object( $value ) ) {
3004                                 $list[ $key ] = $value->$field;
3005                         } else {
3006                                 $list[ $key ] = $value[ $field ];
3007                         }
3008                 }
3009                 return $list;
3010         }
3011
3012         /*
3013          * When index_key is not set for a particular item, push the value
3014          * to the end of the stack. This is how array_column() behaves.
3015          */
3016         $newlist = array();
3017         foreach ( $list as $value ) {
3018                 if ( is_object( $value ) ) {
3019                         if ( isset( $value->$index_key ) ) {
3020                                 $newlist[ $value->$index_key ] = $value->$field;
3021                         } else {
3022                                 $newlist[] = $value->$field;
3023                         }
3024                 } else {
3025                         if ( isset( $value[ $index_key ] ) ) {
3026                                 $newlist[ $value[ $index_key ] ] = $value[ $field ];
3027                         } else {
3028                                 $newlist[] = $value[ $field ];
3029                         }
3030                 }
3031         }
3032
3033         return $newlist;
3034 }
3035
3036 /**
3037  * Determines if Widgets library should be loaded.
3038  *
3039  * Checks to make sure that the widgets library hasn't already been loaded.
3040  * If it hasn't, then it will load the widgets library and run an action hook.
3041  *
3042  * @since 2.2.0
3043  */
3044 function wp_maybe_load_widgets() {
3045         /**
3046          * Filter whether to load the Widgets library.
3047          *
3048          * Passing a falsey value to the filter will effectively short-circuit
3049          * the Widgets library from loading.
3050          *
3051          * @since 2.8.0
3052          *
3053          * @param bool $wp_maybe_load_widgets Whether to load the Widgets library.
3054          *                                    Default true.
3055          */
3056         if ( ! apply_filters( 'load_default_widgets', true ) ) {
3057                 return;
3058         }
3059
3060         require_once( ABSPATH . WPINC . '/default-widgets.php' );
3061
3062         add_action( '_admin_menu', 'wp_widgets_add_menu' );
3063 }
3064
3065 /**
3066  * Append the Widgets menu to the themes main menu.
3067  *
3068  * @since 2.2.0
3069  *
3070  * @uses $submenu The administration submenu list.
3071  */
3072 function wp_widgets_add_menu() {
3073         global $submenu;
3074
3075         if ( ! current_theme_supports( 'widgets' ) )
3076                 return;
3077
3078         $submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' );
3079         ksort( $submenu['themes.php'], SORT_NUMERIC );
3080 }
3081
3082 /**
3083  * Flush all output buffers for PHP 5.2.
3084  *
3085  * Make sure all output buffers are flushed before our singletons are destroyed.
3086  *
3087  * @since 2.2.0
3088  */
3089 function wp_ob_end_flush_all() {
3090         $levels = ob_get_level();
3091         for ($i=0; $i<$levels; $i++)
3092                 ob_end_flush();
3093 }
3094
3095 /**
3096  * Load custom DB error or display WordPress DB error.
3097  *
3098  * If a file exists in the wp-content directory named db-error.php, then it will
3099  * be loaded instead of displaying the WordPress DB error. If it is not found,
3100  * then the WordPress DB error will be displayed instead.
3101  *
3102  * The WordPress DB error sets the HTTP status header to 500 to try to prevent
3103  * search engines from caching the message. Custom DB messages should do the
3104  * same.
3105  *
3106  * This function was backported to WordPress 2.3.2, but originally was added
3107  * in WordPress 2.5.0.
3108  *
3109  * @since 2.3.2
3110  *
3111  * @global wpdb $wpdb WordPress database access abstraction object.
3112  */
3113 function dead_db() {
3114         global $wpdb;
3115
3116         wp_load_translations_early();
3117
3118         // Load custom DB error template, if present.
3119         if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
3120                 require_once( WP_CONTENT_DIR . '/db-error.php' );
3121                 die();
3122         }
3123
3124         // If installing or in the admin, provide the verbose message.
3125         if ( defined('WP_INSTALLING') || defined('WP_ADMIN') )
3126                 wp_die($wpdb->error);
3127
3128         // Otherwise, be terse.
3129         status_header( 500 );
3130         nocache_headers();
3131         header( 'Content-Type: text/html; charset=utf-8' );
3132 ?>
3133 <!DOCTYPE html>
3134 <html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
3135 <head>
3136 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
3137         <title><?php _e( 'Database Error' ); ?></title>
3138
3139 </head>
3140 <body>
3141         <h1><?php _e( 'Error establishing a database connection' ); ?></h1>
3142 </body>
3143 </html>
3144 <?php
3145         die();
3146 }
3147
3148 /**
3149  * Convert a value to non-negative integer.
3150  *
3151  * @since 2.5.0
3152  *
3153  * @param mixed $maybeint Data you wish to have converted to a non-negative integer.
3154  * @return int A non-negative integer.
3155  */
3156 function absint( $maybeint ) {
3157         return abs( intval( $maybeint ) );
3158 }
3159
3160 /**
3161  * Mark a function as deprecated and inform when it has been used.
3162  *
3163  * There is a hook deprecated_function_run that will be called that can be used
3164  * to get the backtrace up to what file and function called the deprecated
3165  * function.
3166  *
3167  * The current behavior is to trigger a user error if WP_DEBUG is true.
3168  *
3169  * This function is to be used in every function that is deprecated.
3170  *
3171  * @since 2.5.0
3172  * @access private
3173  *
3174  * @param string $function    The function that was called.
3175  * @param string $version     The version of WordPress that deprecated the function.
3176  * @param string $replacement Optional. The function that should have been called. Default null.
3177  */
3178 function _deprecated_function( $function, $version, $replacement = null ) {
3179
3180         /**
3181          * Fires when a deprecated function is called.
3182          *
3183          * @since 2.5.0
3184          *
3185          * @param string $function    The function that was called.
3186          * @param string $replacement The function that should have been called.
3187          * @param string $version     The version of WordPress that deprecated the function.
3188          */
3189         do_action( 'deprecated_function_run', $function, $replacement, $version );
3190
3191         /**
3192          * Filter whether to trigger an error for deprecated functions.
3193          *
3194          * @since 2.5.0
3195          *
3196          * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
3197          */
3198         if ( WP_DEBUG && apply_filters( 'deprecated_function_trigger_error', true ) ) {
3199                 if ( function_exists( '__' ) ) {
3200                         if ( ! is_null( $replacement ) )
3201                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) );
3202                         else
3203                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
3204                 } else {
3205                         if ( ! is_null( $replacement ) )
3206                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $function, $version, $replacement ) );
3207                         else
3208                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
3209                 }
3210         }
3211 }
3212
3213 /**
3214  * Mark a file as deprecated and inform when it has been used.
3215  *
3216  * There is a hook deprecated_file_included that will be called that can be used
3217  * to get the backtrace up to what file and function included the deprecated
3218  * file.
3219  *
3220  * The current behavior is to trigger a user error if WP_DEBUG is true.
3221  *
3222  * This function is to be used in every file that is deprecated.
3223  *
3224  * @since 2.5.0
3225  * @access private
3226  *
3227  * @param string $file        The file that was included.
3228  * @param string $version     The version of WordPress that deprecated the file.
3229  * @param string $replacement Optional. The file that should have been included based on ABSPATH.
3230  *                            Default null.
3231  * @param string $message     Optional. A message regarding the change. Default empty.
3232  */
3233 function _deprecated_file( $file, $version, $replacement = null, $message = '' ) {
3234
3235         /**
3236          * Fires when a deprecated file is called.
3237          *
3238          * @since 2.5.0
3239          *
3240          * @param string $file        The file that was called.
3241          * @param string $replacement The file that should have been included based on ABSPATH.
3242          * @param string $version     The version of WordPress that deprecated the file.
3243          * @param string $message     A message regarding the change.
3244          */
3245         do_action( 'deprecated_file_included', $file, $replacement, $version, $message );
3246
3247         /**
3248          * Filter whether to trigger an error for deprecated files.
3249          *
3250          * @since 2.5.0
3251          *
3252          * @param bool $trigger Whether to trigger the error for deprecated files. Default true.
3253          */
3254         if ( WP_DEBUG && apply_filters( 'deprecated_file_trigger_error', true ) ) {
3255                 $message = empty( $message ) ? '' : ' ' . $message;
3256                 if ( function_exists( '__' ) ) {
3257                         if ( ! is_null( $replacement ) )
3258                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $file, $version, $replacement ) . $message );
3259                         else
3260                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $file, $version ) . $message );
3261                 } else {
3262                         if ( ! is_null( $replacement ) )
3263                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $file, $version, $replacement ) . $message );
3264                         else
3265                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $file, $version ) . $message );
3266                 }
3267         }
3268 }
3269 /**
3270  * Mark a function argument as deprecated and inform when it has been used.
3271  *
3272  * This function is to be used whenever a deprecated function argument is used.
3273  * Before this function is called, the argument must be checked for whether it was
3274  * used by comparing it to its default value or evaluating whether it is empty.
3275  * For example:
3276  * <code>
3277  * if ( ! empty( $deprecated ) ) {
3278  *      _deprecated_argument( __FUNCTION__, '3.0' );
3279  * }
3280  * </code>
3281  *
3282  * There is a hook deprecated_argument_run that will be called that can be used
3283  * to get the backtrace up to what file and function used the deprecated
3284  * argument.
3285  *
3286  * The current behavior is to trigger a user error if WP_DEBUG is true.
3287  *
3288  * @since 3.0.0
3289  * @access private
3290  *
3291  * @param string $function The function that was called.
3292  * @param string $version  The version of WordPress that deprecated the argument used.
3293  * @param string $message  Optional. A message regarding the change. Default null.
3294  */
3295 function _deprecated_argument( $function, $version, $message = null ) {
3296
3297         /**
3298          * Fires when a deprecated argument is called.
3299          *
3300          * @since 3.0.0
3301          *
3302          * @param string $function The function that was called.
3303          * @param string $message  A message regarding the change.
3304          * @param string $version  The version of WordPress that deprecated the argument used.
3305          */
3306         do_action( 'deprecated_argument_run', $function, $message, $version );
3307
3308         /**
3309          * Filter whether to trigger an error for deprecated arguments.
3310          *
3311          * @since 3.0.0
3312          *
3313          * @param bool $trigger Whether to trigger the error for deprecated arguments. Default true.
3314          */
3315         if ( WP_DEBUG && apply_filters( 'deprecated_argument_trigger_error', true ) ) {
3316                 if ( function_exists( '__' ) ) {
3317                         if ( ! is_null( $message ) )
3318                                 trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s'), $function, $version, $message ) );
3319                         else
3320                                 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 ) );
3321                 } else {
3322                         if ( ! is_null( $message ) )
3323                                 trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s', $function, $version, $message ) );
3324                         else
3325                                 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 ) );
3326                 }
3327         }
3328 }
3329
3330 /**
3331  * Mark something as being incorrectly called.
3332  *
3333  * There is a hook doing_it_wrong_run that will be called that can be used
3334  * to get the backtrace up to what file and function called the deprecated
3335  * function.
3336  *
3337  * The current behavior is to trigger a user error if WP_DEBUG is true.
3338  *
3339  * @since 3.1.0
3340  * @access private
3341  *
3342  * @param string $function The function that was called.
3343  * @param string $message  A message explaining what has been done incorrectly.
3344  * @param string $version  The version of WordPress where the message was added.
3345  */
3346 function _doing_it_wrong( $function, $message, $version ) {
3347
3348         /**
3349          * Fires when the given function is being used incorrectly.
3350          *
3351          * @since 3.1.0
3352          *
3353          * @param string $function The function that was called.
3354          * @param string $message  A message explaining what has been done incorrectly.
3355          * @param string $version  The version of WordPress where the message was added.
3356          */
3357         do_action( 'doing_it_wrong_run', $function, $message, $version );
3358
3359         /**
3360          * Filter whether to trigger an error for _doing_it_wrong() calls.
3361          *
3362          * @since 3.1.0
3363          *
3364          * @param bool $trigger Whether to trigger the error for _doing_it_wrong() calls. Default true.
3365          */
3366         if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
3367                 if ( function_exists( '__' ) ) {
3368                         $version = is_null( $version ) ? '' : sprintf( __( '(This message was added in version %s.)' ), $version );
3369                         $message .= ' ' . __( 'Please see <a href="http://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.' );
3370                         trigger_error( sprintf( __( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s' ), $function, $message, $version ) );
3371                 } else {
3372                         $version = is_null( $version ) ? '' : sprintf( '(This message was added in version %s.)', $version );
3373                         $message .= ' Please see <a href="http://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.';
3374                         trigger_error( sprintf( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s', $function, $message, $version ) );
3375                 }
3376         }
3377 }
3378
3379 /**
3380  * Is the server running earlier than 1.5.0 version of lighttpd?
3381  *
3382  * @since 2.5.0
3383  *
3384  * @return bool Whether the server is running lighttpd < 1.5.0.
3385  */
3386 function is_lighttpd_before_150() {
3387         $server_parts = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] )? $_SERVER['SERVER_SOFTWARE'] : '' );
3388         $server_parts[1] = isset( $server_parts[1] )? $server_parts[1] : '';
3389         return  'lighttpd' == $server_parts[0] && -1 == version_compare( $server_parts[1], '1.5.0' );
3390 }
3391
3392 /**
3393  * Does the specified module exist in the Apache config?
3394  *
3395  * @since 2.5.0
3396  *
3397  * @param string $mod     The module, e.g. mod_rewrite.
3398  * @param bool   $default Optional. The default return value if the module is not found. Default false.
3399  * @return bool Whether the specified module is loaded.
3400  */
3401 function apache_mod_loaded($mod, $default = false) {
3402         global $is_apache;
3403
3404         if ( !$is_apache )
3405                 return false;
3406
3407         if ( function_exists( 'apache_get_modules' ) ) {
3408                 $mods = apache_get_modules();
3409                 if ( in_array($mod, $mods) )
3410                         return true;
3411         } elseif ( function_exists( 'phpinfo' ) && false === strpos( ini_get( 'disable_functions' ), 'phpinfo' ) ) {
3412                         ob_start();
3413                         phpinfo(8);
3414                         $phpinfo = ob_get_clean();
3415                         if ( false !== strpos($phpinfo, $mod) )
3416                                 return true;
3417         }
3418         return $default;
3419 }
3420
3421 /**
3422  * Check if IIS 7+ supports pretty permalinks.
3423  *
3424  * @since 2.8.0
3425  *
3426  * @return bool Whether IIS7 supports permalinks.
3427  */
3428 function iis7_supports_permalinks() {
3429         global $is_iis7;
3430
3431         $supports_permalinks = false;
3432         if ( $is_iis7 ) {
3433                 /* First we check if the DOMDocument class exists. If it does not exist, then we cannot
3434                  * easily update the xml configuration file, hence we just bail out and tell user that
3435                  * pretty permalinks cannot be used.
3436                  *
3437                  * Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the web site. When
3438                  * URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
3439                  * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
3440                  * via ISAPI then pretty permalinks will not work.
3441                  */
3442                 $supports_permalinks = class_exists('DOMDocument') && isset($_SERVER['IIS_UrlRewriteModule']) && ( php_sapi_name() == 'cgi-fcgi' );
3443         }
3444
3445         /**
3446          * Filter whether IIS 7+ supports pretty permalinks.
3447          *
3448          * @since 2.8.0
3449          *
3450          * @param bool $supports_permalinks Whether IIS7 supports permalinks. Default false.
3451          */
3452         return apply_filters( 'iis7_supports_permalinks', $supports_permalinks );
3453 }
3454
3455 /**
3456  * File validates against allowed set of defined rules.
3457  *
3458  * A return value of '1' means that the $file contains either '..' or './'. A
3459  * return value of '2' means that the $file contains ':' after the first
3460  * character. A return value of '3' means that the file is not in the allowed
3461  * files list.
3462  *
3463  * @since 1.2.0
3464  *
3465  * @param string $file File path.
3466  * @param array $allowed_files List of allowed files.
3467  * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
3468  */
3469 function validate_file( $file, $allowed_files = '' ) {
3470         if ( false !== strpos( $file, '..' ) )
3471                 return 1;
3472
3473         if ( false !== strpos( $file, './' ) )
3474                 return 1;
3475
3476         if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) )
3477                 return 3;
3478
3479         if (':' == substr( $file, 1, 1 ) )
3480                 return 2;
3481
3482         return 0;
3483 }
3484
3485 /**
3486  * Determine if SSL is used.
3487  *
3488  * @since 2.6.0
3489  *
3490  * @return bool True if SSL, false if not used.
3491  */
3492 function is_ssl() {
3493         if ( isset($_SERVER['HTTPS']) ) {
3494                 if ( 'on' == strtolower($_SERVER['HTTPS']) )
3495                         return true;
3496                 if ( '1' == $_SERVER['HTTPS'] )
3497                         return true;
3498         } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
3499                 return true;
3500         }
3501         return false;
3502 }
3503
3504 /**
3505  * Whether SSL login should be forced.
3506  *
3507  * @since 2.6.0
3508  *
3509  * @see force_ssl_admin()
3510  *
3511  * @param string|bool $force Optional Whether to force SSL login. Default null.
3512  * @return bool True if forced, false if not forced.
3513  */
3514 function force_ssl_login( $force = null ) {
3515         return force_ssl_admin( $force );
3516 }
3517
3518 /**
3519  * Whether to force SSL used for the Administration Screens.
3520  *
3521  * @since 2.6.0
3522  *
3523  * @param string|bool $force Optional. Whether to force SSL in admin screens. Default null.
3524  * @return bool True if forced, false if not forced.
3525  */
3526 function force_ssl_admin( $force = null ) {
3527         static $forced = false;
3528
3529         if ( !is_null( $force ) ) {
3530                 $old_forced = $forced;
3531                 $forced = $force;
3532                 return $old_forced;
3533         }
3534
3535         return $forced;
3536 }
3537
3538 /**
3539  * Guess the URL for the site.
3540  *
3541  * Will remove wp-admin links to retrieve only return URLs not in the wp-admin
3542  * directory.
3543  *
3544  * @since 2.6.0
3545  *
3546  * @return string The guessed URL.
3547  */
3548 function wp_guess_url() {
3549         if ( defined('WP_SITEURL') && '' != WP_SITEURL ) {
3550                 $url = WP_SITEURL;
3551         } else {
3552                 $abspath_fix = str_replace( '\\', '/', ABSPATH );
3553                 $script_filename_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
3554
3555                 // The request is for the admin
3556                 if ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false || strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ) {
3557                         $path = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $_SERVER['REQUEST_URI'] );
3558
3559                 // The request is for a file in ABSPATH
3560                 } elseif ( $script_filename_dir . '/' == $abspath_fix ) {
3561                         // Strip off any file/query params in the path
3562                         $path = preg_replace( '#/[^/]*$#i', '', $_SERVER['PHP_SELF'] );
3563
3564                 } else {
3565                         if ( false !== strpos( $_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
3566                                 // Request is hitting a file inside ABSPATH
3567                                 $directory = str_replace( ABSPATH, '', $script_filename_dir );
3568                                 // Strip off the sub directory, and any file/query paramss
3569                                 $path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] );
3570                         } elseif ( false !== strpos( $abspath_fix, $script_filename_dir ) ) {
3571                                 // Request is hitting a file above ABSPATH
3572                                 $subdirectory = substr( $abspath_fix, strpos( $abspath_fix, $script_filename_dir ) + strlen( $script_filename_dir ) );
3573                                 // Strip off any file/query params from the path, appending the sub directory to the install
3574                                 $path = preg_replace( '#/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] ) . $subdirectory;
3575                         } else {
3576                                 $path = $_SERVER['REQUEST_URI'];
3577                         }
3578                 }
3579
3580                 $schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet
3581                 $url = $schema . $_SERVER['HTTP_HOST'] . $path;
3582         }
3583
3584         return rtrim($url, '/');
3585 }
3586
3587 /**
3588  * Temporarily suspend cache additions.
3589  *
3590  * Stops more data being added to the cache, but still allows cache retrieval.
3591  * This is useful for actions, such as imports, when a lot of data would otherwise
3592  * be almost uselessly added to the cache.
3593  *
3594  * Suspension lasts for a single page load at most. Remember to call this
3595  * function again if you wish to re-enable cache adds earlier.
3596  *
3597  * @since 3.3.0
3598  *
3599  * @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
3600  * @return bool The current suspend setting
3601  */
3602 function wp_suspend_cache_addition( $suspend = null ) {
3603         static $_suspend = false;
3604
3605         if ( is_bool( $suspend ) )
3606                 $_suspend = $suspend;
3607
3608         return $_suspend;
3609 }
3610
3611 /**
3612  * Suspend cache invalidation.
3613  *
3614  * Turns cache invalidation on and off. Useful during imports where you don't wont to do
3615  * invalidations every time a post is inserted. Callers must be sure that what they are
3616  * doing won't lead to an inconsistent cache when invalidation is suspended.
3617  *
3618  * @since 2.7.0
3619  *
3620  * @param bool $suspend Optional. Whether to suspend or enable cache invalidation. Default true.
3621  * @return bool The current suspend setting.
3622  */
3623 function wp_suspend_cache_invalidation( $suspend = true ) {
3624         global $_wp_suspend_cache_invalidation;
3625
3626         $current_suspend = $_wp_suspend_cache_invalidation;
3627         $_wp_suspend_cache_invalidation = $suspend;
3628         return $current_suspend;
3629 }
3630
3631 /**
3632  * Determine whether a site is the main site of the current network.
3633  *
3634  * @since 3.0.0
3635  *
3636  * @param int $site_id Optional. Site ID to test. Defaults to current site.
3637  *                     Defaults to current site.
3638  * @return bool True if $site_id is the main site of the network, or if not
3639  *              running Multisite.
3640  */
3641 function is_main_site( $site_id = null ) {
3642         // This is the current network's information; 'site' is old terminology.
3643         global $current_site;
3644
3645         if ( ! is_multisite() )
3646                 return true;
3647
3648         if ( ! $site_id )
3649                 $site_id = get_current_blog_id();
3650
3651         return (int) $site_id === (int) $current_site->blog_id;
3652 }
3653
3654 /**
3655  * Determine whether a network is the main network of the Multisite install.
3656  *
3657  * @since 3.7.0
3658  *
3659  * @param int $network_id Optional. Network ID to test. Defaults to current network.
3660  * @return bool True if $network_id is the main network, or if not running Multisite.
3661  */
3662 function is_main_network( $network_id = null ) {
3663         global $wpdb;
3664
3665         if ( ! is_multisite() )
3666                 return true;
3667
3668         $current_network_id = (int) get_current_site()->id;
3669
3670         if ( ! $network_id )
3671                 $network_id = $current_network_id;
3672         $network_id = (int) $network_id;
3673
3674         if ( defined( 'PRIMARY_NETWORK_ID' ) )
3675                 return $network_id === (int) PRIMARY_NETWORK_ID;
3676
3677         if ( 1 === $current_network_id )
3678                 return $network_id === $current_network_id;
3679
3680         $primary_network_id = (int) wp_cache_get( 'primary_network_id', 'site-options' );
3681
3682         if ( $primary_network_id )
3683                 return $network_id === $primary_network_id;
3684
3685         $primary_network_id = (int) $wpdb->get_var( "SELECT id FROM $wpdb->site ORDER BY id LIMIT 1" );
3686         wp_cache_add( 'primary_network_id', $primary_network_id, 'site-options' );
3687
3688         return $network_id === $primary_network_id;
3689 }
3690
3691 /**
3692  * Determine whether global terms are enabled.
3693  *
3694  * @since 3.0.0
3695  *
3696  * @return bool True if multisite and global terms enabled.
3697  */
3698 function global_terms_enabled() {
3699         if ( ! is_multisite() )
3700                 return false;
3701
3702         static $global_terms = null;
3703         if ( is_null( $global_terms ) ) {
3704
3705                 /**
3706                  * Filter whether global terms are enabled.
3707                  *
3708                  * Passing a non-null value to the filter will effectively short-circuit the function,
3709                  * returning the value of the 'global_terms_enabled' site option instead.
3710                  *
3711                  * @since 3.0.0
3712                  *
3713                  * @param null $anbled Whether global terms are enabled.
3714                  */
3715                 $filter = apply_filters( 'global_terms_enabled', null );
3716                 if ( ! is_null( $filter ) )
3717                         $global_terms = (bool) $filter;
3718                 else
3719                         $global_terms = (bool) get_site_option( 'global_terms_enabled', false );
3720         }
3721         return $global_terms;
3722 }
3723
3724 /**
3725  * gmt_offset modification for smart timezone handling.
3726  *
3727  * Overrides the gmt_offset option if we have a timezone_string available.
3728  *
3729  * @since 2.8.0
3730  *
3731  * @return float|bool Timezone GMT offset, false otherwise.
3732  */
3733 function wp_timezone_override_offset() {
3734         if ( !$timezone_string = get_option( 'timezone_string' ) ) {
3735                 return false;
3736         }
3737
3738         $timezone_object = timezone_open( $timezone_string );
3739         $datetime_object = date_create();
3740         if ( false === $timezone_object || false === $datetime_object ) {
3741                 return false;
3742         }
3743         return round( timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS, 2 );
3744 }
3745
3746 /**
3747  * Sort-helper for timezones.
3748  *
3749  * @since 2.9.0
3750  * @access private
3751  *
3752  * @param array $a
3753  * @param array $b
3754  * @return int
3755  */
3756 function _wp_timezone_choice_usort_callback( $a, $b ) {
3757         // Don't use translated versions of Etc
3758         if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
3759                 // Make the order of these more like the old dropdown
3760                 if ( 'GMT+' === substr( $a['city'], 0, 4 ) && 'GMT+' === substr( $b['city'], 0, 4 ) ) {
3761                         return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
3762                 }
3763                 if ( 'UTC' === $a['city'] ) {
3764                         if ( 'GMT+' === substr( $b['city'], 0, 4 ) ) {
3765                                 return 1;
3766                         }
3767                         return -1;
3768                 }
3769                 if ( 'UTC' === $b['city'] ) {
3770                         if ( 'GMT+' === substr( $a['city'], 0, 4 ) ) {
3771                                 return -1;
3772                         }
3773                         return 1;
3774                 }
3775                 return strnatcasecmp( $a['city'], $b['city'] );
3776         }
3777         if ( $a['t_continent'] == $b['t_continent'] ) {
3778                 if ( $a['t_city'] == $b['t_city'] ) {
3779                         return strnatcasecmp( $a['t_subcity'], $b['t_subcity'] );
3780                 }
3781                 return strnatcasecmp( $a['t_city'], $b['t_city'] );
3782         } else {
3783                 // Force Etc to the bottom of the list
3784                 if ( 'Etc' === $a['continent'] ) {
3785                         return 1;
3786                 }
3787                 if ( 'Etc' === $b['continent'] ) {
3788                         return -1;
3789                 }
3790                 return strnatcasecmp( $a['t_continent'], $b['t_continent'] );
3791         }
3792 }
3793
3794 /**
3795  * Gives a nicely-formatted list of timezone strings.
3796  *
3797  * @since 2.9.0
3798  *
3799  * @param string $selected_zone Selected timezone.
3800  * @return string
3801  */
3802 function wp_timezone_choice( $selected_zone ) {
3803         static $mo_loaded = false;
3804
3805         $continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific');
3806
3807         // Load translations for continents and cities
3808         if ( !$mo_loaded ) {
3809                 $locale = get_locale();
3810                 $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
3811                 load_textdomain( 'continents-cities', $mofile );
3812                 $mo_loaded = true;
3813         }
3814
3815         $zonen = array();
3816         foreach ( timezone_identifiers_list() as $zone ) {
3817                 $zone = explode( '/', $zone );
3818                 if ( !in_array( $zone[0], $continents ) ) {
3819                         continue;
3820                 }
3821
3822                 // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
3823                 $exists = array(
3824                         0 => ( isset( $zone[0] ) && $zone[0] ),
3825                         1 => ( isset( $zone[1] ) && $zone[1] ),
3826                         2 => ( isset( $zone[2] ) && $zone[2] ),
3827                 );
3828                 $exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
3829                 $exists[4] = ( $exists[1] && $exists[3] );
3830                 $exists[5] = ( $exists[2] && $exists[3] );
3831
3832                 $zonen[] = array(
3833                         'continent'   => ( $exists[0] ? $zone[0] : '' ),
3834                         'city'        => ( $exists[1] ? $zone[1] : '' ),
3835                         'subcity'     => ( $exists[2] ? $zone[2] : '' ),
3836                         't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
3837                         't_city'      => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
3838                         't_subcity'   => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' )
3839                 );
3840         }
3841         usort( $zonen, '_wp_timezone_choice_usort_callback' );
3842
3843         $structure = array();
3844
3845         if ( empty( $selected_zone ) ) {
3846                 $structure[] = '<option selected="selected" value="">' . __( 'Select a city' ) . '</option>';
3847         }
3848
3849         foreach ( $zonen as $key => $zone ) {
3850                 // Build value in an array to join later
3851                 $value = array( $zone['continent'] );
3852
3853                 if ( empty( $zone['city'] ) ) {
3854                         // It's at the continent level (generally won't happen)
3855                         $display = $zone['t_continent'];
3856                 } else {
3857                         // It's inside a continent group
3858
3859                         // Continent optgroup
3860                         if ( !isset( $zonen[$key - 1] ) || $zonen[$key - 1]['continent'] !== $zone['continent'] ) {
3861                                 $label = $zone['t_continent'];
3862                                 $structure[] = '<optgroup label="'. esc_attr( $label ) .'">';
3863                         }
3864
3865                         // Add the city to the value
3866                         $value[] = $zone['city'];
3867
3868                         $display = $zone['t_city'];
3869                         if ( !empty( $zone['subcity'] ) ) {
3870                                 // Add the subcity to the value
3871                                 $value[] = $zone['subcity'];
3872                                 $display .= ' - ' . $zone['t_subcity'];
3873                         }
3874                 }
3875
3876                 // Build the value
3877                 $value = join( '/', $value );
3878                 $selected = '';
3879                 if ( $value === $selected_zone ) {
3880                         $selected = 'selected="selected" ';
3881                 }
3882                 $structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . "</option>";
3883
3884                 // Close continent optgroup
3885                 if ( !empty( $zone['city'] ) && ( !isset($zonen[$key + 1]) || (isset( $zonen[$key + 1] ) && $zonen[$key + 1]['continent'] !== $zone['continent']) ) ) {
3886                         $structure[] = '</optgroup>';
3887                 }
3888         }
3889
3890         // Do UTC
3891         $structure[] = '<optgroup label="'. esc_attr__( 'UTC' ) .'">';
3892         $selected = '';
3893         if ( 'UTC' === $selected_zone )
3894                 $selected = 'selected="selected" ';
3895         $structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __('UTC') . '</option>';
3896         $structure[] = '</optgroup>';
3897
3898         // Do manual UTC offsets
3899         $structure[] = '<optgroup label="'. esc_attr__( 'Manual Offsets' ) .'">';
3900         $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,
3901                 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);
3902         foreach ( $offset_range as $offset ) {
3903                 if ( 0 <= $offset )
3904                         $offset_name = '+' . $offset;
3905                 else
3906                         $offset_name = (string) $offset;
3907
3908                 $offset_value = $offset_name;
3909                 $offset_name = str_replace(array('.25','.5','.75'), array(':15',':30',':45'), $offset_name);
3910                 $offset_name = 'UTC' . $offset_name;
3911                 $offset_value = 'UTC' . $offset_value;
3912                 $selected = '';
3913                 if ( $offset_value === $selected_zone )
3914                         $selected = 'selected="selected" ';
3915                 $structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . "</option>";
3916
3917         }
3918         $structure[] = '</optgroup>';
3919
3920         return join( "\n", $structure );
3921 }
3922
3923 /**
3924  * Strip close comment and close php tags from file headers used by WP.
3925  *
3926  * @since 2.8.0
3927  * @access private
3928  *
3929  * @see http://core.trac.wordpress.org/ticket/8497
3930  *
3931  * @param string $str Header comment to clean up.
3932  * @return string
3933  */
3934 function _cleanup_header_comment( $str ) {
3935         return trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $str));
3936 }
3937
3938 /**
3939  * Permanently delete posts, pages, attachments, and comments which have been
3940  * in the trash for EMPTY_TRASH_DAYS.
3941  *
3942  * @since 2.9.0
3943  */
3944 function wp_scheduled_delete() {
3945         global $wpdb;
3946
3947         $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
3948
3949         $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);
3950
3951         foreach ( (array) $posts_to_delete as $post ) {
3952                 $post_id = (int) $post['post_id'];
3953                 if ( !$post_id )
3954                         continue;
3955
3956                 $del_post = get_post($post_id);
3957
3958                 if ( !$del_post || 'trash' != $del_post->post_status ) {
3959                         delete_post_meta($post_id, '_wp_trash_meta_status');
3960                         delete_post_meta($post_id, '_wp_trash_meta_time');
3961                 } else {
3962                         wp_delete_post($post_id);
3963                 }
3964         }
3965
3966         $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);
3967
3968         foreach ( (array) $comments_to_delete as $comment ) {
3969                 $comment_id = (int) $comment['comment_id'];
3970                 if ( !$comment_id )
3971                         continue;
3972
3973                 $del_comment = get_comment($comment_id);
3974
3975                 if ( !$del_comment || 'trash' != $del_comment->comment_approved ) {
3976                         delete_comment_meta($comment_id, '_wp_trash_meta_time');
3977                         delete_comment_meta($comment_id, '_wp_trash_meta_status');
3978                 } else {
3979                         wp_delete_comment($comment_id);
3980                 }
3981         }
3982 }
3983
3984 /**
3985  * Retrieve metadata from a file.
3986  *
3987  * Searches for metadata in the first 8kiB of a file, such as a plugin or theme.
3988  * Each piece of metadata must be on its own line. Fields can not span multiple
3989  * lines, the value will get cut at the end of the first line.
3990  *
3991  * If the file data is not within that first 8kiB, then the author should correct
3992  * their plugin file and move the data headers to the top.
3993  *
3994  * @see http://codex.wordpress.org/File_Header
3995  *
3996  * @since 2.9.0
3997  * @param string $file            Path to the file.
3998  * @param array  $default_headers List of headers, in the format array('HeaderKey' => 'Header Name').
3999  * @param string $context         Optional. If specified adds filter hook "extra_{$context}_headers".
4000  *                                Default empty.
4001  */
4002 function get_file_data( $file, $default_headers, $context = '' ) {
4003         // We don't need to write to the file, so just open for reading.
4004         $fp = fopen( $file, 'r' );
4005
4006         // Pull only the first 8kiB of the file in.
4007         $file_data = fread( $fp, 8192 );
4008
4009         // PHP will close file handle, but we are good citizens.
4010         fclose( $fp );
4011
4012         // Make sure we catch CR-only line endings.
4013         $file_data = str_replace( "\r", "\n", $file_data );
4014
4015         /**
4016          * Filter extra file headers by context.
4017          *
4018          * The dynamic portion of the hook name, $context, refers to the context
4019          * where extra headers might be loaded.
4020          *
4021          * @since 2.9.0
4022          *
4023          * @param array $extra_context_headers Empty array by default.
4024          */
4025         if ( $context && $extra_headers = apply_filters( "extra_{$context}_headers", array() ) ) {
4026                 $extra_headers = array_combine( $extra_headers, $extra_headers ); // keys equal values
4027                 $all_headers = array_merge( $extra_headers, (array) $default_headers );
4028         } else {
4029                 $all_headers = $default_headers;
4030         }
4031
4032         foreach ( $all_headers as $field => $regex ) {
4033                 if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] )
4034                         $all_headers[ $field ] = _cleanup_header_comment( $match[1] );
4035                 else
4036                         $all_headers[ $field ] = '';
4037         }
4038
4039         return $all_headers;
4040 }
4041
4042 /**
4043  * Returns true.
4044  *
4045  * Useful for returning true to filters easily.
4046  *
4047  * @since 3.0.0
4048  *
4049  * @see __return_false()
4050  *
4051  * @return bool True.
4052  */
4053 function __return_true() {
4054         return true;
4055 }
4056
4057 /**
4058  * Returns false.
4059  *
4060  * Useful for returning false to filters easily.
4061  *
4062  * @since 3.0.0
4063  *
4064  * @see __return_true()
4065  *
4066  * @return bool False.
4067  */
4068 function __return_false() {
4069         return false;
4070 }
4071
4072 /**
4073  * Returns 0.
4074  *
4075  * Useful for returning 0 to filters easily.
4076  *
4077  * @since 3.0.0
4078  *
4079  * @return int 0.
4080  */
4081 function __return_zero() {
4082         return 0;
4083 }
4084
4085 /**
4086  * Returns an empty array.
4087  *
4088  * Useful for returning an empty array to filters easily.
4089  *
4090  * @since 3.0.0
4091  *
4092  * @return array Empty array.
4093  */
4094 function __return_empty_array() {
4095         return array();
4096 }
4097
4098 /**
4099  * Returns null.
4100  *
4101  * Useful for returning null to filters easily.
4102  *
4103  * @since 3.4.0
4104  *
4105  * @return null Null value.
4106  */
4107 function __return_null() {
4108         return null;
4109 }
4110
4111 /**
4112  * Returns an empty string.
4113  *
4114  * Useful for returning an empty string to filters easily.
4115  *
4116  * @since 3.7.0
4117  *
4118  * @see __return_null()
4119  *
4120  * @return string Empty string.
4121  */
4122 function __return_empty_string() {
4123         return '';
4124 }
4125
4126 /**
4127  * Send a HTTP header to disable content type sniffing in browsers which support it.
4128  *
4129  * @since 3.0.0
4130  *
4131  * @see http://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
4132  * @see http://src.chromium.org/viewvc/chrome?view=rev&revision=6985
4133  */
4134 function send_nosniff_header() {
4135         @header( 'X-Content-Type-Options: nosniff' );
4136 }
4137
4138 /**
4139  * Return a MySQL expression for selecting the week number based on the start_of_week option.
4140  *
4141  * @internal
4142  * @since 3.0.0
4143  *
4144  * @param string $column Database column.
4145  * @return string SQL clause.
4146  */
4147 function _wp_mysql_week( $column ) {
4148         switch ( $start_of_week = (int) get_option( 'start_of_week' ) ) {
4149         case 1 :
4150                 return "WEEK( $column, 1 )";
4151         case 2 :
4152         case 3 :
4153         case 4 :
4154         case 5 :
4155         case 6 :
4156                 return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
4157         case 0 :
4158         default :
4159                 return "WEEK( $column, 0 )";
4160         }
4161 }
4162
4163 /**
4164  * Find hierarchy loops using a callback function that maps object IDs to parent IDs.
4165  *
4166  * @since 3.1.0
4167  * @access private
4168  *
4169  * @param callback $callback      Function that accepts ( ID, $callback_args ) and outputs parent_ID.
4170  * @param int      $start         The ID to start the loop check at.
4171  * @param int      $start_parent  The parent_ID of $start to use instead of calling $callback( $start ).
4172  *                                Use null to always use $callback
4173  * @param array    $callback_args Optional. Additional arguments to send to $callback.
4174  * @return array IDs of all members of loop.
4175  */
4176 function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_args = array() ) {
4177         $override = is_null( $start_parent ) ? array() : array( $start => $start_parent );
4178
4179         if ( !$arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args ) )
4180                 return array();
4181
4182         return wp_find_hierarchy_loop_tortoise_hare( $callback, $arbitrary_loop_member, $override, $callback_args, true );
4183 }
4184
4185 /**
4186  * Use the "The Tortoise and the Hare" algorithm to detect loops.
4187  *
4188  * For every step of the algorithm, the hare takes two steps and the tortoise one.
4189  * If the hare ever laps the tortoise, there must be a loop.
4190  *
4191  * @since 3.1.0
4192  * @access private
4193  *
4194  * @param callback $callback      Function that accepts ( ID, callback_arg, ... ) and outputs parent_ID.
4195  * @param int      $start         The ID to start the loop check at.
4196  * @param array    $override      Optional. An array of ( ID => parent_ID, ... ) to use instead of $callback.
4197  *                                Default empty array.
4198  * @param array    $callback_args Optional. Additional arguments to send to $callback. Default empty array.
4199  * @param bool     $_return_loop  Optional. Return loop members or just detect presence of loop? Only set
4200  *                                to true if you already know the given $start is part of a loop (otherwise
4201  *                                the returned array might include branches). Default false.
4202  * @return mixed Scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if
4203  *               $_return_loop
4204  */
4205 function wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override = array(), $callback_args = array(), $_return_loop = false ) {
4206         $tortoise = $hare = $evanescent_hare = $start;
4207         $return = array();
4208
4209         // Set evanescent_hare to one past hare
4210         // Increment hare two steps
4211         while (
4212                 $tortoise
4213         &&
4214                 ( $evanescent_hare = isset( $override[$hare] ) ? $override[$hare] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
4215         &&
4216                 ( $hare = isset( $override[$evanescent_hare] ) ? $override[$evanescent_hare] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
4217         ) {
4218                 if ( $_return_loop )
4219                         $return[$tortoise] = $return[$evanescent_hare] = $return[$hare] = true;
4220
4221                 // tortoise got lapped - must be a loop
4222                 if ( $tortoise == $evanescent_hare || $tortoise == $hare )
4223                         return $_return_loop ? $return : $tortoise;
4224
4225                 // Increment tortoise by one step
4226                 $tortoise = isset( $override[$tortoise] ) ? $override[$tortoise] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
4227         }
4228
4229         return false;
4230 }
4231
4232 /**
4233  * Send a HTTP header to limit rendering of pages to same origin iframes.
4234  *
4235  * @since 3.1.3
4236  *
4237  * @see https://developer.mozilla.org/en/the_x-frame-options_response_header
4238  */
4239 function send_frame_options_header() {
4240         @header( 'X-Frame-Options: SAMEORIGIN' );
4241 }
4242
4243 /**
4244  * Retrieve a list of protocols to allow in HTML attributes.
4245  *
4246  * @since 3.3.0
4247  *
4248  * @see wp_kses()
4249  * @see esc_url()
4250  *
4251  * @return array Array of allowed protocols.
4252  */
4253 function wp_allowed_protocols() {
4254         static $protocols;
4255
4256         if ( empty( $protocols ) ) {
4257                 $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp' );
4258
4259                 /**
4260                  * Filter the list of protocols allowed in HTML attributes.
4261                  *
4262                  * @since 3.0.0
4263                  *
4264                  * @param array $protocols Array of allowed protocols e.g. 'http', 'ftp', 'tel', and more.
4265                  */
4266                 $protocols = apply_filters( 'kses_allowed_protocols', $protocols );
4267         }
4268
4269         return $protocols;
4270 }
4271
4272 /**
4273  * Return a comma-separated string of functions that have been called to get
4274  * to the current point in code.
4275  *
4276  * @since 3.4.0
4277  *
4278  * @see http://core.trac.wordpress.org/ticket/19589
4279  *
4280  * @param string $ignore_class Optional. A class to ignore all function calls within - useful
4281  *                             when you want to just give info about the callee. Default null.
4282  * @param int    $skip_frames  Optional. A number of stack frames to skip - useful for unwinding
4283  *                             back to the source of the issue. Default 0.
4284  * @param bool   $pretty       Optional. Whether or not you want a comma separated string or raw
4285  *                             array returned. Default true.
4286  * @return string|array Either a string containing a reversed comma separated trace or an array
4287  *                      of individual calls.
4288  */
4289 function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
4290         if ( version_compare( PHP_VERSION, '5.2.5', '>=' ) )
4291                 $trace = debug_backtrace( false );
4292         else
4293                 $trace = debug_backtrace();
4294
4295         $caller = array();
4296         $check_class = ! is_null( $ignore_class );
4297         $skip_frames++; // skip this function
4298
4299         foreach ( $trace as $call ) {
4300                 if ( $skip_frames > 0 ) {
4301                         $skip_frames--;
4302                 } elseif ( isset( $call['class'] ) ) {
4303                         if ( $check_class && $ignore_class == $call['class'] )
4304                                 continue; // Filter out calls
4305
4306                         $caller[] = "{$call['class']}{$call['type']}{$call['function']}";
4307                 } else {
4308                         if ( in_array( $call['function'], array( 'do_action', 'apply_filters' ) ) ) {
4309                                 $caller[] = "{$call['function']}('{$call['args'][0]}')";
4310                         } elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ) ) ) {
4311                                 $caller[] = $call['function'] . "('" . str_replace( array( WP_CONTENT_DIR, ABSPATH ) , '', $call['args'][0] ) . "')";
4312                         } else {
4313                                 $caller[] = $call['function'];
4314                         }
4315                 }
4316         }
4317         if ( $pretty )
4318                 return join( ', ', array_reverse( $caller ) );
4319         else
4320                 return $caller;
4321 }
4322
4323 /**
4324  * Retrieve ids that are not already present in the cache.
4325  *
4326  * @since 3.4.0
4327  * @access private
4328  *
4329  * @param array  $object_ids ID list.
4330  * @param string $cache_key  The cache bucket to check against.
4331  *
4332  * @return array List of ids not present in the cache.
4333  */
4334 function _get_non_cached_ids( $object_ids, $cache_key ) {
4335         $clean = array();
4336         foreach ( $object_ids as $id ) {
4337                 $id = (int) $id;
4338                 if ( !wp_cache_get( $id, $cache_key ) ) {
4339                         $clean[] = $id;
4340                 }
4341         }
4342
4343         return $clean;
4344 }
4345
4346 /**
4347  * Test if the current device has the capability to upload files.
4348  *
4349  * @since 3.4.0
4350  * @access private
4351  *
4352  * @return bool true|false Whether the device is able to upload files.
4353  */
4354 function _device_can_upload() {
4355         if ( ! wp_is_mobile() )
4356                 return true;
4357
4358         $ua = $_SERVER['HTTP_USER_AGENT'];
4359
4360         if ( strpos($ua, 'iPhone') !== false
4361                 || strpos($ua, 'iPad') !== false
4362                 || strpos($ua, 'iPod') !== false ) {
4363                         return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
4364         }
4365
4366         return true;
4367 }
4368
4369 /**
4370  * Test if a given path is a stream URL
4371  *
4372  * @param string $path The resource path or URL.
4373  * @return bool True if the path is a stream URL.
4374  */
4375 function wp_is_stream( $path ) {
4376         $wrappers = stream_get_wrappers();
4377         $wrappers_re = '(' . join('|', $wrappers) . ')';
4378
4379         return preg_match( "!^$wrappers_re://!", $path ) === 1;
4380 }
4381
4382 /**
4383  * Test if the supplied date is valid for the Gregorian calendar.
4384  *
4385  * @since 3.5.0
4386  *
4387  * @see checkdate()
4388  *
4389  * @param  int    $month       Month number.
4390  * @param  int    $day         Day number.
4391  * @param  int    $year        Year number.
4392  * @param  string $source_date The date to filter.
4393  * @return bool True if valid date, false if not valid date.
4394  */
4395 function wp_checkdate( $month, $day, $year, $source_date ) {
4396         /**
4397          * Filter whether the given date is valid for the Gregorian calendar.
4398          *
4399          * @since 3.5.0
4400          *
4401          * @param bool   $checkdate   Whether the given date is valid.
4402          * @param string $source_date Date to check.
4403          */
4404         return apply_filters( 'wp_checkdate', checkdate( $month, $day, $year ), $source_date );
4405 }
4406
4407 /**
4408  * Load the auth check for monitoring whether the user is still logged in.
4409  *
4410  * Can be disabled with remove_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
4411  *
4412  * This is disabled for certain screens where a login screen could cause an
4413  * inconvenient interruption. A filter called wp_auth_check_load can be used
4414  * for fine-grained control.
4415  *
4416  * @since 3.6.0
4417  */
4418 function wp_auth_check_load() {
4419         if ( ! is_admin() && ! is_user_logged_in() )
4420                 return;
4421
4422         if ( defined( 'IFRAME_REQUEST' ) )
4423                 return;
4424
4425         $screen = get_current_screen();
4426         $hidden = array( 'update', 'update-network', 'update-core', 'update-core-network', 'upgrade', 'upgrade-network', 'network' );
4427         $show = ! in_array( $screen->id, $hidden );
4428
4429         /**
4430          * Filter whether to load the authentication check.
4431          *
4432          * Passing a falsey value to the filter will effectively short-circuit
4433          * loading the authentication check.
4434          *
4435          * @since 3.6.0
4436          *
4437          * @param bool      $show   Whether to load the authentication check.
4438          * @param WP_Screen $screen The current screen object.
4439          */
4440         if ( apply_filters( 'wp_auth_check_load', $show, $screen ) ) {
4441                 wp_enqueue_style( 'wp-auth-check' );
4442                 wp_enqueue_script( 'wp-auth-check' );
4443
4444                 add_action( 'admin_print_footer_scripts', 'wp_auth_check_html', 5 );
4445                 add_action( 'wp_print_footer_scripts', 'wp_auth_check_html', 5 );
4446         }
4447 }
4448
4449 /**
4450  * Output the HTML that shows the wp-login dialog when the user is no longer logged in.
4451  *
4452  * @since 3.6.0
4453  */
4454 function wp_auth_check_html() {
4455         $login_url = wp_login_url();
4456         $current_domain = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
4457         $same_domain = ( strpos( $login_url, $current_domain ) === 0 );
4458
4459         /**
4460          * Filter whether the authentication check originated at the same domain.
4461          *
4462          * @since 3.6.0
4463          *
4464          * @param bool $same_domain Whether the authentication check originated at the same domain.
4465          */
4466         $same_domain = apply_filters( 'wp_auth_check_same_domain', $same_domain );
4467         $wrap_class = $same_domain ? 'hidden' : 'hidden fallback';
4468
4469         ?>
4470         <div id="wp-auth-check-wrap" class="<?php echo $wrap_class; ?>">
4471         <div id="wp-auth-check-bg"></div>
4472         <div id="wp-auth-check">
4473         <div class="wp-auth-check-close" tabindex="0" title="<?php esc_attr_e('Close'); ?>"></div>
4474         <?php
4475
4476         if ( $same_domain ) {
4477                 ?>
4478                 <div id="wp-auth-check-form" data-src="<?php echo esc_url( add_query_arg( array( 'interim-login' => 1 ), $login_url ) ); ?>"></div>
4479                 <?php
4480         }
4481
4482         ?>
4483         <div class="wp-auth-fallback">
4484                 <p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e('Session expired'); ?></b></p>
4485                 <p><a href="<?php echo esc_url( $login_url ); ?>" target="_blank"><?php _e('Please log in again.'); ?></a>
4486                 <?php _e('The login page will open in a new window. After logging in you can close it and return to this page.'); ?></p>
4487         </div>
4488         </div>
4489         </div>
4490         <?php
4491 }
4492
4493 /**
4494  * Check whether a user is still logged in, for the heartbeat.
4495  *
4496  * Send a result that shows a log-in box if the user is no longer logged in,
4497  * or if their cookie is within the grace period.
4498  *
4499  * @since 3.6.0
4500  *
4501  * @param array|object $response  The Heartbeat response object or array.
4502  * @return array|object $response The Heartbeat response object or array with 'wp-auth-check'
4503  *                                value set.
4504  */
4505 function wp_auth_check( $response ) {
4506         $response['wp-auth-check'] = is_user_logged_in() && empty( $GLOBALS['login_grace_period'] );
4507         return $response;
4508 }
4509
4510 /**
4511  * Return RegEx body to liberally match an opening HTML tag.
4512  *
4513  * Matches an opening HTML tag that:
4514  * 1. Is self-closing or
4515  * 2. Has no body but has a closing tag of the same name or
4516  * 3. Contains a body and a closing tag of the same name
4517  *
4518  * Note: this RegEx does not balance inner tags and does not attempt
4519  * to produce valid HTML
4520  *
4521  * @since 3.6.0
4522  *
4523  * @param string $tag An HTML tag name. Example: 'video'.
4524  * @return string Tag RegEx.
4525  */
4526 function get_tag_regex( $tag ) {
4527         if ( empty( $tag ) )
4528                 return;
4529         return sprintf( '<%1$s[^<]*(?:>[\s\S]*<\/%1$s>|\s*\/>)', tag_escape( $tag ) );
4530 }
4531
4532 /**
4533  * Retrieve a canonical form of the provided charset appropriate for passing to PHP
4534  * functions such as htmlspecialchars() and charset html attributes.
4535  *
4536  * @since 3.6.0
4537  * @access private
4538  *
4539  * @see http://core.trac.wordpress.org/ticket/23688
4540  *
4541  * @param string $charset A charset name.
4542  * @return string The canonical form of the charset.
4543  */
4544 function _canonical_charset( $charset ) {
4545         if ( 'UTF-8' === $charset || 'utf-8' === $charset || 'utf8' === $charset ||
4546                 'UTF8' === $charset )
4547                 return 'UTF-8';
4548
4549         if ( 'ISO-8859-1' === $charset || 'iso-8859-1' === $charset ||
4550                 'iso8859-1' === $charset || 'ISO8859-1' === $charset )
4551                 return 'ISO-8859-1';
4552
4553         return $charset;
4554 }
4555
4556 /**
4557  * Set the mbstring internal encoding to a binary safe encoding when func_overload
4558  * is enabled.
4559  *
4560  * When mbstring.func_overload is in use for multi-byte encodings, the results from
4561  * strlen() and similar functions respect the utf8 characters, causing binary data
4562  * to return incorrect lengths.
4563  *
4564  * This function overrides the mbstring encoding to a binary-safe encoding, and
4565  * resets it to the users expected encoding afterwards through the
4566  * `reset_mbstring_encoding` function.
4567  *
4568  * It is safe to recursively call this function, however each
4569  * `mbstring_binary_safe_encoding()` call must be followed up with an equal number
4570  * of `reset_mbstring_encoding()` calls.
4571  *
4572  * @since 3.7.0
4573  *
4574  * @see reset_mbstring_encoding()
4575  *
4576  * @param bool $reset Optional. Whether to reset the encoding back to a previously-set encoding.
4577  *                    Default false.
4578  */
4579 function mbstring_binary_safe_encoding( $reset = false ) {
4580         static $encodings = array();
4581         static $overloaded = null;
4582
4583         if ( is_null( $overloaded ) )
4584                 $overloaded = function_exists( 'mb_internal_encoding' ) && ( ini_get( 'mbstring.func_overload' ) & 2 );
4585
4586         if ( false === $overloaded )
4587                 return;
4588
4589         if ( ! $reset ) {
4590                 $encoding = mb_internal_encoding();
4591                 array_push( $encodings, $encoding );
4592                 mb_internal_encoding( 'ISO-8859-1' );
4593         }
4594
4595         if ( $reset && $encodings ) {
4596                 $encoding = array_pop( $encodings );
4597                 mb_internal_encoding( $encoding );
4598         }
4599 }
4600
4601 /**
4602  * Reset the mbstring internal encoding to a users previously set encoding.
4603  *
4604  * @see mbstring_binary_safe_encoding()
4605  *
4606  * @since 3.7.0
4607  */
4608 function reset_mbstring_encoding() {
4609         mbstring_binary_safe_encoding( true );
4610 }
4611
4612 /**
4613  * Alternative to filter_var( $var, FILTER_VALIDATE_BOOLEAN ).
4614  *
4615  * @since 4.0.0
4616  *
4617  * @param mixed $var Boolean value to validate.
4618  * @return bool Whether the value is validated.
4619  */
4620 function wp_validate_boolean( $var ) {
4621         if ( is_bool( $var ) ) {
4622                 return $var;
4623         }
4624
4625         if ( 'false' === $var ) {
4626                 return false;
4627         }
4628
4629         return (bool) $var;
4630 }