WordPress 3.9
[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  * Converts 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 is true.
24  * @return string|int Formatted date string, or Unix timestamp.
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 'mysql', 'timestamp', or PHP date format string (e.g. 'Y-m-d').
57  * @param int|bool $gmt Optional. Whether to use GMT timezone. Default is false.
58  * @return int|string String if $type is 'gmt', int if $type is 'timestamp'.
59  */
60 function current_time( $type, $gmt = 0 ) {
61         switch ( $type ) {
62                 case 'mysql':
63                         return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', ( time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ) );
64                         break;
65                 case 'timestamp':
66                         return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
67                         break;
68                 default:
69                         return ( $gmt ) ? date( $type ) : date( $type, time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) );
70                         break;
71         }
72 }
73
74 /**
75  * Retrieve the date in localized format, based on timestamp.
76  *
77  * If the locale specifies the locale month and weekday, then the locale will
78  * take over the format for the date. If it isn't, then the date format string
79  * will be used instead.
80  *
81  * @since 0.71
82  *
83  * @param string $dateformatstring Format to display the date.
84  * @param int $unixtimestamp Optional. Unix timestamp.
85  * @param bool $gmt Optional, default is false. Whether to convert to GMT for time.
86  * @return string The date, translated if locale specifies it.
87  */
88 function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
89         global $wp_locale;
90         $i = $unixtimestamp;
91
92         if ( false === $i ) {
93                 if ( ! $gmt )
94                         $i = current_time( 'timestamp' );
95                 else
96                         $i = time();
97                 // we should not let date() interfere with our
98                 // specially computed timestamp
99                 $gmt = true;
100         }
101
102         // store original value for language with untypical grammars
103         // see http://core.trac.wordpress.org/ticket/9396
104         $req_format = $dateformatstring;
105
106         $datefunc = $gmt? 'gmdate' : 'date';
107
108         if ( ( !empty( $wp_locale->month ) ) && ( !empty( $wp_locale->weekday ) ) ) {
109                 $datemonth = $wp_locale->get_month( $datefunc( 'm', $i ) );
110                 $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth );
111                 $dateweekday = $wp_locale->get_weekday( $datefunc( 'w', $i ) );
112                 $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday );
113                 $datemeridiem = $wp_locale->get_meridiem( $datefunc( 'a', $i ) );
114                 $datemeridiem_capital = $wp_locale->get_meridiem( $datefunc( 'A', $i ) );
115                 $dateformatstring = ' '.$dateformatstring;
116                 $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
117                 $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . backslashit( $datemonth ), $dateformatstring );
118                 $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . backslashit( $dateweekday ), $dateformatstring );
119                 $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring );
120                 $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . backslashit( $datemeridiem ), $dateformatstring );
121                 $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring );
122
123                 $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
124         }
125         $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' );
126         $timezone_formats_re = implode( '|', $timezone_formats );
127         if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) {
128                 $timezone_string = get_option( 'timezone_string' );
129                 if ( $timezone_string ) {
130                         $timezone_object = timezone_open( $timezone_string );
131                         $date_object = date_create( null, $timezone_object );
132                         foreach( $timezone_formats as $timezone_format ) {
133                                 if ( false !== strpos( $dateformatstring, $timezone_format ) ) {
134                                         $formatted = date_format( $date_object, $timezone_format );
135                                         $dateformatstring = ' '.$dateformatstring;
136                                         $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring );
137                                         $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
138                                 }
139                         }
140                 }
141         }
142         $j = @$datefunc( $dateformatstring, $i );
143
144         /**
145          * Filter the date formatted based on the locale.
146          *
147          * @since 2.8.0
148          * 
149          * @param string $j          Formatted date string.
150          * @param string $req_format Format to display the date.
151          * @param int    $i          Unix timestamp.
152          * @param bool   $gmt        Whether to convert to GMT for time. Default false.
153          */
154         $j = apply_filters( 'date_i18n', $j, $req_format, $i, $gmt );
155         return $j;
156 }
157
158 /**
159  * Convert integer number to format based on the locale.
160  *
161  * @since 2.3.0
162  *
163  * @param int $number The number to convert based on locale.
164  * @param int $decimals Precision of the number of decimal places.
165  * @return string Converted number in string format.
166  */
167 function number_format_i18n( $number, $decimals = 0 ) {
168         global $wp_locale;
169         $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
170
171         /**
172          * Filter the number formatted based on the locale.
173          *
174          * @since  2.8.0
175          *
176          * @param string $formatted Converted number in string format.
177          */
178         return apply_filters( 'number_format_i18n', $formatted );
179 }
180
181 /**
182  * Convert number of bytes largest unit bytes will fit into.
183  *
184  * It is easier to read 1kB than 1024 bytes and 1MB than 1048576 bytes. Converts
185  * number of bytes to human readable number by taking the number of that unit
186  * that the bytes will go into it. Supports TB value.
187  *
188  * Please note that integers in PHP are limited to 32 bits, unless they are on
189  * 64 bit architecture, then they have 64 bit size. If you need to place the
190  * larger size then what PHP integer type will hold, then use a string. It will
191  * be converted to a double, which should always have 64 bit length.
192  *
193  * Technically the correct unit names for powers of 1024 are KiB, MiB etc.
194  * @link http://en.wikipedia.org/wiki/Byte
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 Precision of number of decimal places. Deprecated.
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 $start_of_week Optional. Start of the week as an integer.
225  * @return array Keys are 'start' and 'end'.
226  */
227 function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
228         $my = substr( $mysqlstring, 0, 4 ); // Mysql string Year
229         $mm = substr( $mysqlstring, 8, 2 ); // Mysql string Month
230         $md = substr( $mysqlstring, 5, 2 ); // Mysql string day
231         $day = mktime( 0, 0, 0, $md, $mm, $my ); // The timestamp for mysqlstring day.
232         $weekday = date( 'w', $day ); // The day of the week from the timestamp
233         if ( !is_numeric($start_of_week) )
234                 $start_of_week = get_option( 'start_of_week' );
235
236         if ( $weekday < $start_of_week )
237                 $weekday += 7;
238
239         $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week ); // The most recent week start day on or before $day
240         $end = $start + 7 * DAY_IN_SECONDS - 1; // $start + 7 days - 1 second
241         return compact( 'start', 'end' );
242 }
243
244 /**
245  * Unserialize value only if it was serialized.
246  *
247  * @since 2.0.0
248  *
249  * @param string $original Maybe unserialized original, if is needed.
250  * @return mixed Unserialized data can be any type.
251  */
252 function maybe_unserialize( $original ) {
253         if ( is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in
254                 return @unserialize( $original );
255         return $original;
256 }
257
258 /**
259  * Check value to find if it was serialized.
260  *
261  * If $data is not an string, then returned value will always be false.
262  * Serialized data is always a string.
263  *
264  * @since 2.0.5
265  *
266  * @param mixed $data Value to check to see if was serialized.
267  * @param bool $strict Optional. Whether to be strict about the end of the string. Defaults true.
268  * @return bool False if not serialized and true if it was.
269  */
270 function is_serialized( $data, $strict = true ) {
271         // if it isn't a string, it isn't serialized
272         if ( ! is_string( $data ) ) {
273                 return false;
274         }
275         $data = trim( $data );
276         if ( 'N;' == $data ) {
277                 return true;
278         }
279         if ( strlen( $data ) < 4 ) {
280                 return false;
281         }
282         if ( ':' !== $data[1] ) {
283                 return false;
284         }
285         if ( $strict ) {
286                 $lastc = substr( $data, -1 );
287                 if ( ';' !== $lastc && '}' !== $lastc ) {
288                         return false;
289                 }
290         } else {
291                 $semicolon = strpos( $data, ';' );
292                 $brace     = strpos( $data, '}' );
293                 // Either ; or } must exist.
294                 if ( false === $semicolon && false === $brace )
295                         return false;
296                 // But neither must be in the first X characters.
297                 if ( false !== $semicolon && $semicolon < 3 )
298                         return false;
299                 if ( false !== $brace && $brace < 4 )
300                         return false;
301         }
302         $token = $data[0];
303         switch ( $token ) {
304                 case 's' :
305                         if ( $strict ) {
306                                 if ( '"' !== substr( $data, -2, 1 ) ) {
307                                         return false;
308                                 }
309                         } elseif ( false === strpos( $data, '"' ) ) {
310                                 return false;
311                         }
312                         // or else fall through
313                 case 'a' :
314                 case 'O' :
315                         return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
316                 case 'b' :
317                 case 'i' :
318                 case 'd' :
319                         $end = $strict ? '$' : '';
320                         return (bool) preg_match( "/^{$token}:[0-9.E-]+;$end/", $data );
321         }
322         return false;
323 }
324
325 /**
326  * Check whether serialized data is of string type.
327  *
328  * @since 2.0.5
329  *
330  * @param mixed $data Serialized data
331  * @return bool False if not a serialized string, true if it is.
332  */
333 function is_serialized_string( $data ) {
334         // if it isn't a string, it isn't a serialized string
335         if ( ! is_string( $data ) ) {
336                 return false;
337         }
338         $data = trim( $data );
339         if ( strlen( $data ) < 4 ) {
340                 return false;
341         } elseif ( ':' !== $data[1] ) {
342                 return false;
343         } elseif ( ';' !== substr( $data, -1 ) ) {
344                 return false;
345         } elseif ( $data[0] !== 's' ) {
346                 return false;
347         } elseif ( '"' !== substr( $data, -2, 1 ) ) {
348                 return false;
349         } else {
350                 return true;
351         }
352 }
353
354 /**
355  * Serialize data, if needed.
356  *
357  * @since 2.0.5
358  *
359  * @param mixed $data Data that might be serialized.
360  * @return mixed A scalar data
361  */
362 function maybe_serialize( $data ) {
363         if ( is_array( $data ) || is_object( $data ) )
364                 return serialize( $data );
365
366         // Double serialization is required for backward compatibility.
367         // See http://core.trac.wordpress.org/ticket/12930
368         if ( is_serialized( $data, false ) )
369                 return serialize( $data );
370
371         return $data;
372 }
373
374 /**
375  * Retrieve post title from XMLRPC XML.
376  *
377  * If the title element is not part of the XML, then the default post title from
378  * the $post_default_title will be used instead.
379  *
380  * @since 0.71
381  *
382  * @global string $post_default_title Default XMLRPC post title.
383  *
384  * @param string $content XMLRPC XML Request content
385  * @return string Post title
386  */
387 function xmlrpc_getposttitle( $content ) {
388         global $post_default_title;
389         if ( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) ) {
390                 $post_title = $matchtitle[1];
391         } else {
392                 $post_title = $post_default_title;
393         }
394         return $post_title;
395 }
396
397 /**
398  * Retrieve the post category or categories from XMLRPC XML.
399  *
400  * If the category element is not found, then the default post category will be
401  * used. The return type then would be what $post_default_category. If the
402  * category is found, then it will always be an array.
403  *
404  * @since 0.71
405  *
406  * @global string $post_default_category Default XMLRPC post category.
407  *
408  * @param string $content XMLRPC XML Request content
409  * @return string|array List of categories or category name.
410  */
411 function xmlrpc_getpostcategory( $content ) {
412         global $post_default_category;
413         if ( preg_match( '/<category>(.+?)<\/category>/is', $content, $matchcat ) ) {
414                 $post_category = trim( $matchcat[1], ',' );
415                 $post_category = explode( ',', $post_category );
416         } else {
417                 $post_category = $post_default_category;
418         }
419         return $post_category;
420 }
421
422 /**
423  * XMLRPC XML content without title and category elements.
424  *
425  * @since 0.71
426  *
427  * @param string $content XMLRPC XML Request content
428  * @return string XMLRPC XML Request content without title and category elements.
429  */
430 function xmlrpc_removepostdata( $content ) {
431         $content = preg_replace( '/<title>(.+?)<\/title>/si', '', $content );
432         $content = preg_replace( '/<category>(.+?)<\/category>/si', '', $content );
433         $content = trim( $content );
434         return $content;
435 }
436
437 /**
438  * Use RegEx to extract URLs from arbitrary content
439  *
440  * @since 3.7.0
441  *
442  * @param string $content
443  * @return array URLs found in passed string
444  */
445 function wp_extract_urls( $content ) {
446         preg_match_all(
447                 "#((?:[\w-]+://?|[\w\d]+[.])[^\s()<>]+[.](?:\([\w\d]+\)|(?:[^`!()\[\]{};:'\".,<>?«»“”‘’\s]|(?:[:]\d+)?/?)+))#",
448                 $content,
449                 $post_links
450         );
451
452         $post_links = array_unique( array_map( 'html_entity_decode', $post_links[0] ) );
453
454         return array_values( $post_links );
455 }
456
457 /**
458  * Check content for video and audio links to add as enclosures.
459  *
460  * Will not add enclosures that have already been added and will
461  * remove enclosures that are no longer in the post. This is called as
462  * pingbacks and trackbacks.
463  *
464  * @since 1.5.0
465  *
466  * @uses $wpdb
467  *
468  * @param string $content Post Content
469  * @param int $post_ID Post ID
470  */
471 function do_enclose( $content, $post_ID ) {
472         global $wpdb;
473
474         //TODO: Tidy this ghetto code up and make the debug code optional
475         include_once( ABSPATH . WPINC . '/class-IXR.php' );
476
477         $post_links = array();
478
479         $pung = get_enclosed( $post_ID );
480
481         $post_links_temp = wp_extract_urls( $content );
482
483         foreach ( $pung as $link_test ) {
484                 if ( ! in_array( $link_test, $post_links_temp ) ) { // link no longer in post
485                         $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, like_escape( $link_test ) . '%') );
486                         foreach ( $mids as $mid )
487                                 delete_metadata_by_mid( 'post', $mid );
488                 }
489         }
490
491         foreach ( (array) $post_links_temp as $link_test ) {
492                 if ( !in_array( $link_test, $pung ) ) { // If we haven't pung it already
493                         $test = @parse_url( $link_test );
494                         if ( false === $test )
495                                 continue;
496                         if ( isset( $test['query'] ) )
497                                 $post_links[] = $link_test;
498                         elseif ( isset($test['path']) && ( $test['path'] != '/' ) &&  ($test['path'] != '' ) )
499                                 $post_links[] = $link_test;
500                 }
501         }
502
503         foreach ( (array) $post_links as $url ) {
504                 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, like_escape( $url ) . '%' ) ) ) {
505
506                         if ( $headers = wp_get_http_headers( $url) ) {
507                                 $len = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0;
508                                 $type = isset( $headers['content-type'] ) ? $headers['content-type'] : '';
509                                 $allowed_types = array( 'video', 'audio' );
510
511                                 // Check to see if we can figure out the mime type from
512                                 // the extension
513                                 $url_parts = @parse_url( $url );
514                                 if ( false !== $url_parts ) {
515                                         $extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION );
516                                         if ( !empty( $extension ) ) {
517                                                 foreach ( wp_get_mime_types() as $exts => $mime ) {
518                                                         if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
519                                                                 $type = $mime;
520                                                                 break;
521                                                         }
522                                                 }
523                                         }
524                                 }
525
526                                 if ( in_array( substr( $type, 0, strpos( $type, "/" ) ), $allowed_types ) ) {
527                                         add_post_meta( $post_ID, 'enclosure', "$url\n$len\n$mime\n" );
528                                 }
529                         }
530                 }
531         }
532 }
533
534 /**
535  * Perform a HTTP HEAD or GET request.
536  *
537  * If $file_path is a writable filename, this will do a GET request and write
538  * the file to that path.
539  *
540  * @since 2.5.0
541  *
542  * @param string $url URL to fetch.
543  * @param string|bool $file_path Optional. File path to write request to.
544  * @param int $red (private) The number of Redirects followed, Upon 5 being hit, returns false.
545  * @return bool|string False on failure and string of headers if HEAD request.
546  */
547 function wp_get_http( $url, $file_path = false, $red = 1 ) {
548         @set_time_limit( 60 );
549
550         if ( $red > 5 )
551                 return false;
552
553         $options = array();
554         $options['redirection'] = 5;
555
556         if ( false == $file_path )
557                 $options['method'] = 'HEAD';
558         else
559                 $options['method'] = 'GET';
560
561         $response = wp_safe_remote_request( $url, $options );
562
563         if ( is_wp_error( $response ) )
564                 return false;
565
566         $headers = wp_remote_retrieve_headers( $response );
567         $headers['response'] = wp_remote_retrieve_response_code( $response );
568
569         // WP_HTTP no longer follows redirects for HEAD requests.
570         if ( 'HEAD' == $options['method'] && in_array($headers['response'], array(301, 302)) && isset( $headers['location'] ) ) {
571                 return wp_get_http( $headers['location'], $file_path, ++$red );
572         }
573
574         if ( false == $file_path )
575                 return $headers;
576
577         // GET request - write it to the supplied filename
578         $out_fp = fopen($file_path, 'w');
579         if ( !$out_fp )
580                 return $headers;
581
582         fwrite( $out_fp,  wp_remote_retrieve_body( $response ) );
583         fclose($out_fp);
584         clearstatcache();
585
586         return $headers;
587 }
588
589 /**
590  * Retrieve HTTP Headers from URL.
591  *
592  * @since 1.5.1
593  *
594  * @param string $url
595  * @param bool $deprecated Not Used.
596  * @return bool|string False on failure, headers on success.
597  */
598 function wp_get_http_headers( $url, $deprecated = false ) {
599         if ( !empty( $deprecated ) )
600                 _deprecated_argument( __FUNCTION__, '2.7' );
601
602         $response = wp_safe_remote_head( $url );
603
604         if ( is_wp_error( $response ) )
605                 return false;
606
607         return wp_remote_retrieve_headers( $response );
608 }
609
610 /**
611  * Whether today is a new day.
612  *
613  * @since 0.71
614  * @uses $day Today
615  * @uses $previousday Previous day
616  *
617  * @return int 1 when new day, 0 if not a new day.
618  */
619 function is_new_day() {
620         global $currentday, $previousday;
621         if ( $currentday != $previousday )
622                 return 1;
623         else
624                 return 0;
625 }
626
627 /**
628  * Build URL query based on an associative and, or indexed array.
629  *
630  * This is a convenient function for easily building url queries. It sets the
631  * separator to '&' and uses _http_build_query() function.
632  *
633  * @see _http_build_query() Used to build the query
634  * @link http://us2.php.net/manual/en/function.http-build-query.php more on what
635  *              http_build_query() does.
636  *
637  * @since 2.3.0
638  *
639  * @param array $data URL-encode key/value pairs.
640  * @return string URL encoded string
641  */
642 function build_query( $data ) {
643         return _http_build_query( $data, null, '&', '', false );
644 }
645
646 // from php.net (modified by Mark Jaquith to behave like the native PHP5 function)
647 function _http_build_query($data, $prefix=null, $sep=null, $key='', $urlencode=true) {
648         $ret = array();
649
650         foreach ( (array) $data as $k => $v ) {
651                 if ( $urlencode)
652                         $k = urlencode($k);
653                 if ( is_int($k) && $prefix != null )
654                         $k = $prefix.$k;
655                 if ( !empty($key) )
656                         $k = $key . '%5B' . $k . '%5D';
657                 if ( $v === null )
658                         continue;
659                 elseif ( $v === FALSE )
660                         $v = '0';
661
662                 if ( is_array($v) || is_object($v) )
663                         array_push($ret,_http_build_query($v, '', $sep, $k, $urlencode));
664                 elseif ( $urlencode )
665                         array_push($ret, $k.'='.urlencode($v));
666                 else
667                         array_push($ret, $k.'='.$v);
668         }
669
670         if ( null === $sep )
671                 $sep = ini_get('arg_separator.output');
672
673         return implode($sep, $ret);
674 }
675
676 /**
677  * Retrieve a modified URL query string.
678  *
679  * You can rebuild the URL and append a new query variable to the URL query by
680  * using this function. You can also retrieve the full URL with query data.
681  *
682  * Adding a single key & value or an associative array. Setting a key value to
683  * an empty string removes the key. Omitting oldquery_or_uri uses the $_SERVER
684  * value. Additional values provided are expected to be encoded appropriately
685  * with urlencode() or rawurlencode().
686  *
687  * @since 1.5.0
688  *
689  * @param mixed $param1 Either newkey or an associative_array
690  * @param mixed $param2 Either newvalue or oldquery or uri
691  * @param mixed $param3 Optional. Old query or uri
692  * @return string New URL query string.
693  */
694 function add_query_arg() {
695         $ret = '';
696         $args = func_get_args();
697         if ( is_array( $args[0] ) ) {
698                 if ( count( $args ) < 2 || false === $args[1] )
699                         $uri = $_SERVER['REQUEST_URI'];
700                 else
701                         $uri = $args[1];
702         } else {
703                 if ( count( $args ) < 3 || false === $args[2] )
704                         $uri = $_SERVER['REQUEST_URI'];
705                 else
706                         $uri = $args[2];
707         }
708
709         if ( $frag = strstr( $uri, '#' ) )
710                 $uri = substr( $uri, 0, -strlen( $frag ) );
711         else
712                 $frag = '';
713
714         if ( 0 === stripos( $uri, 'http://' ) ) {
715                 $protocol = 'http://';
716                 $uri = substr( $uri, 7 );
717         } elseif ( 0 === stripos( $uri, 'https://' ) ) {
718                 $protocol = 'https://';
719                 $uri = substr( $uri, 8 );
720         } else {
721                 $protocol = '';
722         }
723
724         if ( strpos( $uri, '?' ) !== false ) {
725                 list( $base, $query ) = explode( '?', $uri, 2 );
726                 $base .= '?';
727         } elseif ( $protocol || strpos( $uri, '=' ) === false ) {
728                 $base = $uri . '?';
729                 $query = '';
730         } else {
731                 $base = '';
732                 $query = $uri;
733         }
734
735         wp_parse_str( $query, $qs );
736         $qs = urlencode_deep( $qs ); // this re-URL-encodes things that were already in the query string
737         if ( is_array( $args[0] ) ) {
738                 $kayvees = $args[0];
739                 $qs = array_merge( $qs, $kayvees );
740         } else {
741                 $qs[ $args[0] ] = $args[1];
742         }
743
744         foreach ( $qs as $k => $v ) {
745                 if ( $v === false )
746                         unset( $qs[$k] );
747         }
748
749         $ret = build_query( $qs );
750         $ret = trim( $ret, '?' );
751         $ret = preg_replace( '#=(&|$)#', '$1', $ret );
752         $ret = $protocol . $base . $ret . $frag;
753         $ret = rtrim( $ret, '?' );
754         return $ret;
755 }
756
757 /**
758  * Removes an item or list from the query string.
759  *
760  * @since 1.5.0
761  *
762  * @param string|array $key Query key or keys to remove.
763  * @param bool $query When false uses the $_SERVER value.
764  * @return string New URL query string.
765  */
766 function remove_query_arg( $key, $query=false ) {
767         if ( is_array( $key ) ) { // removing multiple keys
768                 foreach ( $key as $k )
769                         $query = add_query_arg( $k, false, $query );
770                 return $query;
771         }
772         return add_query_arg( $key, false, $query );
773 }
774
775 /**
776  * Walks the array while sanitizing the contents.
777  *
778  * @since 0.71
779  *
780  * @param array $array Array to walk while sanitizing contents.
781  * @return array Sanitized $array.
782  */
783 function add_magic_quotes( $array ) {
784         foreach ( (array) $array as $k => $v ) {
785                 if ( is_array( $v ) ) {
786                         $array[$k] = add_magic_quotes( $v );
787                 } else {
788                         $array[$k] = addslashes( $v );
789                 }
790         }
791         return $array;
792 }
793
794 /**
795  * HTTP request for URI to retrieve content.
796  *
797  * @since 1.5.1
798  * @uses wp_remote_get()
799  *
800  * @param string $uri URI/URL of web page to retrieve.
801  * @return bool|string HTTP content. False on failure.
802  */
803 function wp_remote_fopen( $uri ) {
804         $parsed_url = @parse_url( $uri );
805
806         if ( !$parsed_url || !is_array( $parsed_url ) )
807                 return false;
808
809         $options = array();
810         $options['timeout'] = 10;
811
812         $response = wp_safe_remote_get( $uri, $options );
813
814         if ( is_wp_error( $response ) )
815                 return false;
816
817         return wp_remote_retrieve_body( $response );
818 }
819
820 /**
821  * Set up the WordPress query.
822  *
823  * @since 2.0.0
824  *
825  * @param string $query_vars Default WP_Query arguments.
826  */
827 function wp( $query_vars = '' ) {
828         global $wp, $wp_query, $wp_the_query;
829         $wp->main( $query_vars );
830
831         if ( !isset($wp_the_query) )
832                 $wp_the_query = $wp_query;
833 }
834
835 /**
836  * Retrieve the description for the HTTP status.
837  *
838  * @since 2.3.0
839  *
840  * @param int $code HTTP status code.
841  * @return string Empty string if not found, or description if found.
842  */
843 function get_status_header_desc( $code ) {
844         global $wp_header_to_desc;
845
846         $code = absint( $code );
847
848         if ( !isset( $wp_header_to_desc ) ) {
849                 $wp_header_to_desc = array(
850                         100 => 'Continue',
851                         101 => 'Switching Protocols',
852                         102 => 'Processing',
853
854                         200 => 'OK',
855                         201 => 'Created',
856                         202 => 'Accepted',
857                         203 => 'Non-Authoritative Information',
858                         204 => 'No Content',
859                         205 => 'Reset Content',
860                         206 => 'Partial Content',
861                         207 => 'Multi-Status',
862                         226 => 'IM Used',
863
864                         300 => 'Multiple Choices',
865                         301 => 'Moved Permanently',
866                         302 => 'Found',
867                         303 => 'See Other',
868                         304 => 'Not Modified',
869                         305 => 'Use Proxy',
870                         306 => 'Reserved',
871                         307 => 'Temporary Redirect',
872
873                         400 => 'Bad Request',
874                         401 => 'Unauthorized',
875                         402 => 'Payment Required',
876                         403 => 'Forbidden',
877                         404 => 'Not Found',
878                         405 => 'Method Not Allowed',
879                         406 => 'Not Acceptable',
880                         407 => 'Proxy Authentication Required',
881                         408 => 'Request Timeout',
882                         409 => 'Conflict',
883                         410 => 'Gone',
884                         411 => 'Length Required',
885                         412 => 'Precondition Failed',
886                         413 => 'Request Entity Too Large',
887                         414 => 'Request-URI Too Long',
888                         415 => 'Unsupported Media Type',
889                         416 => 'Requested Range Not Satisfiable',
890                         417 => 'Expectation Failed',
891                         418 => 'I\'m a teapot',
892                         422 => 'Unprocessable Entity',
893                         423 => 'Locked',
894                         424 => 'Failed Dependency',
895                         426 => 'Upgrade Required',
896                         428 => 'Precondition Required',
897                         429 => 'Too Many Requests',
898                         431 => 'Request Header Fields Too Large',
899
900                         500 => 'Internal Server Error',
901                         501 => 'Not Implemented',
902                         502 => 'Bad Gateway',
903                         503 => 'Service Unavailable',
904                         504 => 'Gateway Timeout',
905                         505 => 'HTTP Version Not Supported',
906                         506 => 'Variant Also Negotiates',
907                         507 => 'Insufficient Storage',
908                         510 => 'Not Extended',
909                         511 => 'Network Authentication Required',
910                 );
911         }
912
913         if ( isset( $wp_header_to_desc[$code] ) )
914                 return $wp_header_to_desc[$code];
915         else
916                 return '';
917 }
918
919 /**
920  * Set HTTP status header.
921  *
922  * @since 2.0.0
923  * @see get_status_header_desc()
924  *
925  * @param int $code HTTP status code.
926  */
927 function status_header( $code ) {
928         $description = get_status_header_desc( $code );
929
930         if ( empty( $description ) )
931                 return;
932
933         $protocol = $_SERVER['SERVER_PROTOCOL'];
934         if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol )
935                 $protocol = 'HTTP/1.0';
936         $status_header = "$protocol $code $description";
937         if ( function_exists( 'apply_filters' ) )
938
939                 /**
940                  * Filter an HTTP status header.
941                  *
942                  * @since 2.2.0
943                  *
944                  * @param string $status_header HTTP status header.
945                  * @param int    $code          HTTP status code.
946                  * @param string $description   Description for the status code.
947                  * @param string $protocol      Server protocol.
948                  */
949                 $status_header = apply_filters( 'status_header', $status_header, $code, $description, $protocol );
950
951         @header( $status_header, true, $code );
952 }
953
954 /**
955  * Gets the header information to prevent caching.
956  *
957  * The several different headers cover the different ways cache prevention is handled
958  * by different browsers
959  *
960  * @since 2.8.0
961  *
962  * @return array The associative array of header names and field values.
963  */
964 function wp_get_nocache_headers() {
965         $headers = array(
966                 'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
967                 'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
968                 'Pragma' => 'no-cache',
969         );
970
971         if ( function_exists('apply_filters') ) {
972                 /**
973                  * Filter the cache-controlling headers.
974                  *
975                  * @since 2.8.0
976                  *
977                  * @param array $headers {
978                  *     Header names and field values.
979                  *
980                  *     @type string $Expires       Expires header.
981                  *     @type string $Cache-Control Cache-Control header.
982                  *     @type string $Pragma        Pragma header.
983                  * }
984                  */
985                 $headers = (array) apply_filters( 'nocache_headers', $headers );
986         }
987         $headers['Last-Modified'] = false;
988         return $headers;
989 }
990
991 /**
992  * Sets the headers to prevent caching for the different browsers.
993  *
994  * Different browsers support different nocache headers, so several headers must
995  * be sent so that all of them get the point that no caching should occur.
996  *
997  * @since 2.0.0
998  * @see wp_get_nocache_headers()
999  */
1000 function nocache_headers() {
1001         $headers = wp_get_nocache_headers();
1002
1003         unset( $headers['Last-Modified'] );
1004
1005         // In PHP 5.3+, make sure we are not sending a Last-Modified header.
1006         if ( function_exists( 'header_remove' ) ) {
1007                 @header_remove( 'Last-Modified' );
1008         } else {
1009                 // In PHP 5.2, send an empty Last-Modified header, but only as a
1010                 // last resort to override a header already sent. #WP23021
1011                 foreach ( headers_list() as $header ) {
1012                         if ( 0 === stripos( $header, 'Last-Modified' ) ) {
1013                                 $headers['Last-Modified'] = '';
1014                                 break;
1015                         }
1016                 }
1017         }
1018
1019         foreach( $headers as $name => $field_value )
1020                 @header("{$name}: {$field_value}");
1021 }
1022
1023 /**
1024  * Set the headers for caching for 10 days with JavaScript content type.
1025  *
1026  * @since 2.1.0
1027  */
1028 function cache_javascript_headers() {
1029         $expiresOffset = 10 * DAY_IN_SECONDS;
1030         header( "Content-Type: text/javascript; charset=" . get_bloginfo( 'charset' ) );
1031         header( "Vary: Accept-Encoding" ); // Handle proxies
1032         header( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $expiresOffset ) . " GMT" );
1033 }
1034
1035 /**
1036  * Retrieve the number of database queries during the WordPress execution.
1037  *
1038  * @since 2.0.0
1039  *
1040  * @return int Number of database queries
1041  */
1042 function get_num_queries() {
1043         global $wpdb;
1044         return $wpdb->num_queries;
1045 }
1046
1047 /**
1048  * Whether input is yes or no. Must be 'y' to be true.
1049  *
1050  * @since 1.0.0
1051  *
1052  * @param string $yn Character string containing either 'y' or 'n'
1053  * @return bool True if yes, false on anything else
1054  */
1055 function bool_from_yn( $yn ) {
1056         return ( strtolower( $yn ) == 'y' );
1057 }
1058
1059 /**
1060  * Loads the feed template from the use of an action hook.
1061  *
1062  * If the feed action does not have a hook, then the function will die with a
1063  * message telling the visitor that the feed is not valid.
1064  *
1065  * It is better to only have one hook for each feed.
1066  *
1067  * @since 2.1.0
1068  *
1069  * @uses $wp_query Used to tell if the use a comment feed.
1070  */
1071 function do_feed() {
1072         global $wp_query;
1073
1074         $feed = get_query_var( 'feed' );
1075
1076         // Remove the pad, if present.
1077         $feed = preg_replace( '/^_+/', '', $feed );
1078
1079         if ( $feed == '' || $feed == 'feed' )
1080                 $feed = get_default_feed();
1081
1082         $hook = 'do_feed_' . $feed;
1083         if ( ! has_action( $hook ) )
1084                 wp_die( __( 'ERROR: This is not a valid feed template.' ), '', array( 'response' => 404 ) );
1085
1086         /**
1087          * Fires once the given feed is loaded.
1088          *
1089          * The dynamic hook name, $hook, refers to the feed name.
1090          *
1091          * @since 2.1.0
1092          *
1093          * @param bool $is_comment_feed Whether the feed is a comment feed.
1094          */
1095         do_action( $hook, $wp_query->is_comment_feed );
1096 }
1097
1098 /**
1099  * Load the RDF RSS 0.91 Feed template.
1100  *
1101  * @since 2.1.0
1102  */
1103 function do_feed_rdf() {
1104         load_template( ABSPATH . WPINC . '/feed-rdf.php' );
1105 }
1106
1107 /**
1108  * Load the RSS 1.0 Feed Template.
1109  *
1110  * @since 2.1.0
1111  */
1112 function do_feed_rss() {
1113         load_template( ABSPATH . WPINC . '/feed-rss.php' );
1114 }
1115
1116 /**
1117  * Load either the RSS2 comment feed or the RSS2 posts feed.
1118  *
1119  * @since 2.1.0
1120  *
1121  * @param bool $for_comments True for the comment feed, false for normal feed.
1122  */
1123 function do_feed_rss2( $for_comments ) {
1124         if ( $for_comments )
1125                 load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' );
1126         else
1127                 load_template( ABSPATH . WPINC . '/feed-rss2.php' );
1128 }
1129
1130 /**
1131  * Load either Atom comment feed or Atom posts feed.
1132  *
1133  * @since 2.1.0
1134  *
1135  * @param bool $for_comments True for the comment feed, false for normal feed.
1136  */
1137 function do_feed_atom( $for_comments ) {
1138         if ($for_comments)
1139                 load_template( ABSPATH . WPINC . '/feed-atom-comments.php');
1140         else
1141                 load_template( ABSPATH . WPINC . '/feed-atom.php' );
1142 }
1143
1144 /**
1145  * Display the robots.txt file content.
1146  *
1147  * The echo content should be with usage of the permalinks or for creating the
1148  * robots.txt file.
1149  *
1150  * @since 2.1.0
1151  */
1152 function do_robots() {
1153         header( 'Content-Type: text/plain; charset=utf-8' );
1154
1155         /**
1156          * Fires when displaying the robots.txt file.
1157          *
1158          * @since 2.1.0
1159          */
1160         do_action( 'do_robotstxt' );
1161
1162         $output = "User-agent: *\n";
1163         $public = get_option( 'blog_public' );
1164         if ( '0' == $public ) {
1165                 $output .= "Disallow: /\n";
1166         } else {
1167                 $site_url = parse_url( site_url() );
1168                 $path = ( !empty( $site_url['path'] ) ) ? $site_url['path'] : '';
1169                 $output .= "Disallow: $path/wp-admin/\n";
1170                 $output .= "Disallow: $path/wp-includes/\n";
1171         }
1172
1173         /**
1174          * Filter the robots.txt output.
1175          *
1176          * @since 3.0.0
1177          *
1178          * @param string $output Robots.txt output.
1179          * @param bool   $public Whether the site is considered "public".
1180          */
1181         echo apply_filters( 'robots_txt', $output, $public );
1182 }
1183
1184 /**
1185  * Test whether blog is already installed.
1186  *
1187  * The cache will be checked first. If you have a cache plugin, which saves the
1188  * cache values, then this will work. If you use the default WordPress cache,
1189  * and the database goes away, then you might have problems.
1190  *
1191  * Checks for the option siteurl for whether WordPress is installed.
1192  *
1193  * @since 2.1.0
1194  * @uses $wpdb
1195  *
1196  * @return bool Whether blog is already installed.
1197  */
1198 function is_blog_installed() {
1199         global $wpdb;
1200
1201         // Check cache first. If options table goes away and we have true cached, oh well.
1202         if ( wp_cache_get( 'is_blog_installed' ) )
1203                 return true;
1204
1205         $suppress = $wpdb->suppress_errors();
1206         if ( ! defined( 'WP_INSTALLING' ) ) {
1207                 $alloptions = wp_load_alloptions();
1208         }
1209         // If siteurl is not set to autoload, check it specifically
1210         if ( !isset( $alloptions['siteurl'] ) )
1211                 $installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" );
1212         else
1213                 $installed = $alloptions['siteurl'];
1214         $wpdb->suppress_errors( $suppress );
1215
1216         $installed = !empty( $installed );
1217         wp_cache_set( 'is_blog_installed', $installed );
1218
1219         if ( $installed )
1220                 return true;
1221
1222         // If visiting repair.php, return true and let it take over.
1223         if ( defined( 'WP_REPAIRING' ) )
1224                 return true;
1225
1226         $suppress = $wpdb->suppress_errors();
1227
1228         // Loop over the WP tables. If none exist, then scratch install is allowed.
1229         // If one or more exist, suggest table repair since we got here because the options
1230         // table could not be accessed.
1231         $wp_tables = $wpdb->tables();
1232         foreach ( $wp_tables as $table ) {
1233                 // The existence of custom user tables shouldn't suggest an insane state or prevent a clean install.
1234                 if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table )
1235                         continue;
1236                 if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE == $table )
1237                         continue;
1238
1239                 if ( ! $wpdb->get_results( "DESCRIBE $table;" ) )
1240                         continue;
1241
1242                 // One or more tables exist. We are insane.
1243
1244                 wp_load_translations_early();
1245
1246                 // Die with a DB error.
1247                 $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' );
1248                 dead_db();
1249         }
1250
1251         $wpdb->suppress_errors( $suppress );
1252
1253         wp_cache_set( 'is_blog_installed', false );
1254
1255         return false;
1256 }
1257
1258 /**
1259  * Retrieve URL with nonce added to URL query.
1260  *
1261  * @since 2.0.4
1262  *
1263  * @param string $actionurl URL to add nonce action.
1264  * @param string $action Optional. Nonce action name.
1265  * @param string $name Optional. Nonce name.
1266  * @return string Escaped URL with nonce action added.
1267  */
1268 function wp_nonce_url( $actionurl, $action = -1, $name = '_wpnonce' ) {
1269         $actionurl = str_replace( '&amp;', '&', $actionurl );
1270         return esc_html( add_query_arg( $name, wp_create_nonce( $action ), $actionurl ) );
1271 }
1272
1273 /**
1274  * Retrieve or display nonce hidden field for forms.
1275  *
1276  * The nonce field is used to validate that the contents of the form came from
1277  * the location on the current site and not somewhere else. The nonce does not
1278  * offer absolute protection, but should protect against most cases. It is very
1279  * important to use nonce field in forms.
1280  *
1281  * The $action and $name are optional, but if you want to have better security,
1282  * it is strongly suggested to set those two parameters. It is easier to just
1283  * call the function without any parameters, because validation of the nonce
1284  * doesn't require any parameters, but since crackers know what the default is
1285  * it won't be difficult for them to find a way around your nonce and cause
1286  * damage.
1287  *
1288  * The input name will be whatever $name value you gave. The input value will be
1289  * the nonce creation value.
1290  *
1291  * @since 2.0.4
1292  *
1293  * @param string $action Optional. Action name.
1294  * @param string $name Optional. Nonce name.
1295  * @param bool $referer Optional, default true. Whether to set the referer field for validation.
1296  * @param bool $echo Optional, default true. Whether to display or return hidden form field.
1297  * @return string Nonce field.
1298  */
1299 function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true , $echo = true ) {
1300         $name = esc_attr( $name );
1301         $nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />';
1302
1303         if ( $referer )
1304                 $nonce_field .= wp_referer_field( false );
1305
1306         if ( $echo )
1307                 echo $nonce_field;
1308
1309         return $nonce_field;
1310 }
1311
1312 /**
1313  * Retrieve or display referer hidden field for forms.
1314  *
1315  * The referer link is the current Request URI from the server super global. The
1316  * input name is '_wp_http_referer', in case you wanted to check manually.
1317  *
1318  * @since 2.0.4
1319  *
1320  * @param bool $echo Whether to echo or return the referer field.
1321  * @return string Referer field.
1322  */
1323 function wp_referer_field( $echo = true ) {
1324         $referer_field = '<input type="hidden" name="_wp_http_referer" value="'. esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
1325
1326         if ( $echo )
1327                 echo $referer_field;
1328         return $referer_field;
1329 }
1330
1331 /**
1332  * Retrieve or display original referer hidden field for forms.
1333  *
1334  * The input name is '_wp_original_http_referer' and will be either the same
1335  * value of {@link wp_referer_field()}, if that was posted already or it will
1336  * be the current page, if it doesn't exist.
1337  *
1338  * @since 2.0.4
1339  *
1340  * @param bool $echo Whether to echo the original http referer
1341  * @param string $jump_back_to Optional, default is 'current'. Can be 'previous' or page you want to jump back to.
1342  * @return string Original referer field.
1343  */
1344 function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) {
1345         if ( ! $ref = wp_get_original_referer() ) {
1346                 $ref = 'previous' == $jump_back_to ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] );
1347         }
1348         $orig_referer_field = '<input type="hidden" name="_wp_original_http_referer" value="' . esc_attr( $ref ) . '" />';
1349         if ( $echo )
1350                 echo $orig_referer_field;
1351         return $orig_referer_field;
1352 }
1353
1354 /**
1355  * Retrieve referer from '_wp_http_referer' or HTTP referer. If it's the same
1356  * as the current request URL, will return false.
1357  *
1358  * @since 2.0.4
1359  *
1360  * @return string|bool False on failure. Referer URL on success.
1361  */
1362 function wp_get_referer() {
1363         if ( ! function_exists( 'wp_validate_redirect' ) )
1364                 return false;
1365         $ref = false;
1366         if ( ! empty( $_REQUEST['_wp_http_referer'] ) )
1367                 $ref = wp_unslash( $_REQUEST['_wp_http_referer'] );
1368         else if ( ! empty( $_SERVER['HTTP_REFERER'] ) )
1369                 $ref = wp_unslash( $_SERVER['HTTP_REFERER'] );
1370
1371         if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) )
1372                 return wp_validate_redirect( $ref, false );
1373         return false;
1374 }
1375
1376 /**
1377  * Retrieve original referer that was posted, if it exists.
1378  *
1379  * @since 2.0.4
1380  *
1381  * @return string|bool False if no original referer or original referer if set.
1382  */
1383 function wp_get_original_referer() {
1384         if ( ! empty( $_REQUEST['_wp_original_http_referer'] ) && function_exists( 'wp_validate_redirect' ) )
1385                 return wp_validate_redirect( wp_unslash( $_REQUEST['_wp_original_http_referer'] ), false );
1386         return false;
1387 }
1388
1389 /**
1390  * Recursive directory creation based on full path.
1391  *
1392  * Will attempt to set permissions on folders.
1393  *
1394  * @since 2.0.1
1395  *
1396  * @param string $target Full path to attempt to create.
1397  * @return bool Whether the path was created. True if path already exists.
1398  */
1399 function wp_mkdir_p( $target ) {
1400         $wrapper = null;
1401
1402         // strip the protocol
1403         if( wp_is_stream( $target ) ) {
1404                 list( $wrapper, $target ) = explode( '://', $target, 2 );
1405         }
1406
1407         // from php.net/mkdir user contributed notes
1408         $target = str_replace( '//', '/', $target );
1409
1410         // put the wrapper back on the target
1411         if( $wrapper !== null ) {
1412                 $target = $wrapper . '://' . $target;
1413         }
1414
1415         // safe mode fails with a trailing slash under certain PHP versions.
1416         $target = rtrim($target, '/'); // Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
1417         if ( empty($target) )
1418                 $target = '/';
1419
1420         if ( file_exists( $target ) )
1421                 return @is_dir( $target );
1422
1423         // We need to find the permissions of the parent folder that exists and inherit that.
1424         $target_parent = dirname( $target );
1425         while ( '.' != $target_parent && ! is_dir( $target_parent ) ) {
1426                 $target_parent = dirname( $target_parent );
1427         }
1428
1429         // Get the permission bits.
1430         $dir_perms = false;
1431         if ( $stat = @stat( $target_parent ) ) {
1432                 $dir_perms = $stat['mode'] & 0007777;
1433         } else {
1434                 $dir_perms = 0777;
1435         }
1436
1437         if ( @mkdir( $target, $dir_perms, true ) ) {
1438
1439                 // If a umask is set that modifies $dir_perms, we'll have to re-set the $dir_perms correctly with chmod()
1440                 if ( $dir_perms != ( $dir_perms & ~umask() ) ) {
1441                         $folder_parts = explode( '/', substr( $target, strlen( $target_parent ) + 1 ) );
1442                         for ( $i = 1; $i <= count( $folder_parts ); $i++ ) {
1443                                 @chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms );
1444                         }
1445                 }
1446
1447                 return true;
1448         }
1449
1450         return false;
1451 }
1452
1453 /**
1454  * Test if a give filesystem path is absolute ('/foo/bar', 'c:\windows').
1455  *
1456  * @since 2.5.0
1457  *
1458  * @param string $path File path
1459  * @return bool True if path is absolute, false is not absolute.
1460  */
1461 function path_is_absolute( $path ) {
1462         // this is definitive if true but fails if $path does not exist or contains a symbolic link
1463         if ( realpath($path) == $path )
1464                 return true;
1465
1466         if ( strlen($path) == 0 || $path[0] == '.' )
1467                 return false;
1468
1469         // windows allows absolute paths like this
1470         if ( preg_match('#^[a-zA-Z]:\\\\#', $path) )
1471                 return true;
1472
1473         // a path starting with / or \ is absolute; anything else is relative
1474         return ( $path[0] == '/' || $path[0] == '\\' );
1475 }
1476
1477 /**
1478  * Join two filesystem paths together (e.g. 'give me $path relative to $base').
1479  *
1480  * If the $path is absolute, then it the full path is returned.
1481  *
1482  * @since 2.5.0
1483  *
1484  * @param string $base
1485  * @param string $path
1486  * @return string The path with the base or absolute path.
1487  */
1488 function path_join( $base, $path ) {
1489         if ( path_is_absolute($path) )
1490                 return $path;
1491
1492         return rtrim($base, '/') . '/' . ltrim($path, '/');
1493 }
1494
1495 /**
1496  * Normalize a filesystem path.
1497  *
1498  * Replaces backslashes with forward slashes for Windows systems,
1499  * and ensures no duplicate slashes exist.
1500  *
1501  * @since 3.9.0
1502  *
1503  * @param string $path Path to normalize.
1504  * @return string Normalized path.
1505  */
1506 function wp_normalize_path( $path ) {
1507         $path = str_replace( '\\', '/', $path );
1508         $path = preg_replace( '|/+|','/', $path );
1509         return $path;
1510 }
1511
1512 /**
1513  * Determines a writable directory for temporary files.
1514  * Function's preference is the return value of <code>sys_get_temp_dir()</code>,
1515  * followed by your PHP temporary upload directory, followed by WP_CONTENT_DIR,
1516  * before finally defaulting to /tmp/
1517  *
1518  * In the event that this function does not find a writable location,
1519  * It may be overridden by the <code>WP_TEMP_DIR</code> constant in
1520  * your <code>wp-config.php</code> file.
1521  *
1522  * @since 2.5.0
1523  *
1524  * @return string Writable temporary directory
1525  */
1526 function get_temp_dir() {
1527         static $temp;
1528         if ( defined('WP_TEMP_DIR') )
1529                 return trailingslashit(WP_TEMP_DIR);
1530
1531         if ( $temp )
1532                 return trailingslashit( $temp );
1533
1534         if ( function_exists('sys_get_temp_dir') ) {
1535                 $temp = sys_get_temp_dir();
1536                 if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
1537                         return trailingslashit( $temp );
1538         }
1539
1540         $temp = ini_get('upload_tmp_dir');
1541         if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
1542                 return trailingslashit( $temp );
1543
1544         $temp = WP_CONTENT_DIR . '/';
1545         if ( is_dir( $temp ) && wp_is_writable( $temp ) )
1546                 return $temp;
1547
1548         $temp = '/tmp/';
1549         return $temp;
1550 }
1551
1552 /**
1553  * Determine if a directory is writable.
1554  *
1555  * This function is used to work around certain ACL issues
1556  * in PHP primarily affecting Windows Servers.
1557  *
1558  * @see win_is_writable()
1559  *
1560  * @since 3.6.0
1561  *
1562  * @param string $path
1563  * @return bool
1564  */
1565 function wp_is_writable( $path ) {
1566         if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) )
1567                 return win_is_writable( $path );
1568         else
1569                 return @is_writable( $path );
1570 }
1571
1572 /**
1573  * Workaround for Windows bug in is_writable() function
1574  *
1575  * PHP has issues with Windows ACL's for determine if a
1576  * directory is writable or not, this works around them by
1577  * checking the ability to open files rather than relying
1578  * upon PHP to interprate the OS ACL.
1579  *
1580  * @link http://bugs.php.net/bug.php?id=27609
1581  * @link http://bugs.php.net/bug.php?id=30931
1582  *
1583  * @since 2.8.0
1584  *
1585  * @param string $path
1586  * @return bool
1587  */
1588 function win_is_writable( $path ) {
1589
1590         if ( $path[strlen( $path ) - 1] == '/' ) // if it looks like a directory, check a random file within the directory
1591                 return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp');
1592         else if ( is_dir( $path ) ) // If it's a directory (and not a file) check a random file within the directory
1593                 return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' );
1594
1595         // check tmp file for read/write capabilities
1596         $should_delete_tmp_file = !file_exists( $path );
1597         $f = @fopen( $path, 'a' );
1598         if ( $f === false )
1599                 return false;
1600         fclose( $f );
1601         if ( $should_delete_tmp_file )
1602                 unlink( $path );
1603         return true;
1604 }
1605
1606 /**
1607  * Get an array containing the current upload directory's path and url.
1608  *
1609  * Checks the 'upload_path' option, which should be from the web root folder,
1610  * and if it isn't empty it will be used. If it is empty, then the path will be
1611  * 'WP_CONTENT_DIR/uploads'. If the 'UPLOADS' constant is defined, then it will
1612  * override the 'upload_path' option and 'WP_CONTENT_DIR/uploads' path.
1613  *
1614  * The upload URL path is set either by the 'upload_url_path' option or by using
1615  * the 'WP_CONTENT_URL' constant and appending '/uploads' to the path.
1616  *
1617  * If the 'uploads_use_yearmonth_folders' is set to true (checkbox if checked in
1618  * the administration settings panel), then the time will be used. The format
1619  * will be year first and then month.
1620  *
1621  * If the path couldn't be created, then an error will be returned with the key
1622  * 'error' containing the error message. The error suggests that the parent
1623  * directory is not writable by the server.
1624  *
1625  * On success, the returned array will have many indices:
1626  * 'path' - base directory and sub directory or full path to upload directory.
1627  * 'url' - base url and sub directory or absolute URL to upload directory.
1628  * 'subdir' - sub directory if uploads use year/month folders option is on.
1629  * 'basedir' - path without subdir.
1630  * 'baseurl' - URL path without subdir.
1631  * 'error' - set to false.
1632  *
1633  * @since 2.0.0
1634  *
1635  * @param string $time Optional. Time formatted in 'yyyy/mm'.
1636  * @return array See above for description.
1637  */
1638 function wp_upload_dir( $time = null ) {
1639         $siteurl = get_option( 'siteurl' );
1640         $upload_path = trim( get_option( 'upload_path' ) );
1641
1642         if ( empty( $upload_path ) || 'wp-content/uploads' == $upload_path ) {
1643                 $dir = WP_CONTENT_DIR . '/uploads';
1644         } elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) {
1645                 // $dir is absolute, $upload_path is (maybe) relative to ABSPATH
1646                 $dir = path_join( ABSPATH, $upload_path );
1647         } else {
1648                 $dir = $upload_path;
1649         }
1650
1651         if ( !$url = get_option( 'upload_url_path' ) ) {
1652                 if ( empty($upload_path) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) )
1653                         $url = WP_CONTENT_URL . '/uploads';
1654                 else
1655                         $url = trailingslashit( $siteurl ) . $upload_path;
1656         }
1657
1658         // Obey the value of UPLOADS. This happens as long as ms-files rewriting is disabled.
1659         // We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
1660         if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
1661                 $dir = ABSPATH . UPLOADS;
1662                 $url = trailingslashit( $siteurl ) . UPLOADS;
1663         }
1664
1665         // If multisite (and if not the main site in a post-MU network)
1666         if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) {
1667
1668                 if ( ! get_site_option( 'ms_files_rewriting' ) ) {
1669                         // If ms-files rewriting is disabled (networks created post-3.5), it is fairly straightforward:
1670                         // Append sites/%d if we're not on the main site (for post-MU networks). (The extra directory
1671                         // prevents a four-digit ID from conflicting with a year-based directory for the main site.
1672                         // But if a MU-era network has disabled ms-files rewriting manually, they don't need the extra
1673                         // directory, as they never had wp-content/uploads for the main site.)
1674
1675                         if ( defined( 'MULTISITE' ) )
1676                                 $ms_dir = '/sites/' . get_current_blog_id();
1677                         else
1678                                 $ms_dir = '/' . get_current_blog_id();
1679
1680                         $dir .= $ms_dir;
1681                         $url .= $ms_dir;
1682
1683                 } elseif ( defined( 'UPLOADS' ) && ! ms_is_switched() ) {
1684                         // Handle the old-form ms-files.php rewriting if the network still has that enabled.
1685                         // When ms-files rewriting is enabled, then we only listen to UPLOADS when:
1686                         //   1) we are not on the main site in a post-MU network,
1687                         //      as wp-content/uploads is used there, and
1688                         //   2) we are not switched, as ms_upload_constants() hardcodes
1689                         //      these constants to reflect the original blog ID.
1690                         //
1691                         // Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute.
1692                         // (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as
1693                         // as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files
1694                         // rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
1695
1696                         if ( defined( 'BLOGUPLOADDIR' ) )
1697                                 $dir = untrailingslashit( BLOGUPLOADDIR );
1698                         else
1699                                 $dir = ABSPATH . UPLOADS;
1700                         $url = trailingslashit( $siteurl ) . 'files';
1701                 }
1702         }
1703
1704         $basedir = $dir;
1705         $baseurl = $url;
1706
1707         $subdir = '';
1708         if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
1709                 // Generate the yearly and monthly dirs
1710                 if ( !$time )
1711                         $time = current_time( 'mysql' );
1712                 $y = substr( $time, 0, 4 );
1713                 $m = substr( $time, 5, 2 );
1714                 $subdir = "/$y/$m";
1715         }
1716
1717         $dir .= $subdir;
1718         $url .= $subdir;
1719
1720         /**
1721          * Filter the uploads directory data.
1722          *
1723          * @since 2.0.0
1724          *
1725          * @param array $uploads Array of upload directory data with keys of 'path',
1726          *                       'url', 'subdir, 'basedir', and 'error'.
1727          */
1728         $uploads = apply_filters( 'upload_dir',
1729                 array(
1730                         'path'    => $dir,
1731                         'url'     => $url,
1732                         'subdir'  => $subdir,
1733                         'basedir' => $basedir,
1734                         'baseurl' => $baseurl,
1735                         'error'   => false,
1736                 ) );
1737
1738         // Make sure we have an uploads dir
1739         if ( ! wp_mkdir_p( $uploads['path'] ) ) {
1740                 if ( 0 === strpos( $uploads['basedir'], ABSPATH ) )
1741                         $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
1742                 else
1743                         $error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
1744
1745                 $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
1746                 $uploads['error'] = $message;
1747         }
1748
1749         return $uploads;
1750 }
1751
1752 /**
1753  * Get a filename that is sanitized and unique for the given directory.
1754  *
1755  * If the filename is not unique, then a number will be added to the filename
1756  * before the extension, and will continue adding numbers until the filename is
1757  * unique.
1758  *
1759  * The callback is passed three parameters, the first one is the directory, the
1760  * second is the filename, and the third is the extension.
1761  *
1762  * @since 2.5.0
1763  *
1764  * @param string $dir
1765  * @param string $filename
1766  * @param mixed $unique_filename_callback Callback.
1767  * @return string New filename, if given wasn't unique.
1768  */
1769 function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) {
1770         // sanitize the file name before we begin processing
1771         $filename = sanitize_file_name($filename);
1772
1773         // separate the filename into a name and extension
1774         $info = pathinfo($filename);
1775         $ext = !empty($info['extension']) ? '.' . $info['extension'] : '';
1776         $name = basename($filename, $ext);
1777
1778         // edge case: if file is named '.ext', treat as an empty name
1779         if ( $name === $ext )
1780                 $name = '';
1781
1782         // Increment the file number until we have a unique file to save in $dir. Use callback if supplied.
1783         if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) {
1784                 $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext );
1785         } else {
1786                 $number = '';
1787
1788                 // change '.ext' to lower case
1789                 if ( $ext && strtolower($ext) != $ext ) {
1790                         $ext2 = strtolower($ext);
1791                         $filename2 = preg_replace( '|' . preg_quote($ext) . '$|', $ext2, $filename );
1792
1793                         // check for both lower and upper case extension or image sub-sizes may be overwritten
1794                         while ( file_exists($dir . "/$filename") || file_exists($dir . "/$filename2") ) {
1795                                 $new_number = $number + 1;
1796                                 $filename = str_replace( "$number$ext", "$new_number$ext", $filename );
1797                                 $filename2 = str_replace( "$number$ext2", "$new_number$ext2", $filename2 );
1798                                 $number = $new_number;
1799                         }
1800                         return $filename2;
1801                 }
1802
1803                 while ( file_exists( $dir . "/$filename" ) ) {
1804                         if ( '' == "$number$ext" )
1805                                 $filename = $filename . ++$number . $ext;
1806                         else
1807                                 $filename = str_replace( "$number$ext", ++$number . $ext, $filename );
1808                 }
1809         }
1810
1811         return $filename;
1812 }
1813
1814 /**
1815  * Create a file in the upload folder with given content.
1816  *
1817  * If there is an error, then the key 'error' will exist with the error message.
1818  * If success, then the key 'file' will have the unique file path, the 'url' key
1819  * will have the link to the new file. and the 'error' key will be set to false.
1820  *
1821  * This function will not move an uploaded file to the upload folder. It will
1822  * create a new file with the content in $bits parameter. If you move the upload
1823  * file, read the content of the uploaded file, and then you can give the
1824  * filename and content to this function, which will add it to the upload
1825  * folder.
1826  *
1827  * The permissions will be set on the new file automatically by this function.
1828  *
1829  * @since 2.0.0
1830  *
1831  * @param string $name
1832  * @param null $deprecated Never used. Set to null.
1833  * @param mixed $bits File content
1834  * @param string $time Optional. Time formatted in 'yyyy/mm'.
1835  * @return array
1836  */
1837 function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
1838         if ( !empty( $deprecated ) )
1839                 _deprecated_argument( __FUNCTION__, '2.0' );
1840
1841         if ( empty( $name ) )
1842                 return array( 'error' => __( 'Empty filename' ) );
1843
1844         $wp_filetype = wp_check_filetype( $name );
1845         if ( ! $wp_filetype['ext'] && ! current_user_can( 'unfiltered_upload' ) )
1846                 return array( 'error' => __( 'Invalid file type' ) );
1847
1848         $upload = wp_upload_dir( $time );
1849
1850         if ( $upload['error'] !== false )
1851                 return $upload;
1852
1853         /**
1854          * Filter whether to treat the upload bits as an error.
1855          *
1856          * Passing a non-array to the filter will effectively short-circuit preparing
1857          * the upload bits, returning that value instead.
1858          *
1859          * @since 3.0.0
1860          *
1861          * @param mixed $upload_bits_error An array of upload bits data, or a non-array error to return.
1862          */
1863         $upload_bits_error = apply_filters( 'wp_upload_bits', array( 'name' => $name, 'bits' => $bits, 'time' => $time ) );
1864         if ( !is_array( $upload_bits_error ) ) {
1865                 $upload[ 'error' ] = $upload_bits_error;
1866                 return $upload;
1867         }
1868
1869         $filename = wp_unique_filename( $upload['path'], $name );
1870
1871         $new_file = $upload['path'] . "/$filename";
1872         if ( ! wp_mkdir_p( dirname( $new_file ) ) ) {
1873                 if ( 0 === strpos( $upload['basedir'], ABSPATH ) )
1874                         $error_path = str_replace( ABSPATH, '', $upload['basedir'] ) . $upload['subdir'];
1875                 else
1876                         $error_path = basename( $upload['basedir'] ) . $upload['subdir'];
1877
1878                 $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
1879                 return array( 'error' => $message );
1880         }
1881
1882         $ifp = @ fopen( $new_file, 'wb' );
1883         if ( ! $ifp )
1884                 return array( 'error' => sprintf( __( 'Could not write file %s' ), $new_file ) );
1885
1886         @fwrite( $ifp, $bits );
1887         fclose( $ifp );
1888         clearstatcache();
1889
1890         // Set correct file permissions
1891         $stat = @ stat( dirname( $new_file ) );
1892         $perms = $stat['mode'] & 0007777;
1893         $perms = $perms & 0000666;
1894         @ chmod( $new_file, $perms );
1895         clearstatcache();
1896
1897         // Compute the URL
1898         $url = $upload['url'] . "/$filename";
1899
1900         return array( 'file' => $new_file, 'url' => $url, 'error' => false );
1901 }
1902
1903 /**
1904  * Retrieve the file type based on the extension name.
1905  *
1906  * @since 2.5.0
1907  *
1908  * @param string $ext The extension to search.
1909  * @return string|null The file type, example: audio, video, document, spreadsheet, etc.
1910  *                     Null if not found.
1911  */
1912 function wp_ext2type( $ext ) {
1913         $ext = strtolower( $ext );
1914
1915         /**
1916          * Filter file type based on the extension name.
1917          *
1918          * @since 2.5.0
1919          *
1920          * @see wp_ext2type()
1921          *
1922          * @param array $ext2type Multi-dimensional array with extensions for a default set
1923          *                        of file types.
1924          */
1925         $ext2type = apply_filters( 'ext2type', array(
1926                 'image'       => array( 'jpg', 'jpeg', 'jpe',  'gif',  'png',  'bmp',   'tif',  'tiff', 'ico' ),
1927                 'audio'       => array( 'aac', 'ac3',  'aif',  'aiff', 'm3a',  'm4a',   'm4b',  'mka',  'mp1',  'mp2',  'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
1928                 'video'       => array( 'asf', 'avi',  'divx', 'dv',   'flv',  'm4v',   'mkv',  'mov',  'mp4',  'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt',  'rm', 'vob', 'wmv' ),
1929                 'document'    => array( 'doc', 'docx', 'docm', 'dotm', 'odt',  'pages', 'pdf',  'rtf',  'wp',   'wpd' ),
1930                 'spreadsheet' => array( 'numbers',     'ods',  'xls',  'xlsx', 'xlsm',  'xlsb' ),
1931                 'interactive' => array( 'swf', 'key',  'ppt',  'pptx', 'pptm', 'pps',   'ppsx', 'ppsm', 'sldx', 'sldm', 'odp' ),
1932                 'text'        => array( 'asc', 'csv',  'tsv',  'txt' ),
1933                 'archive'     => array( 'bz2', 'cab',  'dmg',  'gz',   'rar',  'sea',   'sit',  'sqx',  'tar',  'tgz',  'zip', '7z' ),
1934                 'code'        => array( 'css', 'htm',  'html', 'php',  'js' ),
1935         ) );
1936
1937         foreach ( $ext2type as $type => $exts )
1938                 if ( in_array( $ext, $exts ) )
1939                         return $type;
1940
1941         return null;
1942 }
1943
1944 /**
1945  * Retrieve the file type from the file name.
1946  *
1947  * You can optionally define the mime array, if needed.
1948  *
1949  * @since 2.0.4
1950  *
1951  * @param string $filename File name or path.
1952  * @param array $mimes Optional. Key is the file extension with value as the mime type.
1953  * @return array Values with extension first and mime type.
1954  */
1955 function wp_check_filetype( $filename, $mimes = null ) {
1956         if ( empty($mimes) )
1957                 $mimes = get_allowed_mime_types();
1958         $type = false;
1959         $ext = false;
1960
1961         foreach ( $mimes as $ext_preg => $mime_match ) {
1962                 $ext_preg = '!\.(' . $ext_preg . ')$!i';
1963                 if ( preg_match( $ext_preg, $filename, $ext_matches ) ) {
1964                         $type = $mime_match;
1965                         $ext = $ext_matches[1];
1966                         break;
1967                 }
1968         }
1969
1970         return compact( 'ext', 'type' );
1971 }
1972
1973 /**
1974  * Attempt to determine the real file type of a file.
1975  * If unable to, the file name extension will be used to determine type.
1976  *
1977  * If it's determined that the extension does not match the file's real type,
1978  * then the "proper_filename" value will be set with a proper filename and extension.
1979  *
1980  * Currently this function only supports validating images known to getimagesize().
1981  *
1982  * @since 3.0.0
1983  *
1984  * @param string $file Full path to the file.
1985  * @param string $filename The name of the file (may differ from $file due to $file being in a tmp directory)
1986  * @param array $mimes Optional. Key is the file extension with value as the mime type.
1987  * @return array Values for the extension, MIME, and either a corrected filename or false if original $filename is valid
1988  */
1989 function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
1990
1991         $proper_filename = false;
1992
1993         // Do basic extension validation and MIME mapping
1994         $wp_filetype = wp_check_filetype( $filename, $mimes );
1995         extract( $wp_filetype );
1996
1997         // We can't do any further validation without a file to work with
1998         if ( ! file_exists( $file ) )
1999                 return compact( 'ext', 'type', 'proper_filename' );
2000
2001         // We're able to validate images using GD
2002         if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) {
2003
2004                 // Attempt to figure out what type of image it actually is
2005                 $imgstats = @getimagesize( $file );
2006
2007                 // If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME
2008                 if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) {
2009                         /**
2010                          * Filter the list mapping image mime types to their respective extensions.
2011                          *
2012                          * @since 3.0.0
2013                          *
2014                          * @param  array $mime_to_ext Array of image mime types and their matching extensions.
2015                          */
2016                         $mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array(
2017                                 'image/jpeg' => 'jpg',
2018                                 'image/png'  => 'png',
2019                                 'image/gif'  => 'gif',
2020                                 'image/bmp'  => 'bmp',
2021                                 'image/tiff' => 'tif',
2022                         ) );
2023
2024                         // Replace whatever is after the last period in the filename with the correct extension
2025                         if ( ! empty( $mime_to_ext[ $imgstats['mime'] ] ) ) {
2026                                 $filename_parts = explode( '.', $filename );
2027                                 array_pop( $filename_parts );
2028                                 $filename_parts[] = $mime_to_ext[ $imgstats['mime'] ];
2029                                 $new_filename = implode( '.', $filename_parts );
2030
2031                                 if ( $new_filename != $filename )
2032                                         $proper_filename = $new_filename; // Mark that it changed
2033
2034                                 // Redefine the extension / MIME
2035                                 $wp_filetype = wp_check_filetype( $new_filename, $mimes );
2036                                 extract( $wp_filetype );
2037                         }
2038                 }
2039         }
2040
2041         /**
2042          * Filter the "real" file type of the given file.
2043          *
2044          * @since 3.0.0
2045          *
2046          * @param array  $wp_check_filetype_and_ext File data array containing 'ext', 'type', and
2047          *                                          'proper_filename' keys.
2048          * @param string $file                      Full path to the file.
2049          * @param string $filename                  The name of the file (may differ from $file due to
2050          *                                          $file being in a tmp directory).
2051          * @param array  $mimes                     Key is the file extension with value as the mime type.
2052          */
2053         return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes );
2054 }
2055
2056 /**
2057  * Retrieve list of mime types and file extensions.
2058  *
2059  * @since 3.5.0
2060  *
2061  * @return array Array of mime types keyed by the file extension regex corresponding to those types.
2062  */
2063 function wp_get_mime_types() {
2064         /**
2065          * Filter the list of mime types and file extensions.
2066          *
2067          * This filter should be used to add, not remove, mime types. To remove
2068          * mime types, use the 'upload_mimes' filter.
2069          *
2070          * @since 3.5.0
2071          *
2072          * @param array $wp_get_mime_types Mime types keyed by the file extension regex
2073          *                                 corresponding to those types.
2074          */
2075         return apply_filters( 'mime_types', array(
2076         // Image formats
2077         'jpg|jpeg|jpe' => 'image/jpeg',
2078         'gif' => 'image/gif',
2079         'png' => 'image/png',
2080         'bmp' => 'image/bmp',
2081         'tif|tiff' => 'image/tiff',
2082         'ico' => 'image/x-icon',
2083         // Video formats
2084         'asf|asx' => 'video/x-ms-asf',
2085         'wmv' => 'video/x-ms-wmv',
2086         'wmx' => 'video/x-ms-wmx',
2087         'wm' => 'video/x-ms-wm',
2088         'avi' => 'video/avi',
2089         'divx' => 'video/divx',
2090         'flv' => 'video/x-flv',
2091         'mov|qt' => 'video/quicktime',
2092         'mpeg|mpg|mpe' => 'video/mpeg',
2093         'mp4|m4v' => 'video/mp4',
2094         'ogv' => 'video/ogg',
2095         'webm' => 'video/webm',
2096         'mkv' => 'video/x-matroska',
2097         // Text formats
2098         'txt|asc|c|cc|h' => 'text/plain',
2099         'csv' => 'text/csv',
2100         'tsv' => 'text/tab-separated-values',
2101         'ics' => 'text/calendar',
2102         'rtx' => 'text/richtext',
2103         'css' => 'text/css',
2104         'htm|html' => 'text/html',
2105         'vtt' => 'text/vtt',
2106         // Audio formats
2107         'mp3|m4a|m4b' => 'audio/mpeg',
2108         'ra|ram' => 'audio/x-realaudio',
2109         'wav' => 'audio/wav',
2110         'ogg|oga' => 'audio/ogg',
2111         'mid|midi' => 'audio/midi',
2112         'wma' => 'audio/x-ms-wma',
2113         'wax' => 'audio/x-ms-wax',
2114         'mka' => 'audio/x-matroska',
2115         // Misc application formats
2116         'rtf' => 'application/rtf',
2117         'js' => 'application/javascript',
2118         'pdf' => 'application/pdf',
2119         'swf' => 'application/x-shockwave-flash',
2120         'class' => 'application/java',
2121         'tar' => 'application/x-tar',
2122         'zip' => 'application/zip',
2123         'gz|gzip' => 'application/x-gzip',
2124         'rar' => 'application/rar',
2125         '7z' => 'application/x-7z-compressed',
2126         'exe' => 'application/x-msdownload',
2127         // MS Office formats
2128         'doc' => 'application/msword',
2129         'pot|pps|ppt' => 'application/vnd.ms-powerpoint',
2130         'wri' => 'application/vnd.ms-write',
2131         'xla|xls|xlt|xlw' => 'application/vnd.ms-excel',
2132         'mdb' => 'application/vnd.ms-access',
2133         'mpp' => 'application/vnd.ms-project',
2134         'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
2135         'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
2136         'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
2137         'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
2138         'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
2139         'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
2140         'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
2141         'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
2142         'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
2143         'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
2144         'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
2145         'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
2146         'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
2147         'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
2148         'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
2149         'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
2150         'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
2151         'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
2152         'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
2153         'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
2154         // OpenOffice formats
2155         'odt' => 'application/vnd.oasis.opendocument.text',
2156         'odp' => 'application/vnd.oasis.opendocument.presentation',
2157         'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
2158         'odg' => 'application/vnd.oasis.opendocument.graphics',
2159         'odc' => 'application/vnd.oasis.opendocument.chart',
2160         'odb' => 'application/vnd.oasis.opendocument.database',
2161         'odf' => 'application/vnd.oasis.opendocument.formula',
2162         // WordPerfect formats
2163         'wp|wpd' => 'application/wordperfect',
2164         // iWork formats
2165         'key' => 'application/vnd.apple.keynote',
2166         'numbers' => 'application/vnd.apple.numbers',
2167         'pages' => 'application/vnd.apple.pages',
2168         ) );
2169 }
2170 /**
2171  * Retrieve list of allowed mime types and file extensions.
2172  *
2173  * @since 2.8.6
2174  *
2175  * @uses wp_get_upload_mime_types() to fetch the list of mime types
2176  *
2177  * @param int|WP_User $user Optional. User to check. Defaults to current user.
2178  * @return array Array of mime types keyed by the file extension regex corresponding to those types.
2179  */
2180 function get_allowed_mime_types( $user = null ) {
2181         $t = wp_get_mime_types();
2182
2183         unset( $t['swf'], $t['exe'] );
2184         if ( function_exists( 'current_user_can' ) )
2185                 $unfiltered = $user ? user_can( $user, 'unfiltered_html' ) : current_user_can( 'unfiltered_html' );
2186
2187         if ( empty( $unfiltered ) )
2188                 unset( $t['htm|html'] );
2189
2190         /**
2191          * Filter list of allowed mime types and file extensions.
2192          *
2193          * @since 2.0.0
2194          *
2195          * @param array            $t    Mime types keyed by the file extension regex corresponding to
2196          *                               those types. 'swf' and 'exe' removed from full list. 'htm|html' also
2197          *                               removed depending on '$user' capabilities.
2198          * @param int|WP_User|null $user User ID, User object or null if not provided (indicates current user).
2199          */
2200         return apply_filters( 'upload_mimes', $t, $user );
2201 }
2202
2203 /**
2204  * Display "Are You Sure" message to confirm the action being taken.
2205  *
2206  * If the action has the nonce explain message, then it will be displayed along
2207  * with the "Are you sure?" message.
2208  *
2209  * @since 2.0.4
2210  *
2211  * @param string $action The nonce action.
2212  */
2213 function wp_nonce_ays( $action ) {
2214         $title = __( 'WordPress Failure Notice' );
2215         if ( 'log-out' == $action ) {
2216                 $html = sprintf( __( 'You are attempting to log out of %s' ), get_bloginfo( 'name' ) ) . '</p><p>';
2217                 $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
2218                 $html .= sprintf( __( "Do you really want to <a href='%s'>log out</a>?"), wp_logout_url( $redirect_to ) );
2219         } else {
2220                 $html = __( 'Are you sure you want to do this?' );
2221                 if ( wp_get_referer() )
2222                         $html .= "</p><p><a href='" . esc_url( remove_query_arg( 'updated', wp_get_referer() ) ) . "'>" . __( 'Please try again.' ) . "</a>";
2223         }
2224
2225         wp_die( $html, $title, array('response' => 403) );
2226 }
2227
2228 /**
2229  * Kill WordPress execution and display HTML message with error message.
2230  *
2231  * This function complements the die() PHP function. The difference is that
2232  * HTML will be displayed to the user. It is recommended to use this function
2233  * only, when the execution should not continue any further. It is not
2234  * recommended to call this function very often and try to handle as many errors
2235  * as possible silently.
2236  *
2237  * @since 2.0.4
2238  *
2239  * @param string $message Error message.
2240  * @param string $title Error title.
2241  * @param string|array $args Optional arguments to control behavior.
2242  */
2243 function wp_die( $message = '', $title = '', $args = array() ) {
2244         if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
2245                 /**
2246                  * Filter callback for killing WordPress execution for AJAX requests.
2247                  *
2248                  * @since 3.4.0
2249                  *
2250                  * @param callback $function Callback function name.
2251                  */
2252                 $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
2253         } elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
2254                 /**
2255                  * Filter callback for killing WordPress execution for XML-RPC requests.
2256                  *
2257                  * @since 3.4.0
2258                  *
2259                  * @param callback $function Callback function name.
2260                  */
2261                 $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
2262         } else {
2263                 /**
2264                  * Filter callback for killing WordPress execution for all non-AJAX, non-XML-RPC requests.
2265                  *
2266                  * @since 3.0.0
2267                  *
2268                  * @param callback $function Callback function name.
2269                  */
2270                 $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
2271         }
2272
2273         call_user_func( $function, $message, $title, $args );
2274 }
2275
2276 /**
2277  * Kill WordPress execution and display HTML message with error message.
2278  *
2279  * This is the default handler for wp_die if you want a custom one for your
2280  * site then you can overload using the wp_die_handler filter in wp_die
2281  *
2282  * @since 3.0.0
2283  * @access private
2284  *
2285  * @param string $message Error message.
2286  * @param string $title Error title.
2287  * @param string|array $args Optional arguments to control behavior.
2288  */
2289 function _default_wp_die_handler( $message, $title = '', $args = array() ) {
2290         $defaults = array( 'response' => 500 );
2291         $r = wp_parse_args($args, $defaults);
2292
2293         $have_gettext = function_exists('__');
2294
2295         if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) {
2296                 if ( empty( $title ) ) {
2297                         $error_data = $message->get_error_data();
2298                         if ( is_array( $error_data ) && isset( $error_data['title'] ) )
2299                                 $title = $error_data['title'];
2300                 }
2301                 $errors = $message->get_error_messages();
2302                 switch ( count( $errors ) ) :
2303                 case 0 :
2304                         $message = '';
2305                         break;
2306                 case 1 :
2307                         $message = "<p>{$errors[0]}</p>";
2308                         break;
2309                 default :
2310                         $message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $errors ) . "</li>\n\t</ul>";
2311                         break;
2312                 endswitch;
2313         } elseif ( is_string( $message ) ) {
2314                 $message = "<p>$message</p>";
2315         }
2316
2317         if ( isset( $r['back_link'] ) && $r['back_link'] ) {
2318                 $back_text = $have_gettext? __('&laquo; Back') : '&laquo; Back';
2319                 $message .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
2320         }
2321
2322         if ( ! did_action( 'admin_head' ) ) :
2323                 if ( !headers_sent() ) {
2324                         status_header( $r['response'] );
2325                         nocache_headers();
2326                         header( 'Content-Type: text/html; charset=utf-8' );
2327                 }
2328
2329                 if ( empty($title) )
2330                         $title = $have_gettext ? __('WordPress &rsaquo; Error') : 'WordPress &rsaquo; Error';
2331
2332                 $text_direction = 'ltr';
2333                 if ( isset($r['text_direction']) && 'rtl' == $r['text_direction'] )
2334                         $text_direction = 'rtl';
2335                 elseif ( function_exists( 'is_rtl' ) && is_rtl() )
2336                         $text_direction = 'rtl';
2337 ?>
2338 <!DOCTYPE html>
2339 <!-- 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
2340 -->
2341 <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'"; ?>>
2342 <head>
2343         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2344         <title><?php echo $title ?></title>
2345         <style type="text/css">
2346                 html {
2347                         background: #f1f1f1;
2348                 }
2349                 body {
2350                         background: #fff;
2351                         color: #444;
2352                         font-family: "Open Sans", sans-serif;
2353                         margin: 2em auto;
2354                         padding: 1em 2em;
2355                         max-width: 700px;
2356                         -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2357                         box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2358                 }
2359                 h1 {
2360                         border-bottom: 1px solid #dadada;
2361                         clear: both;
2362                         color: #666;
2363                         font: 24px "Open Sans", sans-serif;
2364                         margin: 30px 0 0 0;
2365                         padding: 0;
2366                         padding-bottom: 7px;
2367                 }
2368                 #error-page {
2369                         margin-top: 50px;
2370                 }
2371                 #error-page p {
2372                         font-size: 14px;
2373                         line-height: 1.5;
2374                         margin: 25px 0 20px;
2375                 }
2376                 #error-page code {
2377                         font-family: Consolas, Monaco, monospace;
2378                 }
2379                 ul li {
2380                         margin-bottom: 10px;
2381                         font-size: 14px ;
2382                 }
2383                 a {
2384                         color: #21759B;
2385                         text-decoration: none;
2386                 }
2387                 a:hover {
2388                         color: #D54E21;
2389                 }
2390                 .button {
2391                         background: #f7f7f7;
2392                         border: 1px solid #cccccc;
2393                         color: #555;
2394                         display: inline-block;
2395                         text-decoration: none;
2396                         font-size: 13px;
2397                         line-height: 26px;
2398                         height: 28px;
2399                         margin: 0;
2400                         padding: 0 10px 1px;
2401                         cursor: pointer;
2402                         -webkit-border-radius: 3px;
2403                         -webkit-appearance: none;
2404                         border-radius: 3px;
2405                         white-space: nowrap;
2406                         -webkit-box-sizing: border-box;
2407                         -moz-box-sizing:    border-box;
2408                         box-sizing:         border-box;
2409
2410                         -webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0,0,0,.08);
2411                         box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0,0,0,.08);
2412                         vertical-align: top;
2413                 }
2414
2415                 .button.button-large {
2416                         height: 29px;
2417                         line-height: 28px;
2418                         padding: 0 12px;
2419                 }
2420
2421                 .button:hover,
2422                 .button:focus {
2423                         background: #fafafa;
2424                         border-color: #999;
2425                         color: #222;
2426                 }
2427
2428                 .button:focus  {
2429                         -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,.2);
2430                         box-shadow: 1px 1px 1px rgba(0,0,0,.2);
2431                 }
2432
2433                 .button:active {
2434                         background: #eee;
2435                         border-color: #999;
2436                         color: #333;
2437                         -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2438                         box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2439                 }
2440
2441                 <?php if ( 'rtl' == $text_direction ) : ?>
2442                 body { font-family: Tahoma, Arial; }
2443                 <?php endif; ?>
2444         </style>
2445 </head>
2446 <body id="error-page">
2447 <?php endif; // ! did_action( 'admin_head' ) ?>
2448         <?php echo $message; ?>
2449 </body>
2450 </html>
2451 <?php
2452         die();
2453 }
2454
2455 /**
2456  * Kill WordPress execution and display XML message with error message.
2457  *
2458  * This is the handler for wp_die when processing XMLRPC requests.
2459  *
2460  * @since 3.2.0
2461  * @access private
2462  *
2463  * @param string $message Error message.
2464  * @param string $title Error title.
2465  * @param string|array $args Optional arguments to control behavior.
2466  */
2467 function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) {
2468         global $wp_xmlrpc_server;
2469         $defaults = array( 'response' => 500 );
2470
2471         $r = wp_parse_args($args, $defaults);
2472
2473         if ( $wp_xmlrpc_server ) {
2474                 $error = new IXR_Error( $r['response'] , $message);
2475                 $wp_xmlrpc_server->output( $error->getXml() );
2476         }
2477         die();
2478 }
2479
2480 /**
2481  * Kill WordPress ajax execution.
2482  *
2483  * This is the handler for wp_die when processing Ajax requests.
2484  *
2485  * @since 3.4.0
2486  * @access private
2487  *
2488  * @param string $message Optional. Response to print.
2489  */
2490 function _ajax_wp_die_handler( $message = '' ) {
2491         if ( is_scalar( $message ) )
2492                 die( (string) $message );
2493         die( '0' );
2494 }
2495
2496 /**
2497  * Kill WordPress execution.
2498  *
2499  * This is the handler for wp_die when processing APP requests.
2500  *
2501  * @since 3.4.0
2502  * @access private
2503  *
2504  * @param string $message Optional. Response to print.
2505  */
2506 function _scalar_wp_die_handler( $message = '' ) {
2507         if ( is_scalar( $message ) )
2508                 die( (string) $message );
2509         die();
2510 }
2511
2512 /**
2513  * Send a JSON response back to an Ajax request.
2514  *
2515  * @since 3.5.0
2516  *
2517  * @param mixed $response Variable (usually an array or object) to encode as JSON, then print and die.
2518  */
2519 function wp_send_json( $response ) {
2520         @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
2521         echo json_encode( $response );
2522         if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
2523                 wp_die();
2524         else
2525                 die;
2526 }
2527
2528 /**
2529  * Send a JSON response back to an Ajax request, indicating success.
2530  *
2531  * @since 3.5.0
2532  *
2533  * @param mixed $data Data to encode as JSON, then print and die.
2534  */
2535 function wp_send_json_success( $data = null ) {
2536         $response = array( 'success' => true );
2537
2538         if ( isset( $data ) )
2539                 $response['data'] = $data;
2540
2541         wp_send_json( $response );
2542 }
2543
2544 /**
2545  * Send a JSON response back to an Ajax request, indicating failure.
2546  *
2547  * @since 3.5.0
2548  *
2549  * @param mixed $data Data to encode as JSON, then print and die.
2550  */
2551 function wp_send_json_error( $data = null ) {
2552         $response = array( 'success' => false );
2553
2554         if ( isset( $data ) )
2555                 $response['data'] = $data;
2556
2557         wp_send_json( $response );
2558 }
2559
2560 /**
2561  * Retrieve the WordPress home page URL.
2562  *
2563  * If the constant named 'WP_HOME' exists, then it will be used and returned by
2564  * the function. This can be used to counter the redirection on your local
2565  * development environment.
2566  *
2567  * @access private
2568  * @since 2.2.0
2569  *
2570  * @param string $url URL for the home location
2571  * @return string Homepage location.
2572  */
2573 function _config_wp_home( $url = '' ) {
2574         if ( defined( 'WP_HOME' ) )
2575                 return untrailingslashit( WP_HOME );
2576         return $url;
2577 }
2578
2579 /**
2580  * Retrieve the WordPress site URL.
2581  *
2582  * If the constant named 'WP_SITEURL' is defined, then the value in that
2583  * constant will always be returned. This can be used for debugging a site on
2584  * your localhost while not having to change the database to your URL.
2585  *
2586  * @access private
2587  * @since 2.2.0
2588  *
2589  * @param string $url URL to set the WordPress site location.
2590  * @return string The WordPress Site URL
2591  */
2592 function _config_wp_siteurl( $url = '' ) {
2593         if ( defined( 'WP_SITEURL' ) )
2594                 return untrailingslashit( WP_SITEURL );
2595         return $url;
2596 }
2597
2598 /**
2599  * Set the localized direction for MCE plugin.
2600  *
2601  * Will only set the direction to 'rtl', if the WordPress locale has the text
2602  * direction set to 'rtl'.
2603  *
2604  * Fills in the 'directionality' setting, enables the 'directionality' plugin,
2605  * and adds the 'ltr' button to 'toolbar1', formerly 'theme_advanced_buttons1' array
2606  * keys. These keys are then returned in the $input (TinyMCE settings) array.
2607  *
2608  * @access private
2609  * @since 2.1.0
2610  *
2611  * @param array $input MCE settings array.
2612  * @return array Direction set for 'rtl', if needed by locale.
2613  */
2614 function _mce_set_direction( $input ) {
2615         if ( is_rtl() ) {
2616                 $input['directionality'] = 'rtl';
2617                 $input['plugins'] .= ',directionality';
2618                 $input['toolbar1'] .= ',ltr';
2619         }
2620
2621         return $input;
2622 }
2623
2624
2625 /**
2626  * Convert smiley code to the icon graphic file equivalent.
2627  *
2628  * You can turn off smilies, by going to the write setting screen and unchecking
2629  * the box, or by setting 'use_smilies' option to false or removing the option.
2630  *
2631  * Plugins may override the default smiley list by setting the $wpsmiliestrans
2632  * to an array, with the key the code the blogger types in and the value the
2633  * image file.
2634  *
2635  * The $wp_smiliessearch global is for the regular expression and is set each
2636  * time the function is called.
2637  *
2638  * The full list of smilies can be found in the function and won't be listed in
2639  * the description. Probably should create a Codex page for it, so that it is
2640  * available.
2641  *
2642  * @global array $wpsmiliestrans
2643  * @global array $wp_smiliessearch
2644  * @since 2.2.0
2645  */
2646 function smilies_init() {
2647         global $wpsmiliestrans, $wp_smiliessearch;
2648
2649         // don't bother setting up smilies if they are disabled
2650         if ( !get_option( 'use_smilies' ) )
2651                 return;
2652
2653         if ( !isset( $wpsmiliestrans ) ) {
2654                 $wpsmiliestrans = array(
2655                 ':mrgreen:' => 'icon_mrgreen.gif',
2656                 ':neutral:' => 'icon_neutral.gif',
2657                 ':twisted:' => 'icon_twisted.gif',
2658                   ':arrow:' => 'icon_arrow.gif',
2659                   ':shock:' => 'icon_eek.gif',
2660                   ':smile:' => 'icon_smile.gif',
2661                     ':???:' => 'icon_confused.gif',
2662                    ':cool:' => 'icon_cool.gif',
2663                    ':evil:' => 'icon_evil.gif',
2664                    ':grin:' => 'icon_biggrin.gif',
2665                    ':idea:' => 'icon_idea.gif',
2666                    ':oops:' => 'icon_redface.gif',
2667                    ':razz:' => 'icon_razz.gif',
2668                    ':roll:' => 'icon_rolleyes.gif',
2669                    ':wink:' => 'icon_wink.gif',
2670                     ':cry:' => 'icon_cry.gif',
2671                     ':eek:' => 'icon_surprised.gif',
2672                     ':lol:' => 'icon_lol.gif',
2673                     ':mad:' => 'icon_mad.gif',
2674                     ':sad:' => 'icon_sad.gif',
2675                       '8-)' => 'icon_cool.gif',
2676                       '8-O' => 'icon_eek.gif',
2677                       ':-(' => 'icon_sad.gif',
2678                       ':-)' => 'icon_smile.gif',
2679                       ':-?' => 'icon_confused.gif',
2680                       ':-D' => 'icon_biggrin.gif',
2681                       ':-P' => 'icon_razz.gif',
2682                       ':-o' => 'icon_surprised.gif',
2683                       ':-x' => 'icon_mad.gif',
2684                       ':-|' => 'icon_neutral.gif',
2685                       ';-)' => 'icon_wink.gif',
2686                 // This one transformation breaks regular text with frequency.
2687                 //     '8)' => 'icon_cool.gif',
2688                        '8O' => 'icon_eek.gif',
2689                        ':(' => 'icon_sad.gif',
2690                        ':)' => 'icon_smile.gif',
2691                        ':?' => 'icon_confused.gif',
2692                        ':D' => 'icon_biggrin.gif',
2693                        ':P' => 'icon_razz.gif',
2694                        ':o' => 'icon_surprised.gif',
2695                        ':x' => 'icon_mad.gif',
2696                        ':|' => 'icon_neutral.gif',
2697                        ';)' => 'icon_wink.gif',
2698                       ':!:' => 'icon_exclaim.gif',
2699                       ':?:' => 'icon_question.gif',
2700                 );
2701         }
2702
2703         if (count($wpsmiliestrans) == 0) {
2704                 return;
2705         }
2706
2707         /*
2708          * NOTE: we sort the smilies in reverse key order. This is to make sure
2709          * we match the longest possible smilie (:???: vs :?) as the regular
2710          * expression used below is first-match
2711          */
2712         krsort($wpsmiliestrans);
2713
2714         $wp_smiliessearch = '/((?:\s|^)';
2715
2716         $subchar = '';
2717         foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
2718                 $firstchar = substr($smiley, 0, 1);
2719                 $rest = substr($smiley, 1);
2720
2721                 // new subpattern?
2722                 if ($firstchar != $subchar) {
2723                         if ($subchar != '') {
2724                                 $wp_smiliessearch .= ')(?=\s|$))|((?:\s|^)'; ;
2725                         }
2726                         $subchar = $firstchar;
2727                         $wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:';
2728                 } else {
2729                         $wp_smiliessearch .= '|';
2730                 }
2731                 $wp_smiliessearch .= preg_quote($rest, '/');
2732         }
2733
2734         $wp_smiliessearch .= ')(?=\s|$))/m';
2735
2736 }
2737
2738 /**
2739  * Merge user defined arguments into defaults array.
2740  *
2741  * This function is used throughout WordPress to allow for both string or array
2742  * to be merged into another array.
2743  *
2744  * @since 2.2.0
2745  *
2746  * @param string|array $args Value to merge with $defaults
2747  * @param array $defaults Array that serves as the defaults.
2748  * @return array Merged user defined values with defaults.
2749  */
2750 function wp_parse_args( $args, $defaults = '' ) {
2751         if ( is_object( $args ) )
2752                 $r = get_object_vars( $args );
2753         elseif ( is_array( $args ) )
2754                 $r =& $args;
2755         else
2756                 wp_parse_str( $args, $r );
2757
2758         if ( is_array( $defaults ) )
2759                 return array_merge( $defaults, $r );
2760         return $r;
2761 }
2762
2763 /**
2764  * Clean up an array, comma- or space-separated list of IDs.
2765  *
2766  * @since 3.0.0
2767  *
2768  * @param array|string $list
2769  * @return array Sanitized array of IDs
2770  */
2771 function wp_parse_id_list( $list ) {
2772         if ( !is_array($list) )
2773                 $list = preg_split('/[\s,]+/', $list);
2774
2775         return array_unique(array_map('absint', $list));
2776 }
2777
2778 /**
2779  * Extract a slice of an array, given a list of keys.
2780  *
2781  * @since 3.1.0
2782  *
2783  * @param array $array The original array
2784  * @param array $keys The list of keys
2785  * @return array The array slice
2786  */
2787 function wp_array_slice_assoc( $array, $keys ) {
2788         $slice = array();
2789         foreach ( $keys as $key )
2790                 if ( isset( $array[ $key ] ) )
2791                         $slice[ $key ] = $array[ $key ];
2792
2793         return $slice;
2794 }
2795
2796 /**
2797  * Filters a list of objects, based on a set of key => value arguments.
2798  *
2799  * @since 3.0.0
2800  *
2801  * @param array $list An array of objects to filter
2802  * @param array $args An array of key => value arguments to match against each object
2803  * @param string $operator The logical operation to perform. 'or' means only one element
2804  *      from the array needs to match; 'and' means all elements must match. The default is 'and'.
2805  * @param bool|string $field A field from the object to place instead of the entire object
2806  * @return array A list of objects or object fields
2807  */
2808 function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) {
2809         if ( ! is_array( $list ) )
2810                 return array();
2811
2812         $list = wp_list_filter( $list, $args, $operator );
2813
2814         if ( $field )
2815                 $list = wp_list_pluck( $list, $field );
2816
2817         return $list;
2818 }
2819
2820 /**
2821  * Filters a list of objects, based on a set of key => value arguments.
2822  *
2823  * @since 3.1.0
2824  *
2825  * @param array $list An array of objects to filter
2826  * @param array $args An array of key => value arguments to match against each object
2827  * @param string $operator The logical operation to perform:
2828  *    'AND' means all elements from the array must match;
2829  *    'OR' means only one element needs to match;
2830  *    'NOT' means no elements may match.
2831  *   The default is 'AND'.
2832  * @return array
2833  */
2834 function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
2835         if ( ! is_array( $list ) )
2836                 return array();
2837
2838         if ( empty( $args ) )
2839                 return $list;
2840
2841         $operator = strtoupper( $operator );
2842         $count = count( $args );
2843         $filtered = array();
2844
2845         foreach ( $list as $key => $obj ) {
2846                 $to_match = (array) $obj;
2847
2848                 $matched = 0;
2849                 foreach ( $args as $m_key => $m_value ) {
2850                         if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] )
2851                                 $matched++;
2852                 }
2853
2854                 if ( ( 'AND' == $operator && $matched == $count )
2855                   || ( 'OR' == $operator && $matched > 0 )
2856                   || ( 'NOT' == $operator && 0 == $matched ) ) {
2857                         $filtered[$key] = $obj;
2858                 }
2859         }
2860
2861         return $filtered;
2862 }
2863
2864 /**
2865  * Pluck a certain field out of each object in a list.
2866  *
2867  * @since 3.1.0
2868  *
2869  * @param array $list A list of objects or arrays
2870  * @param int|string $field A field from the object to place instead of the entire object
2871  * @return array
2872  */
2873 function wp_list_pluck( $list, $field ) {
2874         foreach ( $list as $key => $value ) {
2875                 if ( is_object( $value ) )
2876                         $list[ $key ] = $value->$field;
2877                 else
2878                         $list[ $key ] = $value[ $field ];
2879         }
2880
2881         return $list;
2882 }
2883
2884 /**
2885  * Determines if Widgets library should be loaded.
2886  *
2887  * Checks to make sure that the widgets library hasn't already been loaded. If
2888  * it hasn't, then it will load the widgets library and run an action hook.
2889  *
2890  * @since 2.2.0
2891  * @uses add_action() Calls '_admin_menu' hook with 'wp_widgets_add_menu' value.
2892  */
2893 function wp_maybe_load_widgets() {
2894         /**
2895          * Filter whether to load the Widgets library.
2896          *
2897          * @since 2.8.0
2898          *
2899          * @param bool $wp_maybe_load_widgets Whether to load the Widgets library.
2900          *                                    Default true.
2901          */
2902         if ( ! apply_filters( 'load_default_widgets', true ) ) {
2903                 return;
2904         }
2905         require_once( ABSPATH . WPINC . '/default-widgets.php' );
2906         add_action( '_admin_menu', 'wp_widgets_add_menu' );
2907 }
2908
2909 /**
2910  * Append the Widgets menu to the themes main menu.
2911  *
2912  * @since 2.2.0
2913  * @uses $submenu The administration submenu list.
2914  */
2915 function wp_widgets_add_menu() {
2916         global $submenu;
2917
2918         if ( ! current_theme_supports( 'widgets' ) )
2919                 return;
2920
2921         $submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' );
2922         ksort( $submenu['themes.php'], SORT_NUMERIC );
2923 }
2924
2925 /**
2926  * Flush all output buffers for PHP 5.2.
2927  *
2928  * Make sure all output buffers are flushed before our singletons our destroyed.
2929  *
2930  * @since 2.2.0
2931  */
2932 function wp_ob_end_flush_all() {
2933         $levels = ob_get_level();
2934         for ($i=0; $i<$levels; $i++)
2935                 ob_end_flush();
2936 }
2937
2938 /**
2939  * Load custom DB error or display WordPress DB error.
2940  *
2941  * If a file exists in the wp-content directory named db-error.php, then it will
2942  * be loaded instead of displaying the WordPress DB error. If it is not found,
2943  * then the WordPress DB error will be displayed instead.
2944  *
2945  * The WordPress DB error sets the HTTP status header to 500 to try to prevent
2946  * search engines from caching the message. Custom DB messages should do the
2947  * same.
2948  *
2949  * This function was backported to WordPress 2.3.2, but originally was added
2950  * in WordPress 2.5.0.
2951  *
2952  * @since 2.3.2
2953  * @uses $wpdb
2954  */
2955 function dead_db() {
2956         global $wpdb;
2957
2958         wp_load_translations_early();
2959
2960         // Load custom DB error template, if present.
2961         if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
2962                 require_once( WP_CONTENT_DIR . '/db-error.php' );
2963                 die();
2964         }
2965
2966         // If installing or in the admin, provide the verbose message.
2967         if ( defined('WP_INSTALLING') || defined('WP_ADMIN') )
2968                 wp_die($wpdb->error);
2969
2970         // Otherwise, be terse.
2971         status_header( 500 );
2972         nocache_headers();
2973         header( 'Content-Type: text/html; charset=utf-8' );
2974 ?>
2975 <!DOCTYPE html>
2976 <html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
2977 <head>
2978 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2979         <title><?php _e( 'Database Error' ); ?></title>
2980
2981 </head>
2982 <body>
2983         <h1><?php _e( 'Error establishing a database connection' ); ?></h1>
2984 </body>
2985 </html>
2986 <?php
2987         die();
2988 }
2989
2990 /**
2991  * Converts value to nonnegative integer.
2992  *
2993  * @since 2.5.0
2994  *
2995  * @param mixed $maybeint Data you wish to have converted to a nonnegative integer
2996  * @return int An nonnegative integer
2997  */
2998 function absint( $maybeint ) {
2999         return abs( intval( $maybeint ) );
3000 }
3001
3002 /**
3003  * Determines if the blog can be accessed over SSL.
3004  *
3005  * Determines if blog can be accessed over SSL by using cURL to access the site
3006  * using the https in the siteurl. Requires cURL extension to work correctly.
3007  *
3008  * @since 2.5.0
3009  *
3010  * @param string $url
3011  * @return bool Whether SSL access is available
3012  */
3013 function url_is_accessable_via_ssl($url)
3014 {
3015         if ( in_array( 'curl', get_loaded_extensions() ) ) {
3016                 $ssl = set_url_scheme( $url, 'https' );
3017
3018                 $ch = curl_init();
3019                 curl_setopt($ch, CURLOPT_URL, $ssl);
3020                 curl_setopt($ch, CURLOPT_FAILONERROR, true);
3021                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
3022                 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
3023                 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
3024
3025                 curl_exec($ch);
3026
3027                 $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
3028                 curl_close ($ch);
3029
3030                 if ($status == 200 || $status == 401) {
3031                         return true;
3032                 }
3033         }
3034         return false;
3035 }
3036
3037 /**
3038  * Marks a function as deprecated and informs when it has been used.
3039  *
3040  * There is a hook deprecated_function_run that will be called that can be used
3041  * to get the backtrace up to what file and function called the deprecated
3042  * function.
3043  *
3044  * The current behavior is to trigger a user error if WP_DEBUG is true.
3045  *
3046  * This function is to be used in every function that is deprecated.
3047  *
3048  * @since 2.5.0
3049  * @access private
3050  *
3051  * @param string $function The function that was called
3052  * @param string $version The version of WordPress that deprecated the function
3053  * @param string $replacement Optional. The function that should have been called
3054  */
3055 function _deprecated_function( $function, $version, $replacement = null ) {
3056
3057         /**
3058          * Fires when a deprecated function is called.
3059          *
3060          * @since 2.5.0
3061          *
3062          * @param string $function    The function that was called.
3063          * @param string $replacement The function that should have been called.
3064          * @param string $version     The version of WordPress that deprecated the function.
3065          */
3066         do_action( 'deprecated_function_run', $function, $replacement, $version );
3067
3068         /**
3069          * Filter whether to trigger an error for deprecated functions.
3070          *
3071          * @since 2.5.0
3072          *
3073          * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
3074          */
3075         if ( WP_DEBUG && apply_filters( 'deprecated_function_trigger_error', true ) ) {
3076                 if ( function_exists( '__' ) ) {
3077                         if ( ! is_null( $replacement ) )
3078                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) );
3079                         else
3080                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
3081                 } else {
3082                         if ( ! is_null( $replacement ) )
3083                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $function, $version, $replacement ) );
3084                         else
3085                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
3086                 }
3087         }
3088 }
3089
3090 /**
3091  * Marks a file as deprecated and informs when it has been used.
3092  *
3093  * There is a hook deprecated_file_included that will be called that can be used
3094  * to get the backtrace up to what file and function included the deprecated
3095  * file.
3096  *
3097  * The current behavior is to trigger a user error if WP_DEBUG is true.
3098  *
3099  * This function is to be used in every file that is deprecated.
3100  *
3101  * @since 2.5.0
3102  * @access private
3103  *
3104  * @param string $file The file that was included
3105  * @param string $version The version of WordPress that deprecated the file
3106  * @param string $replacement Optional. The file that should have been included based on ABSPATH
3107  * @param string $message Optional. A message regarding the change
3108  */
3109 function _deprecated_file( $file, $version, $replacement = null, $message = '' ) {
3110
3111         /**
3112          * Fires when a deprecated file is called.
3113          *
3114          * @since 2.5.0
3115          *
3116          * @param string $file        The file that was called.
3117          * @param string $replacement The file that should have been included based on ABSPATH.
3118          * @param string $version     The version of WordPress that deprecated the file.
3119          * @param string $message     A message regarding the change.
3120          */
3121         do_action( 'deprecated_file_included', $file, $replacement, $version, $message );
3122
3123         /**
3124          * Filter whether to trigger an error for deprecated files.
3125          *
3126          * @since 2.5.0
3127          *
3128          * @param bool $trigger Whether to trigger the error for deprecated files. Default true.
3129          */
3130         if ( WP_DEBUG && apply_filters( 'deprecated_file_trigger_error', true ) ) {
3131                 $message = empty( $message ) ? '' : ' ' . $message;
3132                 if ( function_exists( '__' ) ) {
3133                         if ( ! is_null( $replacement ) )
3134                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $file, $version, $replacement ) . $message );
3135                         else
3136                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $file, $version ) . $message );
3137                 } else {
3138                         if ( ! is_null( $replacement ) )
3139                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $file, $version, $replacement ) . $message );
3140                         else
3141                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $file, $version ) . $message );
3142                 }
3143         }
3144 }
3145 /**
3146  * Marks a function argument as deprecated and informs when it has been used.
3147  *
3148  * This function is to be used whenever a deprecated function argument is used.
3149  * Before this function is called, the argument must be checked for whether it was
3150  * used by comparing it to its default value or evaluating whether it is empty.
3151  * For example:
3152  * <code>
3153  * if ( !empty($deprecated) )
3154  *      _deprecated_argument( __FUNCTION__, '3.0' );
3155  * </code>
3156  *
3157  * There is a hook deprecated_argument_run that will be called that can be used
3158  * to get the backtrace up to what file and function used the deprecated
3159  * argument.
3160  *
3161  * The current behavior is to trigger a user error if WP_DEBUG is true.
3162  *
3163  * @since 3.0.0
3164  * @access private
3165  *
3166  * @param string $function The function that was called
3167  * @param string $version The version of WordPress that deprecated the argument used
3168  * @param string $message Optional. A message regarding the change.
3169  */
3170 function _deprecated_argument( $function, $version, $message = null ) {
3171
3172         /**
3173          * Fires when a deprecated argument is called.
3174          *
3175          * @since 3.0.0
3176          *
3177          * @param string $function The function that was called.
3178          * @param string $message  A message regarding the change.
3179          * @param string $version  The version of WordPress that deprecated the argument used.
3180          */
3181         do_action( 'deprecated_argument_run', $function, $message, $version );
3182
3183         /**
3184          * Filter whether to trigger an error for deprecated arguments.
3185          *
3186          * @since 3.0.0
3187          *
3188          * @param bool $trigger Whether to trigger the error for deprecated arguments. Default true.
3189          */
3190         if ( WP_DEBUG && apply_filters( 'deprecated_argument_trigger_error', true ) ) {
3191                 if ( function_exists( '__' ) ) {
3192                         if ( ! is_null( $message ) )
3193                                 trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s'), $function, $version, $message ) );
3194                         else
3195                                 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 ) );
3196                 } else {
3197                         if ( ! is_null( $message ) )
3198                                 trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s', $function, $version, $message ) );
3199                         else
3200                                 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 ) );
3201                 }
3202         }
3203 }
3204
3205 /**
3206  * Marks something as being incorrectly called.
3207  *
3208  * There is a hook doing_it_wrong_run that will be called that can be used
3209  * to get the backtrace up to what file and function called the deprecated
3210  * function.
3211  *
3212  * The current behavior is to trigger a user error if WP_DEBUG is true.
3213  *
3214  * @since 3.1.0
3215  * @access private
3216  *
3217  * @param string $function The function that was called.
3218  * @param string $message A message explaining what has been done incorrectly.
3219  * @param string $version The version of WordPress where the message was added.
3220  */
3221 function _doing_it_wrong( $function, $message, $version ) {
3222
3223         /**
3224          * Fires when the given function is being used incorrectly.
3225          *
3226          * @since 3.1.0
3227          *
3228          * @param string $function The function that was called.
3229          * @param string $message  A message explaining what has been done incorrectly.
3230          * @param string $version  The version of WordPress where the message was added.
3231          */
3232         do_action( 'doing_it_wrong_run', $function, $message, $version );
3233
3234         /**
3235          * Filter whether to trigger an error for _doing_it_wrong() calls.
3236          *
3237          * @since 3.1.0
3238          *
3239          * @param bool $trigger Whether to trigger the error for _doing_it_wrong() calls. Default true.
3240          */
3241         if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
3242                 if ( function_exists( '__' ) ) {
3243                         $version = is_null( $version ) ? '' : sprintf( __( '(This message was added in version %s.)' ), $version );
3244                         $message .= ' ' . __( 'Please see <a href="http://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.' );
3245                         trigger_error( sprintf( __( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s' ), $function, $message, $version ) );
3246                 } else {
3247                         $version = is_null( $version ) ? '' : sprintf( '(This message was added in version %s.)', $version );
3248                         $message .= ' Please see <a href="http://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.';
3249                         trigger_error( sprintf( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s', $function, $message, $version ) );
3250                 }
3251         }
3252 }
3253
3254 /**
3255  * Is the server running earlier than 1.5.0 version of lighttpd?
3256  *
3257  * @since 2.5.0
3258  *
3259  * @return bool Whether the server is running lighttpd < 1.5.0
3260  */
3261 function is_lighttpd_before_150() {
3262         $server_parts = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] )? $_SERVER['SERVER_SOFTWARE'] : '' );
3263         $server_parts[1] = isset( $server_parts[1] )? $server_parts[1] : '';
3264         return  'lighttpd' == $server_parts[0] && -1 == version_compare( $server_parts[1], '1.5.0' );
3265 }
3266
3267 /**
3268  * Does the specified module exist in the Apache config?
3269  *
3270  * @since 2.5.0
3271  *
3272  * @param string $mod e.g. mod_rewrite
3273  * @param bool $default The default return value if the module is not found
3274  * @return bool
3275  */
3276 function apache_mod_loaded($mod, $default = false) {
3277         global $is_apache;
3278
3279         if ( !$is_apache )
3280                 return false;
3281
3282         if ( function_exists('apache_get_modules') ) {
3283                 $mods = apache_get_modules();
3284                 if ( in_array($mod, $mods) )
3285                         return true;
3286         } elseif ( function_exists('phpinfo') ) {
3287                         ob_start();
3288                         phpinfo(8);
3289                         $phpinfo = ob_get_clean();
3290                         if ( false !== strpos($phpinfo, $mod) )
3291                                 return true;
3292         }
3293         return $default;
3294 }
3295
3296 /**
3297  * Check if IIS 7+ supports pretty permalinks.
3298  *
3299  * @since 2.8.0
3300  *
3301  * @return bool
3302  */
3303 function iis7_supports_permalinks() {
3304         global $is_iis7;
3305
3306         $supports_permalinks = false;
3307         if ( $is_iis7 ) {
3308                 /* First we check if the DOMDocument class exists. If it does not exist, then we cannot
3309                  * easily update the xml configuration file, hence we just bail out and tell user that
3310                  * pretty permalinks cannot be used.
3311                  *
3312                  * Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the web site. When
3313                  * URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
3314                  * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
3315                  * via ISAPI then pretty permalinks will not work.
3316                  */
3317                 $supports_permalinks = class_exists('DOMDocument') && isset($_SERVER['IIS_UrlRewriteModule']) && ( php_sapi_name() == 'cgi-fcgi' );
3318         }
3319
3320         /**
3321          * Filter whether IIS 7+ supports pretty permalinks.
3322          *
3323          * @since 2.8.0
3324          *
3325          * @param bool $supports_permalinks Whether IIS7 supports permalinks. Default false.
3326          */
3327         return apply_filters( 'iis7_supports_permalinks', $supports_permalinks );
3328 }
3329
3330 /**
3331  * File validates against allowed set of defined rules.
3332  *
3333  * A return value of '1' means that the $file contains either '..' or './'. A
3334  * return value of '2' means that the $file contains ':' after the first
3335  * character. A return value of '3' means that the file is not in the allowed
3336  * files list.
3337  *
3338  * @since 1.2.0
3339  *
3340  * @param string $file File path.
3341  * @param array $allowed_files List of allowed files.
3342  * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
3343  */
3344 function validate_file( $file, $allowed_files = '' ) {
3345         if ( false !== strpos( $file, '..' ) )
3346                 return 1;
3347
3348         if ( false !== strpos( $file, './' ) )
3349                 return 1;
3350
3351         if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) )
3352                 return 3;
3353
3354         if (':' == substr( $file, 1, 1 ) )
3355                 return 2;
3356
3357         return 0;
3358 }
3359
3360 /**
3361  * Determine if SSL is used.
3362  *
3363  * @since 2.6.0
3364  *
3365  * @return bool True if SSL, false if not used.
3366  */
3367 function is_ssl() {
3368         if ( isset($_SERVER['HTTPS']) ) {
3369                 if ( 'on' == strtolower($_SERVER['HTTPS']) )
3370                         return true;
3371                 if ( '1' == $_SERVER['HTTPS'] )
3372                         return true;
3373         } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
3374                 return true;
3375         }
3376         return false;
3377 }
3378
3379 /**
3380  * Whether SSL login should be forced.
3381  *
3382  * @since 2.6.0
3383  *
3384  * @param string|bool $force Optional.
3385  * @return bool True if forced, false if not forced.
3386  */
3387 function force_ssl_login( $force = null ) {
3388         static $forced = false;
3389
3390         if ( !is_null( $force ) ) {
3391                 $old_forced = $forced;
3392                 $forced = $force;
3393                 return $old_forced;
3394         }
3395
3396         return $forced;
3397 }
3398
3399 /**
3400  * Whether to force SSL used for the Administration Screens.
3401  *
3402  * @since 2.6.0
3403  *
3404  * @param string|bool $force
3405  * @return bool True if forced, false if not forced.
3406  */
3407 function force_ssl_admin( $force = null ) {
3408         static $forced = false;
3409
3410         if ( !is_null( $force ) ) {
3411                 $old_forced = $forced;
3412                 $forced = $force;
3413                 return $old_forced;
3414         }
3415
3416         return $forced;
3417 }
3418
3419 /**
3420  * Guess the URL for the site.
3421  *
3422  * Will remove wp-admin links to retrieve only return URLs not in the wp-admin
3423  * directory.
3424  *
3425  * @since 2.6.0
3426  *
3427  * @return string
3428  */
3429 function wp_guess_url() {
3430         if ( defined('WP_SITEURL') && '' != WP_SITEURL ) {
3431                 $url = WP_SITEURL;
3432         } else {
3433                 $abspath_fix = str_replace( '\\', '/', ABSPATH );
3434                 $script_filename_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
3435
3436                 // The request is for the admin
3437                 if ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false || strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ) {
3438                         $path = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $_SERVER['REQUEST_URI'] );
3439
3440                 // The request is for a file in ABSPATH
3441                 } elseif ( $script_filename_dir . '/' == $abspath_fix ) {
3442                         // Strip off any file/query params in the path
3443                         $path = preg_replace( '#/[^/]*$#i', '', $_SERVER['PHP_SELF'] );
3444
3445                 } else {
3446                         if ( false !== strpos( $_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
3447                                 // Request is hitting a file inside ABSPATH
3448                                 $directory = str_replace( ABSPATH, '', $script_filename_dir );
3449                                 // Strip off the sub directory, and any file/query paramss
3450                                 $path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] );
3451                         } elseif ( false !== strpos( $abspath_fix, $script_filename_dir ) ) {
3452                                 // Request is hitting a file above ABSPATH
3453                                 $subdirectory = substr( $abspath_fix, strpos( $abspath_fix, $script_filename_dir ) + strlen( $script_filename_dir ) );
3454                                 // Strip off any file/query params from the path, appending the sub directory to the install
3455                                 $path = preg_replace( '#/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] ) . $subdirectory;
3456                         } else {
3457                                 $path = $_SERVER['REQUEST_URI'];
3458                         }
3459                 }
3460
3461                 $schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet
3462                 $url = $schema . $_SERVER['HTTP_HOST'] . $path;
3463         }
3464
3465         return rtrim($url, '/');
3466 }
3467
3468 /**
3469  * Temporarily suspend cache additions.
3470  *
3471  * Stops more data being added to the cache, but still allows cache retrieval.
3472  * This is useful for actions, such as imports, when a lot of data would otherwise
3473  * be almost uselessly added to the cache.
3474  *
3475  * Suspension lasts for a single page load at most. Remember to call this
3476  * function again if you wish to re-enable cache adds earlier.
3477  *
3478  * @since 3.3.0
3479  *
3480  * @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
3481  * @return bool The current suspend setting
3482  */
3483 function wp_suspend_cache_addition( $suspend = null ) {
3484         static $_suspend = false;
3485
3486         if ( is_bool( $suspend ) )
3487                 $_suspend = $suspend;
3488
3489         return $_suspend;
3490 }
3491
3492 /**
3493  * Suspend cache invalidation.
3494  *
3495  * Turns cache invalidation on and off. Useful during imports where you don't wont to do invalidations
3496  * every time a post is inserted. Callers must be sure that what they are doing won't lead to an inconsistent
3497  * cache when invalidation is suspended.
3498  *
3499  * @since 2.7.0
3500  *
3501  * @param bool $suspend Whether to suspend or enable cache invalidation
3502  * @return bool The current suspend setting
3503  */
3504 function wp_suspend_cache_invalidation($suspend = true) {
3505         global $_wp_suspend_cache_invalidation;
3506
3507         $current_suspend = $_wp_suspend_cache_invalidation;
3508         $_wp_suspend_cache_invalidation = $suspend;
3509         return $current_suspend;
3510 }
3511
3512 /**
3513  * Whether a site is the main site of the current network.
3514  *
3515  * @since 3.0.0
3516  *
3517  * @param int $site_id Optional. Site ID to test. Defaults to current site.
3518  * @return bool True if $site_id is the main site of the network, or if not running multisite.
3519  */
3520 function is_main_site( $site_id = null ) {
3521         // This is the current network's information; 'site' is old terminology.
3522         global $current_site;
3523
3524         if ( ! is_multisite() )
3525                 return true;
3526
3527         if ( ! $site_id )
3528                 $site_id = get_current_blog_id();
3529
3530         return (int) $site_id === (int) $current_site->blog_id;
3531 }
3532
3533 /**
3534  * Whether a network is the main network of the multisite install.
3535  *
3536  * @since 3.7.0
3537  *
3538  * @param int $network_id Optional. Network ID to test. Defaults to current network.
3539  * @return bool True if $network_id is the main network, or if not running multisite.
3540  */
3541 function is_main_network( $network_id = null ) {
3542         global $wpdb;
3543
3544         if ( ! is_multisite() )
3545                 return true;
3546
3547         $current_network_id = (int) get_current_site()->id;
3548
3549         if ( ! $network_id )
3550                 $network_id = $current_network_id;
3551         $network_id = (int) $network_id;
3552
3553         if ( defined( 'PRIMARY_NETWORK_ID' ) )
3554                 return $network_id === (int) PRIMARY_NETWORK_ID;
3555
3556         if ( 1 === $current_network_id )
3557                 return $network_id === $current_network_id;
3558
3559         $primary_network_id = (int) wp_cache_get( 'primary_network_id', 'site-options' );
3560
3561         if ( $primary_network_id )
3562                 return $network_id === $primary_network_id;
3563
3564         $primary_network_id = (int) $wpdb->get_var( "SELECT id FROM $wpdb->site ORDER BY id LIMIT 1" );
3565         wp_cache_add( 'primary_network_id', $primary_network_id, 'site-options' );
3566
3567         return $network_id === $primary_network_id;
3568 }
3569
3570 /**
3571  * Whether global terms are enabled.
3572  *
3573  *
3574  * @since 3.0.0
3575  *
3576  * @return bool True if multisite and global terms enabled
3577  */
3578 function global_terms_enabled() {
3579         if ( ! is_multisite() )
3580                 return false;
3581
3582         static $global_terms = null;
3583         if ( is_null( $global_terms ) ) {
3584
3585                 /**
3586                  * Filter whether global terms are enabled.
3587                  *
3588                  * Passing a non-null value to the filter will effectively short-circuit the function,
3589                  * returning the value of the 'global_terms_enabled' site option instead.
3590                  *
3591                  * @since 3.0.0
3592                  *
3593                  * @param null $anbled Whether global terms are enabled.
3594                  */
3595                 $filter = apply_filters( 'global_terms_enabled', null );
3596                 if ( ! is_null( $filter ) )
3597                         $global_terms = (bool) $filter;
3598                 else
3599                         $global_terms = (bool) get_site_option( 'global_terms_enabled', false );
3600         }
3601         return $global_terms;
3602 }
3603
3604 /**
3605  * gmt_offset modification for smart timezone handling.
3606  *
3607  * Overrides the gmt_offset option if we have a timezone_string available.
3608  *
3609  * @since 2.8.0
3610  *
3611  * @return float|bool
3612  */
3613 function wp_timezone_override_offset() {
3614         if ( !$timezone_string = get_option( 'timezone_string' ) ) {
3615                 return false;
3616         }
3617
3618         $timezone_object = timezone_open( $timezone_string );
3619         $datetime_object = date_create();
3620         if ( false === $timezone_object || false === $datetime_object ) {
3621                 return false;
3622         }
3623         return round( timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS, 2 );
3624 }
3625
3626 /**
3627  * Sort-helper for timezones.
3628  *
3629  * @since 2.9.0
3630  *
3631  * @param array $a
3632  * @param array $b
3633  * @return int
3634  */
3635 function _wp_timezone_choice_usort_callback( $a, $b ) {
3636         // Don't use translated versions of Etc
3637         if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
3638                 // Make the order of these more like the old dropdown
3639                 if ( 'GMT+' === substr( $a['city'], 0, 4 ) && 'GMT+' === substr( $b['city'], 0, 4 ) ) {
3640                         return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
3641                 }
3642                 if ( 'UTC' === $a['city'] ) {
3643                         if ( 'GMT+' === substr( $b['city'], 0, 4 ) ) {
3644                                 return 1;
3645                         }
3646                         return -1;
3647                 }
3648                 if ( 'UTC' === $b['city'] ) {
3649                         if ( 'GMT+' === substr( $a['city'], 0, 4 ) ) {
3650                                 return -1;
3651                         }
3652                         return 1;
3653                 }
3654                 return strnatcasecmp( $a['city'], $b['city'] );
3655         }
3656         if ( $a['t_continent'] == $b['t_continent'] ) {
3657                 if ( $a['t_city'] == $b['t_city'] ) {
3658                         return strnatcasecmp( $a['t_subcity'], $b['t_subcity'] );
3659                 }
3660                 return strnatcasecmp( $a['t_city'], $b['t_city'] );
3661         } else {
3662                 // Force Etc to the bottom of the list
3663                 if ( 'Etc' === $a['continent'] ) {
3664                         return 1;
3665                 }
3666                 if ( 'Etc' === $b['continent'] ) {
3667                         return -1;
3668                 }
3669                 return strnatcasecmp( $a['t_continent'], $b['t_continent'] );
3670         }
3671 }
3672
3673 /**
3674  * Gives a nicely formatted list of timezone strings.
3675  *
3676  * @since 2.9.0
3677  *
3678  * @param string $selected_zone Selected Zone
3679  * @return string
3680  */
3681 function wp_timezone_choice( $selected_zone ) {
3682         static $mo_loaded = false;
3683
3684         $continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific');
3685
3686         // Load translations for continents and cities
3687         if ( !$mo_loaded ) {
3688                 $locale = get_locale();
3689                 $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
3690                 load_textdomain( 'continents-cities', $mofile );
3691                 $mo_loaded = true;
3692         }
3693
3694         $zonen = array();
3695         foreach ( timezone_identifiers_list() as $zone ) {
3696                 $zone = explode( '/', $zone );
3697                 if ( !in_array( $zone[0], $continents ) ) {
3698                         continue;
3699                 }
3700
3701                 // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
3702                 $exists = array(
3703                         0 => ( isset( $zone[0] ) && $zone[0] ),
3704                         1 => ( isset( $zone[1] ) && $zone[1] ),
3705                         2 => ( isset( $zone[2] ) && $zone[2] ),
3706                 );
3707                 $exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
3708                 $exists[4] = ( $exists[1] && $exists[3] );
3709                 $exists[5] = ( $exists[2] && $exists[3] );
3710
3711                 $zonen[] = array(
3712                         'continent'   => ( $exists[0] ? $zone[0] : '' ),
3713                         'city'        => ( $exists[1] ? $zone[1] : '' ),
3714                         'subcity'     => ( $exists[2] ? $zone[2] : '' ),
3715                         't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
3716                         't_city'      => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
3717                         't_subcity'   => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' )
3718                 );
3719         }
3720         usort( $zonen, '_wp_timezone_choice_usort_callback' );
3721
3722         $structure = array();
3723
3724         if ( empty( $selected_zone ) ) {
3725                 $structure[] = '<option selected="selected" value="">' . __( 'Select a city' ) . '</option>';
3726         }
3727
3728         foreach ( $zonen as $key => $zone ) {
3729                 // Build value in an array to join later
3730                 $value = array( $zone['continent'] );
3731
3732                 if ( empty( $zone['city'] ) ) {
3733                         // It's at the continent level (generally won't happen)
3734                         $display = $zone['t_continent'];
3735                 } else {
3736                         // It's inside a continent group
3737
3738                         // Continent optgroup
3739                         if ( !isset( $zonen[$key - 1] ) || $zonen[$key - 1]['continent'] !== $zone['continent'] ) {
3740                                 $label = $zone['t_continent'];
3741                                 $structure[] = '<optgroup label="'. esc_attr( $label ) .'">';
3742                         }
3743
3744                         // Add the city to the value
3745                         $value[] = $zone['city'];
3746
3747                         $display = $zone['t_city'];
3748                         if ( !empty( $zone['subcity'] ) ) {
3749                                 // Add the subcity to the value
3750                                 $value[] = $zone['subcity'];
3751                                 $display .= ' - ' . $zone['t_subcity'];