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