]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/user.php
Wordpress 3.7
[autoinstalls/wordpress.git] / wp-includes / user.php
1 <?php
2 /**
3  * WordPress User API
4  *
5  * @package WordPress
6  */
7
8 /**
9  * Authenticate user with remember capability.
10  *
11  * The credentials is an array that has 'user_login', 'user_password', and
12  * 'remember' indices. If the credentials is not given, then the log in form
13  * will be assumed and used if set.
14  *
15  * The various authentication cookies will be set by this function and will be
16  * set for a longer period depending on if the 'remember' credential is set to
17  * true.
18  *
19  * @since 2.5.0
20  *
21  * @param array $credentials Optional. User info in order to sign on.
22  * @param bool $secure_cookie Optional. Whether to use secure cookie.
23  * @return object Either WP_Error on failure, or WP_User on success.
24  */
25 function wp_signon( $credentials = '', $secure_cookie = '' ) {
26         if ( empty($credentials) ) {
27                 if ( ! empty($_POST['log']) )
28                         $credentials['user_login'] = $_POST['log'];
29                 if ( ! empty($_POST['pwd']) )
30                         $credentials['user_password'] = $_POST['pwd'];
31                 if ( ! empty($_POST['rememberme']) )
32                         $credentials['remember'] = $_POST['rememberme'];
33         }
34
35         if ( !empty($credentials['remember']) )
36                 $credentials['remember'] = true;
37         else
38                 $credentials['remember'] = false;
39
40         // TODO do we deprecate the wp_authentication action?
41         do_action_ref_array('wp_authenticate', array(&$credentials['user_login'], &$credentials['user_password']));
42
43         if ( '' === $secure_cookie )
44                 $secure_cookie = is_ssl();
45
46         $secure_cookie = apply_filters('secure_signon_cookie', $secure_cookie, $credentials);
47
48         global $auth_secure_cookie; // XXX ugly hack to pass this to wp_authenticate_cookie
49         $auth_secure_cookie = $secure_cookie;
50
51         add_filter('authenticate', 'wp_authenticate_cookie', 30, 3);
52
53         $user = wp_authenticate($credentials['user_login'], $credentials['user_password']);
54
55         if ( is_wp_error($user) ) {
56                 if ( $user->get_error_codes() == array('empty_username', 'empty_password') ) {
57                         $user = new WP_Error('', '');
58                 }
59
60                 return $user;
61         }
62
63         wp_set_auth_cookie($user->ID, $credentials['remember'], $secure_cookie);
64         do_action('wp_login', $user->user_login, $user);
65         return $user;
66 }
67
68 /**
69  * Authenticate the user using the username and password.
70  */
71 add_filter('authenticate', 'wp_authenticate_username_password', 20, 3);
72 function wp_authenticate_username_password($user, $username, $password) {
73         if ( is_a($user, 'WP_User') ) { return $user; }
74
75         if ( empty($username) || empty($password) ) {
76                 if ( is_wp_error( $user ) )
77                         return $user;
78
79                 $error = new WP_Error();
80
81                 if ( empty($username) )
82                         $error->add('empty_username', __('<strong>ERROR</strong>: The username field is empty.'));
83
84                 if ( empty($password) )
85                         $error->add('empty_password', __('<strong>ERROR</strong>: The password field is empty.'));
86
87                 return $error;
88         }
89
90         $user = get_user_by('login', $username);
91
92         if ( !$user )
93                 return new WP_Error( 'invalid_username', sprintf( __( '<strong>ERROR</strong>: Invalid username. <a href="%s" title="Password Lost and Found">Lost your password</a>?' ), wp_lostpassword_url() ) );
94
95         $user = apply_filters('wp_authenticate_user', $user, $password);
96         if ( is_wp_error($user) )
97                 return $user;
98
99         if ( !wp_check_password($password, $user->user_pass, $user->ID) )
100                 return new WP_Error( 'incorrect_password', sprintf( __( '<strong>ERROR</strong>: The password you entered for the username <strong>%1$s</strong> is incorrect. <a href="%2$s" title="Password Lost and Found">Lost your password</a>?' ),
101                 $username, wp_lostpassword_url() ) );
102
103         return $user;
104 }
105
106 /**
107  * Authenticate the user using the WordPress auth cookie.
108  */
109 function wp_authenticate_cookie($user, $username, $password) {
110         if ( is_a($user, 'WP_User') ) { return $user; }
111
112         if ( empty($username) && empty($password) ) {
113                 $user_id = wp_validate_auth_cookie();
114                 if ( $user_id )
115                         return new WP_User($user_id);
116
117                 global $auth_secure_cookie;
118
119                 if ( $auth_secure_cookie )
120                         $auth_cookie = SECURE_AUTH_COOKIE;
121                 else
122                         $auth_cookie = AUTH_COOKIE;
123
124                 if ( !empty($_COOKIE[$auth_cookie]) )
125                         return new WP_Error('expired_session', __('Please log in again.'));
126
127                 // If the cookie is not set, be silent.
128         }
129
130         return $user;
131 }
132
133 /**
134  * For multisite blogs, check if the authenticated user has been marked as a
135  * spammer, or if the user's primary blog has been marked as spam.
136  *
137  * @since 3.7.0
138  */
139 function wp_authenticate_spam_check( $user ) {
140         if ( $user && is_a( $user, 'WP_User' ) && is_multisite() ) {
141                 $spammed = apply_filters( 'check_is_user_spammed', is_user_spammy(), $user );
142
143                 if ( $spammed )
144                         return new WP_Error( 'spammer_account', __( '<strong>ERROR</strong>: Your account has been marked as a spammer.' ) );
145         }
146         return $user;
147 }
148
149 /**
150  * Number of posts user has written.
151  *
152  * @since 3.0.0
153  * @uses $wpdb WordPress database object for queries.
154  *
155  * @param int $userid User ID.
156  * @return int Amount of posts user has written.
157  */
158 function count_user_posts($userid) {
159         global $wpdb;
160
161         $where = get_posts_by_author_sql('post', true, $userid);
162
163         $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" );
164
165         return apply_filters('get_usernumposts', $count, $userid);
166 }
167
168 /**
169  * Number of posts written by a list of users.
170  *
171  * @since 3.0.0
172  *
173  * @param array $users Array of user IDs.
174  * @param string $post_type Optional. Post type to check. Defaults to post.
175  * @param bool $public_only Optional. Only return counts for public posts.  Defaults to false.
176  * @return array Amount of posts each user has written.
177  */
178 function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) {
179         global $wpdb;
180
181         $count = array();
182         if ( empty( $users ) || ! is_array( $users ) )
183                 return $count;
184
185         $userlist = implode( ',', array_map( 'absint', $users ) );
186         $where = get_posts_by_author_sql( $post_type, true, null, $public_only );
187
188         $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N );
189         foreach ( $result as $row ) {
190                 $count[ $row[0] ] = $row[1];
191         }
192
193         foreach ( $users as $id ) {
194                 if ( ! isset( $count[ $id ] ) )
195                         $count[ $id ] = 0;
196         }
197
198         return $count;
199 }
200
201 //
202 // User option functions
203 //
204
205 /**
206  * Get the current user's ID
207  *
208  * @since MU
209  *
210  * @uses wp_get_current_user
211  *
212  * @return int The current user's ID
213  */
214 function get_current_user_id() {
215         $user = wp_get_current_user();
216         return ( isset( $user->ID ) ? (int) $user->ID : 0 );
217 }
218
219 /**
220  * Retrieve user option that can be either per Site or per Network.
221  *
222  * If the user ID is not given, then the current user will be used instead. If
223  * the user ID is given, then the user data will be retrieved. The filter for
224  * the result, will also pass the original option name and finally the user data
225  * object as the third parameter.
226  *
227  * The option will first check for the per site name and then the per Network name.
228  *
229  * @since 2.0.0
230  * @uses $wpdb WordPress database object for queries.
231  * @uses apply_filters() Calls 'get_user_option_$option' hook with result,
232  *              option parameter, and user data object.
233  *
234  * @param string $option User option name.
235  * @param int $user Optional. User ID.
236  * @param bool $deprecated Use get_option() to check for an option in the options table.
237  * @return mixed
238  */
239 function get_user_option( $option, $user = 0, $deprecated = '' ) {
240         global $wpdb;
241
242         if ( !empty( $deprecated ) )
243                 _deprecated_argument( __FUNCTION__, '3.0' );
244
245         if ( empty( $user ) )
246                 $user = get_current_user_id();
247
248         if ( ! $user = get_userdata( $user ) )
249                 return false;
250
251         $prefix = $wpdb->get_blog_prefix();
252         if ( $user->has_prop( $prefix . $option ) ) // Blog specific
253                 $result = $user->get( $prefix . $option );
254         elseif ( $user->has_prop( $option ) ) // User specific and cross-blog
255                 $result = $user->get( $option );
256         else
257                 $result = false;
258
259         return apply_filters("get_user_option_{$option}", $result, $option, $user);
260 }
261
262 /**
263  * Update user option with global blog capability.
264  *
265  * User options are just like user metadata except that they have support for
266  * global blog options. If the 'global' parameter is false, which it is by default
267  * it will prepend the WordPress table prefix to the option name.
268  *
269  * Deletes the user option if $newvalue is empty.
270  *
271  * @since 2.0.0
272  * @uses $wpdb WordPress database object for queries
273  *
274  * @param int $user_id User ID
275  * @param string $option_name User option name.
276  * @param mixed $newvalue User option value.
277  * @param bool $global Optional. Whether option name is global or blog specific. Default false (blog specific).
278  * @return unknown
279  */
280 function update_user_option( $user_id, $option_name, $newvalue, $global = false ) {
281         global $wpdb;
282
283         if ( !$global )
284                 $option_name = $wpdb->get_blog_prefix() . $option_name;
285
286         return update_user_meta( $user_id, $option_name, $newvalue );
287 }
288
289 /**
290  * Delete user option with global blog capability.
291  *
292  * User options are just like user metadata except that they have support for
293  * global blog options. If the 'global' parameter is false, which it is by default
294  * it will prepend the WordPress table prefix to the option name.
295  *
296  * @since 3.0.0
297  * @uses $wpdb WordPress database object for queries
298  *
299  * @param int $user_id User ID
300  * @param string $option_name User option name.
301  * @param bool $global Optional. Whether option name is global or blog specific. Default false (blog specific).
302  * @return unknown
303  */
304 function delete_user_option( $user_id, $option_name, $global = false ) {
305         global $wpdb;
306
307         if ( !$global )
308                 $option_name = $wpdb->get_blog_prefix() . $option_name;
309         return delete_user_meta( $user_id, $option_name );
310 }
311
312 /**
313  * WordPress User Query class.
314  *
315  * @since 3.1.0
316  */
317 class WP_User_Query {
318
319         /**
320          * Query vars, after parsing
321          *
322          * @since 3.5.0
323          * @access public
324          * @var array
325          */
326         var $query_vars = array();
327
328         /**
329          * List of found user ids
330          *
331          * @since 3.1.0
332          * @access private
333          * @var array
334          */
335         var $results;
336
337         /**
338          * Total number of found users for the current query
339          *
340          * @since 3.1.0
341          * @access private
342          * @var int
343          */
344         var $total_users = 0;
345
346         // SQL clauses
347         var $query_fields;
348         var $query_from;
349         var $query_where;
350         var $query_orderby;
351         var $query_limit;
352
353         /**
354          * PHP5 constructor
355          *
356          * @since 3.1.0
357          *
358          * @param string|array $args The query variables
359          * @return WP_User_Query
360          */
361         function __construct( $query = null ) {
362                 if ( !empty( $query ) ) {
363                         $this->query_vars = wp_parse_args( $query, array(
364                                 'blog_id' => $GLOBALS['blog_id'],
365                                 'role' => '',
366                                 'meta_key' => '',
367                                 'meta_value' => '',
368                                 'meta_compare' => '',
369                                 'include' => array(),
370                                 'exclude' => array(),
371                                 'search' => '',
372                                 'search_columns' => array(),
373                                 'orderby' => 'login',
374                                 'order' => 'ASC',
375                                 'offset' => '',
376                                 'number' => '',
377                                 'count_total' => true,
378                                 'fields' => 'all',
379                                 'who' => ''
380                         ) );
381
382                         $this->prepare_query();
383                         $this->query();
384                 }
385         }
386
387         /**
388          * Prepare the query variables
389          *
390          * @since 3.1.0
391          * @access private
392          */
393         function prepare_query() {
394                 global $wpdb;
395
396                 $qv =& $this->query_vars;
397
398                 if ( is_array( $qv['fields'] ) ) {
399                         $qv['fields'] = array_unique( $qv['fields'] );
400
401                         $this->query_fields = array();
402                         foreach ( $qv['fields'] as $field ) {
403                                 $field = 'ID' === $field ? 'ID' : sanitize_key( $field );
404                                 $this->query_fields[] = "$wpdb->users.$field";
405                         }
406                         $this->query_fields = implode( ',', $this->query_fields );
407                 } elseif ( 'all' == $qv['fields'] ) {
408                         $this->query_fields = "$wpdb->users.*";
409                 } else {
410                         $this->query_fields = "$wpdb->users.ID";
411                 }
412
413                 if ( isset( $qv['count_total'] ) && $qv['count_total'] )
414                         $this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields;
415
416                 $this->query_from = "FROM $wpdb->users";
417                 $this->query_where = "WHERE 1=1";
418
419                 // sorting
420                 if ( isset( $qv['orderby'] ) ) {
421                         if ( in_array( $qv['orderby'], array('nicename', 'email', 'url', 'registered') ) ) {
422                                 $orderby = 'user_' . $qv['orderby'];
423                         } elseif ( in_array( $qv['orderby'], array('user_nicename', 'user_email', 'user_url', 'user_registered') ) ) {
424                                 $orderby = $qv['orderby'];
425                         } elseif ( 'name' == $qv['orderby'] || 'display_name' == $qv['orderby'] ) {
426                                 $orderby = 'display_name';
427                         } elseif ( 'post_count' == $qv['orderby'] ) {
428                                 // todo: avoid the JOIN
429                                 $where = get_posts_by_author_sql('post');
430                                 $this->query_from .= " LEFT OUTER JOIN (
431                                         SELECT post_author, COUNT(*) as post_count
432                                         FROM $wpdb->posts
433                                         $where
434                                         GROUP BY post_author
435                                 ) p ON ({$wpdb->users}.ID = p.post_author)
436                                 ";
437                                 $orderby = 'post_count';
438                         } elseif ( 'ID' == $qv['orderby'] || 'id' == $qv['orderby'] ) {
439                                 $orderby = 'ID';
440                         } elseif ( 'meta_value' == $qv['orderby'] ) {
441                                 $orderby = "$wpdb->usermeta.meta_value";
442                         } else {
443                                 $orderby = 'user_login';
444                         }
445                 }
446
447                 if ( empty( $orderby ) )
448                         $orderby = 'user_login';
449
450                 $qv['order'] = isset( $qv['order'] ) ? strtoupper( $qv['order'] ) : '';
451                 if ( 'ASC' == $qv['order'] )
452                         $order = 'ASC';
453                 else
454                         $order = 'DESC';
455                 $this->query_orderby = "ORDER BY $orderby $order";
456
457                 // limit
458                 if ( isset( $qv['number'] ) && $qv['number'] ) {
459                         if ( $qv['offset'] )
460                                 $this->query_limit = $wpdb->prepare("LIMIT %d, %d", $qv['offset'], $qv['number']);
461                         else
462                                 $this->query_limit = $wpdb->prepare("LIMIT %d", $qv['number']);
463                 }
464
465                 $search = '';
466                 if ( isset( $qv['search'] ) )
467                         $search = trim( $qv['search'] );
468
469                 if ( $search ) {
470                         $leading_wild = ( ltrim($search, '*') != $search );
471                         $trailing_wild = ( rtrim($search, '*') != $search );
472                         if ( $leading_wild && $trailing_wild )
473                                 $wild = 'both';
474                         elseif ( $leading_wild )
475                                 $wild = 'leading';
476                         elseif ( $trailing_wild )
477                                 $wild = 'trailing';
478                         else
479                                 $wild = false;
480                         if ( $wild )
481                                 $search = trim($search, '*');
482
483                         $search_columns = array();
484                         if ( $qv['search_columns'] )
485                                 $search_columns = array_intersect( $qv['search_columns'], array( 'ID', 'user_login', 'user_email', 'user_url', 'user_nicename' ) );
486                         if ( ! $search_columns ) {
487                                 if ( false !== strpos( $search, '@') )
488                                         $search_columns = array('user_email');
489                                 elseif ( is_numeric($search) )
490                                         $search_columns = array('user_login', 'ID');
491                                 elseif ( preg_match('|^https?://|', $search) && ! ( is_multisite() && wp_is_large_network( 'users' ) ) )
492                                         $search_columns = array('user_url');
493                                 else
494                                         $search_columns = array('user_login', 'user_nicename');
495                         }
496
497                         $search_columns = apply_filters( 'user_search_columns', $search_columns, $search, $this );
498
499                         $this->query_where .= $this->get_search_sql( $search, $search_columns, $wild );
500                 }
501
502                 $blog_id = 0;
503                 if ( isset( $qv['blog_id'] ) )
504                         $blog_id = absint( $qv['blog_id'] );
505
506                 if ( isset( $qv['who'] ) && 'authors' == $qv['who'] && $blog_id ) {
507                         $qv['meta_key'] = $wpdb->get_blog_prefix( $blog_id ) . 'user_level';
508                         $qv['meta_value'] = 0;
509                         $qv['meta_compare'] = '!=';
510                         $qv['blog_id'] = $blog_id = 0; // Prevent extra meta query
511                 }
512
513                 $role = '';
514                 if ( isset( $qv['role'] ) )
515                         $role = trim( $qv['role'] );
516
517                 if ( $blog_id && ( $role || is_multisite() ) ) {
518                         $cap_meta_query = array();
519                         $cap_meta_query['key'] = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities';
520
521                         if ( $role ) {
522                                 $cap_meta_query['value'] = '"' . $role . '"';
523                                 $cap_meta_query['compare'] = 'like';
524                         }
525
526                         $qv['meta_query'][] = $cap_meta_query;
527                 }
528
529                 $meta_query = new WP_Meta_Query();
530                 $meta_query->parse_query_vars( $qv );
531
532                 if ( !empty( $meta_query->queries ) ) {
533                         $clauses = $meta_query->get_sql( 'user', $wpdb->users, 'ID', $this );
534                         $this->query_from .= $clauses['join'];
535                         $this->query_where .= $clauses['where'];
536
537                         if ( 'OR' == $meta_query->relation )
538                                 $this->query_fields = 'DISTINCT ' . $this->query_fields;
539                 }
540
541                 if ( ! empty( $qv['include'] ) ) {
542                         $ids = implode( ',', wp_parse_id_list( $qv['include'] ) );
543                         $this->query_where .= " AND $wpdb->users.ID IN ($ids)";
544                 } elseif ( ! empty( $qv['exclude'] ) ) {
545                         $ids = implode( ',', wp_parse_id_list( $qv['exclude'] ) );
546                         $this->query_where .= " AND $wpdb->users.ID NOT IN ($ids)";
547                 }
548
549                 do_action_ref_array( 'pre_user_query', array( &$this ) );
550         }
551
552         /**
553          * Execute the query, with the current variables
554          *
555          * @since 3.1.0
556          * @access private
557          */
558         function query() {
559                 global $wpdb;
560
561                 $qv =& $this->query_vars;
562
563                 if ( is_array( $qv['fields'] ) || 'all' == $qv['fields'] ) {
564                         $this->results = $wpdb->get_results("SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit");
565                 } else {
566                         $this->results = $wpdb->get_col("SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit");
567                 }
568
569                 if ( isset( $qv['count_total'] ) && $qv['count_total'] )
570                         $this->total_users = $wpdb->get_var( apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()' ) );
571
572                 if ( !$this->results )
573                         return;
574
575                 if ( 'all_with_meta' == $qv['fields'] ) {
576                         cache_users( $this->results );
577
578                         $r = array();
579                         foreach ( $this->results as $userid )
580                                 $r[ $userid ] = new WP_User( $userid, '', $qv['blog_id'] );
581
582                         $this->results = $r;
583                 } elseif ( 'all' == $qv['fields'] ) {
584                         foreach ( $this->results as $key => $user ) {
585                                 $this->results[ $key ] = new WP_User( $user );
586                         }
587                 }
588         }
589
590         /**
591          * Retrieve query variable.
592          *
593          * @since 3.5.0
594          * @access public
595          *
596          * @param string $query_var Query variable key.
597          * @return mixed
598          */
599         function get( $query_var ) {
600                 if ( isset( $this->query_vars[$query_var] ) )
601                         return $this->query_vars[$query_var];
602
603                 return null;
604         }
605
606         /**
607          * Set query variable.
608          *
609          * @since 3.5.0
610          * @access public
611          *
612          * @param string $query_var Query variable key.
613          * @param mixed $value Query variable value.
614          */
615         function set( $query_var, $value ) {
616                 $this->query_vars[$query_var] = $value;
617         }
618
619         /*
620          * Used internally to generate an SQL string for searching across multiple columns
621          *
622          * @access protected
623          * @since 3.1.0
624          *
625          * @param string $string
626          * @param array $cols
627          * @param bool $wild Whether to allow wildcard searches. Default is false for Network Admin, true for
628          *  single site. Single site allows leading and trailing wildcards, Network Admin only trailing.
629          * @return string
630          */
631         function get_search_sql( $string, $cols, $wild = false ) {
632                 $string = esc_sql( $string );
633
634                 $searches = array();
635                 $leading_wild = ( 'leading' == $wild || 'both' == $wild ) ? '%' : '';
636                 $trailing_wild = ( 'trailing' == $wild || 'both' == $wild ) ? '%' : '';
637                 foreach ( $cols as $col ) {
638                         if ( 'ID' == $col )
639                                 $searches[] = "$col = '$string'";
640                         else
641                                 $searches[] = "$col LIKE '$leading_wild" . like_escape($string) . "$trailing_wild'";
642                 }
643
644                 return ' AND (' . implode(' OR ', $searches) . ')';
645         }
646
647         /**
648          * Return the list of users
649          *
650          * @since 3.1.0
651          * @access public
652          *
653          * @return array
654          */
655         function get_results() {
656                 return $this->results;
657         }
658
659         /**
660          * Return the total number of users for the current query
661          *
662          * @since 3.1.0
663          * @access public
664          *
665          * @return array
666          */
667         function get_total() {
668                 return $this->total_users;
669         }
670 }
671
672 /**
673  * Retrieve list of users matching criteria.
674  *
675  * @since 3.1.0
676  * @uses $wpdb
677  * @uses WP_User_Query See for default arguments and information.
678  *
679  * @param array $args Optional.
680  * @return array List of users.
681  */
682 function get_users( $args = array() ) {
683
684         $args = wp_parse_args( $args );
685         $args['count_total'] = false;
686
687         $user_search = new WP_User_Query($args);
688
689         return (array) $user_search->get_results();
690 }
691
692 /**
693  * Get the blogs a user belongs to.
694  *
695  * @since 3.0.0
696  *
697  * @param int $user_id User ID
698  * @param bool $all Whether to retrieve all blogs, or only blogs that are not marked as deleted, archived, or spam.
699  * @return array A list of the user's blogs. An empty array if the user doesn't exist or belongs to no blogs.
700  */
701 function get_blogs_of_user( $user_id, $all = false ) {
702         global $wpdb;
703
704         $user_id = (int) $user_id;
705
706         // Logged out users can't have blogs
707         if ( empty( $user_id ) )
708                 return array();
709
710         $keys = get_user_meta( $user_id );
711         if ( empty( $keys ) )
712                 return array();
713
714         if ( ! is_multisite() ) {
715                 $blog_id = get_current_blog_id();
716                 $blogs = array( $blog_id => new stdClass );
717                 $blogs[ $blog_id ]->userblog_id = $blog_id;
718                 $blogs[ $blog_id ]->blogname = get_option('blogname');
719                 $blogs[ $blog_id ]->domain = '';
720                 $blogs[ $blog_id ]->path = '';
721                 $blogs[ $blog_id ]->site_id = 1;
722                 $blogs[ $blog_id ]->siteurl = get_option('siteurl');
723                 $blogs[ $blog_id ]->archived = 0;
724                 $blogs[ $blog_id ]->spam = 0;
725                 $blogs[ $blog_id ]->deleted = 0;
726                 return $blogs;
727         }
728
729         $blogs = array();
730
731         if ( isset( $keys[ $wpdb->base_prefix . 'capabilities' ] ) && defined( 'MULTISITE' ) ) {
732                 $blog = get_blog_details( 1 );
733                 if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
734                         $blogs[ 1 ] = (object) array(
735                                 'userblog_id' => 1,
736                                 'blogname'    => $blog->blogname,
737                                 'domain'      => $blog->domain,
738                                 'path'        => $blog->path,
739                                 'site_id'     => $blog->site_id,
740                                 'siteurl'     => $blog->siteurl,
741                                 'archived'    => 0,
742                                 'spam'        => 0,
743                                 'deleted'     => 0
744                         );
745                 }
746                 unset( $keys[ $wpdb->base_prefix . 'capabilities' ] );
747         }
748
749         $keys = array_keys( $keys );
750
751         foreach ( $keys as $key ) {
752                 if ( 'capabilities' !== substr( $key, -12 ) )
753                         continue;
754                 if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) )
755                         continue;
756                 $blog_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key );
757                 if ( ! is_numeric( $blog_id ) )
758                         continue;
759
760                 $blog_id = (int) $blog_id;
761                 $blog = get_blog_details( $blog_id );
762                 if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
763                         $blogs[ $blog_id ] = (object) array(
764                                 'userblog_id' => $blog_id,
765                                 'blogname'    => $blog->blogname,
766                                 'domain'      => $blog->domain,
767                                 'path'        => $blog->path,
768                                 'site_id'     => $blog->site_id,
769                                 'siteurl'     => $blog->siteurl,
770                                 'archived'    => 0,
771                                 'spam'        => 0,
772                                 'deleted'     => 0
773                         );
774                 }
775         }
776
777         return apply_filters( 'get_blogs_of_user', $blogs, $user_id, $all );
778 }
779
780 /**
781  * Find out whether a user is a member of a given blog.
782  *
783  * @since MU 1.1
784  * @uses get_blogs_of_user()
785  *
786  * @param int $user_id Optional. The unique ID of the user. Defaults to the current user.
787  * @param int $blog_id Optional. ID of the blog to check. Defaults to the current site.
788  * @return bool
789  */
790 function is_user_member_of_blog( $user_id = 0, $blog_id = 0 ) {
791         $user_id = (int) $user_id;
792         $blog_id = (int) $blog_id;
793
794         if ( empty( $user_id ) )
795                 $user_id = get_current_user_id();
796
797         if ( empty( $blog_id ) )
798                 $blog_id = get_current_blog_id();
799
800         $blogs = get_blogs_of_user( $user_id );
801         return array_key_exists( $blog_id, $blogs );
802 }
803
804 /**
805  * Add meta data field to a user.
806  *
807  * Post meta data is called "Custom Fields" on the Administration Screens.
808  *
809  * @since 3.0.0
810  * @uses add_metadata()
811  * @link http://codex.wordpress.org/Function_Reference/add_user_meta
812  *
813  * @param int $user_id Post ID.
814  * @param string $meta_key Metadata name.
815  * @param mixed $meta_value Metadata value.
816  * @param bool $unique Optional, default is false. Whether the same key should not be added.
817  * @return int|bool Meta ID on success, false on failure.
818  */
819 function add_user_meta($user_id, $meta_key, $meta_value, $unique = false) {
820         return add_metadata('user', $user_id, $meta_key, $meta_value, $unique);
821 }
822
823 /**
824  * Remove metadata matching criteria from a user.
825  *
826  * You can match based on the key, or key and value. Removing based on key and
827  * value, will keep from removing duplicate metadata with the same key. It also
828  * allows removing all metadata matching key, if needed.
829  *
830  * @since 3.0.0
831  * @uses delete_metadata()
832  * @link http://codex.wordpress.org/Function_Reference/delete_user_meta
833  *
834  * @param int $user_id user ID
835  * @param string $meta_key Metadata name.
836  * @param mixed $meta_value Optional. Metadata value.
837  * @return bool True on success, false on failure.
838  */
839 function delete_user_meta($user_id, $meta_key, $meta_value = '') {
840         return delete_metadata('user', $user_id, $meta_key, $meta_value);
841 }
842
843 /**
844  * Retrieve user meta field for a user.
845  *
846  * @since 3.0.0
847  * @uses get_metadata()
848  * @link http://codex.wordpress.org/Function_Reference/get_user_meta
849  *
850  * @param int $user_id Post ID.
851  * @param string $key Optional. The meta key to retrieve. By default, returns data for all keys.
852  * @param bool $single Whether to return a single value.
853  * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
854  *  is true.
855  */
856 function get_user_meta($user_id, $key = '', $single = false) {
857         return get_metadata('user', $user_id, $key, $single);
858 }
859
860 /**
861  * Update user meta field based on user ID.
862  *
863  * Use the $prev_value parameter to differentiate between meta fields with the
864  * same key and user ID.
865  *
866  * If the meta field for the user does not exist, it will be added.
867  *
868  * @since 3.0.0
869  * @uses update_metadata
870  * @link http://codex.wordpress.org/Function_Reference/update_user_meta
871  *
872  * @param int $user_id Post ID.
873  * @param string $meta_key Metadata key.
874  * @param mixed $meta_value Metadata value.
875  * @param mixed $prev_value Optional. Previous value to check before removing.
876  * @return bool True on success, false on failure.
877  */
878 function update_user_meta($user_id, $meta_key, $meta_value, $prev_value = '') {
879         return update_metadata('user', $user_id, $meta_key, $meta_value, $prev_value);
880 }
881
882 /**
883  * Count number of users who have each of the user roles.
884  *
885  * Assumes there are neither duplicated nor orphaned capabilities meta_values.
886  * Assumes role names are unique phrases. Same assumption made by WP_User_Query::prepare_query()
887  * Using $strategy = 'time' this is CPU-intensive and should handle around 10^7 users.
888  * Using $strategy = 'memory' this is memory-intensive and should handle around 10^5 users, but see WP Bug #12257.
889  *
890  * @since 3.0.0
891  * @param string $strategy 'time' or 'memory'
892  * @return array Includes a grand total and an array of counts indexed by role strings.
893  */
894 function count_users($strategy = 'time') {
895         global $wpdb, $wp_roles;
896
897         // Initialize
898         $id = get_current_blog_id();
899         $blog_prefix = $wpdb->get_blog_prefix($id);
900         $result = array();
901
902         if ( 'time' == $strategy ) {
903                 global $wp_roles;
904
905                 if ( ! isset( $wp_roles ) )
906                         $wp_roles = new WP_Roles();
907
908                 $avail_roles = $wp_roles->get_names();
909
910                 // Build a CPU-intensive query that will return concise information.
911                 $select_count = array();
912                 foreach ( $avail_roles as $this_role => $name ) {
913                         $select_count[] = "COUNT(NULLIF(`meta_value` LIKE '%\"" . like_escape( $this_role ) . "\"%', false))";
914                 }
915                 $select_count = implode(', ', $select_count);
916
917                 // Add the meta_value index to the selection list, then run the query.
918                 $row = $wpdb->get_row( "SELECT $select_count, COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'", ARRAY_N );
919
920                 // Run the previous loop again to associate results with role names.
921                 $col = 0;
922                 $role_counts = array();
923                 foreach ( $avail_roles as $this_role => $name ) {
924                         $count = (int) $row[$col++];
925                         if ($count > 0) {
926                                 $role_counts[$this_role] = $count;
927                         }
928                 }
929
930                 // Get the meta_value index from the end of the result set.
931                 $total_users = (int) $row[$col];
932
933                 $result['total_users'] = $total_users;
934                 $result['avail_roles'] =& $role_counts;
935         } else {
936                 $avail_roles = array();
937
938                 $users_of_blog = $wpdb->get_col( "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'" );
939
940                 foreach ( $users_of_blog as $caps_meta ) {
941                         $b_roles = maybe_unserialize($caps_meta);
942                         if ( ! is_array( $b_roles ) )
943                                 continue;
944                         foreach ( $b_roles as $b_role => $val ) {
945                                 if ( isset($avail_roles[$b_role]) ) {
946                                         $avail_roles[$b_role]++;
947                                 } else {
948                                         $avail_roles[$b_role] = 1;
949                                 }
950                         }
951                 }
952
953                 $result['total_users'] = count( $users_of_blog );
954                 $result['avail_roles'] =& $avail_roles;
955         }
956
957         return $result;
958 }
959
960 //
961 // Private helper functions
962 //
963
964 /**
965  * Set up global user vars.
966  *
967  * Used by wp_set_current_user() for back compat. Might be deprecated in the future.
968  *
969  * @since 2.0.4
970  * @global string $userdata User description.
971  * @global string $user_login The user username for logging in
972  * @global int $user_level The level of the user
973  * @global int $user_ID The ID of the user
974  * @global string $user_email The email address of the user
975  * @global string $user_url The url in the user's profile
976  * @global string $user_identity The display name of the user
977  *
978  * @param int $for_user_id Optional. User ID to set up global data.
979  */
980 function setup_userdata($for_user_id = '') {
981         global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_identity;
982
983         if ( '' == $for_user_id )
984                 $for_user_id = get_current_user_id();
985         $user = get_userdata( $for_user_id );
986
987         if ( ! $user ) {
988                 $user_ID = 0;
989                 $user_level = 0;
990                 $userdata = null;
991                 $user_login = $user_email = $user_url = $user_identity = '';
992                 return;
993         }
994
995         $user_ID    = (int) $user->ID;
996         $user_level = (int) $user->user_level;
997         $userdata   = $user;
998         $user_login = $user->user_login;
999         $user_email = $user->user_email;
1000         $user_url   = $user->user_url;
1001         $user_identity = $user->display_name;
1002 }
1003
1004 /**
1005  * Create dropdown HTML content of users.
1006  *
1007  * The content can either be displayed, which it is by default or retrieved by
1008  * setting the 'echo' argument. The 'include' and 'exclude' arguments do not
1009  * need to be used; all users will be displayed in that case. Only one can be
1010  * used, either 'include' or 'exclude', but not both.
1011  *
1012  * The available arguments are as follows:
1013  * <ol>
1014  * <li>show_option_all - Text to show all and whether HTML option exists.</li>
1015  * <li>show_option_none - Text for show none and whether HTML option exists.</li>
1016  * <li>hide_if_only_one_author - Don't create the dropdown if there is only one user.</li>
1017  * <li>orderby - SQL order by clause for what order the users appear. Default is 'display_name'.</li>
1018  * <li>order - Default is 'ASC'. Can also be 'DESC'.</li>
1019  * <li>include - User IDs to include.</li>
1020  * <li>exclude - User IDs to exclude.</li>
1021  * <li>multi - Default is 'false'. Whether to skip the ID attribute on the 'select' element. A 'true' value is overridden when id argument is set.</li>
1022  * <li>show - Default is 'display_name'. User table column to display. If the selected item is empty then the user_login will be displayed in parentheses</li>
1023  * <li>echo - Default is '1'. Whether to display or retrieve content.</li>
1024  * <li>selected - Which User ID is selected.</li>
1025  * <li>include_selected - Always include the selected user ID in the dropdown. Default is false.</li>
1026  * <li>name - Default is 'user'. Name attribute of select element.</li>
1027  * <li>id - Default is the value of the 'name' parameter. ID attribute of select element.</li>
1028  * <li>class - Class attribute of select element.</li>
1029  * <li>blog_id - ID of blog (Multisite only). Defaults to ID of current blog.</li>
1030  * <li>who - Which users to query. Currently only 'authors' is supported. Default is all users.</li>
1031  * </ol>
1032  *
1033  * @since 2.3.0
1034  * @uses $wpdb WordPress database object for queries
1035  *
1036  * @param string|array $args Optional. Override defaults.
1037  * @return string|null Null on display. String of HTML content on retrieve.
1038  */
1039 function wp_dropdown_users( $args = '' ) {
1040         $defaults = array(
1041                 'show_option_all' => '', 'show_option_none' => '', 'hide_if_only_one_author' => '',
1042                 'orderby' => 'display_name', 'order' => 'ASC',
1043                 'include' => '', 'exclude' => '', 'multi' => 0,
1044                 'show' => 'display_name', 'echo' => 1,
1045                 'selected' => 0, 'name' => 'user', 'class' => '', 'id' => '',
1046                 'blog_id' => $GLOBALS['blog_id'], 'who' => '', 'include_selected' => false
1047         );
1048
1049         $defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0;
1050
1051         $r = wp_parse_args( $args, $defaults );
1052         extract( $r, EXTR_SKIP );
1053
1054         $query_args = wp_array_slice_assoc( $r, array( 'blog_id', 'include', 'exclude', 'orderby', 'order', 'who' ) );
1055         $query_args['fields'] = array( 'ID', 'user_login', $show );
1056         $users = get_users( $query_args );
1057
1058         $output = '';
1059         if ( !empty($users) && ( empty($hide_if_only_one_author) || count($users) > 1 ) ) {
1060                 $name = esc_attr( $name );
1061                 if ( $multi && ! $id )
1062                         $id = '';
1063                 else
1064                         $id = $id ? " id='" . esc_attr( $id ) . "'" : " id='$name'";
1065
1066                 $output = "<select name='{$name}'{$id} class='$class'>\n";
1067
1068                 if ( $show_option_all )
1069                         $output .= "\t<option value='0'>$show_option_all</option>\n";
1070
1071                 if ( $show_option_none ) {
1072                         $_selected = selected( -1, $selected, false );
1073                         $output .= "\t<option value='-1'$_selected>$show_option_none</option>\n";
1074                 }
1075
1076                 $found_selected = false;
1077                 foreach ( (array) $users as $user ) {
1078                         $user->ID = (int) $user->ID;
1079                         $_selected = selected( $user->ID, $selected, false );
1080                         if ( $_selected )
1081                                 $found_selected = true;
1082                         $display = !empty($user->$show) ? $user->$show : '('. $user->user_login . ')';
1083                         $output .= "\t<option value='$user->ID'$_selected>" . esc_html($display) . "</option>\n";
1084                 }
1085
1086                 if ( $include_selected && ! $found_selected && ( $selected > 0 ) ) {
1087                         $user = get_userdata( $selected );
1088                         $_selected = selected( $user->ID, $selected, false );
1089                         $display = !empty($user->$show) ? $user->$show : '('. $user->user_login . ')';
1090                         $output .= "\t<option value='$user->ID'$_selected>" . esc_html($display) . "</option>\n";
1091                 }
1092
1093                 $output .= "</select>";
1094         }
1095
1096         $output = apply_filters('wp_dropdown_users', $output);
1097
1098         if ( $echo )
1099                 echo $output;
1100
1101         return $output;
1102 }
1103
1104 /**
1105  * Sanitize user field based on context.
1106  *
1107  * Possible context values are:  'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The
1108  * 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display'
1109  * when calling filters.
1110  *
1111  * @since 2.3.0
1112  * @uses apply_filters() Calls 'edit_$field' passing $value and $user_id if $context == 'edit'.
1113  *  $field is prefixed with 'user_' if it isn't already.
1114  * @uses apply_filters() Calls 'pre_$field' passing $value if $context == 'db'. $field is prefixed with
1115  *  'user_' if it isn't already.
1116  * @uses apply_filters() Calls '$field' passing $value, $user_id and $context if $context == anything
1117  *  other than 'raw', 'edit' and 'db'. $field is prefixed with 'user_' if it isn't already.
1118  *
1119  * @param string $field The user Object field name.
1120  * @param mixed $value The user Object value.
1121  * @param int $user_id user ID.
1122  * @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display',
1123  *               'attribute' and 'js'.
1124  * @return mixed Sanitized value.
1125  */
1126 function sanitize_user_field($field, $value, $user_id, $context) {
1127         $int_fields = array('ID');
1128         if ( in_array($field, $int_fields) )
1129                 $value = (int) $value;
1130
1131         if ( 'raw' == $context )
1132                 return $value;
1133
1134         if ( !is_string($value) && !is_numeric($value) )
1135                 return $value;
1136
1137         $prefixed = false !== strpos( $field, 'user_' );
1138
1139         if ( 'edit' == $context ) {
1140                 if ( $prefixed ) {
1141                         $value = apply_filters("edit_{$field}", $value, $user_id);
1142                 } else {
1143                         $value = apply_filters("edit_user_{$field}", $value, $user_id);
1144                 }
1145
1146                 if ( 'description' == $field )
1147                         $value = esc_html( $value ); // textarea_escaped?
1148                 else
1149                         $value = esc_attr($value);
1150         } else if ( 'db' == $context ) {
1151                 if ( $prefixed ) {
1152                         $value = apply_filters("pre_{$field}", $value);
1153                 } else {
1154                         $value = apply_filters("pre_user_{$field}", $value);
1155                 }
1156         } else {
1157                 // Use display filters by default.
1158                 if ( $prefixed )
1159                         $value = apply_filters($field, $value, $user_id, $context);
1160                 else
1161                         $value = apply_filters("user_{$field}", $value, $user_id, $context);
1162         }
1163
1164         if ( 'user_url' == $field )
1165                 $value = esc_url($value);
1166
1167         if ( 'attribute' == $context )
1168                 $value = esc_attr($value);
1169         else if ( 'js' == $context )
1170                 $value = esc_js($value);
1171
1172         return $value;
1173 }
1174
1175 /**
1176  * Update all user caches
1177  *
1178  * @since 3.0.0
1179  *
1180  * @param object $user User object to be cached
1181  */
1182 function update_user_caches($user) {
1183         wp_cache_add($user->ID, $user, 'users');
1184         wp_cache_add($user->user_login, $user->ID, 'userlogins');
1185         wp_cache_add($user->user_email, $user->ID, 'useremail');
1186         wp_cache_add($user->user_nicename, $user->ID, 'userslugs');
1187 }
1188
1189 /**
1190  * Clean all user caches
1191  *
1192  * @since 3.0.0
1193  *
1194  * @param WP_User|int $user User object or ID to be cleaned from the cache
1195  */
1196 function clean_user_cache( $user ) {
1197         if ( is_numeric( $user ) )
1198                 $user = new WP_User( $user );
1199
1200         if ( ! $user->exists() )
1201                 return;
1202
1203         wp_cache_delete( $user->ID, 'users' );
1204         wp_cache_delete( $user->user_login, 'userlogins' );
1205         wp_cache_delete( $user->user_email, 'useremail' );
1206         wp_cache_delete( $user->user_nicename, 'userslugs' );
1207 }
1208
1209 /**
1210  * Checks whether the given username exists.
1211  *
1212  * @since 2.0.0
1213  *
1214  * @param string $username Username.
1215  * @return null|int The user's ID on success, and null on failure.
1216  */
1217 function username_exists( $username ) {
1218         if ( $user = get_user_by('login', $username ) ) {
1219                 return $user->ID;
1220         } else {
1221                 return null;
1222         }
1223 }
1224
1225 /**
1226  * Checks whether the given email exists.
1227  *
1228  * @since 2.1.0
1229  * @uses $wpdb
1230  *
1231  * @param string $email Email.
1232  * @return bool|int The user's ID on success, and false on failure.
1233  */
1234 function email_exists( $email ) {
1235         if ( $user = get_user_by('email', $email) )
1236                 return $user->ID;
1237
1238         return false;
1239 }
1240
1241 /**
1242  * Checks whether an username is valid.
1243  *
1244  * @since 2.0.1
1245  * @uses apply_filters() Calls 'validate_username' hook on $valid check and $username as parameters
1246  *
1247  * @param string $username Username.
1248  * @return bool Whether username given is valid
1249  */
1250 function validate_username( $username ) {
1251         $sanitized = sanitize_user( $username, true );
1252         $valid = ( $sanitized == $username );
1253         return apply_filters( 'validate_username', $valid, $username );
1254 }
1255
1256 /**
1257  * Insert an user into the database.
1258  *
1259  * Can update a current user or insert a new user based on whether the user's ID
1260  * is present.
1261  *
1262  * Can be used to update the user's info (see below), set the user's role, and
1263  * set the user's preference on whether they want the rich editor on.
1264  *
1265  * Most of the $userdata array fields have filters associated with the values.
1266  * The exceptions are 'rich_editing', 'role', 'jabber', 'aim', 'yim',
1267  * 'user_registered', and 'ID'. The filters have the prefix 'pre_user_' followed
1268  * by the field name. An example using 'description' would have the filter
1269  * called, 'pre_user_description' that can be hooked into.
1270  *
1271  * The $userdata array can contain the following fields:
1272  * 'ID' - An integer that will be used for updating an existing user.
1273  * 'user_pass' - A string that contains the plain text password for the user.
1274  * 'user_login' - A string that contains the user's username for logging in.
1275  * 'user_nicename' - A string that contains a URL-friendly name for the user.
1276  *              The default is the user's username.
1277  * 'user_url' - A string containing the user's URL for the user's web site.
1278  * 'user_email' - A string containing the user's email address.
1279  * 'display_name' - A string that will be shown on the site. Defaults to user's
1280  *              username. It is likely that you will want to change this, for appearance.
1281  * 'nickname' - The user's nickname, defaults to the user's username.
1282  * 'first_name' - The user's first name.
1283  * 'last_name' - The user's last name.
1284  * 'description' - A string containing content about the user.
1285  * 'rich_editing' - A string for whether to enable the rich editor. False
1286  *              if not empty.
1287  * 'user_registered' - The date the user registered. Format is 'Y-m-d H:i:s'.
1288  * 'role' - A string used to set the user's role.
1289  * 'jabber' - User's Jabber account.
1290  * 'aim' - User's AOL IM account.
1291  * 'yim' - User's Yahoo IM account.
1292  *
1293  * @since 2.0.0
1294  * @uses $wpdb WordPress database layer.
1295  * @uses apply_filters() Calls filters for most of the $userdata fields with the prefix 'pre_user'. See note above.
1296  * @uses do_action() Calls 'profile_update' hook when updating giving the user's ID
1297  * @uses do_action() Calls 'user_register' hook when creating a new user giving the user's ID
1298  *
1299  * @param mixed $userdata An array of user data or a user object of type stdClass or WP_User.
1300  * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not be created.
1301  */
1302 function wp_insert_user( $userdata ) {
1303         global $wpdb;
1304
1305         if ( is_a( $userdata, 'stdClass' ) )
1306                 $userdata = get_object_vars( $userdata );
1307         elseif ( is_a( $userdata, 'WP_User' ) )
1308                 $userdata = $userdata->to_array();
1309
1310         extract( $userdata, EXTR_SKIP );
1311
1312         // Are we updating or creating?
1313         if ( !empty($ID) ) {
1314                 $ID = (int) $ID;
1315                 $update = true;
1316                 $old_user_data = WP_User::get_data_by( 'id', $ID );
1317         } else {
1318                 $update = false;
1319                 // Hash the password
1320                 $user_pass = wp_hash_password($user_pass);
1321         }
1322
1323         $user_login = sanitize_user($user_login, true);
1324         $user_login = apply_filters('pre_user_login', $user_login);
1325
1326         //Remove any non-printable chars from the login string to see if we have ended up with an empty username
1327         $user_login = trim($user_login);
1328
1329         if ( empty($user_login) )
1330                 return new WP_Error('empty_user_login', __('Cannot create a user with an empty login name.') );
1331
1332         if ( !$update && username_exists( $user_login ) )
1333                 return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) );
1334
1335         if ( empty($user_nicename) )
1336                 $user_nicename = sanitize_title( $user_login );
1337         $user_nicename = apply_filters('pre_user_nicename', $user_nicename);
1338
1339         if ( empty($user_url) )
1340                 $user_url = '';
1341         $user_url = apply_filters('pre_user_url', $user_url);
1342
1343         if ( empty($user_email) )
1344                 $user_email = '';
1345         $user_email = apply_filters('pre_user_email', $user_email);
1346
1347         if ( !$update && ! defined( 'WP_IMPORTING' ) && email_exists($user_email) )
1348                 return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) );
1349
1350         if ( empty($nickname) )
1351                 $nickname = $user_login;
1352         $nickname = apply_filters('pre_user_nickname', $nickname);
1353
1354         if ( empty($first_name) )
1355                 $first_name = '';
1356         $first_name = apply_filters('pre_user_first_name', $first_name);
1357
1358         if ( empty($last_name) )
1359                 $last_name = '';
1360         $last_name = apply_filters('pre_user_last_name', $last_name);
1361
1362         if ( empty( $display_name ) ) {
1363                 if ( $update )
1364                         $display_name = $user_login;
1365                 elseif ( $first_name && $last_name )
1366                         /* translators: 1: first name, 2: last name */
1367                         $display_name = sprintf( _x( '%1$s %2$s', 'Display name based on first name and last name' ), $first_name, $last_name );
1368                 elseif ( $first_name )
1369                         $display_name = $first_name;
1370                 elseif ( $last_name )
1371                         $display_name = $last_name;
1372                 else
1373                         $display_name = $user_login;
1374         }
1375         $display_name = apply_filters( 'pre_user_display_name', $display_name );
1376
1377         if ( empty($description) )
1378                 $description = '';
1379         $description = apply_filters('pre_user_description', $description);
1380
1381         if ( empty($rich_editing) )
1382                 $rich_editing = 'true';
1383
1384         if ( empty($comment_shortcuts) )
1385                 $comment_shortcuts = 'false';
1386
1387         if ( empty($admin_color) )
1388                 $admin_color = 'fresh';
1389         $admin_color = preg_replace('|[^a-z0-9 _.\-@]|i', '', $admin_color);
1390
1391         if ( empty($use_ssl) )
1392                 $use_ssl = 0;
1393
1394         if ( empty($user_registered) )
1395                 $user_registered = gmdate('Y-m-d H:i:s');
1396
1397         if ( empty($show_admin_bar_front) )
1398                 $show_admin_bar_front = 'true';
1399
1400         $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login));
1401
1402         if ( $user_nicename_check ) {
1403                 $suffix = 2;
1404                 while ($user_nicename_check) {
1405                         $alt_user_nicename = $user_nicename . "-$suffix";
1406                         $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $alt_user_nicename, $user_login));
1407                         $suffix++;
1408                 }
1409                 $user_nicename = $alt_user_nicename;
1410         }
1411
1412         $data = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' );
1413         $data = wp_unslash( $data );
1414
1415         if ( $update ) {
1416                 $wpdb->update( $wpdb->users, $data, compact( 'ID' ) );
1417                 $user_id = (int) $ID;
1418         } else {
1419                 $wpdb->insert( $wpdb->users, $data + compact( 'user_login' ) );
1420                 $user_id = (int) $wpdb->insert_id;
1421         }
1422
1423         $user = new WP_User( $user_id );
1424
1425         foreach ( _get_additional_user_keys( $user ) as $key ) {
1426                 if ( isset( $$key ) )
1427                         update_user_meta( $user_id, $key, $$key );
1428         }
1429
1430         if ( isset($role) )
1431                 $user->set_role($role);
1432         elseif ( !$update )
1433                 $user->set_role(get_option('default_role'));
1434
1435         wp_cache_delete($user_id, 'users');
1436         wp_cache_delete($user_login, 'userlogins');
1437
1438         if ( $update )
1439                 do_action('profile_update', $user_id, $old_user_data);
1440         else
1441                 do_action('user_register', $user_id);
1442
1443         return $user_id;
1444 }
1445
1446 /**
1447  * Update an user in the database.
1448  *
1449  * It is possible to update a user's password by specifying the 'user_pass'
1450  * value in the $userdata parameter array.
1451  *
1452  * If current user's password is being updated, then the cookies will be
1453  * cleared.
1454  *
1455  * @since 2.0.0
1456  * @see wp_insert_user() For what fields can be set in $userdata
1457  * @uses wp_insert_user() Used to update existing user or add new one if user doesn't exist already
1458  *
1459  * @param mixed $userdata An array of user data or a user object of type stdClass or WP_User.
1460  * @return int|WP_Error The updated user's ID or a WP_Error object if the user could not be updated.
1461  */
1462 function wp_update_user($userdata) {
1463         if ( is_a( $userdata, 'stdClass' ) )
1464                 $userdata = get_object_vars( $userdata );
1465         elseif ( is_a( $userdata, 'WP_User' ) )
1466                 $userdata = $userdata->to_array();
1467
1468         $ID = (int) $userdata['ID'];
1469
1470         // First, get all of the original fields
1471         $user_obj = get_userdata( $ID );
1472         if ( ! $user_obj )
1473                 return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
1474
1475         $user = $user_obj->to_array();
1476
1477         // Add additional custom fields
1478         foreach ( _get_additional_user_keys( $user_obj ) as $key ) {
1479                 $user[ $key ] = get_user_meta( $ID, $key, true );
1480         }
1481
1482         // Escape data pulled from DB.
1483         $user = add_magic_quotes( $user );
1484
1485         // If password is changing, hash it now.
1486         if ( ! empty($userdata['user_pass']) ) {
1487                 $plaintext_pass = $userdata['user_pass'];
1488                 $userdata['user_pass'] = wp_hash_password($userdata['user_pass']);
1489         }
1490
1491         wp_cache_delete($user[ 'user_email' ], 'useremail');
1492
1493         // Merge old and new fields with new fields overwriting old ones.
1494         $userdata = array_merge($user, $userdata);
1495         $user_id = wp_insert_user($userdata);
1496
1497         // Update the cookies if the password changed.
1498         $current_user = wp_get_current_user();
1499         if ( $current_user->ID == $ID ) {
1500                 if ( isset($plaintext_pass) ) {
1501                         wp_clear_auth_cookie();
1502                         wp_set_auth_cookie($ID);
1503                 }
1504         }
1505
1506         return $user_id;
1507 }
1508
1509 /**
1510  * A simpler way of inserting an user into the database.
1511  *
1512  * Creates a new user with just the username, password, and email. For more
1513  * complex user creation use wp_insert_user() to specify more information.
1514  *
1515  * @since 2.0.0
1516  * @see wp_insert_user() More complete way to create a new user
1517  *
1518  * @param string $username The user's username.
1519  * @param string $password The user's password.
1520  * @param string $email The user's email (optional).
1521  * @return int The new user's ID.
1522  */
1523 function wp_create_user($username, $password, $email = '') {
1524         $user_login = wp_slash( $username );
1525         $user_email = wp_slash( $email    );
1526         $user_pass = $password;
1527
1528         $userdata = compact('user_login', 'user_email', 'user_pass');
1529         return wp_insert_user($userdata);
1530 }
1531
1532 /**
1533  * Return a list of meta keys that wp_insert_user() is supposed to set.
1534  *
1535  * @since 3.3.0
1536  * @access private
1537  *
1538  * @param object $user WP_User instance.
1539  * @return array
1540  */
1541 function _get_additional_user_keys( $user ) {
1542         $keys = array( 'first_name', 'last_name', 'nickname', 'description', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl', 'show_admin_bar_front' );
1543         return array_merge( $keys, array_keys( wp_get_user_contact_methods( $user ) ) );
1544 }
1545
1546 /**
1547  * Set up the user contact methods.
1548  *
1549  * Default contact methods were removed in 3.6. A filter dictates contact methods.
1550  *
1551  * @since 3.7.0
1552  *
1553  * @param WP_User $user Optional. WP_User object.
1554  * @return array Array of contact methods and their labels.
1555  */
1556 function wp_get_user_contact_methods( $user = null ) {
1557         $methods = array();
1558         if ( get_site_option( 'initial_db_version' ) < 23588 ) {
1559                 $methods = array(
1560                         'aim'    => __( 'AIM' ),
1561                         'yim'    => __( 'Yahoo IM' ),
1562                         'jabber' => __( 'Jabber / Google Talk' )
1563                 );
1564         }
1565
1566         /**
1567          * Filter the user contact methods.
1568          *
1569          * @since 2.9.0
1570          *
1571          * @param array   $methods Array of contact methods and their labels.
1572          * @param WP_User $user    Optional. WP_User object.
1573          */
1574         return apply_filters( 'user_contactmethods', $methods, $user );
1575 }
1576
1577 /**
1578  * The old private function for setting up user contact methods.
1579  *
1580  * @since 2.9.0
1581  * @access private
1582  */
1583 function _wp_get_user_contactmethods( $user = null ) {
1584         return wp_get_user_contact_methods( $user );
1585 }
1586
1587 /**
1588  * Retrieves a user row based on password reset key and login
1589  *
1590  * A key is considered 'expired' if it exactly matches the value of the
1591  * user_activation_key field, rather than being matched after going through the
1592  * hashing process. This field is now hashed; old values are no longer accepted
1593  * but have a different WP_Error code so good user feedback can be provided.
1594  *
1595  * @uses $wpdb WordPress Database object
1596  *
1597  * @param string $key       Hash to validate sending user's password.
1598  * @param string $login     The user login.
1599  * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys.
1600  */
1601 function check_password_reset_key($key, $login) {
1602         global $wpdb, $wp_hasher;
1603
1604         $key = preg_replace('/[^a-z0-9]/i', '', $key);
1605
1606         if ( empty( $key ) || !is_string( $key ) )
1607                 return new WP_Error('invalid_key', __('Invalid key'));
1608
1609         if ( empty($login) || !is_string($login) )
1610                 return new WP_Error('invalid_key', __('Invalid key'));
1611
1612         $row = $wpdb->get_row( $wpdb->prepare( "SELECT ID, user_activation_key FROM $wpdb->users WHERE user_login = %s", $login ) );
1613         if ( ! $row )
1614                 return new WP_Error('invalid_key', __('Invalid key'));
1615
1616         if ( empty( $wp_hasher ) ) {
1617                 require_once ABSPATH . 'wp-includes/class-phpass.php';
1618                 $wp_hasher = new PasswordHash( 8, true );
1619         }
1620
1621         if ( $wp_hasher->CheckPassword( $key, $row->user_activation_key ) )
1622                 return get_userdata( $row->ID );
1623
1624         if ( $key === $row->user_activation_key ) {
1625                 $return = new WP_Error( 'expired_key', __( 'Invalid key' ) );
1626                 $user_id = $row->ID;
1627
1628                 /**
1629                  * Filter the return value of check_password_reset_key() when an
1630                  * old-style key is used (plain-text key was stored in the database).
1631                  *
1632                  * @since 3.7.0
1633                  *
1634                  * @param WP_Error $return  A WP_Error object denoting an expired key.
1635                  *                          Return a WP_User object to validate the key.
1636                  * @param int      $user_id The matched user ID.
1637                  */
1638                 return apply_filters( 'password_reset_key_expired', $return, $user_id );
1639         }
1640
1641         return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
1642 }
1643
1644 /**
1645  * Handles resetting the user's password.
1646  *
1647  * @param object $user The user
1648  * @param string $new_pass New password for the user in plaintext
1649  */
1650 function reset_password( $user, $new_pass ) {
1651         do_action( 'password_reset', $user, $new_pass );
1652
1653         wp_set_password( $new_pass, $user->ID );
1654         update_user_option( $user->ID, 'default_password_nag', false, true );
1655
1656         wp_password_change_notification( $user );
1657 }
1658
1659 /**
1660  * Handles registering a new user.
1661  *
1662  * @param string $user_login User's username for logging in
1663  * @param string $user_email User's email address to send password and add
1664  * @return int|WP_Error Either user's ID or error on failure.
1665  */
1666 function register_new_user( $user_login, $user_email ) {
1667         $errors = new WP_Error();
1668
1669         $sanitized_user_login = sanitize_user( $user_login );
1670         $user_email = apply_filters( 'user_registration_email', $user_email );
1671
1672         // Check the username
1673         if ( $sanitized_user_login == '' ) {
1674                 $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.' ) );
1675         } elseif ( ! validate_username( $user_login ) ) {
1676                 $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
1677                 $sanitized_user_login = '';
1678         } elseif ( username_exists( $sanitized_user_login ) ) {
1679                 $errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) );
1680         }
1681
1682         // Check the e-mail address
1683         if ( $user_email == '' ) {
1684                 $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your e-mail address.' ) );
1685         } elseif ( ! is_email( $user_email ) ) {
1686                 $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ) );
1687                 $user_email = '';
1688         } elseif ( email_exists( $user_email ) ) {
1689                 $errors->add( 'email_exists', __( '<strong>ERROR</strong>: This email is already registered, please choose another one.' ) );
1690         }
1691
1692         do_action( 'register_post', $sanitized_user_login, $user_email, $errors );
1693
1694         $errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
1695
1696         if ( $errors->get_error_code() )
1697                 return $errors;
1698
1699         $user_pass = wp_generate_password( 12, false );
1700         $user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email );
1701         if ( ! $user_id || is_wp_error( $user_id ) ) {
1702                 $errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you&hellip; please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
1703                 return $errors;
1704         }
1705
1706         update_user_option( $user_id, 'default_password_nag', true, true ); //Set up the Password change nag.
1707
1708         wp_new_user_notification( $user_id, $user_pass );
1709
1710         return $user_id;
1711 }