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