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