root/trunk/wp-includes/functions.php

Revision 1530, 89.1 kB (checked in by donncha, 24 seconds ago)

WP Merge with revision 9808

  • Property svn:eol-style set to native
Line 
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     global $wp_locale;
27     $m = $mysqlstring;
28     if ( empty( $m ) )
29         return false;
30
31     if( 'G' == $dateformatstring ) {
32         return gmmktime(
33             (int) substr( $m, 11, 2 ), (int) substr( $m, 14, 2 ), (int) substr( $m, 17, 2 ),
34             (int) substr( $m, 5, 2 ), (int) substr( $m, 8, 2 ), (int) substr( $m, 0, 4 )
35         );
36     }
37
38     $i = mktime(
39         (int) substr( $m, 11, 2 ), (int) substr( $m, 14, 2 ), (int) substr( $m, 17, 2 ),
40         (int) substr( $m, 5, 2 ), (int) substr( $m, 8, 2 ), (int) substr( $m, 0, 4 )
41     );
42
43     if( 'U' == $dateformatstring )
44         return $i;
45
46     if ( -1 == $i || false == $i )
47         $i = 0;
48
49     if ( !empty( $wp_locale->month ) && !empty( $wp_locale->weekday ) && $translate ) {
50         $datemonth = $wp_locale->get_month( date( 'm', $i ) );
51         $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth );
52         $dateweekday = $wp_locale->get_weekday( date( 'w', $i ) );
53         $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday );
54         $datemeridiem = $wp_locale->get_meridiem( date( 'a', $i ) );
55         $datemeridiem_capital = $wp_locale->get_meridiem( date( 'A', $i ) );
56         $dateformatstring = ' ' . $dateformatstring;
57         $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
58         $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . backslashit( $datemonth ), $dateformatstring );
59         $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . backslashit( $dateweekday ), $dateformatstring );
60         $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring );
61         $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . backslashit( $datemeridiem ), $dateformatstring );
62         $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring );
63
64         $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
65     }
66     $j = @date( $dateformatstring, $i );
67
68     /*
69     if ( !$j ) // for debug purposes
70         echo $i." ".$mysqlstring;
71     */
72
73     return $j;
74 }
75
76 /**
77  * Retrieve the current time based on specified type.
78  *
79  * The 'mysql' type will return the time in the format for MySQL DATETIME field.
80  * The 'timestamp' type will return the current timestamp.
81  *
82  * If the $gmt is set to either '1' or 'true', then both types will use the
83  * GMT offset in the WordPress option to add the GMT offset to the time.
84  *
85  * @since 1.0.0
86  *
87  * @param string $type Either 'mysql' or 'timestamp'.
88  * @param int|bool $gmt Optional. Whether to use $gmt offset. Default is false.
89  * @return int|string String if $type is 'gmt', int if $type is 'timestamp'.
90  */
91 function current_time( $type, $gmt = 0 ) {
92     switch ( $type ) {
93         case 'mysql':
94             return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', ( time() + ( get_option( 'gmt_offset' ) * 3600 ) ) );
95             break;
96         case 'timestamp':
97             return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * 3600 );
98             break;
99     }
100 }
101
102 /**
103  * Retrieve the date in localized format, based on timestamp.
104  *
105  * If the locale specifies the locale month and weekday, then the locale will
106  * take over the format for the date. If it isn't, then the date format string
107  * will be used instead.
108  *
109  * @since 0.71
110  *
111  * @param string $dateformatstring Format to display the date
112  * @param int $unixtimestamp Unix timestamp
113  * @return string The date, translated if locale specifies it.
114  */
115 function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
116     global $wp_locale;
117     $i = $unixtimestamp;
118     // Sanity check for PHP 5.1.0-
119     if ( false === $i || intval($i) < 0 ) {
120         if ( ! $gmt )
121             $i = current_time( 'timestamp' );
122         else
123             $i = time();
124         // we should not let date() interfere with our
125         // specially computed timestamp
126         $gmt = true;
127     }
128
129     $datefunc = $gmt? 'gmdate' : 'date';
130
131     if ( ( !empty( $wp_locale->month ) ) && ( !empty( $wp_locale->weekday ) ) ) {
132         $datemonth = $wp_locale->get_month( $datefunc( 'm', $i ) );
133         $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth );
134         $dateweekday = $wp_locale->get_weekday( $datefunc( 'w', $i ) );
135         $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday );
136         $datemeridiem = $wp_locale->get_meridiem( $datefunc( 'a', $i ) );
137         $datemeridiem_capital = $wp_locale->get_meridiem( $datefunc( 'A', $i ) );
138         $dateformatstring = ' '.$dateformatstring;
139         $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
140         $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . backslashit( $datemonth ), $dateformatstring );
141         $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . backslashit( $dateweekday ), $dateformatstring );
142         $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring );
143         $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . backslashit( $datemeridiem ), $dateformatstring );
144         $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring );
145
146         $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
147     }
148     $j = @$datefunc( $dateformatstring, $i );
149     return $j;
150 }
151
152 /**
153  * Convert number to format based on the locale.
154  *
155  * @since 2.3.0
156  *
157  * @param mixed $number The number to convert based on locale.
158  * @param int $decimals Precision of the number of decimal places.
159  * @return string Converted number in string format.
160  */
161 function number_format_i18n( $number, $decimals = null ) {
162     global $wp_locale;
163     // let the user override the precision only
164     $decimals = ( is_null( $decimals ) ) ? $wp_locale->number_format['decimals'] : intval( $decimals );
165
166     return number_format( $number, $decimals, $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
167 }
168
169 /**
170  * Convert number of bytes largest unit bytes will fit into.
171  *
172  * It is easier to read 1kB than 1024 bytes and 1MB than 1048576 bytes. Converts
173  * number of bytes to human readable number by taking the number of that unit
174  * that the bytes will go into it. Supports TB value.
175  *
176  * Please note that integers in PHP are limited to 32 bits, unless they are on
177  * 64 bit architecture, then they have 64 bit size. If you need to place the
178  * larger size then what PHP integer type will hold, then use a string. It will
179  * be converted to a double, which should always have 64 bit length.
180  *
181  * Technically the correct unit names for powers of 1024 are KiB, MiB etc.
182  * @link http://en.wikipedia.org/wiki/Byte
183  *
184  * @since 2.3.0
185  *
186  * @param int|string $bytes Number of bytes. Note max integer size for integers.
187  * @param int $decimals Precision of number of decimal places.
188  * @return bool|string False on failure. Number string on success.
189  */
190 function size_format( $bytes, $decimals = null ) {
191     $quant = array(
192         // ========================= Origin ====
193         'TB' => 1099511627776// pow( 1024, 4)
194         'GB' => 1073741824,     // pow( 1024, 3)
195         'MB' => 1048576,        // pow( 1024, 2)
196         'kB' => 1024,           // pow( 1024, 1)
197         'B ' => 1,              // pow( 1024, 0)
198     );
199
200     foreach ( $quant as $unit => $mag )
201         if ( doubleval($bytes) >= $mag )
202             return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
203
204     return false;
205 }
206
207 /**
208  * Get the week start and end from the datetime or date string from mysql.
209  *
210  * @since 0.71
211  *
212  * @param string $mysqlstring Date or datetime field type from mysql.
213  * @param int $start_of_week Optional. Start of the week as an integer.
214  * @return array Keys are 'start' and 'end'.
215  */
216 function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
217     $my = substr( $mysqlstring, 0, 4 ); // Mysql string Year
218     $mm = substr( $mysqlstring, 8, 2 ); // Mysql string Month
219     $md = substr( $mysqlstring, 5, 2 ); // Mysql string day
220     $day = mktime( 0, 0, 0, $md, $mm, $my ); // The timestamp for mysqlstring day.
221     $weekday = date( 'w', $day ); // The day of the week from the timestamp
222     $i = 86400; // One day
223     if( !is_numeric($start_of_week) )
224         $start_of_week = get_option( 'start_of_week' );
225
226     if ( $weekday < $start_of_week )
227         $weekday = 7 - $start_of_week - $weekday;
228
229     while ( $weekday > $start_of_week ) {
230         $weekday = date( 'w', $day );
231         if ( $weekday < $start_of_week )
232             $weekday = 7 - $start_of_week - $weekday;
233
234         $day -= 86400;
235         $i = 0;
236     }
237     $week['start'] = $day + 86400 - $i;
238     $week['end'] = $week['start'] + 604799;
239     return $week;
240 }
241
242 /**
243  * Unserialize value only if it was serialized.
244  *
245  * @since 2.0.0
246  *
247  * @param string $original Maybe unserialized original, if is needed.
248  * @return mixed Unserialized data can be any type.
249  */
250 function maybe_unserialize( $original ) {
251     if ( is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in
252         if ( false !== $gm = @unserialize( $original ) )
253             return $gm;
254     return $original;
255 }
256
257 /**
258  * Check value to find if it was serialized.
259  *
260  * If $data is not an string, then returned value will always be false.
261  * Serialized data is always a string.
262  *
263  * @since 2.0.5
264  *
265  * @param mixed $data Value to check to see if was serialized.
266  * @return bool False if not serialized and true if it was.
267  */
268 function is_serialized( $data ) {
269     // if it isn't a string, it isn't serialized
270     if ( !is_string( $data ) )
271         return false;
272     $data = trim( $data );
273     if ( 'N;' == $data )
274         return true;
275     if ( !preg_match( '/^([adObis]):/', $data, $badions ) )
276         return false;
277     switch ( $badions[1] ) {
278         case 'a' :
279         case 'O' :
280         case 's' :
281             if ( preg_match( "/^{$badions[1]}:[0-9]+:.*[;}]\$/s", $data ) )
282                 return true;
283             break;
284         case 'b' :
285         case 'i' :
286         case 'd' :
287             if ( preg_match( "/^{$badions[1]}:[0-9.E-]+;\$/", $data ) )
288                 return true;
289             break;
290     }
291     return false;
292 }
293
294 /**
295  * Check whether serialized data is of string type.
296  *
297  * @since 2.0.5
298  *
299  * @param mixed $data Serialized data
300  * @return bool False if not a serialized string, true if it is.
301  */
302 function is_serialized_string( $data ) {
303     // if it isn't a string, it isn't a serialized string
304     if ( !is_string( $data ) )
305         return false;
306     $data = trim( $data );
307     if ( preg_match( '/^s:[0-9]+:.*;$/s', $data ) ) // this should fetch all serialized strings
308         return true;
309     return false;
310 }
311
312 /**
313  * Retrieve option value based on setting name.
314  *
315  * If the option does not exist or does not have a value, then the return value
316  * will be false. This is useful to check whether you need to install an option
317  * and is commonly used during installation of plugin options and to test
318  * whether upgrading is required.
319  *
320  * You can "short-circuit" the retrieval of the option from the database for
321  * your plugin or core options that aren't protected. You can do so by hooking
322  * into the 'pre_option_$option' with the $option being replaced by the option
323  * name. You should not try to override special options, but you will not be
324  * prevented from doing so.
325  *
326  * There is a second filter called 'option_$option' with the $option being
327  * replaced with the option name. This gives the value as the only parameter.
328  *
329  * If the option was serialized, when the option was added and, or updated, then
330  * it will be unserialized, when it is returned.
331  *
332  * @since 1.5.0
333  * @package WordPress
334  * @subpackage Option
335  * @uses apply_filters() Calls 'pre_option_$optionname' false to allow
336  *        overwriting the option value in a plugin.
337  * @uses apply_filters() Calls 'option_$optionname' with the option name value.
338  *
339  * @param string $setting Name of option to retrieve. Should already be SQL-escaped
340  * @return mixed Value set for the option.
341  */
342 function get_option( $setting, $default = false ) {
343     global $wpdb, $switched, $current_blog;
344
345     $wpdb->hide_errors();
346     // Allow plugins to short-circuit options.
347     $pre = apply_filters( 'pre_option_' . $setting, false );
348     if ( false !== $pre )
349         return $pre;
350
351     $value = _get_option_cache( $setting );
352     if ( false === $value )
353             return $default;
354
355     // If home is not set use siteurl.
356     if ( 'home' == $setting && '' == $value )
357         return get_option( 'siteurl' );
358
359     if ( in_array( $setting, array('siteurl', 'home', 'category_base', 'tag_base') ) )
360         $value = untrailingslashit( $value );
361
362     if (! unserialize($value) )
363         $value = stripslashes( $value );
364
365     return apply_filters( 'option_' . $setting, maybe_unserialize( $value ) );
366 }
367
368 /**
369  * Protect WordPress special option from being modified.
370  *
371  * Will die if $option is in protected list. Protected options are 'alloptions'
372  * and 'notoptions' options.
373  *
374  * @since 2.2.0
375  * @package WordPress
376  * @subpackage Option
377  *
378  * @param string $option Option name.
379  */
380 function wp_protect_special_option( $option ) {
381     $protected = array( 'alloptions', 'notoptions' );
382     if ( in_array( $option, $protected ) )
383         die( sprintf( __( '%s is a protected WP option and may not be modified' ), wp_specialchars( $option ) ) );
384 }
385
386 /**
387  * Print option value after sanitizing for forms.
388  *
389  * @uses attribute_escape Sanitizes value.
390  * @since 1.5.0
391  * @package WordPress
392  * @subpackage Option
393  *
394  * @param string $option Option name.
395  */
396 function form_option( $option ) {
397     echo attribute_escape (get_option( $option ) );
398 }
399
400 /**
401  * Retrieve all autoload options or all options, if no autoloaded ones exist.
402  *
403  * This is different from wp_load_alloptions(), in this that function does not
404  * cache all options and will retrieve all options from the database every time
405  * it is called.
406  *
407  * @since 1.0.0
408  * @package WordPress
409  * @subpackage Option
410  * @uses apply_filters() Calls 'pre_option_$optionname' hook with option value as parameter.
411  * @uses apply_filters() Calls 'all_options' on options list.
412  *
413  * @return array List of all options.
414  */
415 function get_alloptions() {
416     global $wpdb;
417     $show = $wpdb->hide_errors();
418     if ( !$options = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'" ) )
419         $options = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
420     $wpdb->show_errors($show);
421
422     foreach ( (array) $options as $option ) {
423         // "When trying to design a foolproof system,
424         //  never underestimate the ingenuity of the fools :)" -- Dougal
425         if ( in_array( $option->option_name, array( 'siteurl', 'home', 'category_base', 'tag_base' ) ) )
426             $option->option_value = untrailingslashit( $option->option_value );
427         $value = maybe_unserialize( $option->option_value );
428         $all_options->{$option->option_name} = apply_filters( 'pre_option_' . $option->option_name, $value );
429     }
430     return apply_filters( 'all_options', $all_options );
431 }
432
433 /**
434  * Loads and caches all autoloaded options, if available or all options.
435  *
436  * This is different from get_alloptions(), in that this function will cache the
437  * options and will return the cached options when called again.
438  *
439  * @since 2.2.0
440  * @package WordPress
441  * @subpackage Option
442  *
443  * @return array List all options.
444  */
445 function wp_load_alloptions() {
446     global $wpdb;
447     global $_wp_alloptions;
448     global $blog_id;
449
450     if( !defined( 'WP_INSTALLING' ) ) {
451         if ( !empty($_wp_alloptions[$blog_id]) )
452             return $_wp_alloptions[$blog_id];
453
454         $alloptions = wp_cache_get('alloptions', 'options');
455
456         if ( false !== $alloptions ) {
457             $_wp_alloptions[$blog_id] = $alloptions;
458             return $alloptions;
459         }
460
461         $_wp_alloptions[$blog_id] = array();
462     }
463
464     $suppress = $wpdb->suppress_errors();
465     // order by option_id asc in case there are duplicate values - this makes the most recent value overwrite the others in the array
466     $alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options FORCE INDEX(PRIMARY) ORDER BY option_id ASC" );
467     $wpdb->suppress_errors($suppress);
468     foreach ( (array) $alloptions_db as $o )
469         $_wp_alloptions[$blog_id][$o->option_name] = $o->option_value;
470
471     wp_cache_set('alloptions', $_wp_alloptions[$blog_id], 'options');
472
473     return $_wp_alloptions[$blog_id];
474 }
475
476 function _get_option_cache( $setting ) {
477     global $_wp_alloptions;
478     global $blog_id;
479     
480     wp_load_alloptions();
481
482     if ( isset($_wp_alloptions[$blog_id][$setting]) )
483         return $_wp_alloptions[$blog_id][$setting];
484
485     return false;
486 }
487
488 function _set_option_cache( $setting, $value ) {
489     global $_wp_alloptions;
490     global $blog_id;
491
492     wp_load_alloptions();
493
494     $_wp_alloptions[$blog_id][$setting] = $value;
495
496     wp_cache_delete('alloptions', 'options');
497 }
498
499 function _delete_option_cache( $setting ) {
500     global $_wp_alloptions;
501     global $blog_id;
502
503     wp_load_alloptions();
504
505     if ( isset($_wp_alloptions[$blog_id][$setting]) )
506         unset($_wp_alloptions[$blog_id][$setting]);
507
508     wp_cache_delete('alloptions', 'options');
509 }
510
511 /**
512  * Update the value of an option that was already added.
513  *
514  * You do not need to serialize values, if the value needs to be serialize, then
515  * it will be serialized before it is inserted into the database. Remember,
516  * resources can not be serialized or added as an option.
517  *
518  * If the option does not exist, then the option will be added with the option
519  * value, but you will not be able to set whether it is autoloaded. If you want
520  * to set whether an option autoloaded, then you need to use the add_option().
521  *
522  * When the option is updated, then the filter named
523  * 'update_option_$option_name', with the $option_name as the $option_name
524  * parameter value, will be called. The hook should accept two parameters, the
525  * first is the old parameter and the second is the new parameter.
526  *
527  * @since 1.0.0
528  * @package WordPress
529  * @subpackage Option
530  *
531  * @param string $option_name Option name. Expected to not be SQL-escaped
532  * @param mixed $newvalue Option value.
533  * @return bool False if value was not updated and true if value was updated.
534  */
535 function update_option( $option_name, $newvalue ) {
536     global $wpdb;
537
538     wp_protect_special_option( $option_name );
539
540     $safe_option_name = $wpdb->escape( $option_name );
541     $newvalue = sanitize_option( $option_name, $newvalue );
542
543     $oldvalue = get_option( $safe_option_name );
544
545     $newvalue = apply_filters( 'pre_update_option_' . $option_name, $newvalue, $oldvalue );
546
547     // If the new and old values are the same, no need to update.
548     if ( $newvalue === $oldvalue )
549         return false;
550
551     if ( false === $oldvalue ) {
552         add_option( $option_name, $newvalue );
553         return true;
554     }
555
556     $_newvalue = $newvalue;
557     $newvalue = maybe_serialize( $newvalue );
558
559     _