]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/functions.php
aea813b7d007880cd447594a51bae0832ff543d0
[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         if ( $target_parent && '.' != $target_parent ) {
1376                 $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                 return true;
1384         }
1385
1386         return false;
1387 }
1388
1389 /**
1390  * Test if a give filesystem path is absolute ('/foo/bar', 'c:\windows').
1391  *
1392  * @since 2.5.0
1393  *
1394  * @param string $path File path
1395  * @return bool True if path is absolute, false is not absolute.
1396  */
1397 function path_is_absolute( $path ) {
1398         // this is definitive if true but fails if $path does not exist or contains a symbolic link
1399         if ( realpath($path) == $path )
1400                 return true;
1401
1402         if ( strlen($path) == 0 || $path[0] == '.' )
1403                 return false;
1404
1405         // windows allows absolute paths like this
1406         if ( preg_match('#^[a-zA-Z]:\\\\#', $path) )
1407                 return true;
1408
1409         // a path starting with / or \ is absolute; anything else is relative
1410         return ( $path[0] == '/' || $path[0] == '\\' );
1411 }
1412
1413 /**
1414  * Join two filesystem paths together (e.g. 'give me $path relative to $base').
1415  *
1416  * If the $path is absolute, then it the full path is returned.
1417  *
1418  * @since 2.5.0
1419  *
1420  * @param string $base
1421  * @param string $path
1422  * @return string The path with the base or absolute path.
1423  */
1424 function path_join( $base, $path ) {
1425         if ( path_is_absolute($path) )
1426                 return $path;
1427
1428         return rtrim($base, '/') . '/' . ltrim($path, '/');
1429 }
1430
1431 /**
1432  * Determines a writable directory for temporary files.
1433  * Function's preference is the return value of <code>sys_get_temp_dir()</code>,
1434  * followed by your PHP temporary upload directory, followed by WP_CONTENT_DIR,
1435  * before finally defaulting to /tmp/
1436  *
1437  * In the event that this function does not find a writable location,
1438  * It may be overridden by the <code>WP_TEMP_DIR</code> constant in
1439  * your <code>wp-config.php</code> file.
1440  *
1441  * @since 2.5.0
1442  *
1443  * @return string Writable temporary directory
1444  */
1445 function get_temp_dir() {
1446         static $temp;
1447         if ( defined('WP_TEMP_DIR') )
1448                 return trailingslashit(WP_TEMP_DIR);
1449
1450         if ( $temp )
1451                 return trailingslashit( rtrim( $temp, '\\' ) );
1452
1453         if ( function_exists('sys_get_temp_dir') ) {
1454                 $temp = sys_get_temp_dir();
1455                 if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
1456                         return trailingslashit( rtrim( $temp, '\\' ) );
1457         }
1458
1459         $temp = ini_get('upload_tmp_dir');
1460         if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
1461                 return trailingslashit( rtrim( $temp, '\\' ) );
1462
1463         $temp = WP_CONTENT_DIR . '/';
1464         if ( is_dir( $temp ) && wp_is_writable( $temp ) )
1465                 return $temp;
1466
1467         $temp = '/tmp/';
1468         return $temp;
1469 }
1470
1471 /**
1472  * Determine if a directory is writable.
1473  *
1474  * This function is used to work around certain ACL issues
1475  * in PHP primarily affecting Windows Servers.
1476  *
1477  * @see win_is_writable()
1478  *
1479  * @since 3.6.0
1480  *
1481  * @param string $path
1482  * @return bool
1483  */
1484 function wp_is_writable( $path ) {
1485         if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) )
1486                 return win_is_writable( $path );
1487         else
1488                 return @is_writable( $path );
1489 }
1490
1491 /**
1492  * Workaround for Windows bug in is_writable() function
1493  *
1494  * PHP has issues with Windows ACL's for determine if a
1495  * directory is writable or not, this works around them by
1496  * checking the ability to open files rather than relying
1497  * upon PHP to interprate the OS ACL.
1498  *
1499  * @link http://bugs.php.net/bug.php?id=27609
1500  * @link http://bugs.php.net/bug.php?id=30931
1501  *
1502  * @since 2.8.0
1503  *
1504  * @param string $path
1505  * @return bool
1506  */
1507 function win_is_writable( $path ) {
1508
1509         if ( $path[strlen( $path ) - 1] == '/' ) // if it looks like a directory, check a random file within the directory
1510                 return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp');
1511         else if ( is_dir( $path ) ) // If it's a directory (and not a file) check a random file within the directory
1512                 return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' );
1513
1514         // check tmp file for read/write capabilities
1515         $should_delete_tmp_file = !file_exists( $path );
1516         $f = @fopen( $path, 'a' );
1517         if ( $f === false )
1518                 return false;
1519         fclose( $f );
1520         if ( $should_delete_tmp_file )
1521                 unlink( $path );
1522         return true;
1523 }
1524
1525 /**
1526  * Get an array containing the current upload directory's path and url.
1527  *
1528  * Checks the 'upload_path' option, which should be from the web root folder,
1529  * and if it isn't empty it will be used. If it is empty, then the path will be
1530  * 'WP_CONTENT_DIR/uploads'. If the 'UPLOADS' constant is defined, then it will
1531  * override the 'upload_path' option and 'WP_CONTENT_DIR/uploads' path.
1532  *
1533  * The upload URL path is set either by the 'upload_url_path' option or by using
1534  * the 'WP_CONTENT_URL' constant and appending '/uploads' to the path.
1535  *
1536  * If the 'uploads_use_yearmonth_folders' is set to true (checkbox if checked in
1537  * the administration settings panel), then the time will be used. The format
1538  * will be year first and then month.
1539  *
1540  * If the path couldn't be created, then an error will be returned with the key
1541  * 'error' containing the error message. The error suggests that the parent
1542  * directory is not writable by the server.
1543  *
1544  * On success, the returned array will have many indices:
1545  * 'path' - base directory and sub directory or full path to upload directory.
1546  * 'url' - base url and sub directory or absolute URL to upload directory.
1547  * 'subdir' - sub directory if uploads use year/month folders option is on.
1548  * 'basedir' - path without subdir.
1549  * 'baseurl' - URL path without subdir.
1550  * 'error' - set to false.
1551  *
1552  * @since 2.0.0
1553  * @uses apply_filters() Calls 'upload_dir' on returned array.
1554  *
1555  * @param string $time Optional. Time formatted in 'yyyy/mm'.
1556  * @return array See above for description.
1557  */
1558 function wp_upload_dir( $time = null ) {
1559         $siteurl = get_option( 'siteurl' );
1560         $upload_path = trim( get_option( 'upload_path' ) );
1561
1562         if ( empty( $upload_path ) || 'wp-content/uploads' == $upload_path ) {
1563                 $dir = WP_CONTENT_DIR . '/uploads';
1564         } elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) {
1565                 // $dir is absolute, $upload_path is (maybe) relative to ABSPATH
1566                 $dir = path_join( ABSPATH, $upload_path );
1567         } else {
1568                 $dir = $upload_path;
1569         }
1570
1571         if ( !$url = get_option( 'upload_url_path' ) ) {
1572                 if ( empty($upload_path) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) )
1573                         $url = WP_CONTENT_URL . '/uploads';
1574                 else
1575                         $url = trailingslashit( $siteurl ) . $upload_path;
1576         }
1577
1578         // Obey the value of UPLOADS. This happens as long as ms-files rewriting is disabled.
1579         // We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
1580         if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
1581                 $dir = ABSPATH . UPLOADS;
1582                 $url = trailingslashit( $siteurl ) . UPLOADS;
1583         }
1584
1585         // If multisite (and if not the main site in a post-MU network)
1586         if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) {
1587
1588                 if ( ! get_site_option( 'ms_files_rewriting' ) ) {
1589                         // If ms-files rewriting is disabled (networks created post-3.5), it is fairly straightforward:
1590                         // Append sites/%d if we're not on the main site (for post-MU networks). (The extra directory
1591                         // prevents a four-digit ID from conflicting with a year-based directory for the main site.
1592                         // But if a MU-era network has disabled ms-files rewriting manually, they don't need the extra
1593                         // directory, as they never had wp-content/uploads for the main site.)
1594
1595                         if ( defined( 'MULTISITE' ) )
1596                                 $ms_dir = '/sites/' . get_current_blog_id();
1597                         else
1598                                 $ms_dir = '/' . get_current_blog_id();
1599
1600                         $dir .= $ms_dir;
1601                         $url .= $ms_dir;
1602
1603                 } elseif ( defined( 'UPLOADS' ) && ! ms_is_switched() ) {
1604                         // Handle the old-form ms-files.php rewriting if the network still has that enabled.
1605                         // When ms-files rewriting is enabled, then we only listen to UPLOADS when:
1606                         //   1) we are not on the main site in a post-MU network,
1607                         //      as wp-content/uploads is used there, and
1608                         //   2) we are not switched, as ms_upload_constants() hardcodes
1609                         //      these constants to reflect the original blog ID.
1610                         //
1611                         // Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute.
1612                         // (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as
1613                         // as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files
1614                         // rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
1615
1616                         if ( defined( 'BLOGUPLOADDIR' ) )
1617                                 $dir = untrailingslashit( BLOGUPLOADDIR );
1618                         else
1619                                 $dir = ABSPATH . UPLOADS;
1620                         $url = trailingslashit( $siteurl ) . 'files';
1621                 }
1622         }
1623
1624         $basedir = $dir;
1625         $baseurl = $url;
1626
1627         $subdir = '';
1628         if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
1629                 // Generate the yearly and monthly dirs
1630                 if ( !$time )
1631                         $time = current_time( 'mysql' );
1632                 $y = substr( $time, 0, 4 );
1633                 $m = substr( $time, 5, 2 );
1634                 $subdir = "/$y/$m";
1635         }
1636
1637         $dir .= $subdir;
1638         $url .= $subdir;
1639
1640         $uploads = apply_filters( 'upload_dir',
1641                 array(
1642                         'path'    => $dir,
1643                         'url'     => $url,
1644                         'subdir'  => $subdir,
1645                         'basedir' => $basedir,
1646                         'baseurl' => $baseurl,
1647                         'error'   => false,
1648                 ) );
1649
1650         // Make sure we have an uploads dir
1651         if ( ! wp_mkdir_p( $uploads['path'] ) ) {
1652                 if ( 0 === strpos( $uploads['basedir'], ABSPATH ) )
1653                         $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
1654                 else
1655                         $error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
1656
1657                 $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
1658                 $uploads['error'] = $message;
1659         }
1660
1661         return $uploads;
1662 }
1663
1664 /**
1665  * Get a filename that is sanitized and unique for the given directory.
1666  *
1667  * If the filename is not unique, then a number will be added to the filename
1668  * before the extension, and will continue adding numbers until the filename is
1669  * unique.
1670  *
1671  * The callback is passed three parameters, the first one is the directory, the
1672  * second is the filename, and the third is the extension.
1673  *
1674  * @since 2.5.0
1675  *
1676  * @param string $dir
1677  * @param string $filename
1678  * @param mixed $unique_filename_callback Callback.
1679  * @return string New filename, if given wasn't unique.
1680  */
1681 function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) {
1682         // sanitize the file name before we begin processing
1683         $filename = sanitize_file_name($filename);
1684
1685         // separate the filename into a name and extension
1686         $info = pathinfo($filename);
1687         $ext = !empty($info['extension']) ? '.' . $info['extension'] : '';
1688         $name = basename($filename, $ext);
1689
1690         // edge case: if file is named '.ext', treat as an empty name
1691         if ( $name === $ext )
1692                 $name = '';
1693
1694         // Increment the file number until we have a unique file to save in $dir. Use callback if supplied.
1695         if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) {
1696                 $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext );
1697         } else {
1698                 $number = '';
1699
1700                 // change '.ext' to lower case
1701                 if ( $ext && strtolower($ext) != $ext ) {
1702                         $ext2 = strtolower($ext);
1703                         $filename2 = preg_replace( '|' . preg_quote($ext) . '$|', $ext2, $filename );
1704
1705                         // check for both lower and upper case extension or image sub-sizes may be overwritten
1706                         while ( file_exists($dir . "/$filename") || file_exists($dir . "/$filename2") ) {
1707                                 $new_number = $number + 1;
1708                                 $filename = str_replace( "$number$ext", "$new_number$ext", $filename );
1709                                 $filename2 = str_replace( "$number$ext2", "$new_number$ext2", $filename2 );
1710                                 $number = $new_number;
1711                         }
1712                         return $filename2;
1713                 }
1714
1715                 while ( file_exists( $dir . "/$filename" ) ) {
1716                         if ( '' == "$number$ext" )
1717                                 $filename = $filename . ++$number . $ext;
1718                         else
1719                                 $filename = str_replace( "$number$ext", ++$number . $ext, $filename );
1720                 }
1721         }
1722
1723         return $filename;
1724 }
1725
1726 /**
1727  * Create a file in the upload folder with given content.
1728  *
1729  * If there is an error, then the key 'error' will exist with the error message.
1730  * If success, then the key 'file' will have the unique file path, the 'url' key
1731  * will have the link to the new file. and the 'error' key will be set to false.
1732  *
1733  * This function will not move an uploaded file to the upload folder. It will
1734  * create a new file with the content in $bits parameter. If you move the upload
1735  * file, read the content of the uploaded file, and then you can give the
1736  * filename and content to this function, which will add it to the upload
1737  * folder.
1738  *
1739  * The permissions will be set on the new file automatically by this function.
1740  *
1741  * @since 2.0.0
1742  *
1743  * @param string $name
1744  * @param null $deprecated Never used. Set to null.
1745  * @param mixed $bits File content
1746  * @param string $time Optional. Time formatted in 'yyyy/mm'.
1747  * @return array
1748  */
1749 function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
1750         if ( !empty( $deprecated ) )
1751                 _deprecated_argument( __FUNCTION__, '2.0' );
1752
1753         if ( empty( $name ) )
1754                 return array( 'error' => __( 'Empty filename' ) );
1755
1756         $wp_filetype = wp_check_filetype( $name );
1757         if ( ! $wp_filetype['ext'] && ! current_user_can( 'unfiltered_upload' ) )
1758                 return array( 'error' => __( 'Invalid file type' ) );
1759
1760         $upload = wp_upload_dir( $time );
1761
1762         if ( $upload['error'] !== false )
1763                 return $upload;
1764
1765         $upload_bits_error = apply_filters( 'wp_upload_bits', array( 'name' => $name, 'bits' => $bits, 'time' => $time ) );
1766         if ( !is_array( $upload_bits_error ) ) {
1767                 $upload[ 'error' ] = $upload_bits_error;
1768                 return $upload;
1769         }
1770
1771         $filename = wp_unique_filename( $upload['path'], $name );
1772
1773         $new_file = $upload['path'] . "/$filename";
1774         if ( ! wp_mkdir_p( dirname( $new_file ) ) ) {
1775                 if ( 0 === strpos( $upload['basedir'], ABSPATH ) )
1776                         $error_path = str_replace( ABSPATH, '', $upload['basedir'] ) . $upload['subdir'];
1777                 else
1778                         $error_path = basename( $upload['basedir'] ) . $upload['subdir'];
1779
1780                 $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
1781                 return array( 'error' => $message );
1782         }
1783
1784         $ifp = @ fopen( $new_file, 'wb' );
1785         if ( ! $ifp )
1786                 return array( 'error' => sprintf( __( 'Could not write file %s' ), $new_file ) );
1787
1788         @fwrite( $ifp, $bits );
1789         fclose( $ifp );
1790         clearstatcache();
1791
1792         // Set correct file permissions
1793         $stat = @ stat( dirname( $new_file ) );
1794         $perms = $stat['mode'] & 0007777;
1795         $perms = $perms & 0000666;
1796         @ chmod( $new_file, $perms );
1797         clearstatcache();
1798
1799         // Compute the URL
1800         $url = $upload['url'] . "/$filename";
1801
1802         return array( 'file' => $new_file, 'url' => $url, 'error' => false );
1803 }
1804
1805 /**
1806  * Retrieve the file type based on the extension name.
1807  *
1808  * @package WordPress
1809  * @since 2.5.0
1810  * @uses apply_filters() Calls 'ext2type' hook on default supported types.
1811  *
1812  * @param string $ext The extension to search.
1813  * @return string|null The file type, example: audio, video, document, spreadsheet, etc. Null if not found.
1814  */
1815 function wp_ext2type( $ext ) {
1816         $ext = strtolower( $ext );
1817         $ext2type = apply_filters( 'ext2type', array(
1818                 'image'       => array( 'jpg', 'jpeg', 'jpe',  'gif',  'png',  'bmp',   'tif',  'tiff', 'ico' ),
1819                 'audio'       => array( 'aac', 'ac3',  'aif',  'aiff', 'm3a',  'm4a',   'm4b',  'mka',  'mp1',  'mp2',  'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
1820                 'video'       => array( 'asf', 'avi',  'divx', 'dv',   'flv',  'm4v',   'mkv',  'mov',  'mp4',  'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt',  'rm', 'vob', 'wmv' ),
1821                 'document'    => array( 'doc', 'docx', 'docm', 'dotm', 'odt',  'pages', 'pdf',  'rtf',  'wp',   'wpd' ),
1822                 'spreadsheet' => array( 'numbers',     'ods',  'xls',  'xlsx', 'xlsm',  'xlsb' ),
1823                 'interactive' => array( 'swf', 'key',  'ppt',  'pptx', 'pptm', 'pps',   'ppsx', 'ppsm', 'sldx', 'sldm', 'odp' ),
1824                 'text'        => array( 'asc', 'csv',  'tsv',  'txt' ),
1825                 'archive'     => array( 'bz2', 'cab',  'dmg',  'gz',   'rar',  'sea',   'sit',  'sqx',  'tar',  'tgz',  'zip', '7z' ),
1826                 'code'        => array( 'css', 'htm',  'html', 'php',  'js' ),
1827         ) );
1828
1829         foreach ( $ext2type as $type => $exts )
1830                 if ( in_array( $ext, $exts ) )
1831                         return $type;
1832
1833         return null;
1834 }
1835
1836 /**
1837  * Retrieve the file type from the file name.
1838  *
1839  * You can optionally define the mime array, if needed.
1840  *
1841  * @since 2.0.4
1842  *
1843  * @param string $filename File name or path.
1844  * @param array $mimes Optional. Key is the file extension with value as the mime type.
1845  * @return array Values with extension first and mime type.
1846  */
1847 function wp_check_filetype( $filename, $mimes = null ) {
1848         if ( empty($mimes) )
1849                 $mimes = get_allowed_mime_types();
1850         $type = false;
1851         $ext = false;
1852
1853         foreach ( $mimes as $ext_preg => $mime_match ) {
1854                 $ext_preg = '!\.(' . $ext_preg . ')$!i';
1855                 if ( preg_match( $ext_preg, $filename, $ext_matches ) ) {
1856                         $type = $mime_match;
1857                         $ext = $ext_matches[1];
1858                         break;
1859                 }
1860         }
1861
1862         return compact( 'ext', 'type' );
1863 }
1864
1865 /**
1866  * Attempt to determine the real file type of a file.
1867  * If unable to, the file name extension will be used to determine type.
1868  *
1869  * If it's determined that the extension does not match the file's real type,
1870  * then the "proper_filename" value will be set with a proper filename and extension.
1871  *
1872  * Currently this function only supports validating images known to getimagesize().
1873  *
1874  * @since 3.0.0
1875  *
1876  * @param string $file Full path to the file.
1877  * @param string $filename The name of the file (may differ from $file due to $file being in a tmp directory)
1878  * @param array $mimes Optional. Key is the file extension with value as the mime type.
1879  * @return array Values for the extension, MIME, and either a corrected filename or false if original $filename is valid
1880  */
1881 function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
1882
1883         $proper_filename = false;
1884
1885         // Do basic extension validation and MIME mapping
1886         $wp_filetype = wp_check_filetype( $filename, $mimes );
1887         extract( $wp_filetype );
1888
1889         // We can't do any further validation without a file to work with
1890         if ( ! file_exists( $file ) )
1891                 return compact( 'ext', 'type', 'proper_filename' );
1892
1893         // We're able to validate images using GD
1894         if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) {
1895
1896                 // Attempt to figure out what type of image it actually is
1897                 $imgstats = @getimagesize( $file );
1898
1899                 // If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME
1900                 if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) {
1901                         // This is a simplified array of MIMEs that getimagesize() can detect and their extensions
1902                         // You shouldn't need to use this filter, but it's here just in case
1903                         $mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array(
1904                                 'image/jpeg' => 'jpg',
1905                                 'image/png'  => 'png',
1906                                 'image/gif'  => 'gif',
1907                                 'image/bmp'  => 'bmp',
1908                                 'image/tiff' => 'tif',
1909                         ) );
1910
1911                         // Replace whatever is after the last period in the filename with the correct extension
1912                         if ( ! empty( $mime_to_ext[ $imgstats['mime'] ] ) ) {
1913                                 $filename_parts = explode( '.', $filename );
1914                                 array_pop( $filename_parts );
1915                                 $filename_parts[] = $mime_to_ext[ $imgstats['mime'] ];
1916                                 $new_filename = implode( '.', $filename_parts );
1917
1918                                 if ( $new_filename != $filename )
1919                                         $proper_filename = $new_filename; // Mark that it changed
1920
1921                                 // Redefine the extension / MIME
1922                                 $wp_filetype = wp_check_filetype( $new_filename, $mimes );
1923                                 extract( $wp_filetype );
1924                         }
1925                 }
1926         }
1927
1928         // Let plugins try and validate other types of files
1929         // Should return an array in the style of array( 'ext' => $ext, 'type' => $type, 'proper_filename' => $proper_filename )
1930         return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes );
1931 }
1932
1933 /**
1934  * Retrieve list of mime types and file extensions.
1935  *
1936  * @since 3.5.0
1937  *
1938  * @uses apply_filters() Calls 'mime_types' on returned array. This filter should
1939  * be used to add types, not remove them. To remove types use the upload_mimes filter.
1940  *
1941  * @return array Array of mime types keyed by the file extension regex corresponding to those types.
1942  */
1943 function wp_get_mime_types() {
1944         // Accepted MIME types are set here as PCRE unless provided.
1945         return apply_filters( 'mime_types', array(
1946         // Image formats
1947         'jpg|jpeg|jpe' => 'image/jpeg',
1948         'gif' => 'image/gif',
1949         'png' => 'image/png',
1950         'bmp' => 'image/bmp',
1951         'tif|tiff' => 'image/tiff',
1952         'ico' => 'image/x-icon',
1953         // Video formats
1954         'asf|asx' => 'video/x-ms-asf',
1955         'wmv' => 'video/x-ms-wmv',
1956         'wmx' => 'video/x-ms-wmx',
1957         'wm' => 'video/x-ms-wm',
1958         'avi' => 'video/avi',
1959         'divx' => 'video/divx',
1960         'flv' => 'video/x-flv',
1961         'mov|qt' => 'video/quicktime',
1962         'mpeg|mpg|mpe' => 'video/mpeg',
1963         'mp4|m4v' => 'video/mp4',
1964         'ogv' => 'video/ogg',
1965         'webm' => 'video/webm',
1966         'mkv' => 'video/x-matroska',
1967         // Text formats
1968         'txt|asc|c|cc|h' => 'text/plain',
1969         'csv' => 'text/csv',
1970         'tsv' => 'text/tab-separated-values',
1971         'ics' => 'text/calendar',
1972         'rtx' => 'text/richtext',
1973         'css' => 'text/css',
1974         'htm|html' => 'text/html',
1975         // Audio formats
1976         'mp3|m4a|m4b' => 'audio/mpeg',
1977         'ra|ram' => 'audio/x-realaudio',
1978         'wav' => 'audio/wav',
1979         'ogg|oga' => 'audio/ogg',
1980         'mid|midi' => 'audio/midi',
1981         'wma' => 'audio/x-ms-wma',
1982         'wax' => 'audio/x-ms-wax',
1983         'mka' => 'audio/x-matroska',
1984         // Misc application formats
1985         'rtf' => 'application/rtf',
1986         'js' => 'application/javascript',
1987         'pdf' => 'application/pdf',
1988         'swf' => 'application/x-shockwave-flash',
1989         'class' => 'application/java',
1990         'tar' => 'application/x-tar',
1991         'zip' => 'application/zip',
1992         'gz|gzip' => 'application/x-gzip',
1993         'rar' => 'application/rar',
1994         '7z' => 'application/x-7z-compressed',
1995         'exe' => 'application/x-msdownload',
1996         // MS Office formats
1997         'doc' => 'application/msword',
1998         'pot|pps|ppt' => 'application/vnd.ms-powerpoint',
1999         'wri' => 'application/vnd.ms-write',
2000         'xla|xls|xlt|xlw' => 'application/vnd.ms-excel',
2001         'mdb' => 'application/vnd.ms-access',
2002         'mpp' => 'application/vnd.ms-project',
2003         'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
2004         'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
2005         'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
2006         'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
2007         'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
2008         'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
2009         'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
2010         'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
2011         'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
2012         'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
2013         'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
2014         'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
2015         'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
2016         'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
2017         'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
2018         'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
2019         'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
2020         'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
2021         'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
2022         'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
2023         // OpenOffice formats
2024         'odt' => 'application/vnd.oasis.opendocument.text',
2025         'odp' => 'application/vnd.oasis.opendocument.presentation',
2026         'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
2027         'odg' => 'application/vnd.oasis.opendocument.graphics',
2028         'odc' => 'application/vnd.oasis.opendocument.chart',
2029         'odb' => 'application/vnd.oasis.opendocument.database',
2030         'odf' => 'application/vnd.oasis.opendocument.formula',
2031         // WordPerfect formats
2032         'wp|wpd' => 'application/wordperfect',
2033         // iWork formats
2034         'key' => 'application/vnd.apple.keynote',
2035         'numbers' => 'application/vnd.apple.numbers',
2036         'pages' => 'application/vnd.apple.pages',
2037         ) );
2038 }
2039 /**
2040  * Retrieve list of allowed mime types and file extensions.
2041  *
2042  * @since 2.8.6
2043  *
2044  * @uses apply_filters() Calls 'upload_mimes' on returned array
2045  * @uses wp_get_upload_mime_types() to fetch the list of mime types
2046  *
2047  * @param int|WP_User $user Optional. User to check. Defaults to current user.
2048  * @return array Array of mime types keyed by the file extension regex corresponding to those types.
2049  */
2050 function get_allowed_mime_types( $user = null ) {
2051         $t = wp_get_mime_types();
2052
2053         unset( $t['swf'], $t['exe'] );
2054         if ( function_exists( 'current_user_can' ) )
2055                 $unfiltered = $user ? user_can( $user, 'unfiltered_html' ) : current_user_can( 'unfiltered_html' );
2056
2057         if ( empty( $unfiltered ) )
2058                 unset( $t['htm|html'] );
2059
2060         return apply_filters( 'upload_mimes', $t, $user );
2061 }
2062
2063 /**
2064  * Display "Are You Sure" message to confirm the action being taken.
2065  *
2066  * If the action has the nonce explain message, then it will be displayed along
2067  * with the "Are you sure?" message.
2068  *
2069  * @package WordPress
2070  * @subpackage Security
2071  * @since 2.0.4
2072  *
2073  * @param string $action The nonce action.
2074  */
2075 function wp_nonce_ays( $action ) {
2076         $title = __( 'WordPress Failure Notice' );
2077         if ( 'log-out' == $action ) {
2078                 $html = sprintf( __( 'You are attempting to log out of %s' ), get_bloginfo( 'name' ) ) . '</p><p>';
2079                 $html .= sprintf( __( "Do you really want to <a href='%s'>log out</a>?"), wp_logout_url() );
2080         } else {
2081                 $html = __( 'Are you sure you want to do this?' );
2082                 if ( wp_get_referer() )
2083                         $html .= "</p><p><a href='" . esc_url( remove_query_arg( 'updated', wp_get_referer() ) ) . "'>" . __( 'Please try again.' ) . "</a>";
2084         }
2085
2086         wp_die( $html, $title, array('response' => 403) );
2087 }
2088
2089 /**
2090  * Kill WordPress execution and display HTML message with error message.
2091  *
2092  * This function complements the die() PHP function. The difference is that
2093  * HTML will be displayed to the user. It is recommended to use this function
2094  * only, when the execution should not continue any further. It is not
2095  * recommended to call this function very often and try to handle as many errors
2096  * as possible silently.
2097  *
2098  * @since 2.0.4
2099  *
2100  * @param string $message Error message.
2101  * @param string $title Error title.
2102  * @param string|array $args Optional arguments to control behavior.
2103  */
2104 function wp_die( $message = '', $title = '', $args = array() ) {
2105         if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
2106                 $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
2107         elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST )
2108                 $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
2109         else
2110                 $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
2111
2112         call_user_func( $function, $message, $title, $args );
2113 }
2114
2115 /**
2116  * Kill WordPress execution and display HTML message with error message.
2117  *
2118  * This is the default handler for wp_die if you want a custom one for your
2119  * site then you can overload using the wp_die_handler filter in wp_die
2120  *
2121  * @since 3.0.0
2122  * @access private
2123  *
2124  * @param string $message Error message.
2125  * @param string $title Error title.
2126  * @param string|array $args Optional arguments to control behavior.
2127  */
2128 function _default_wp_die_handler( $message, $title = '', $args = array() ) {
2129         $defaults = array( 'response' => 500 );
2130         $r = wp_parse_args($args, $defaults);
2131
2132         $have_gettext = function_exists('__');
2133
2134         if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) {
2135                 if ( empty( $title ) ) {
2136                         $error_data = $message->get_error_data();
2137                         if ( is_array( $error_data ) && isset( $error_data['title'] ) )
2138                                 $title = $error_data['title'];
2139                 }
2140                 $errors = $message->get_error_messages();
2141                 switch ( count( $errors ) ) :
2142                 case 0 :
2143                         $message = '';
2144                         break;
2145                 case 1 :
2146                         $message = "<p>{$errors[0]}</p>";
2147                         break;
2148                 default :
2149                         $message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $errors ) . "</li>\n\t</ul>";
2150                         break;
2151                 endswitch;
2152         } elseif ( is_string( $message ) ) {
2153                 $message = "<p>$message</p>";
2154         }
2155
2156         if ( isset( $r['back_link'] ) && $r['back_link'] ) {
2157                 $back_text = $have_gettext? __('&laquo; Back') : '&laquo; Back';
2158                 $message .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
2159         }
2160
2161         if ( ! did_action( 'admin_head' ) ) :
2162                 if ( !headers_sent() ) {
2163                         status_header( $r['response'] );
2164                         nocache_headers();
2165                         header( 'Content-Type: text/html; charset=utf-8' );
2166                 }
2167
2168                 if ( empty($title) )
2169                         $title = $have_gettext ? __('WordPress &rsaquo; Error') : 'WordPress &rsaquo; Error';
2170
2171                 $text_direction = 'ltr';
2172                 if ( isset($r['text_direction']) && 'rtl' == $r['text_direction'] )
2173                         $text_direction = 'rtl';
2174                 elseif ( function_exists( 'is_rtl' ) && is_rtl() )
2175                         $text_direction = 'rtl';
2176 ?>
2177 <!DOCTYPE html>
2178 <!-- 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
2179 -->
2180 <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'"; ?>>
2181 <head>
2182         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2183         <title><?php echo $title ?></title>
2184         <style type="text/css">
2185                 html {
2186                         background: #f9f9f9;
2187                 }
2188                 body {
2189                         background: #fff;
2190                         color: #333;
2191                         font-family: sans-serif;
2192                         margin: 2em auto;
2193                         padding: 1em 2em;
2194                         -webkit-border-radius: 3px;
2195                         border-radius: 3px;
2196                         border: 1px solid #dfdfdf;
2197                         max-width: 700px;
2198                 }
2199                 h1 {
2200                         border-bottom: 1px solid #dadada;
2201                         clear: both;
2202                         color: #666;
2203                         font: 24px Georgia, "Times New Roman", Times, serif;
2204                         margin: 30px 0 0 0;
2205                         padding: 0;
2206                         padding-bottom: 7px;
2207                 }
2208                 #error-page {
2209                         margin-top: 50px;
2210                 }
2211                 #error-page p {
2212                         font-size: 14px;
2213                         line-height: 1.5;
2214                         margin: 25px 0 20px;
2215                 }
2216                 #error-page code {
2217                         font-family: Consolas, Monaco, monospace;
2218                 }
2219                 ul li {
2220                         margin-bottom: 10px;
2221                         font-size: 14px ;
2222                 }
2223                 a {
2224                         color: #21759B;
2225                         text-decoration: none;
2226                 }
2227                 a:hover {
2228                         color: #D54E21;
2229                 }
2230                 .button {
2231                         display: inline-block;
2232                         text-decoration: none;
2233                         font-size: 14px;
2234                         line-height: 23px;
2235                         height: 24px;
2236                         margin: 0;
2237                         padding: 0 10px 1px;
2238                         cursor: pointer;
2239                         border-width: 1px;
2240                         border-style: solid;
2241                         -webkit-border-radius: 3px;
2242                         border-radius: 3px;
2243                         white-space: nowrap;
2244                         -webkit-box-sizing: border-box;
2245                         -moz-box-sizing:    border-box;
2246                         box-sizing:         border-box;
2247                         background: #f3f3f3;
2248                         background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#f4f4f4));
2249                         background-image: -webkit-linear-gradient(top, #fefefe, #f4f4f4);
2250                         background-image:    -moz-linear-gradient(top, #fefefe, #f4f4f4);
2251                         background-image:      -o-linear-gradient(top, #fefefe, #f4f4f4);
2252                         background-image:   linear-gradient(to bottom, #fefefe, #f4f4f4);
2253                         border-color: #bbb;
2254                         color: #333;
2255                         text-shadow: 0 1px 0 #fff;
2256                 }
2257
2258                 .button.button-large {
2259                         height: 29px;
2260                         line-height: 28px;
2261                         padding: 0 12px;
2262                 }
2263
2264                 .button:hover,
2265                 .button:focus {
2266                         background: #f3f3f3;
2267                         background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f3f3f3));
2268                         background-image: -webkit-linear-gradient(top, #fff, #f3f3f3);
2269                         background-image:    -moz-linear-gradient(top, #fff, #f3f3f3);
2270                         background-image:     -ms-linear-gradient(top, #fff, #f3f3f3);
2271                         background-image:      -o-linear-gradient(top, #fff, #f3f3f3);
2272                         background-image:   linear-gradient(to bottom, #fff, #f3f3f3);
2273                         border-color: #999;
2274                         color: #222;
2275                 }
2276
2277                 .button:focus  {
2278                         -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,.2);
2279                         box-shadow: 1px 1px 1px rgba(0,0,0,.2);
2280                 }
2281
2282                 .button:active {
2283                         outline: none;
2284                         background: #eee;
2285                         background-image: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#fefefe));
2286                         background-image: -webkit-linear-gradient(top, #f4f4f4, #fefefe);
2287                         background-image:    -moz-linear-gradient(top, #f4f4f4, #fefefe);
2288                         background-image:     -ms-linear-gradient(top, #f4f4f4, #fefefe);
2289                         background-image:      -o-linear-gradient(top, #f4f4f4, #fefefe);
2290                         background-image:   linear-gradient(to bottom, #f4f4f4, #fefefe);
2291                         border-color: #999;
2292                         color: #333;
2293                         text-shadow: 0 -1px 0 #fff;
2294                         -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2295                         box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2296                 }
2297
2298                 <?php if ( 'rtl' == $text_direction ) : ?>
2299                 body { font-family: Tahoma, Arial; }
2300                 <?php endif; ?>
2301         </style>
2302 </head>
2303 <body id="error-page">
2304 <?php endif; // ! did_action( 'admin_head' ) ?>
2305         <?php echo $message; ?>
2306 </body>
2307 </html>
2308 <?php
2309         die();
2310 }
2311
2312 /**
2313  * Kill WordPress execution and display XML message with error message.
2314  *
2315  * This is the handler for wp_die when processing XMLRPC requests.
2316  *
2317  * @since 3.2.0
2318  * @access private
2319  *
2320  * @param string $message Error message.
2321  * @param string $title Error title.
2322  * @param string|array $args Optional arguments to control behavior.
2323  */
2324 function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) {
2325         global $wp_xmlrpc_server;
2326         $defaults = array( 'response' => 500 );
2327
2328         $r = wp_parse_args($args, $defaults);
2329
2330         if ( $wp_xmlrpc_server ) {
2331                 $error = new IXR_Error( $r['response'] , $message);
2332                 $wp_xmlrpc_server->output( $error->getXml() );
2333         }
2334         die();
2335 }
2336
2337 /**
2338  * Kill WordPress ajax execution.
2339  *
2340  * This is the handler for wp_die when processing Ajax requests.
2341  *
2342  * @since 3.4.0
2343  * @access private
2344  *
2345  * @param string $message Optional. Response to print.
2346  */
2347 function _ajax_wp_die_handler( $message = '' ) {
2348         if ( is_scalar( $message ) )
2349                 die( (string) $message );
2350         die( '0' );
2351 }
2352
2353 /**
2354  * Kill WordPress execution.
2355  *
2356  * This is the handler for wp_die when processing APP requests.
2357  *
2358  * @since 3.4.0
2359  * @access private
2360  *
2361  * @param string $message Optional. Response to print.
2362  */
2363 function _scalar_wp_die_handler( $message = '' ) {
2364         if ( is_scalar( $message ) )
2365                 die( (string) $message );
2366         die();
2367 }
2368
2369 /**
2370  * Send a JSON response back to an Ajax request.
2371  *
2372  * @since 3.5.0
2373  *
2374  * @param mixed $response Variable (usually an array or object) to encode as JSON, then print and die.
2375  */
2376 function wp_send_json( $response ) {
2377         @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
2378         echo json_encode( $response );
2379         if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
2380                 wp_die();
2381         else
2382                 die;
2383 }
2384
2385 /**
2386  * Send a JSON response back to an Ajax request, indicating success.
2387  *
2388  * @since 3.5.0
2389  *
2390  * @param mixed $data Data to encode as JSON, then print and die.
2391  */
2392 function wp_send_json_success( $data = null ) {
2393         $response = array( 'success' => true );
2394
2395         if ( isset( $data ) )
2396                 $response['data'] = $data;
2397
2398         wp_send_json( $response );
2399 }
2400
2401 /**
2402  * Send a JSON response back to an Ajax request, indicating failure.
2403  *
2404  * @since 3.5.0
2405  *
2406  * @param mixed $data Data to encode as JSON, then print and die.
2407  */
2408 function wp_send_json_error( $data = null ) {
2409         $response = array( 'success' => false );
2410
2411         if ( isset( $data ) )
2412                 $response['data'] = $data;
2413
2414         wp_send_json( $response );
2415 }
2416
2417 /**
2418  * Retrieve the WordPress home page URL.
2419  *
2420  * If the constant named 'WP_HOME' exists, then it will be used and returned by
2421  * the function. This can be used to counter the redirection on your local
2422  * development environment.
2423  *
2424  * @access private
2425  * @package WordPress
2426  * @since 2.2.0
2427  *
2428  * @param string $url URL for the home location
2429  * @return string Homepage location.
2430  */
2431 function _config_wp_home( $url = '' ) {
2432         if ( defined( 'WP_HOME' ) )
2433                 return untrailingslashit( WP_HOME );
2434         return $url;
2435 }
2436
2437 /**
2438  * Retrieve the WordPress site URL.
2439  *
2440  * If the constant named 'WP_SITEURL' is defined, then the value in that
2441  * constant will always be returned. This can be used for debugging a site on
2442  * your localhost while not having to change the database to your URL.
2443  *
2444  * @access private
2445  * @package WordPress
2446  * @since 2.2.0
2447  *
2448  * @param string $url URL to set the WordPress site location.
2449  * @return string The WordPress Site URL
2450  */
2451 function _config_wp_siteurl( $url = '' ) {
2452         if ( defined( 'WP_SITEURL' ) )
2453                 return untrailingslashit( WP_SITEURL );
2454         return $url;
2455 }
2456
2457 /**
2458  * Set the localized direction for MCE plugin.
2459  *
2460  * Will only set the direction to 'rtl', if the WordPress locale has the text
2461  * direction set to 'rtl'.
2462  *
2463  * Fills in the 'directionality', 'plugins', and 'theme_advanced_button1' array
2464  * keys. These keys are then returned in the $input array.
2465  *
2466  * @access private
2467  * @package WordPress
2468  * @subpackage MCE
2469  * @since 2.1.0
2470  *
2471  * @param array $input MCE plugin array.
2472  * @return array Direction set for 'rtl', if needed by locale.
2473  */
2474 function _mce_set_direction( $input ) {
2475         if ( is_rtl() ) {
2476                 $input['directionality'] = 'rtl';
2477                 $input['plugins'] .= ',directionality';
2478                 $input['theme_advanced_buttons1'] .= ',ltr';
2479         }
2480
2481         return $input;
2482 }
2483
2484 /**
2485  * Convert smiley code to the icon graphic file equivalent.
2486  *
2487  * You can turn off smilies, by going to the write setting screen and unchecking
2488  * the box, or by setting 'use_smilies' option to false or removing the option.
2489  *
2490  * Plugins may override the default smiley list by setting the $wpsmiliestrans
2491  * to an array, with the key the code the blogger types in and the value the
2492  * image file.
2493  *
2494  * The $wp_smiliessearch global is for the regular expression and is set each
2495  * time the function is called.
2496  *
2497  * The full list of smilies can be found in the function and won't be listed in
2498  * the description. Probably should create a Codex page for it, so that it is
2499  * available.
2500  *
2501  * @global array $wpsmiliestrans
2502  * @global array $wp_smiliessearch
2503  * @since 2.2.0
2504  */
2505 function smilies_init() {
2506         global $wpsmiliestrans, $wp_smiliessearch;
2507
2508         // don't bother setting up smilies if they are disabled
2509         if ( !get_option( 'use_smilies' ) )
2510                 return;
2511
2512         if ( !isset( $wpsmiliestrans ) ) {
2513                 $wpsmiliestrans = array(
2514                 ':mrgreen:' => 'icon_mrgreen.gif',
2515                 ':neutral:' => 'icon_neutral.gif',
2516                 ':twisted:' => 'icon_twisted.gif',
2517                   ':arrow:' => 'icon_arrow.gif',
2518                   ':shock:' => 'icon_eek.gif',
2519                   ':smile:' => 'icon_smile.gif',
2520                     ':???:' => 'icon_confused.gif',
2521                    ':cool:' => 'icon_cool.gif',
2522                    ':evil:' => 'icon_evil.gif',
2523                    ':grin:' => 'icon_biggrin.gif',
2524                    ':idea:' => 'icon_idea.gif',
2525                    ':oops:' => 'icon_redface.gif',
2526                    ':razz:' => 'icon_razz.gif',
2527                    ':roll:' => 'icon_rolleyes.gif',
2528                    ':wink:' => 'icon_wink.gif',
2529                     ':cry:' => 'icon_cry.gif',
2530                     ':eek:' => 'icon_surprised.gif',
2531                     ':lol:' => 'icon_lol.gif',
2532                     ':mad:' => 'icon_mad.gif',
2533                     ':sad:' => 'icon_sad.gif',
2534                       '8-)' => 'icon_cool.gif',
2535                       '8-O' => 'icon_eek.gif',
2536                       ':-(' => 'icon_sad.gif',
2537                       ':-)' => 'icon_smile.gif',
2538                       ':-?' => 'icon_confused.gif',
2539                       ':-D' => 'icon_biggrin.gif',
2540                       ':-P' => 'icon_razz.gif',
2541                       ':-o' => 'icon_surprised.gif',
2542                       ':-x' => 'icon_mad.gif',
2543                       ':-|' => 'icon_neutral.gif',
2544                       ';-)' => 'icon_wink.gif',
2545                 // This one transformation breaks regular text with frequency.
2546                 //     '8)' => 'icon_cool.gif',
2547                        '8O' => 'icon_eek.gif',
2548                        ':(' => 'icon_sad.gif',
2549                        ':)' => 'icon_smile.gif',
2550                        ':?' => 'icon_confused.gif',
2551                        ':D' => 'icon_biggrin.gif',
2552                        ':P' => 'icon_razz.gif',
2553                        ':o' => 'icon_surprised.gif',
2554                        ':x' => 'icon_mad.gif',
2555                        ':|' => 'icon_neutral.gif',
2556                        ';)' => 'icon_wink.gif',
2557                       ':!:' => 'icon_exclaim.gif',
2558                       ':?:' => 'icon_question.gif',
2559                 );
2560         }
2561
2562         if (count($wpsmiliestrans) == 0) {
2563                 return;
2564         }
2565
2566         /*
2567          * NOTE: we sort the smilies in reverse key order. This is to make sure
2568          * we match the longest possible smilie (:???: vs :?) as the regular
2569          * expression used below is first-match
2570          */
2571         krsort($wpsmiliestrans);
2572
2573         $wp_smiliessearch = '/(?:\s|^)';
2574
2575         $subchar = '';
2576         foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
2577                 $firstchar = substr($smiley, 0, 1);
2578                 $rest = substr($smiley, 1);
2579
2580                 // new subpattern?
2581                 if ($firstchar != $subchar) {
2582                         if ($subchar != '') {
2583                                 $wp_smiliessearch .= ')|(?:\s|^)';
2584                         }
2585                         $subchar = $firstchar;
2586                         $wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:';
2587                 } else {
2588                         $wp_smiliessearch .= '|';
2589                 }
2590                 $wp_smiliessearch .= preg_quote($rest, '/');
2591         }
2592
2593         $wp_smiliessearch .= ')(?:\s|$)/m';
2594 }
2595
2596 /**
2597  * Merge user defined arguments into defaults array.
2598  *
2599  * This function is used throughout WordPress to allow for both string or array
2600  * to be merged into another array.
2601  *
2602  * @since 2.2.0
2603  *
2604  * @param string|array $args Value to merge with $defaults
2605  * @param array $defaults Array that serves as the defaults.
2606  * @return array Merged user defined values with defaults.
2607  */
2608 function wp_parse_args( $args, $defaults = '' ) {
2609         if ( is_object( $args ) )
2610                 $r = get_object_vars( $args );
2611         elseif ( is_array( $args ) )
2612                 $r =& $args;
2613         else
2614                 wp_parse_str( $args, $r );
2615
2616         if ( is_array( $defaults ) )
2617                 return array_merge( $defaults, $r );
2618         return $r;
2619 }
2620
2621 /**
2622  * Clean up an array, comma- or space-separated list of IDs.
2623  *
2624  * @since 3.0.0
2625  *
2626  * @param array|string $list
2627  * @return array Sanitized array of IDs
2628  */
2629 function wp_parse_id_list( $list ) {
2630         if ( !is_array($list) )
2631                 $list = preg_split('/[\s,]+/', $list);
2632
2633         return array_unique(array_map('absint', $list));
2634 }
2635
2636 /**
2637  * Extract a slice of an array, given a list of keys.
2638  *
2639  * @since 3.1.0
2640  *
2641  * @param array $array The original array
2642  * @param array $keys The list of keys
2643  * @return array The array slice
2644  */
2645 function wp_array_slice_assoc( $array, $keys ) {
2646         $slice = array();
2647         foreach ( $keys as $key )
2648                 if ( isset( $array[ $key ] ) )
2649                         $slice[ $key ] = $array[ $key ];
2650
2651         return $slice;
2652 }
2653
2654 /**
2655  * Filters a list of objects, based on a set of key => value arguments.
2656  *
2657  * @since 3.0.0
2658  *
2659  * @param array $list An array of objects to filter
2660  * @param array $args An array of key => value arguments to match against each object
2661  * @param string $operator The logical operation to perform. 'or' means only one element
2662  *      from the array needs to match; 'and' means all elements must match. The default is 'and'.
2663  * @param bool|string $field A field from the object to place instead of the entire object
2664  * @return array A list of objects or object fields
2665  */
2666 function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) {
2667         if ( ! is_array( $list ) )
2668                 return array();
2669
2670         $list = wp_list_filter( $list, $args, $operator );
2671
2672         if ( $field )
2673                 $list = wp_list_pluck( $list, $field );
2674
2675         return $list;
2676 }
2677
2678 /**
2679  * Filters a list of objects, based on a set of key => value arguments.
2680  *
2681  * @since 3.1.0
2682  *
2683  * @param array $list An array of objects to filter
2684  * @param array $args An array of key => value arguments to match against each object
2685  * @param string $operator The logical operation to perform:
2686  *    'AND' means all elements from the array must match;
2687  *    'OR' means only one element needs to match;
2688  *    'NOT' means no elements may match.
2689  *   The default is 'AND'.
2690  * @return array
2691  */
2692 function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
2693         if ( ! is_array( $list ) )
2694                 return array();
2695
2696         if ( empty( $args ) )
2697                 return $list;
2698
2699         $operator = strtoupper( $operator );
2700         $count = count( $args );
2701         $filtered = array();
2702
2703         foreach ( $list as $key => $obj ) {
2704                 $to_match = (array) $obj;
2705
2706                 $matched = 0;
2707                 foreach ( $args as $m_key => $m_value ) {
2708                         if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] )
2709                                 $matched++;
2710                 }
2711
2712                 if ( ( 'AND' == $operator && $matched == $count )
2713                   || ( 'OR' == $operator && $matched > 0 )
2714                   || ( 'NOT' == $operator && 0 == $matched ) ) {
2715                         $filtered[$key] = $obj;
2716                 }
2717         }
2718
2719         return $filtered;
2720 }
2721
2722 /**
2723  * Pluck a certain field out of each object in a list.
2724  *
2725  * @since 3.1.0
2726  *
2727  * @param array $list A list of objects or arrays
2728  * @param int|string $field A field from the object to place instead of the entire object
2729  * @return array
2730  */
2731 function wp_list_pluck( $list, $field ) {
2732         foreach ( $list as $key => $value ) {
2733                 if ( is_object( $value ) )
2734                         $list[ $key ] = $value->$field;
2735                 else
2736                         $list[ $key ] = $value[ $field ];
2737         }
2738
2739         return $list;
2740 }
2741
2742 /**
2743  * Determines if Widgets library should be loaded.
2744  *
2745  * Checks to make sure that the widgets library hasn't already been loaded. If
2746  * it hasn't, then it will load the widgets library and run an action hook.
2747  *
2748  * @since 2.2.0
2749  * @uses add_action() Calls '_admin_menu' hook with 'wp_widgets_add_menu' value.
2750  */
2751 function wp_maybe_load_widgets() {
2752         if ( ! apply_filters('load_default_widgets', true) )
2753                 return;
2754         require_once( ABSPATH . WPINC . '/default-widgets.php' );
2755         add_action( '_admin_menu', 'wp_widgets_add_menu' );
2756 }
2757
2758 /**
2759  * Append the Widgets menu to the themes main menu.
2760  *
2761  * @since 2.2.0
2762  * @uses $submenu The administration submenu list.
2763  */
2764 function wp_widgets_add_menu() {
2765         global $submenu;
2766
2767         if ( ! current_theme_supports( 'widgets' ) )
2768                 return;
2769
2770         $submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' );
2771         ksort( $submenu['themes.php'], SORT_NUMERIC );
2772 }
2773
2774 /**
2775  * Flush all output buffers for PHP 5.2.
2776  *
2777  * Make sure all output buffers are flushed before our singletons our destroyed.
2778  *
2779  * @since 2.2.0
2780  */
2781 function wp_ob_end_flush_all() {
2782         $levels = ob_get_level();
2783         for ($i=0; $i<$levels; $i++)
2784                 ob_end_flush();
2785 }
2786
2787 /**
2788  * Load custom DB error or display WordPress DB error.
2789  *
2790  * If a file exists in the wp-content directory named db-error.php, then it will
2791  * be loaded instead of displaying the WordPress DB error. If it is not found,
2792  * then the WordPress DB error will be displayed instead.
2793  *
2794  * The WordPress DB error sets the HTTP status header to 500 to try to prevent
2795  * search engines from caching the message. Custom DB messages should do the
2796  * same.
2797  *
2798  * This function was backported to WordPress 2.3.2, but originally was added
2799  * in WordPress 2.5.0.
2800  *
2801  * @since 2.3.2
2802  * @uses $wpdb
2803  */
2804 function dead_db() {
2805         global $wpdb;
2806
2807         // Load custom DB error template, if present.
2808         if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
2809                 require_once( WP_CONTENT_DIR . '/db-error.php' );
2810                 die();
2811         }
2812
2813         // If installing or in the admin, provide the verbose message.
2814         if ( defined('WP_INSTALLING') || defined('WP_ADMIN') )
2815                 wp_die($wpdb->error);
2816
2817         // Otherwise, be terse.
2818         status_header( 500 );
2819         nocache_headers();
2820         header( 'Content-Type: text/html; charset=utf-8' );
2821
2822         wp_load_translations_early();
2823 ?>
2824 <!DOCTYPE html>
2825 <html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
2826 <head>
2827 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2828         <title><?php _e( 'Database Error' ); ?></title>
2829
2830 </head>
2831 <body>
2832         <h1><?php _e( 'Error establishing a database connection' ); ?></h1>
2833 </body>
2834 </html>
2835 <?php
2836         die();
2837 }
2838
2839 /**
2840  * Converts value to nonnegative integer.
2841  *
2842  * @since 2.5.0
2843  *
2844  * @param mixed $maybeint Data you wish to have converted to a nonnegative integer
2845  * @return int An nonnegative integer
2846  */
2847 function absint( $maybeint ) {
2848         return abs( intval( $maybeint ) );
2849 }
2850
2851 /**
2852  * Determines if the blog can be accessed over SSL.
2853  *
2854  * Determines if blog can be accessed over SSL by using cURL to access the site
2855  * using the https in the siteurl. Requires cURL extension to work correctly.
2856  *
2857  * @since 2.5.0
2858  *
2859  * @param string $url
2860  * @return bool Whether SSL access is available
2861  */
2862 function url_is_accessable_via_ssl($url)
2863 {
2864         if ( in_array( 'curl', get_loaded_extensions() ) ) {
2865                 $ssl = set_url_scheme( $url, 'https' );
2866
2867                 $ch = curl_init();
2868                 curl_setopt($ch, CURLOPT_URL, $ssl);
2869                 curl_setopt($ch, CURLOPT_FAILONERROR, true);
2870                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
2871                 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
2872                 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
2873
2874                 curl_exec($ch);
2875
2876                 $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2877                 curl_close ($ch);
2878
2879                 if ($status == 200 || $status == 401) {
2880                         return true;
2881                 }
2882         }
2883         return false;
2884 }
2885
2886 /**
2887  * Marks a function as deprecated and informs when it has been used.
2888  *
2889  * There is a hook deprecated_function_run that will be called that can be used
2890  * to get the backtrace up to what file and function called the deprecated
2891  * function.
2892  *
2893  * The current behavior is to trigger a user error if WP_DEBUG is true.
2894  *
2895  * This function is to be used in every function that is deprecated.
2896  *
2897  * @package WordPress
2898  * @subpackage Debug
2899  * @since 2.5.0
2900  * @access private
2901  *
2902  * @uses do_action() Calls 'deprecated_function_run' and passes the function name, what to use instead,
2903  *   and the version the function was deprecated in.
2904  * @uses apply_filters() Calls 'deprecated_function_trigger_error' and expects boolean value of true to do
2905  *   trigger or false to not trigger error.
2906  *
2907  * @param string $function The function that was called
2908  * @param string $version The version of WordPress that deprecated the function
2909  * @param string $replacement Optional. The function that should have been called
2910  */
2911 function _deprecated_function( $function, $version, $replacement = null ) {
2912
2913         do_action( 'deprecated_function_run', $function, $replacement, $version );
2914
2915         // Allow plugin to filter the output error trigger
2916         if ( WP_DEBUG && apply_filters( 'deprecated_function_trigger_error', true ) ) {
2917                 if ( function_exists( '__' ) ) {
2918                         if ( ! is_null( $replacement ) )
2919                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) );
2920                         else
2921                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
2922                 } else {
2923                         if ( ! is_null( $replacement ) )
2924                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $function, $version, $replacement ) );
2925                         else
2926                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
2927                 }
2928         }
2929 }
2930
2931 /**
2932  * Marks a file as deprecated and informs when it has been used.
2933  *
2934  * There is a hook deprecated_file_included that will be called that can be used
2935  * to get the backtrace up to what file and function included the deprecated
2936  * file.
2937  *
2938  * The current behavior is to trigger a user error if WP_DEBUG is true.
2939  *
2940  * This function is to be used in every file that is deprecated.
2941  *
2942  * @package WordPress
2943  * @subpackage Debug
2944  * @since 2.5.0
2945  * @access private
2946  *
2947  * @uses do_action() Calls 'deprecated_file_included' and passes the file name, what to use instead,
2948  *   the version in which the file was deprecated, and any message regarding the change.
2949  * @uses apply_filters() Calls 'deprecated_file_trigger_error' and expects boolean value of true to do
2950  *   trigger or false to not trigger error.
2951  *
2952  * @param string $file The file that was included
2953  * @param string $version The version of WordPress that deprecated the file
2954  * @param string $replacement Optional. The file that should have been included based on ABSPATH
2955  * @param string $message Optional. A message regarding the change
2956  */
2957 function _deprecated_file( $file, $version, $replacement = null, $message = '' ) {
2958
2959         do_action( 'deprecated_file_included', $file, $replacement, $version, $message );
2960
2961         // Allow plugin to filter the output error trigger
2962         if ( WP_DEBUG && apply_filters( 'deprecated_file_trigger_error', true ) ) {
2963                 $message = empty( $message ) ? '' : ' ' . $message;
2964                 if ( function_exists( '__' ) ) {
2965                         if ( ! is_null( $replacement ) )
2966                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $file, $version, $replacement ) . $message );
2967                         else
2968                                 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $file, $version ) . $message );
2969                 } else {
2970                         if ( ! is_null( $replacement ) )
2971                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $file, $version, $replacement ) . $message );
2972                         else
2973                                 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $file, $version ) . $message );
2974                 }
2975         }
2976 }
2977 /**
2978  * Marks a function argument as deprecated and informs when it has been used.
2979  *
2980  * This function is to be used whenever a deprecated function argument is used.
2981  * Before this function is called, the argument must be checked for whether it was
2982  * used by comparing it to its default value or evaluating whether it is empty.
2983  * For example:
2984  * <code>
2985  * if ( !empty($deprecated) )
2986  *      _deprecated_argument( __FUNCTION__, '3.0' );
2987  * </code>
2988  *
2989  * There is a hook deprecated_argument_run that will be called that can be used
2990  * to get the backtrace up to what file and function used the deprecated
2991  * argument.
2992  *
2993  * The current behavior is to trigger a user error if WP_DEBUG is true.
2994  *
2995  * @package WordPress
2996  * @subpackage Debug
2997  * @since 3.0.0
2998  * @access private
2999  *
3000  * @uses do_action() Calls 'deprecated_argument_run' and passes the function name, a message on the change,
3001  *   and the version in which the argument was deprecated.
3002  * @uses apply_filters() Calls 'deprecated_argument_trigger_error' and expects boolean value of true to do
3003  *   trigger or false to not trigger error.
3004  *
3005  * @param string $function The function that was called
3006  * @param string $version The version of WordPress that deprecated the argument used
3007  * @param string $message Optional. A message regarding the change.
3008  */
3009 function _deprecated_argument( $function, $version, $message = null ) {
3010
3011         do_action( 'deprecated_argument_run', $function, $message, $version );
3012
3013         // Allow plugin to filter the output error trigger
3014         if ( WP_DEBUG && apply_filters( 'deprecated_argument_trigger_error', true ) ) {
3015                 if ( function_exists( '__' ) ) {
3016                         if ( ! is_null( $message ) )
3017                                 trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s'), $function, $version, $message ) );
3018                         else
3019                                 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 ) );
3020                 } else {
3021                         if ( ! is_null( $message ) )
3022                                 trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s', $function, $version, $message ) );
3023                         else
3024                                 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 ) );
3025                 }
3026         }
3027 }
3028
3029 /**
3030  * Marks something as being incorrectly called.
3031  *
3032  * There is a hook doing_it_wrong_run that will be called that can be used
3033  * to get the backtrace up to what file and function called the deprecated
3034  * function.
3035  *
3036  * The current behavior is to trigger a user error if WP_DEBUG is true.
3037  *
3038  * @package WordPress
3039  * @subpackage Debug
3040  * @since 3.1.0
3041  * @access private
3042  *
3043  * @uses do_action() Calls 'doing_it_wrong_run' and passes the function arguments.
3044  * @uses apply_filters() Calls 'doing_it_wrong_trigger_error' and expects boolean value of true to do
3045  *   trigger or false to not trigger error.
3046  *
3047  * @param string $function The function that was called.
3048  * @param string $message A message explaining what has been done incorrectly.
3049  * @param string $version The version of WordPress where the message was added.
3050  */
3051 function _doing_it_wrong( $function, $message, $version ) {
3052
3053         do_action( 'doing_it_wrong_run', $function, $message, $version );
3054
3055         // Allow plugin to filter the output error trigger
3056         if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
3057                 if ( function_exists( '__' ) ) {
3058                         $version = is_null( $version ) ? '' : sprintf( __( '(This message was added in version %s.)' ), $version );
3059                         $message .= ' ' . __( 'Please see <a href="http://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.' );
3060                         trigger_error( sprintf( __( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s' ), $function, $message, $version ) );
3061                 } else {
3062                         $version = is_null( $version ) ? '' : sprintf( '(This message was added in version %s.)', $version );
3063                         $message .= ' Please see <a href="http://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.';
3064                         trigger_error( sprintf( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s', $function, $message, $version ) );
3065                 }
3066         }
3067 }
3068
3069 /**
3070  * Is the server running earlier than 1.5.0 version of lighttpd?
3071  *
3072  * @since 2.5.0
3073  *
3074  * @return bool Whether the server is running lighttpd < 1.5.0
3075  */
3076 function is_lighttpd_before_150() {
3077         $server_parts = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] )? $_SERVER['SERVER_SOFTWARE'] : '' );
3078         $server_parts[1] = isset( $server_parts[1] )? $server_parts[1] : '';
3079         return  'lighttpd' == $server_parts[0] && -1 == version_compare( $server_parts[1], '1.5.0' );
3080 }
3081
3082 /**
3083  * Does the specified module exist in the Apache config?
3084  *
3085  * @since 2.5.0
3086  *
3087  * @param string $mod e.g. mod_rewrite
3088  * @param bool $default The default return value if the module is not found
3089  * @return bool
3090  */
3091 function apache_mod_loaded($mod, $default = false) {
3092         global $is_apache;
3093
3094         if ( !$is_apache )
3095                 return false;
3096
3097         if ( function_exists('apache_get_modules') ) {
3098                 $mods = apache_get_modules();
3099                 if ( in_array($mod, $mods) )
3100                         return true;
3101         } elseif ( function_exists('phpinfo') ) {
3102                         ob_start();
3103                         phpinfo(8);
3104                         $phpinfo = ob_get_clean();
3105                         if ( false !== strpos($phpinfo, $mod) )
3106                                 return true;
3107         }
3108         return $default;
3109 }
3110
3111 /**
3112  * Check if IIS 7+ supports pretty permalinks.
3113  *
3114  * @since 2.8.0
3115  *
3116  * @return bool
3117  */
3118 function iis7_supports_permalinks() {
3119         global $is_iis7;
3120
3121         $supports_permalinks = false;
3122         if ( $is_iis7 ) {
3123                 /* First we check if the DOMDocument class exists. If it does not exist, then we cannot
3124                  * easily update the xml configuration file, hence we just bail out and tell user that
3125                  * pretty permalinks cannot be used.
3126                  *
3127                  * Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the web site. When
3128                  * URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
3129                  * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
3130                  * via ISAPI then pretty permalinks will not work.
3131                  */
3132                 $supports_permalinks = class_exists('DOMDocument') && isset($_SERVER['IIS_UrlRewriteModule']) && ( php_sapi_name() == 'cgi-fcgi' );
3133         }
3134
3135         return apply_filters('iis7_supports_permalinks', $supports_permalinks);
3136 }
3137
3138 /**
3139  * File validates against allowed set of defined rules.
3140  *
3141  * A return value of '1' means that the $file contains either '..' or './'. A
3142  * return value of '2' means that the $file contains ':' after the first
3143  * character. A return value of '3' means that the file is not in the allowed
3144  * files list.
3145  *
3146  * @since 1.2.0
3147  *
3148  * @param string $file File path.
3149  * @param array $allowed_files List of allowed files.
3150  * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
3151  */
3152 function validate_file( $file, $allowed_files = '' ) {
3153         if ( false !== strpos( $file, '..' ) )
3154                 return 1;
3155
3156         if ( false !== strpos( $file, './' ) )
3157                 return 1;
3158
3159         if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) )
3160                 return 3;
3161
3162         if (':' == substr( $file, 1, 1 ) )
3163                 return 2;
3164
3165         return 0;
3166 }
3167
3168 /**
3169  * Determine if SSL is used.
3170  *
3171  * @since 2.6.0
3172  *
3173  * @return bool True if SSL, false if not used.
3174  */
3175 function is_ssl() {
3176         if ( isset($_SERVER['HTTPS']) ) {
3177                 if ( 'on' == strtolower($_SERVER['HTTPS']) )
3178                         return true;
3179                 if ( '1' == $_SERVER['HTTPS'] )
3180                         return true;
3181         } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
3182                 return true;
3183         }
3184         return false;
3185 }
3186
3187 /**
3188  * Whether SSL login should be forced.
3189  *
3190  * @since 2.6.0
3191  *
3192  * @param string|bool $force Optional.
3193  * @return bool True if forced, false if not forced.
3194  */
3195 function force_ssl_login( $force = null ) {
3196         static $forced = false;
3197
3198         if ( !is_null( $force ) ) {
3199                 $old_forced = $forced;
3200                 $forced = $force;
3201                 return $old_forced;
3202         }
3203
3204         return $forced;
3205 }
3206
3207 /**
3208  * Whether to force SSL used for the Administration Screens.
3209  *
3210  * @since 2.6.0
3211  *
3212  * @param string|bool $force
3213  * @return bool True if forced, false if not forced.
3214  */
3215 function force_ssl_admin( $force = null ) {
3216         static $forced = false;
3217
3218         if ( !is_null( $force ) ) {
3219                 $old_forced = $forced;
3220                 $forced = $force;
3221                 return $old_forced;
3222         }
3223
3224         return $forced;
3225 }
3226
3227 /**
3228  * Guess the URL for the site.
3229  *
3230  * Will remove wp-admin links to retrieve only return URLs not in the wp-admin
3231  * directory.
3232  *
3233  * @since 2.6.0
3234  *
3235  * @return string
3236  */
3237 function wp_guess_url() {
3238         if ( defined('WP_SITEURL') && '' != WP_SITEURL ) {
3239                 $url = WP_SITEURL;
3240         } else {
3241                 $abspath_fix = str_replace( '\\', '/', ABSPATH );
3242                 $script_filename_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
3243
3244                 // The request is for the admin
3245                 if ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false || strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ) {
3246                         $path = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $_SERVER['REQUEST_URI'] );
3247
3248                 // The request is for a file in ABSPATH
3249                 } elseif ( $script_filename_dir . '/' == $abspath_fix ) {
3250                         // Strip off any file/query params in the path
3251                         $path = preg_replace( '#/[^/]*$#i', '', $_SERVER['PHP_SELF'] );
3252
3253                 } else {
3254                         if ( false !== strpos( $_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
3255                                 // Request is hitting a file inside ABSPATH
3256                                 $directory = str_replace( ABSPATH, '', $script_filename_dir );
3257                                 // Strip off the sub directory, and any file/query paramss
3258                                 $path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] );
3259                         } elseif ( false !== strpos( $abspath_fix, $script_filename_dir ) ) {
3260                                 // Request is hitting a file above ABSPATH
3261                                 $subdirectory = str_replace( $script_filename_dir, '', $abspath_fix );
3262                                 // Strip off any file/query params from the path, appending the sub directory to the install
3263                                 $path = preg_replace( '#/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] ) . $subdirectory;
3264                         } else {
3265                                 $path = $_SERVER['REQUEST_URI'];
3266                         }
3267                 }
3268
3269                 $schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet
3270                 $url = $schema . $_SERVER['HTTP_HOST'] . $path;
3271         }
3272
3273         return rtrim($url, '/');
3274 }
3275
3276 /**
3277  * Temporarily suspend cache additions.
3278  *
3279  * Stops more data being added to the cache, but still allows cache retrieval.
3280  * This is useful for actions, such as imports, when a lot of data would otherwise
3281  * be almost uselessly added to the cache.
3282  *
3283  * Suspension lasts for a single page load at most. Remember to call this
3284  * function again if you wish to re-enable cache adds earlier.
3285  *
3286  * @since 3.3.0
3287  *
3288  * @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
3289  * @return bool The current suspend setting
3290  */
3291 function wp_suspend_cache_addition( $suspend = null ) {
3292         static $_suspend = false;
3293
3294         if ( is_bool( $suspend ) )
3295                 $_suspend = $suspend;
3296
3297         return $_suspend;
3298 }
3299
3300 /**
3301  * Suspend cache invalidation.
3302  *
3303  * Turns cache invalidation on and off. Useful during imports where you don't wont to do invalidations
3304  * every time a post is inserted. Callers must be sure that what they are doing won't lead to an inconsistent
3305  * cache when invalidation is suspended.
3306  *
3307  * @since 2.7.0
3308  *
3309  * @param bool $suspend Whether to suspend or enable cache invalidation
3310  * @return bool The current suspend setting
3311  */
3312 function wp_suspend_cache_invalidation($suspend = true) {
3313         global $_wp_suspend_cache_invalidation;
3314
3315         $current_suspend = $_wp_suspend_cache_invalidation;
3316         $_wp_suspend_cache_invalidation = $suspend;
3317         return $current_suspend;
3318 }
3319
3320 /**
3321  * Whether a site is the main site of the current network.
3322  *
3323  * @since 3.0.0
3324  *
3325  * @param int $site_id Optional. Site ID to test. Defaults to current site.
3326  * @return bool True if $site_id is the main site of the network, or if not running multisite.
3327  */
3328 function is_main_site( $site_id = null ) {
3329         // This is the current network's information; 'site' is old terminology.
3330         global $current_site;
3331
3332         if ( ! is_multisite() )
3333                 return true;
3334
3335         if ( ! $site_id )
3336                 $site_id = get_current_blog_id();
3337
3338         return (int) $site_id === (int) $current_site->blog_id;
3339 }
3340
3341 /**
3342  * Whether a network is the main network of the multisite install.
3343  *
3344  * @since 3.7.0
3345  *
3346  * @param int $network_id Optional. Network ID to test. Defaults to current network.
3347  * @return bool True if $network_id is the main network, or if not running multisite.
3348  */
3349 function is_main_network( $network_id = null ) {
3350         global $current_site, $wpdb;
3351
3352         if ( ! is_multisite() )
3353                 return true;
3354
3355         $current_network_id = (int) $current_site->id;
3356
3357         if ( ! $network_id )
3358                 $network_id = $current_network_id;
3359         $network_id = (int) $network_id;
3360
3361         if ( defined( 'PRIMARY_NETWORK_ID' ) )
3362                 return $network_id === (int) PRIMARY_NETWORK_ID;
3363
3364         if ( 1 === $current_network_id )
3365                 return $network_id === $current_network_id;
3366
3367         $primary_network_id = (int) wp_cache_get( 'primary_network_id', 'site-options' );
3368
3369         if ( $primary_network_id )
3370                 return $network_id === $primary_network_id;
3371
3372         $primary_network_id = (int) $wpdb->get_var( "SELECT id FROM $wpdb->site ORDER BY id LIMIT 1" );
3373         wp_cache_add( 'primary_network_id', $primary_network_id, 'site-options' );
3374
3375         return $network_id === $primary_network_id;
3376 }
3377
3378 /**
3379  * Whether global terms are enabled.
3380  *
3381  *
3382  * @since 3.0.0
3383  * @package WordPress
3384  *
3385  * @return bool True if multisite and global terms enabled
3386  */
3387 function global_terms_enabled() {
3388         if ( ! is_multisite() )
3389                 return false;
3390
3391         static $global_terms = null;
3392         if ( is_null( $global_terms ) ) {
3393                 $filter = apply_filters( 'global_terms_enabled', null );
3394                 if ( ! is_null( $filter ) )
3395                         $global_terms = (bool) $filter;
3396                 else
3397                         $global_terms = (bool) get_site_option( 'global_terms_enabled', false );
3398         }
3399         return $global_terms;
3400 }
3401
3402 /**
3403  * gmt_offset modification for smart timezone handling.
3404  *
3405  * Overrides the gmt_offset option if we have a timezone_string available.
3406  *
3407  * @since 2.8.0
3408  *
3409  * @return float|bool
3410  */
3411 function wp_timezone_override_offset() {
3412         if ( !$timezone_string = get_option( 'timezone_string' ) ) {
3413                 return false;
3414         }
3415
3416         $timezone_object = timezone_open( $timezone_string );
3417         $datetime_object = date_create();
3418         if ( false === $timezone_object || false === $datetime_object ) {
3419                 return false;
3420         }
3421         return round( timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS, 2 );
3422 }
3423
3424 /**
3425  * Sort-helper for timezones.
3426  *
3427  * @since 2.9.0
3428  *
3429  * @param array $a
3430  * @param array $b
3431  * @return int
3432  */
3433 function _wp_timezone_choice_usort_callback( $a, $b ) {
3434         // Don't use translated versions of Etc
3435         if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
3436                 // Make the order of these more like the old dropdown
3437                 if ( 'GMT+' === substr( $a['city'], 0, 4 ) && 'GMT+' === substr( $b['city'], 0, 4 ) ) {
3438                         return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
3439                 }
3440                 if ( 'UTC' === $a['city'] ) {
3441                         if ( 'GMT+' === substr( $b['city'], 0, 4 ) ) {
3442                                 return 1;
3443                         }
3444                         return -1;
3445                 }
3446                 if ( 'UTC' === $b['city'] ) {
3447                         if ( 'GMT+' === substr( $a['city'], 0, 4 ) ) {
3448                                 return -1;
3449                         }
3450                         return 1;
3451                 }
3452                 return strnatcasecmp( $a['city'], $b['city'] );
3453         }
3454         if ( $a['t_continent'] == $b['t_continent'] ) {
3455                 if ( $a['t_city'] == $b['t_city'] ) {
3456                         return strnatcasecmp( $a['t_subcity'], $b['t_subcity'] );
3457                 }
3458                 return strnatcasecmp( $a['t_city'], $b['t_city'] );
3459         } else {
3460                 // Force Etc to the bottom of the list
3461                 if ( 'Etc' === $a['continent'] ) {
3462                         return 1;
3463                 }
3464                 if ( 'Etc' === $b['continent'] ) {
3465                         return -1;
3466                 }
3467                 return strnatcasecmp( $a['t_continent'], $b['t_continent'] );
3468         }
3469 }
3470
3471 /**
3472  * Gives a nicely formatted list of timezone strings.
3473  *
3474  * @since 2.9.0
3475  *
3476  * @param string $selected_zone Selected Zone
3477  * @return string
3478  */
3479 function wp_timezone_choice( $selected_zone ) {
3480         static $mo_loaded = false;
3481
3482         $continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific');
3483
3484         // Load translations for continents and cities
3485         if ( !$mo_loaded ) {
3486                 $locale = get_locale();
3487                 $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
3488                 load_textdomain( 'continents-cities', $mofile );
3489                 $mo_loaded = true;
3490         }
3491
3492         $zonen = array();
3493         foreach ( timezone_identifiers_list() as $zone ) {
3494                 $zone = explode( '/', $zone );
3495                 if ( !in_array( $zone[0], $continents ) ) {
3496                         continue;
3497                 }
3498
3499                 // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
3500                 $exists = array(
3501                         0 => ( isset( $zone[0] ) && $zone[0] ),
3502                         1 => ( isset( $zone[1] ) && $zone[1] ),
3503                         2 => ( isset( $zone[2] ) && $zone[2] ),
3504                 );
3505                 $exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
3506                 $exists[4] = ( $exists[1] && $exists[3] );
3507                 $exists[5] = ( $exists[2] && $exists[3] );
3508
3509                 $zonen[] = array(
3510                         'continent'   => ( $exists[0] ? $zone[0] : '' ),
3511                         'city'        => ( $exists[1] ? $zone[1] : '' ),
3512                         'subcity'     => ( $exists[2] ? $zone[2] : '' ),
3513                         't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
3514                         't_city'      => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
3515                         't_subcity'   => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' )
3516                 );
3517         }
3518         usort( $zonen, '_wp_timezone_choice_usort_callback' );
3519
3520         $structure = array();
3521
3522         if ( empty( $selected_zone ) ) {
3523                 $structure[] = '<option selected="selected" value="">' . __( 'Select a city' ) . '</option>';
3524         }
3525
3526         foreach ( $zonen as $key => $zone ) {
3527                 // Build value in an array to join later
3528                 $value = array( $zone['continent'] );
3529
3530                 if ( empty( $zone['city'] ) ) {
3531                         // It's at the continent level (generally won't happen)
3532                         $display = $zone['t_continent'];
3533                 } else {
3534                         // It's inside a continent group
3535
3536                         // Continent optgroup
3537                         if ( !isset( $zonen[$key - 1] ) || $zonen[$key - 1]['continent'] !== $zone['continent'] ) {
3538                                 $label = $zone['t_continent'];
3539                                 $structure[] = '<optgroup label="'. esc_attr( $label ) .'">';
3540                         }
3541
3542                         // Add the city to the value
3543                         $value[] = $zone['city'];
3544
3545                         $display = $zone['t_city'];
3546                         if ( !empty( $zone['subcity'] ) ) {
3547                                 // Add the subcity to the value
3548                                 $value[] = $zone['subcity'];
3549                                 $display .= ' - ' . $zone['t_subcity'];
3550                         }
3551                 }
3552
3553                 // Build the value
3554                 $value = join( '/', $value );
3555                 $selected = '';
3556                 if ( $value === $selected_zone ) {
3557                         $selected = 'selected="selected" ';
3558                 }
3559                 $structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . "</option>";
3560
3561                 // Close continent optgroup
3562                 if ( !empty( $zone['city'] ) && ( !isset($zonen[$key + 1]) || (isset( $zonen[$key + 1] ) && $zonen[$key + 1]['continent'] !== $zone['continent']) ) ) {
3563                         $structure[] = '</optgroup>';
3564                 }
3565         }
3566
3567         // Do UTC
3568         $structure[] = '<optgroup label="'. esc_attr__( 'UTC' ) .'">';
3569         $selected = '';
3570         if ( 'UTC' === $selected_zone )
3571                 $selected = 'selected="selected" ';
3572         $structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __('UTC') . '</option>';
3573         $structure[] = '</optgroup>';
3574
3575         // Do manual UTC offsets
3576         $structure[] = '<optgroup label="'. esc_attr__( 'Manual Offsets' ) .'">';
3577         $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,
3578                 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);
3579         foreach ( $offset_range as $offset ) {
3580                 if ( 0 <= $offset )
3581                         $offset_name = '+' . $offset;
3582                 else
3583                         $offset_name = (string) $offset;
3584
3585                 $offset_value = $offset_name;
3586                 $offset_name = str_replace(array('.25','.5','.75'), array(':15',':30',':45'), $offset_name);
3587                 $offset_name = 'UTC' . $offset_name;
3588                 $offset_value = 'UTC' . $offset_value;
3589                 $selected = '';
3590                 if ( $offset_value === $selected_zone )
3591                         $selected = 'selected="selected" ';
3592                 $structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . "</option>";
3593
3594         }
3595         $structure[] = '</optgroup>';
3596
3597         return join( "\n", $structure );
3598 }
3599
3600 /**
3601  * Strip close comment and close php tags from file headers used by WP.
3602  * See http://core.trac.wordpress.org/ticket/8497
3603  *
3604  * @since 2.8.0
3605  *
3606  * @param string $str
3607  * @return string
3608  */
3609 function _cleanup_header_comment($str) {
3610         return trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $str));
3611 }
3612
3613 /**
3614  * Permanently deletes posts, pages, attachments, and comments which have been in the trash for EMPTY_TRASH_DAYS.
3615  *
3616  * @since 2.9.0
3617  */
3618 function wp_scheduled_delete() {
3619         global $wpdb;
3620
3621         $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
3622
3623         $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);
3624
3625         foreach ( (array) $posts_to_delete as $post ) {
3626                 $post_id = (int) $post['post_id'];
3627                 if ( !$post_id )
3628                         continue;
3629
3630                 $del_post = get_post($post_id);
3631
3632                 if ( !$del_post || 'trash' != $del_post->post_status ) {
3633                         delete_post_meta($post_id, '_wp_trash_meta_status');
3634                         delete_post_meta($post_id, '_wp_trash_meta_time');
3635                 } else {
3636                         wp_delete_post($post_id);
3637                 }
3638         }
3639
3640         $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);
3641
3642         foreach ( (array) $comments_to_delete as $comment ) {
3643                 $comment_id = (int) $comment['comment_id'];
3644                 if ( !$comment_id )
3645                         continue;
3646
3647                 $del_comment = get_comment($comment_id);
3648
3649                 if ( !$del_comment || 'trash' != $del_comment->comment_approved ) {
3650                         delete_comment_meta($comment_id, '_wp_trash_meta_time');
3651                         delete_comment_meta($comment_id, '_wp_trash_meta_status');
3652                 } else {
3653                         wp_delete_comment($comment_id);
3654                 }
3655         }
3656 }
3657
3658 /**
3659  * Retrieve metadata from a file.
3660  *
3661  * Searches for metadata in the first 8kiB of a file, such as a plugin or theme.
3662  * Each piece of metadata must be on its own line. Fields can not span multiple
3663  * lines, the value will get cut at the end of the first line.
3664  *
3665  * If the file data is not within that first 8kiB, then the author should correct
3666  * their plugin file and move the data headers to the top.
3667  *
3668  * @see http://codex.wordpress.org/File_Header
3669  *
3670  * @since 2.9.0
3671  * @param string $file Path to the file
3672  * @param array $default_headers List of headers, in the format array('HeaderKey' => 'Header Name')
3673  * @param string $context If specified adds filter hook "extra_{$context}_headers"
3674  */
3675 function get_file_data( $file, $default_headers, $context = '' ) {
3676         // We don't need to write to the file, so just open for reading.
3677         $fp = fopen( $file, 'r' );
3678
3679         // Pull only the first 8kiB of the file in.
3680         $file_data = fread( $fp, 8192 );
3681
3682         // PHP will close file handle, but we are good citizens.
3683         fclose( $fp );
3684
3685         // Make sure we catch CR-only line endings.
3686         $file_data = str_replace( "\r", "\n", $file_data );
3687
3688         if ( $context && $extra_headers = apply_filters( "extra_{$context}_headers", array() ) ) {
3689                 $extra_headers = array_combine( $extra_headers, $extra_headers ); // keys equal values
3690                 $all_headers = array_merge( $extra_headers, (array) $default_headers );
3691         } else {
3692                 $all_headers = $default_headers;
3693         }
3694
3695         foreach ( $all_headers as $field => $regex ) {
3696                 if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] )
3697                         $all_headers[ $field ] = _cleanup_header_comment( $match[1] );
3698                 else
3699                         $all_headers[ $field ] = '';
3700         }
3701
3702         return $all_headers;
3703 }
3704
3705 /**
3706  * Returns true.
3707  *
3708  * Useful for returning true to filters easily.
3709  *
3710  * @since 3.0.0
3711  * @see __return_false()
3712  * @return bool true
3713  */
3714 function __return_true() {
3715         return true;
3716 }
3717
3718 /**
3719  * Returns false.
3720  *
3721  * Useful for returning false to filters easily.
3722  *
3723  * @since 3.0.0
3724  * @see __return_true()
3725  * @return bool false
3726  */
3727 function __return_false() {
3728         return false;
3729 }
3730
3731 /**
3732  * Returns 0.
3733  *
3734  * Useful for returning 0 to filters easily.
3735  *
3736  * @since 3.0.0
3737  * @see __return_zero()
3738  * @return int 0
3739  */
3740 function __return_zero() {
3741         return 0;
3742 }
3743
3744 /**
3745  * Returns an empty array.
3746  *
3747  * Useful for returning an empty array to filters easily.
3748  *
3749  * @since 3.0.0
3750  * @see __return_zero()
3751  * @return array Empty array
3752  */
3753 function __return_empty_array() {
3754         return array();
3755 }
3756
3757 /**
3758  * Returns null.
3759  *
3760  * Useful for returning null to filters easily.
3761  *
3762  * @since 3.4.0
3763  * @return null
3764  */
3765 function __return_null() {
3766         return null;
3767 }
3768
3769 /**
3770  * Returns an empty string.
3771  *
3772  * Useful for returning an empty string to filters easily.
3773  *
3774  * @since 3.7.0
3775  * @see __return_null()
3776  * @return string Empty string
3777  */
3778 function __return_empty_string() {
3779         return '';
3780 }
3781
3782 /**
3783  * Send a HTTP header to disable content type sniffing in browsers which support it.
3784  *
3785  * @link http://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
3786  * @link http://src.chromium.org/viewvc/chrome?view=rev&revision=6985
3787  *
3788  * @since 3.0.0
3789  * @return none
3790  */
3791 function send_nosniff_header() {
3792         @header( 'X-Content-Type-Options: nosniff' );
3793 }
3794
3795 /**
3796  * Returns a MySQL expression for selecting the week number based on the start_of_week option.
3797  *
3798  * @internal
3799  * @since 3.0.0
3800  * @param string $column
3801  * @return string
3802  */
3803 function _wp_mysql_week( $column ) {
3804         switch ( $start_of_week = (int) get_option( 'start_of_week' ) ) {
3805         default :
3806         case 0 :
3807                 return "WEEK( $column, 0 )";
3808         case 1 :
3809                 return "WEEK( $column, 1 )";
3810         case 2 :
3811         case 3 :
3812         case 4 :
3813         case 5 :
3814         case 6 :
3815                 return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
3816         }
3817 }
3818
3819 /**
3820  * Finds hierarchy loops using a callback function that maps object IDs to parent IDs.
3821  *
3822  * @since 3.1.0
3823  * @access private
3824  *
3825  * @param callback $callback function that accepts ( ID, $callback_args ) and outputs parent_ID
3826  * @param int $start The ID to start the loop check at
3827  * @param int $start_parent the parent_ID of $start to use instead of calling $callback( $start ). Use null to always use $callback
3828  * @param array $callback_args optional additional arguments to send to $callback
3829  * @return array IDs of all members of loop
3830  */
3831 function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_args = array() ) {
3832         $override = is_null( $start_parent ) ? array() : array( $start => $start_parent );
3833
3834         if ( !$arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args ) )
3835                 return array();
3836
3837         return wp_find_hierarchy_loop_tortoise_hare( $callback, $arbitrary_loop_member, $override, $callback_args, true );
3838 }
3839
3840 /**
3841  * Uses the "The Tortoise and the Hare" algorithm to detect loops.
3842  *
3843  * For every step of the algorithm, the hare takes two steps and the tortoise one.
3844  * If the hare ever laps the tortoise, there must be a loop.
3845  *
3846  * @since 3.1.0
3847  * @access private
3848  *
3849  * @param callback $callback function that accepts ( ID, callback_arg, ... ) and outputs parent_ID
3850  * @param int $start The ID to start the loop check at
3851  * @param array $override an array of ( ID => parent_ID, ... ) to use instead of $callback
3852  * @param array $callback_args optional additional arguments to send to $callback
3853  * @param bool $_return_loop Return loop members or just detect presence of loop?
3854  *             Only set to true if you already know the given $start is part of a loop
3855  *             (otherwise the returned array might include branches)
3856  * @return mixed scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if $_return_loop
3857  */
3858 function wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override = array(), $callback_args = array(), $_return_loop = false ) {
3859         $tortoise = $hare = $evanescent_hare = $start;
3860         $return = array();
3861
3862         // Set evanescent_hare to one past hare
3863         // Increment hare two steps
3864         while (
3865                 $tortoise
3866         &&
3867                 ( $evanescent_hare = isset( $override[$hare] ) ? $override[$hare] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
3868         &&
3869                 ( $hare = isset( $override[$evanescent_hare] ) ? $override[$evanescent_hare] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
3870         ) {
3871                 if ( $_return_loop )
3872                         $return[$tortoise] = $return[$evanescent_hare] = $return[$hare] = true;
3873
3874                 // tortoise got lapped - must be a loop
3875                 if ( $tortoise == $evanescent_hare || $tortoise == $hare )
3876                         return $_return_loop ? $return : $tortoise;
3877
3878                 // Increment tortoise by one step
3879                 $tortoise = isset( $override[$tortoise] ) ? $override[$tortoise] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
3880         }
3881
3882         return false;
3883 }
3884
3885 /**
3886  * Send a HTTP header to limit rendering of pages to same origin iframes.
3887  *
3888  * @link https://developer.mozilla.org/en/the_x-frame-options_response_header
3889  *
3890  * @since 3.1.3
3891  * @return none
3892  */
3893 function send_frame_options_header() {
3894         @header( 'X-Frame-Options: SAMEORIGIN' );
3895 }
3896
3897 /**
3898  * Retrieve a list of protocols to allow in HTML attributes.
3899  *
3900  * @since 3.3.0
3901  * @see wp_kses()
3902  * @see esc_url()
3903  *
3904  * @return array Array of allowed protocols
3905  */
3906 function wp_allowed_protocols() {
3907         static $protocols;
3908
3909         if ( empty( $protocols ) ) {
3910                 $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp' );
3911                 $protocols = apply_filters( 'kses_allowed_protocols', $protocols );
3912         }
3913
3914         return $protocols;
3915 }
3916
3917 /**
3918  * Return a comma separated string of functions that have been called to get to the current point in code.
3919  *
3920  * @link http://core.trac.wordpress.org/ticket/19589
3921  * @since 3.4
3922  *
3923  * @param string $ignore_class A class to ignore all function calls within - useful when you want to just give info about the callee
3924  * @param int $skip_frames A number of stack frames to skip - useful for unwinding back to the source of the issue
3925  * @param bool $pretty Whether or not you want a comma separated string or raw array returned
3926  * @return string|array Either a string containing a reversed comma separated trace or an array of individual calls.
3927  */
3928 function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
3929         if ( version_compare( PHP_VERSION, '5.2.5', '>=' ) )
3930                 $trace = debug_backtrace( false );
3931         else
3932                 $trace = debug_backtrace();
3933
3934         $caller = array();
3935         $check_class = ! is_null( $ignore_class );
3936         $skip_frames++; // skip this function
3937
3938         foreach ( $trace as $call ) {
3939                 if ( $skip_frames > 0 ) {
3940                         $skip_frames--;
3941                 } elseif ( isset( $call['class'] ) ) {
3942                         if ( $check_class && $ignore_class == $call['class'] )
3943                                 continue; // Filter out calls
3944
3945                         $caller[] = "{$call['class']}{$call['type']}{$call['function']}";
3946                 } else {
3947                         if ( in_array( $call['function'], array( 'do_action', 'apply_filters' ) ) ) {
3948                                 $caller[] = "{$call['function']}('{$call['args'][0]}')";
3949                         } elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ) ) ) {
3950                                 $caller[] = $call['function'] . "('" . str_replace( array( WP_CONTENT_DIR, ABSPATH ) , '', $call['args'][0] ) . "')";
3951                         } else {
3952                                 $caller[] = $call['function'];
3953                         }
3954                 }
3955         }
3956         if ( $pretty )
3957                 return join( ', ', array_reverse( $caller ) );
3958         else
3959                 return $caller;
3960 }
3961
3962 /**
3963  * Retrieve ids that are not already present in the cache
3964  *
3965  * @since 3.4.0
3966  *
3967  * @param array $object_ids ID list
3968  * @param string $cache_key The cache bucket to check against
3969  *
3970  * @return array
3971  */
3972 function _get_non_cached_ids( $object_ids, $cache_key ) {
3973         $clean = array();
3974         foreach ( $object_ids as $id ) {
3975                 $id = (int) $id;
3976                 if ( !wp_cache_get( $id, $cache_key ) ) {
3977                         $clean[] = $id;
3978                 }
3979         }
3980
3981         return $clean;
3982 }
3983
3984 /**
3985  * Test if the current device has the capability to upload files.
3986  *
3987  * @since 3.4.0
3988  * @access private
3989  *
3990  * @return bool true|false
3991  */
3992 function _device_can_upload() {
3993         if ( ! wp_is_mobile() )
3994                 return true;
3995
3996         $ua = $_SERVER['HTTP_USER_AGENT'];
3997
3998         if ( strpos($ua, 'iPhone') !== false
3999                 || strpos($ua, 'iPad') !== false
4000                 || strpos($ua, 'iPod') !== false ) {
4001                         return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
4002         }
4003
4004         return true;
4005 }
4006
4007 /**
4008  * Test if a given path is a stream URL
4009  *
4010  * @param string $path The resource path or URL
4011  * @return bool True if the path is a stream URL
4012  */
4013 function wp_is_stream( $path ) {
4014         $wrappers = stream_get_wrappers();
4015         $wrappers_re = '(' . join('|', $wrappers) . ')';
4016
4017         return preg_match( "!^$wrappers_re://!", $path ) === 1;
4018 }
4019
4020 /**
4021  * Test if the supplied date is valid for the Gregorian calendar
4022  *
4023  * @since 3.5.0
4024  *
4025  * @return bool true|false
4026  */
4027 function wp_checkdate( $month, $day, $year, $source_date ) {
4028         return apply_filters( 'wp_checkdate', checkdate( $month, $day, $year ), $source_date );
4029 }
4030
4031 /**
4032  * Load the auth check for monitoring whether the user is still logged in.
4033  *
4034  * Can be disabled with remove_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
4035  *
4036  * This is disabled for certain screens where a login screen could cause an
4037  * inconvenient interruption. A filter called wp_auth_check_load can be used
4038  * for fine-grained control.
4039  *
4040  * @since 3.6.0
4041  */
4042 function wp_auth_check_load() {
4043         if ( ! is_admin() && ! is_user_logged_in() )
4044                 return;
4045
4046         if ( defined( 'IFRAME_REQUEST' ) )
4047                 return;
4048
4049         $screen = get_current_screen();
4050         $hidden = array( 'update', 'update-network', 'update-core', 'update-core-network', 'upgrade', 'upgrade-network', 'network' );
4051         $show = ! in_array( $screen->id, $hidden );
4052
4053         if ( apply_filters( 'wp_auth_check_load', $show, $screen ) ) {
4054                 wp_enqueue_style( 'wp-auth-check' );
4055                 wp_enqueue_script( 'wp-auth-check' );
4056
4057                 add_action( 'admin_print_footer_scripts', 'wp_auth_check_html', 5 );
4058                 add_action( 'wp_print_footer_scripts', 'wp_auth_check_html', 5 );
4059         }
4060 }
4061
4062 /**
4063  * Output the HTML that shows the wp-login dialog when the user is no longer logged in.
4064  *
4065  * @since 3.6.0
4066  */
4067 function wp_auth_check_html() {
4068         $login_url = wp_login_url();
4069         $current_domain = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
4070         $same_domain = ( strpos( $login_url, $current_domain ) === 0 );
4071
4072         if ( $same_domain && force_ssl_login() && ! force_ssl_admin() )
4073                 $same_domain = false;
4074
4075         // Let plugins change this if they know better.
4076         $same_domain = apply_filters( 'wp_auth_check_same_domain', $same_domain );
4077         $wrap_class = $same_domain ? 'hidden' : 'hidden fallback';
4078
4079         ?>
4080         <div id="wp-auth-check-wrap" class="<?php echo $wrap_class; ?>">
4081         <div id="wp-auth-check-bg"></div>
4082         <div id="wp-auth-check">
4083         <div class="wp-auth-check-close" tabindex="0" title="<?php esc_attr_e('Close'); ?>"></div>
4084         <?php
4085
4086         if ( $same_domain ) {
4087                 ?>
4088                 <div id="wp-auth-check-form" data-src="<?php echo esc_url( add_query_arg( array( 'interim-login' => 1 ), $login_url ) ); ?>"></div>
4089                 <?php
4090         }
4091
4092         ?>
4093         <div class="wp-auth-fallback">
4094                 <p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e('Session expired'); ?></b></p>
4095                 <p><a href="<?php echo esc_url( $login_url ); ?>" target="_blank"><?php _e('Please log in again.'); ?></a>
4096                 <?php _e('The login page will open in a new window. After logging in you can close it and return to this page.'); ?></p>
4097         </div>
4098         </div>
4099         </div>
4100         <?php
4101 }
4102
4103 /**
4104  * Check whether a user is still logged in, for the heartbeat.
4105  *
4106  * Send a result that shows a log-in box if the user is no longer logged in,
4107  * or if their cookie is within the grace period.
4108  *
4109  * @since 3.6.0
4110  */
4111 function wp_auth_check( $response, $data ) {
4112         $response['wp-auth-check'] = is_user_logged_in() && empty( $GLOBALS['login_grace_period'] );
4113         return $response;
4114 }
4115
4116 /**
4117  * Return RegEx body to liberally match an opening HTML tag that:
4118  * 1. Is self-closing or
4119  * 2. Has no body but has a closing tag of the same name or
4120  * 3. Contains a body and a closing tag of the same name
4121  *
4122  * Note: this RegEx does not balance inner tags and does not attempt to produce valid HTML
4123  *
4124  * @since 3.6.0
4125  *
4126  * @param string $tag An HTML tag name. Example: 'video'
4127  * @return string
4128  */
4129 function get_tag_regex( $tag ) {
4130         if ( empty( $tag ) )
4131                 return;
4132         return sprintf( '<%1$s[^<]*(?:>[\s\S]*<\/%1$s>|\s*\/>)', tag_escape( $tag ) );
4133 }
4134
4135 /**
4136  * Return a canonical form of the provided charset appropriate for passing to PHP
4137  * functions such as htmlspecialchars() and charset html attributes.
4138  *
4139  * @link http://core.trac.wordpress.org/ticket/23688
4140  * @since 3.6.0
4141  *
4142  * @param string A charset name
4143  * @return string The canonical form of the charset
4144  */
4145 function _canonical_charset( $charset ) {
4146         if ( 'UTF-8' === $charset || 'utf-8' === $charset || 'utf8' === $charset ||
4147                 'UTF8' === $charset )
4148                 return 'UTF-8';
4149
4150         if ( 'ISO-8859-1' === $charset || 'iso-8859-1' === $charset ||
4151                 'iso8859-1' === $charset || 'ISO8859-1' === $charset )
4152                 return 'ISO-8859-1';
4153
4154         return $charset;
4155 }
4156
4157 /**
4158  * Sets the mbstring internal encoding to a binary safe encoding whne func_overload is enabled.
4159  *
4160  * When mbstring.func_overload is in use for multi-byte encodings, the results from strlen() and
4161  * similar functions respect the utf8 characters, causing binary data to return incorrect lengths.
4162  *
4163  * This function overrides the mbstring encoding to a binary-safe encoding, and resets it to the
4164  * users expected encoding afterwards through the `reset_mbstring_encoding` function.
4165  *
4166  * It is safe to recursively call this function, however each `mbstring_binary_safe_encoding()`
4167  * call must be followed up with an equal number of `reset_mbstring_encoding()` calls.
4168  *
4169  * @see reset_mbstring_encoding()
4170  *
4171  * @since 3.7.0
4172  *
4173  * @param bool $reset Whether to reset the encoding back to a previously-set encoding.
4174  */
4175 function mbstring_binary_safe_encoding( $reset = false ) {
4176         static $encodings = array();
4177         static $overloaded = null;
4178
4179         if ( is_null( $overloaded ) )
4180                 $overloaded = function_exists( 'mb_internal_encoding' ) && ( ini_get( 'mbstring.func_overload' ) & 2 );
4181
4182         if ( false === $overloaded )
4183                 return;
4184
4185         if ( ! $reset ) {
4186                 $encoding = mb_internal_encoding();
4187                 array_push( $encodings, $encoding );
4188                 mb_internal_encoding( 'ISO-8859-1' );
4189         }
4190
4191         if ( $reset && $encodings ) {
4192                 $encoding = array_pop( $encodings );
4193                 mb_internal_encoding( $encoding );
4194         }
4195 }
4196
4197 /**
4198  * Resets the mbstring internal encoding to a users previously set encoding.
4199  *
4200  * @see mbstring_binary_safe_encoding()
4201  *
4202  * @since 3.7.0
4203  */
4204 function reset_mbstring_encoding() {
4205         mbstring_binary_safe_encoding( true );
4206 }