]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/pluggable.php
WordPress 4.1
[autoinstalls/wordpress.git] / wp-includes / pluggable.php
1 <?php
2 /**
3  * These functions can be replaced via plugins. If plugins do not redefine these
4  * functions, then these will be used instead.
5  *
6  * @package WordPress
7  */
8
9 if ( !function_exists('wp_set_current_user') ) :
10 /**
11  * Changes the current user by ID or name.
12  *
13  * Set $id to null and specify a name if you do not know a user's ID.
14  *
15  * Some WordPress functionality is based on the current user and not based on
16  * the signed in user. Therefore, it opens the ability to edit and perform
17  * actions on users who aren't signed in.
18  *
19  * @since 2.0.3
20  * @global object $current_user The current user object which holds the user data.
21  *
22  * @param int $id User ID
23  * @param string $name User's username
24  * @return WP_User Current user User object
25  */
26 function wp_set_current_user($id, $name = '') {
27         global $current_user;
28
29         if ( isset( $current_user ) && ( $current_user instanceof WP_User ) && ( $id == $current_user->ID ) )
30                 return $current_user;
31
32         $current_user = new WP_User( $id, $name );
33
34         setup_userdata( $current_user->ID );
35
36         /**
37          * Fires after the current user is set.
38          *
39          * @since 2.0.1
40          */
41         do_action( 'set_current_user' );
42
43         return $current_user;
44 }
45 endif;
46
47 if ( !function_exists('wp_get_current_user') ) :
48 /**
49  * Retrieve the current user object.
50  *
51  * @since 2.0.3
52  *
53  * @return WP_User Current user WP_User object
54  */
55 function wp_get_current_user() {
56         global $current_user;
57
58         get_currentuserinfo();
59
60         return $current_user;
61 }
62 endif;
63
64 if ( !function_exists('get_currentuserinfo') ) :
65 /**
66  * Populate global variables with information about the currently logged in user.
67  *
68  * Will set the current user, if the current user is not set. The current user
69  * will be set to the logged-in person. If no user is logged-in, then it will
70  * set the current user to 0, which is invalid and won't have any permissions.
71  *
72  * @since 0.71
73  *
74  * @uses $current_user Checks if the current user is set
75  *
76  * @return null|false False on XML-RPC Request and invalid auth cookie. Null when current user set.
77  */
78 function get_currentuserinfo() {
79         global $current_user;
80
81         if ( ! empty( $current_user ) ) {
82                 if ( $current_user instanceof WP_User )
83                         return;
84
85                 // Upgrade stdClass to WP_User
86                 if ( is_object( $current_user ) && isset( $current_user->ID ) ) {
87                         $cur_id = $current_user->ID;
88                         $current_user = null;
89                         wp_set_current_user( $cur_id );
90                         return;
91                 }
92
93                 // $current_user has a junk value. Force to WP_User with ID 0.
94                 $current_user = null;
95                 wp_set_current_user( 0 );
96                 return false;
97         }
98
99         if ( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST ) {
100                 wp_set_current_user( 0 );
101                 return false;
102         }
103
104         /**
105          * Filter the current user.
106          *
107          * The default filters use this to determine the current user from the
108          * request's cookies, if available.
109          *
110          * Returning a value of false will effectively short-circuit setting
111          * the current user.
112          *
113          * @since 3.9.0
114          *
115          * @param int|bool $user_id User ID if one has been determined, false otherwise.
116          */
117         $user_id = apply_filters( 'determine_current_user', false );
118         if ( ! $user_id ) {
119                 wp_set_current_user( 0 );
120                 return false;
121         }
122
123         wp_set_current_user( $user_id );
124 }
125 endif;
126
127 if ( !function_exists('get_userdata') ) :
128 /**
129  * Retrieve user info by user ID.
130  *
131  * @since 0.71
132  *
133  * @param int $user_id User ID
134  * @return WP_User|bool WP_User object on success, false on failure.
135  */
136 function get_userdata( $user_id ) {
137         return get_user_by( 'id', $user_id );
138 }
139 endif;
140
141 if ( !function_exists('get_user_by') ) :
142 /**
143  * Retrieve user info by a given field
144  *
145  * @since 2.8.0
146  *
147  * @param string $field The field to retrieve the user with. id | slug | email | login
148  * @param int|string $value A value for $field. A user ID, slug, email address, or login name.
149  * @return WP_User|bool WP_User object on success, false on failure.
150  */
151 function get_user_by( $field, $value ) {
152         $userdata = WP_User::get_data_by( $field, $value );
153
154         if ( !$userdata )
155                 return false;
156
157         $user = new WP_User;
158         $user->init( $userdata );
159
160         return $user;
161 }
162 endif;
163
164 if ( !function_exists('cache_users') ) :
165 /**
166  * Retrieve info for user lists to prevent multiple queries by get_userdata()
167  *
168  * @since 3.0.0
169  *
170  * @param array $user_ids User ID numbers list
171  */
172 function cache_users( $user_ids ) {
173         global $wpdb;
174
175         $clean = _get_non_cached_ids( $user_ids, 'users' );
176
177         if ( empty( $clean ) )
178                 return;
179
180         $list = implode( ',', $clean );
181
182         $users = $wpdb->get_results( "SELECT * FROM $wpdb->users WHERE ID IN ($list)" );
183
184         $ids = array();
185         foreach ( $users as $user ) {
186                 update_user_caches( $user );
187                 $ids[] = $user->ID;
188         }
189         update_meta_cache( 'user', $ids );
190 }
191 endif;
192
193 if ( !function_exists( 'wp_mail' ) ) :
194 /**
195  * Send mail, similar to PHP's mail
196  *
197  * A true return value does not automatically mean that the user received the
198  * email successfully. It just only means that the method used was able to
199  * process the request without any errors.
200  *
201  * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from
202  * creating a from address like 'Name <email@address.com>' when both are set. If
203  * just 'wp_mail_from' is set, then just the email address will be used with no
204  * name.
205  *
206  * The default content type is 'text/plain' which does not allow using HTML.
207  * However, you can set the content type of the email by using the
208  * 'wp_mail_content_type' filter.
209  *
210  * The default charset is based on the charset used on the blog. The charset can
211  * be set using the 'wp_mail_charset' filter.
212  *
213  * @since 1.2.1
214  *
215  * @uses PHPMailer
216  *
217  * @param string|array $to Array or comma-separated list of email addresses to send message.
218  * @param string $subject Email subject
219  * @param string $message Message contents
220  * @param string|array $headers Optional. Additional headers.
221  * @param string|array $attachments Optional. Files to attach.
222  * @return bool Whether the email contents were sent successfully.
223  */
224 function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
225         // Compact the input, apply the filters, and extract them back out
226
227         /**
228          * Filter the wp_mail() arguments.
229          *
230          * @since 2.2.0
231          *
232          * @param array $args A compacted array of wp_mail() arguments, including the "to" email,
233          *                    subject, message, headers, and attachments values.
234          */
235         $atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) );
236
237         if ( isset( $atts['to'] ) ) {
238                 $to = $atts['to'];
239         }
240
241         if ( isset( $atts['subject'] ) ) {
242                 $subject = $atts['subject'];
243         }
244
245         if ( isset( $atts['message'] ) ) {
246                 $message = $atts['message'];
247         }
248
249         if ( isset( $atts['headers'] ) ) {
250                 $headers = $atts['headers'];
251         }
252
253         if ( isset( $atts['attachments'] ) ) {
254                 $attachments = $atts['attachments'];
255         }
256
257         if ( ! is_array( $attachments ) ) {
258                 $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );
259         }
260         global $phpmailer;
261
262         // (Re)create it, if it's gone missing
263         if ( !is_object( $phpmailer ) || !is_a( $phpmailer, 'PHPMailer' ) ) {
264                 require_once ABSPATH . WPINC . '/class-phpmailer.php';
265                 require_once ABSPATH . WPINC . '/class-smtp.php';
266                 $phpmailer = new PHPMailer( true );
267         }
268
269         // Headers
270         if ( empty( $headers ) ) {
271                 $headers = array();
272         } else {
273                 if ( !is_array( $headers ) ) {
274                         // Explode the headers out, so this function can take both
275                         // string headers and an array of headers.
276                         $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
277                 } else {
278                         $tempheaders = $headers;
279                 }
280                 $headers = array();
281                 $cc = array();
282                 $bcc = array();
283
284                 // If it's actually got contents
285                 if ( !empty( $tempheaders ) ) {
286                         // Iterate through the raw headers
287                         foreach ( (array) $tempheaders as $header ) {
288                                 if ( strpos($header, ':') === false ) {
289                                         if ( false !== stripos( $header, 'boundary=' ) ) {
290                                                 $parts = preg_split('/boundary=/i', trim( $header ) );
291                                                 $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) );
292                                         }
293                                         continue;
294                                 }
295                                 // Explode them out
296                                 list( $name, $content ) = explode( ':', trim( $header ), 2 );
297
298                                 // Cleanup crew
299                                 $name    = trim( $name    );
300                                 $content = trim( $content );
301
302                                 switch ( strtolower( $name ) ) {
303                                         // Mainly for legacy -- process a From: header if it's there
304                                         case 'from':
305                                                 if ( strpos($content, '<' ) !== false ) {
306                                                         // So... making my life hard again?
307                                                         $from_name = substr( $content, 0, strpos( $content, '<' ) - 1 );
308                                                         $from_name = str_replace( '"', '', $from_name );
309                                                         $from_name = trim( $from_name );
310
311                                                         $from_email = substr( $content, strpos( $content, '<' ) + 1 );
312                                                         $from_email = str_replace( '>', '', $from_email );
313                                                         $from_email = trim( $from_email );
314                                                 } else {
315                                                         $from_email = trim( $content );
316                                                 }
317                                                 break;
318                                         case 'content-type':
319                                                 if ( strpos( $content, ';' ) !== false ) {
320                                                         list( $type, $charset ) = explode( ';', $content );
321                                                         $content_type = trim( $type );
322                                                         if ( false !== stripos( $charset, 'charset=' ) ) {
323                                                                 $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset ) );
324                                                         } elseif ( false !== stripos( $charset, 'boundary=' ) ) {
325                                                                 $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset ) );
326                                                                 $charset = '';
327                                                         }
328                                                 } else {
329                                                         $content_type = trim( $content );
330                                                 }
331                                                 break;
332                                         case 'cc':
333                                                 $cc = array_merge( (array) $cc, explode( ',', $content ) );
334                                                 break;
335                                         case 'bcc':
336                                                 $bcc = array_merge( (array) $bcc, explode( ',', $content ) );
337                                                 break;
338                                         default:
339                                                 // Add it to our grand headers array
340                                                 $headers[trim( $name )] = trim( $content );
341                                                 break;
342                                 }
343                         }
344                 }
345         }
346
347         // Empty out the values that may be set
348         $phpmailer->ClearAllRecipients();
349         $phpmailer->ClearAttachments();
350         $phpmailer->ClearCustomHeaders();
351         $phpmailer->ClearReplyTos();
352
353         // From email and name
354         // If we don't have a name from the input headers
355         if ( !isset( $from_name ) )
356                 $from_name = 'WordPress';
357
358         /* If we don't have an email from the input headers default to wordpress@$sitename
359          * Some hosts will block outgoing mail from this address if it doesn't exist but
360          * there's no easy alternative. Defaulting to admin_email might appear to be another
361          * option but some hosts may refuse to relay mail from an unknown domain. See
362          * https://core.trac.wordpress.org/ticket/5007.
363          */
364
365         if ( !isset( $from_email ) ) {
366                 // Get the site domain and get rid of www.
367                 $sitename = strtolower( $_SERVER['SERVER_NAME'] );
368                 if ( substr( $sitename, 0, 4 ) == 'www.' ) {
369                         $sitename = substr( $sitename, 4 );
370                 }
371
372                 $from_email = 'wordpress@' . $sitename;
373         }
374
375         /**
376          * Filter the email address to send from.
377          *
378          * @since 2.2.0
379          *
380          * @param string $from_email Email address to send from.
381          */
382         $phpmailer->From = apply_filters( 'wp_mail_from', $from_email );
383
384         /**
385          * Filter the name to associate with the "from" email address.
386          *
387          * @since 2.3.0
388          *
389          * @param string $from_name Name associated with the "from" email address.
390          */
391         $phpmailer->FromName = apply_filters( 'wp_mail_from_name', $from_name );
392
393         // Set destination addresses
394         if ( !is_array( $to ) )
395                 $to = explode( ',', $to );
396
397         foreach ( (array) $to as $recipient ) {
398                 try {
399                         // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
400                         $recipient_name = '';
401                         if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
402                                 if ( count( $matches ) == 3 ) {
403                                         $recipient_name = $matches[1];
404                                         $recipient = $matches[2];
405                                 }
406                         }
407                         $phpmailer->AddAddress( $recipient, $recipient_name);
408                 } catch ( phpmailerException $e ) {
409                         continue;
410                 }
411         }
412
413         // Set mail's subject and body
414         $phpmailer->Subject = $subject;
415         $phpmailer->Body    = $message;
416
417         // Add any CC and BCC recipients
418         if ( !empty( $cc ) ) {
419                 foreach ( (array) $cc as $recipient ) {
420                         try {
421                                 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
422                                 $recipient_name = '';
423                                 if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
424                                         if ( count( $matches ) == 3 ) {
425                                                 $recipient_name = $matches[1];
426                                                 $recipient = $matches[2];
427                                         }
428                                 }
429                                 $phpmailer->AddCc( $recipient, $recipient_name );
430                         } catch ( phpmailerException $e ) {
431                                 continue;
432                         }
433                 }
434         }
435
436         if ( !empty( $bcc ) ) {
437                 foreach ( (array) $bcc as $recipient) {
438                         try {
439                                 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
440                                 $recipient_name = '';
441                                 if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
442                                         if ( count( $matches ) == 3 ) {
443                                                 $recipient_name = $matches[1];
444                                                 $recipient = $matches[2];
445                                         }
446                                 }
447                                 $phpmailer->AddBcc( $recipient, $recipient_name );
448                         } catch ( phpmailerException $e ) {
449                                 continue;
450                         }
451                 }
452         }
453
454         // Set to use PHP's mail()
455         $phpmailer->IsMail();
456
457         // Set Content-Type and charset
458         // If we don't have a content-type from the input headers
459         if ( !isset( $content_type ) )
460                 $content_type = 'text/plain';
461
462         /**
463          * Filter the wp_mail() content type.
464          *
465          * @since 2.3.0
466          *
467          * @param string $content_type Default wp_mail() content type.
468          */
469         $content_type = apply_filters( 'wp_mail_content_type', $content_type );
470
471         $phpmailer->ContentType = $content_type;
472
473         // Set whether it's plaintext, depending on $content_type
474         if ( 'text/html' == $content_type )
475                 $phpmailer->IsHTML( true );
476
477         // If we don't have a charset from the input headers
478         if ( !isset( $charset ) )
479                 $charset = get_bloginfo( 'charset' );
480
481         // Set the content-type and charset
482
483         /**
484          * Filter the default wp_mail() charset.
485          *
486          * @since 2.3.0
487          *
488          * @param string $charset Default email charset.
489          */
490         $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
491
492         // Set custom headers
493         if ( !empty( $headers ) ) {
494                 foreach( (array) $headers as $name => $content ) {
495                         $phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
496                 }
497
498                 if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) )
499                         $phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
500         }
501
502         if ( !empty( $attachments ) ) {
503                 foreach ( $attachments as $attachment ) {
504                         try {
505                                 $phpmailer->AddAttachment($attachment);
506                         } catch ( phpmailerException $e ) {
507                                 continue;
508                         }
509                 }
510         }
511
512         /**
513          * Fires after PHPMailer is initialized.
514          *
515          * @since 2.2.0
516          *
517          * @param PHPMailer &$phpmailer The PHPMailer instance, passed by reference.
518          */
519         do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) );
520
521         // Send!
522         try {
523                 return $phpmailer->Send();
524         } catch ( phpmailerException $e ) {
525                 return false;
526         }
527 }
528 endif;
529
530 if ( !function_exists('wp_authenticate') ) :
531 /**
532  * Checks a user's login information and logs them in if it checks out.
533  *
534  * @since 2.5.0
535  *
536  * @param string $username User's username
537  * @param string $password User's password
538  * @return WP_User|WP_Error WP_User object if login successful, otherwise WP_Error object.
539  */
540 function wp_authenticate($username, $password) {
541         $username = sanitize_user($username);
542         $password = trim($password);
543
544         /**
545          * Filter the user to authenticate.
546          *
547          * If a non-null value is passed, the filter will effectively short-circuit
548          * authentication, returning an error instead.
549          *
550          * @since 2.8.0
551          *
552          * @param null|WP_User $user     User to authenticate.
553          * @param string       $username User login.
554          * @param string       $password User password
555          */
556         $user = apply_filters( 'authenticate', null, $username, $password );
557
558         if ( $user == null ) {
559                 // TODO what should the error message be? (Or would these even happen?)
560                 // Only needed if all authentication handlers fail to return anything.
561                 $user = new WP_Error('authentication_failed', __('<strong>ERROR</strong>: Invalid username or incorrect password.'));
562         }
563
564         $ignore_codes = array('empty_username', 'empty_password');
565
566         if (is_wp_error($user) && !in_array($user->get_error_code(), $ignore_codes) ) {
567                 /**
568                  * Fires after a user login has failed.
569                  *
570                  * @since 2.5.0
571                  *
572                  * @param string $username User login.
573                  */
574                 do_action( 'wp_login_failed', $username );
575         }
576
577         return $user;
578 }
579 endif;
580
581 if ( !function_exists('wp_logout') ) :
582 /**
583  * Log the current user out.
584  *
585  * @since 2.5.0
586  */
587 function wp_logout() {
588         wp_destroy_current_session();
589         wp_clear_auth_cookie();
590
591         /**
592          * Fires after a user is logged-out.
593          *
594          * @since 1.5.0
595          */
596         do_action( 'wp_logout' );
597 }
598 endif;
599
600 if ( !function_exists('wp_validate_auth_cookie') ) :
601 /**
602  * Validates authentication cookie.
603  *
604  * The checks include making sure that the authentication cookie is set and
605  * pulling in the contents (if $cookie is not used).
606  *
607  * Makes sure the cookie is not expired. Verifies the hash in cookie is what is
608  * should be and compares the two.
609  *
610  * @since 2.5.0
611  *
612  * @param string $cookie Optional. If used, will validate contents instead of cookie's
613  * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
614  * @return bool|int False if invalid cookie, User ID if valid.
615  */
616 function wp_validate_auth_cookie($cookie = '', $scheme = '') {
617         if ( ! $cookie_elements = wp_parse_auth_cookie($cookie, $scheme) ) {
618                 /**
619                  * Fires if an authentication cookie is malformed.
620                  *
621                  * @since 2.7.0
622                  *
623                  * @param string $cookie Malformed auth cookie.
624                  * @param string $scheme Authentication scheme. Values include 'auth', 'secure_auth',
625                  *                       or 'logged_in'.
626                  */
627                 do_action( 'auth_cookie_malformed', $cookie, $scheme );
628                 return false;
629         }
630
631         $scheme = $cookie_elements['scheme'];
632         $username = $cookie_elements['username'];
633         $hmac = $cookie_elements['hmac'];
634         $token = $cookie_elements['token'];
635         $expired = $expiration = $cookie_elements['expiration'];
636
637         // Allow a grace period for POST and AJAX requests
638         if ( defined('DOING_AJAX') || 'POST' == $_SERVER['REQUEST_METHOD'] ) {
639                 $expired += HOUR_IN_SECONDS;
640         }
641
642         // Quick check to see if an honest cookie has expired
643         if ( $expired < time() ) {
644                 /**
645                  * Fires once an authentication cookie has expired.
646                  *
647                  * @since 2.7.0
648                  *
649                  * @param array $cookie_elements An array of data for the authentication cookie.
650                  */
651                 do_action( 'auth_cookie_expired', $cookie_elements );
652                 return false;
653         }
654
655         $user = get_user_by('login', $username);
656         if ( ! $user ) {
657                 /**
658                  * Fires if a bad username is entered in the user authentication process.
659                  *
660                  * @since 2.7.0
661                  *
662                  * @param array $cookie_elements An array of data for the authentication cookie.
663                  */
664                 do_action( 'auth_cookie_bad_username', $cookie_elements );
665                 return false;
666         }
667
668         $pass_frag = substr($user->user_pass, 8, 4);
669
670         $key = wp_hash( $username . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );
671
672         // If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
673         $algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
674         $hash = hash_hmac( $algo, $username . '|' . $expiration . '|' . $token, $key );
675
676         if ( ! hash_equals( $hash, $hmac ) ) {
677                 /**
678                  * Fires if a bad authentication cookie hash is encountered.
679                  *
680                  * @since 2.7.0
681                  *
682                  * @param array $cookie_elements An array of data for the authentication cookie.
683                  */
684                 do_action( 'auth_cookie_bad_hash', $cookie_elements );
685                 return false;
686         }
687
688         $manager = WP_Session_Tokens::get_instance( $user->ID );
689         if ( ! $manager->verify( $token ) ) {
690                 do_action( 'auth_cookie_bad_session_token', $cookie_elements );
691                 return false;
692         }
693
694         // AJAX/POST grace period set above
695         if ( $expiration < time() ) {
696                 $GLOBALS['login_grace_period'] = 1;
697         }
698
699         /**
700          * Fires once an authentication cookie has been validated.
701          *
702          * @since 2.7.0
703          *
704          * @param array   $cookie_elements An array of data for the authentication cookie.
705          * @param WP_User $user            User object.
706          */
707         do_action( 'auth_cookie_valid', $cookie_elements, $user );
708
709         return $user->ID;
710 }
711 endif;
712
713 if ( !function_exists('wp_generate_auth_cookie') ) :
714 /**
715  * Generate authentication cookie contents.
716  *
717  * @since 2.5.0
718  *
719  * @param int $user_id User ID
720  * @param int $expiration Cookie expiration in seconds
721  * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
722  * @param string $token User's session token to use for this cookie
723  * @return string Authentication cookie contents. Empty string if user does not exist.
724  */
725 function wp_generate_auth_cookie( $user_id, $expiration, $scheme = 'auth', $token = '' ) {
726         $user = get_userdata($user_id);
727         if ( ! $user ) {
728                 return '';
729         }
730
731         if ( ! $token ) {
732                 $manager = WP_Session_Tokens::get_instance( $user_id );
733                 $token = $manager->create( $expiration );
734         }
735
736         $pass_frag = substr($user->user_pass, 8, 4);
737
738         $key = wp_hash( $user->user_login . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );
739
740         // If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
741         $algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
742         $hash = hash_hmac( $algo, $user->user_login . '|' . $expiration . '|' . $token, $key );
743
744         $cookie = $user->user_login . '|' . $expiration . '|' . $token . '|' . $hash;
745
746         /**
747          * Filter the authentication cookie.
748          *
749          * @since 2.5.0
750          *
751          * @param string $cookie     Authentication cookie.
752          * @param int    $user_id    User ID.
753          * @param int    $expiration Authentication cookie expiration in seconds.
754          * @param string $scheme     Cookie scheme used. Accepts 'auth', 'secure_auth', or 'logged_in'.
755          * @param string $token      User's session token used.
756          */
757         return apply_filters( 'auth_cookie', $cookie, $user_id, $expiration, $scheme, $token );
758 }
759 endif;
760
761 if ( !function_exists('wp_parse_auth_cookie') ) :
762 /**
763  * Parse a cookie into its components
764  *
765  * @since 2.7.0
766  *
767  * @param string $cookie
768  * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
769  * @return array Authentication cookie components
770  */
771 function wp_parse_auth_cookie($cookie = '', $scheme = '') {
772         if ( empty($cookie) ) {
773                 switch ($scheme){
774                         case 'auth':
775                                 $cookie_name = AUTH_COOKIE;
776                                 break;
777                         case 'secure_auth':
778                                 $cookie_name = SECURE_AUTH_COOKIE;
779                                 break;
780                         case "logged_in":
781                                 $cookie_name = LOGGED_IN_COOKIE;
782                                 break;
783                         default:
784                                 if ( is_ssl() ) {
785                                         $cookie_name = SECURE_AUTH_COOKIE;
786                                         $scheme = 'secure_auth';
787                                 } else {
788                                         $cookie_name = AUTH_COOKIE;
789                                         $scheme = 'auth';
790                                 }
791             }
792
793                 if ( empty($_COOKIE[$cookie_name]) )
794                         return false;
795                 $cookie = $_COOKIE[$cookie_name];
796         }
797
798         $cookie_elements = explode('|', $cookie);
799         if ( count( $cookie_elements ) !== 4 ) {
800                 return false;
801         }
802
803         list( $username, $expiration, $token, $hmac ) = $cookie_elements;
804
805         return compact( 'username', 'expiration', 'token', 'hmac', 'scheme' );
806 }
807 endif;
808
809 if ( !function_exists('wp_set_auth_cookie') ) :
810 /**
811  * Sets the authentication cookies based on user ID.
812  *
813  * The $remember parameter increases the time that the cookie will be kept. The
814  * default the cookie is kept without remembering is two days. When $remember is
815  * set, the cookies will be kept for 14 days or two weeks.
816  *
817  * @since 2.5.0
818  *
819  * @param int $user_id User ID
820  * @param bool $remember Whether to remember the user
821  * @param mixed $secure  Whether the admin cookies should only be sent over HTTPS.
822  *                       Default is_ssl().
823  */
824 function wp_set_auth_cookie($user_id, $remember = false, $secure = '') {
825         if ( $remember ) {
826                 /**
827                  * Filter the duration of the authentication cookie expiration period.
828                  *
829                  * @since 2.8.0
830                  *
831                  * @param int  $length   Duration of the expiration period in seconds.
832                  * @param int  $user_id  User ID.
833                  * @param bool $remember Whether to remember the user login. Default false.
834                  */
835                 $expiration = time() + apply_filters( 'auth_cookie_expiration', 14 * DAY_IN_SECONDS, $user_id, $remember );
836
837                 /*
838                  * Ensure the browser will continue to send the cookie after the expiration time is reached.
839                  * Needed for the login grace period in wp_validate_auth_cookie().
840                  */
841                 $expire = $expiration + ( 12 * HOUR_IN_SECONDS );
842         } else {
843                 /** This filter is documented in wp-includes/pluggable.php */
844                 $expiration = time() + apply_filters( 'auth_cookie_expiration', 2 * DAY_IN_SECONDS, $user_id, $remember );
845                 $expire = 0;
846         }
847
848         if ( '' === $secure ) {
849                 $secure = is_ssl();
850         }
851
852         // Frontend cookie is secure when the auth cookie is secure and the site's home URL is forced HTTPS.
853         $secure_logged_in_cookie = $secure && 'https' === parse_url( get_option( 'home' ), PHP_URL_SCHEME );
854
855         /**
856          * Filter whether the connection is secure.
857          *
858          * @since 3.1.0
859          *
860          * @param bool $secure  Whether the connection is secure.
861          * @param int  $user_id User ID.
862          */
863         $secure = apply_filters( 'secure_auth_cookie', $secure, $user_id );
864
865         /**
866          * Filter whether to use a secure cookie when logged-in.
867          *
868          * @since 3.1.0
869          *
870          * @param bool $secure_logged_in_cookie Whether to use a secure cookie when logged-in.
871          * @param int  $user_id                 User ID.
872          * @param bool $secure                  Whether the connection is secure.
873          */
874         $secure_logged_in_cookie = apply_filters( 'secure_logged_in_cookie', $secure_logged_in_cookie, $user_id, $secure );
875
876         if ( $secure ) {
877                 $auth_cookie_name = SECURE_AUTH_COOKIE;
878                 $scheme = 'secure_auth';
879         } else {
880                 $auth_cookie_name = AUTH_COOKIE;
881                 $scheme = 'auth';
882         }
883
884         $manager = WP_Session_Tokens::get_instance( $user_id );
885         $token = $manager->create( $expiration );
886
887         $auth_cookie = wp_generate_auth_cookie( $user_id, $expiration, $scheme, $token );
888         $logged_in_cookie = wp_generate_auth_cookie( $user_id, $expiration, 'logged_in', $token );
889
890         /**
891          * Fires immediately before the authentication cookie is set.
892          *
893          * @since 2.5.0
894          *
895          * @param string $auth_cookie Authentication cookie.
896          * @param int    $expire      Login grace period in seconds. Default 43,200 seconds, or 12 hours.
897          * @param int    $expiration  Duration in seconds the authentication cookie should be valid.
898          *                            Default 1,209,600 seconds, or 14 days.
899          * @param int    $user_id     User ID.
900          * @param string $scheme      Authentication scheme. Values include 'auth', 'secure_auth', or 'logged_in'.
901          */
902         do_action( 'set_auth_cookie', $auth_cookie, $expire, $expiration, $user_id, $scheme );
903
904         /**
905          * Fires immediately before the secure authentication cookie is set.
906          *
907          * @since 2.6.0
908          *
909          * @param string $logged_in_cookie The logged-in cookie.
910          * @param int    $expire           Login grace period in seconds. Default 43,200 seconds, or 12 hours.
911          * @param int    $expiration       Duration in seconds the authentication cookie should be valid.
912          *                                 Default 1,209,600 seconds, or 14 days.
913          * @param int    $user_id          User ID.
914          * @param string $scheme           Authentication scheme. Default 'logged_in'.
915          */
916         do_action( 'set_logged_in_cookie', $logged_in_cookie, $expire, $expiration, $user_id, 'logged_in' );
917
918         setcookie($auth_cookie_name, $auth_cookie, $expire, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
919         setcookie($auth_cookie_name, $auth_cookie, $expire, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
920         setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, COOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true);
921         if ( COOKIEPATH != SITECOOKIEPATH )
922                 setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, SITECOOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true);
923 }
924 endif;
925
926 if ( !function_exists('wp_clear_auth_cookie') ) :
927 /**
928  * Removes all of the cookies associated with authentication.
929  *
930  * @since 2.5.0
931  */
932 function wp_clear_auth_cookie() {
933         /**
934          * Fires just before the authentication cookies are cleared.
935          *
936          * @since 2.7.0
937          */
938         do_action( 'clear_auth_cookie' );
939
940         setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH,   COOKIE_DOMAIN );
941         setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH,   COOKIE_DOMAIN );
942         setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
943         setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
944         setcookie( LOGGED_IN_COOKIE,   ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,          COOKIE_DOMAIN );
945         setcookie( LOGGED_IN_COOKIE,   ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH,      COOKIE_DOMAIN );
946
947         // Old cookies
948         setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
949         setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
950         setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
951         setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
952
953         // Even older cookies
954         setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
955         setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
956         setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
957         setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
958 }
959 endif;
960
961 if ( !function_exists('is_user_logged_in') ) :
962 /**
963  * Checks if the current visitor is a logged in user.
964  *
965  * @since 2.0.0
966  *
967  * @return bool True if user is logged in, false if not logged in.
968  */
969 function is_user_logged_in() {
970         $user = wp_get_current_user();
971
972         if ( ! $user->exists() )
973                 return false;
974
975         return true;
976 }
977 endif;
978
979 if ( !function_exists('auth_redirect') ) :
980 /**
981  * Checks if a user is logged in, if not it redirects them to the login page.
982  *
983  * @since 1.5.0
984  */
985 function auth_redirect() {
986         // Checks if a user is logged in, if not redirects them to the login page
987
988         $secure = ( is_ssl() || force_ssl_admin() );
989
990         /**
991          * Filter whether to use a secure authentication redirect.
992          *
993          * @since 3.1.0
994          *
995          * @param bool $secure Whether to use a secure authentication redirect. Default false.
996          */
997         $secure = apply_filters( 'secure_auth_redirect', $secure );
998
999         // If https is required and request is http, redirect
1000         if ( $secure && !is_ssl() && false !== strpos($_SERVER['REQUEST_URI'], 'wp-admin') ) {
1001                 if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
1002                         wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
1003                         exit();
1004                 } else {
1005                         wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1006                         exit();
1007                 }
1008         }
1009
1010         if ( is_user_admin() ) {
1011                 $scheme = 'logged_in';
1012         } else {
1013                 /**
1014                  * Filter the authentication redirect scheme.
1015                  *
1016                  * @since 2.9.0
1017                  *
1018                  * @param string $scheme Authentication redirect scheme. Default empty.
1019                  */
1020                 $scheme = apply_filters( 'auth_redirect_scheme', '' );
1021         }
1022
1023         if ( $user_id = wp_validate_auth_cookie( '',  $scheme) ) {
1024                 /**
1025                  * Fires before the authentication redirect.
1026                  *
1027                  * @since 2.8.0
1028                  *
1029                  * @param int $user_id User ID.
1030                  */
1031                 do_action( 'auth_redirect', $user_id );
1032
1033                 // If the user wants ssl but the session is not ssl, redirect.
1034                 if ( !$secure && get_user_option('use_ssl', $user_id) && false !== strpos($_SERVER['REQUEST_URI'], 'wp-admin') ) {
1035                         if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
1036                                 wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
1037                                 exit();
1038                         } else {
1039                                 wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1040                                 exit();
1041                         }
1042                 }
1043
1044                 return;  // The cookie is good so we're done
1045         }
1046
1047         // The cookie is no good so force login
1048         nocache_headers();
1049
1050         $redirect = ( strpos( $_SERVER['REQUEST_URI'], '/options.php' ) && wp_get_referer() ) ? wp_get_referer() : set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1051
1052         $login_url = wp_login_url($redirect, true);
1053
1054         wp_redirect($login_url);
1055         exit();
1056 }
1057 endif;
1058
1059 if ( !function_exists('check_admin_referer') ) :
1060 /**
1061  * Makes sure that a user was referred from another admin page.
1062  *
1063  * To avoid security exploits.
1064  *
1065  * @since 1.2.0
1066  *
1067  * @param int|string $action    Action nonce
1068  * @param string     $query_arg Where to look for nonce in $_REQUEST (since 2.5)
1069  */
1070 function check_admin_referer($action = -1, $query_arg = '_wpnonce') {
1071         if ( -1 == $action )
1072                 _doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '3.2' );
1073
1074         $adminurl = strtolower(admin_url());
1075         $referer = strtolower(wp_get_referer());
1076         $result = isset($_REQUEST[$query_arg]) ? wp_verify_nonce($_REQUEST[$query_arg], $action) : false;
1077         if ( !$result && !(-1 == $action && strpos($referer, $adminurl) === 0) ) {
1078                 wp_nonce_ays($action);
1079                 die();
1080         }
1081
1082         /**
1083          * Fires once the admin request has been validated or not.
1084          *
1085          * @since 1.5.1
1086          *
1087          * @param string $action The nonce action.
1088          * @param bool   $result Whether the admin request nonce was validated.
1089          */
1090         do_action( 'check_admin_referer', $action, $result );
1091         return $result;
1092 }
1093 endif;
1094
1095 if ( !function_exists('check_ajax_referer') ) :
1096 /**
1097  * Verifies the AJAX request to prevent processing requests external of the blog.
1098  *
1099  * @since 2.0.3
1100  *
1101  * @param int|string $action    Action nonce
1102  * @param string     $query_arg Where to look for nonce in $_REQUEST (since 2.5)
1103  */
1104 function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
1105         $nonce = '';
1106
1107         if ( $query_arg && isset( $_REQUEST[ $query_arg ] ) )
1108                 $nonce = $_REQUEST[ $query_arg ];
1109         elseif ( isset( $_REQUEST['_ajax_nonce'] ) )
1110                 $nonce = $_REQUEST['_ajax_nonce'];
1111         elseif ( isset( $_REQUEST['_wpnonce'] ) )
1112                 $nonce = $_REQUEST['_wpnonce'];
1113
1114         $result = wp_verify_nonce( $nonce, $action );
1115
1116         if ( $die && false == $result ) {
1117                 if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
1118                         wp_die( -1 );
1119                 else
1120                         die( '-1' );
1121         }
1122
1123         /**
1124          * Fires once the AJAX request has been validated or not.
1125          *
1126          * @since 2.1.0
1127          *
1128          * @param string $action The AJAX nonce action.
1129          * @param bool   $result Whether the AJAX request nonce was validated.
1130          */
1131         do_action( 'check_ajax_referer', $action, $result );
1132
1133         return $result;
1134 }
1135 endif;
1136
1137 if ( !function_exists('wp_redirect') ) :
1138 /**
1139  * Redirects to another page.
1140  *
1141  * @since 1.5.1
1142  *
1143  * @param string $location The path to redirect to.
1144  * @param int $status Status code to use.
1145  * @return bool False if $location is not provided, true otherwise.
1146  */
1147 function wp_redirect($location, $status = 302) {
1148         global $is_IIS;
1149
1150         /**
1151          * Filter the redirect location.
1152          *
1153          * @since 2.1.0
1154          *
1155          * @param string $location The path to redirect to.
1156          * @param int    $status   Status code to use.
1157          */
1158         $location = apply_filters( 'wp_redirect', $location, $status );
1159
1160         /**
1161          * Filter the redirect status code.
1162          *
1163          * @since 2.3.0
1164          *
1165          * @param int    $status   Status code to use.
1166          * @param string $location The path to redirect to.
1167          */
1168         $status = apply_filters( 'wp_redirect_status', $status, $location );
1169
1170         if ( ! $location )
1171                 return false;
1172
1173         $location = wp_sanitize_redirect($location);
1174
1175         if ( !$is_IIS && php_sapi_name() != 'cgi-fcgi' )
1176                 status_header($status); // This causes problems on IIS and some FastCGI setups
1177
1178         header("Location: $location", true, $status);
1179
1180         return true;
1181 }
1182 endif;
1183
1184 if ( !function_exists('wp_sanitize_redirect') ) :
1185 /**
1186  * Sanitizes a URL for use in a redirect.
1187  *
1188  * @since 2.3.0
1189  *
1190  * @return string redirect-sanitized URL
1191  **/
1192 function wp_sanitize_redirect($location) {
1193         $location = preg_replace('|[^a-z0-9-~+_.?#=&;,/:%!*\[\]()]|i', '', $location);
1194         $location = wp_kses_no_null($location);
1195
1196         // remove %0d and %0a from location
1197         $strip = array('%0d', '%0a', '%0D', '%0A');
1198         $location = _deep_replace($strip, $location);
1199         return $location;
1200 }
1201 endif;
1202
1203 if ( !function_exists('wp_safe_redirect') ) :
1204 /**
1205  * Performs a safe (local) redirect, using wp_redirect().
1206  *
1207  * Checks whether the $location is using an allowed host, if it has an absolute
1208  * path. A plugin can therefore set or remove allowed host(s) to or from the
1209  * list.
1210  *
1211  * If the host is not allowed, then the redirect is to wp-admin on the siteurl
1212  * instead. This prevents malicious redirects which redirect to another host,
1213  * but only used in a few places.
1214  *
1215  * @since 2.3.0
1216  *
1217  * @return void Does not return anything
1218  **/
1219 function wp_safe_redirect($location, $status = 302) {
1220
1221         // Need to look at the URL the way it will end up in wp_redirect()
1222         $location = wp_sanitize_redirect($location);
1223
1224         $location = wp_validate_redirect($location, admin_url());
1225
1226         wp_redirect($location, $status);
1227 }
1228 endif;
1229
1230 if ( !function_exists('wp_validate_redirect') ) :
1231 /**
1232  * Validates a URL for use in a redirect.
1233  *
1234  * Checks whether the $location is using an allowed host, if it has an absolute
1235  * path. A plugin can therefore set or remove allowed host(s) to or from the
1236  * list.
1237  *
1238  * If the host is not allowed, then the redirect is to $default supplied
1239  *
1240  * @since 2.8.1
1241  *
1242  * @param string $location The redirect to validate
1243  * @param string $default The value to return if $location is not allowed
1244  * @return string redirect-sanitized URL
1245  **/
1246 function wp_validate_redirect($location, $default = '') {
1247         $location = trim( $location );
1248         // browsers will assume 'http' is your protocol, and will obey a redirect to a URL starting with '//'
1249         if ( substr($location, 0, 2) == '//' )
1250                 $location = 'http:' . $location;
1251
1252         // In php 5 parse_url may fail if the URL query part contains http://, bug #38143
1253         $test = ( $cut = strpos($location, '?') ) ? substr( $location, 0, $cut ) : $location;
1254
1255         $lp  = parse_url($test);
1256
1257         // Give up if malformed URL
1258         if ( false === $lp )
1259                 return $default;
1260
1261         // Allow only http and https schemes. No data:, etc.
1262         if ( isset($lp['scheme']) && !('http' == $lp['scheme'] || 'https' == $lp['scheme']) )
1263                 return $default;
1264
1265         // Reject if scheme is set but host is not. This catches urls like https:host.com for which parse_url does not set the host field.
1266         if ( isset($lp['scheme'])  && !isset($lp['host']) )
1267                 return $default;
1268
1269         $wpp = parse_url(home_url());
1270
1271         /**
1272          * Filter the whitelist of hosts to redirect to.
1273          *
1274          * @since 2.3.0
1275          *
1276          * @param array       $hosts An array of allowed hosts.
1277          * @param bool|string $host  The parsed host; empty if not isset.
1278          */
1279         $allowed_hosts = (array) apply_filters( 'allowed_redirect_hosts', array($wpp['host']), isset($lp['host']) ? $lp['host'] : '' );
1280
1281         if ( isset($lp['host']) && ( !in_array($lp['host'], $allowed_hosts) && $lp['host'] != strtolower($wpp['host'])) )
1282                 $location = $default;
1283
1284         return $location;
1285 }
1286 endif;
1287
1288 if ( ! function_exists('wp_notify_postauthor') ) :
1289 /**
1290  * Notify an author (and/or others) of a comment/trackback/pingback on a post.
1291  *
1292  * @since 1.0.0
1293  *
1294  * @param int $comment_id Comment ID
1295  * @param string $deprecated Not used
1296  * @return bool True on completion. False if no email addresses were specified.
1297  */
1298 function wp_notify_postauthor( $comment_id, $deprecated = null ) {
1299         if ( null !== $deprecated ) {
1300                 _deprecated_argument( __FUNCTION__, '3.8' );
1301         }
1302
1303         $comment = get_comment( $comment_id );
1304         if ( empty( $comment ) )
1305                 return false;
1306
1307         $post    = get_post( $comment->comment_post_ID );
1308         $author  = get_userdata( $post->post_author );
1309
1310         // Who to notify? By default, just the post author, but others can be added.
1311         $emails = array();
1312         if ( $author ) {
1313                 $emails[] = $author->user_email;
1314         }
1315
1316         /**
1317          * Filter the list of email addresses to receive a comment notification.
1318          *
1319          * By default, only post authors are notified of comments. This filter allows
1320          * others to be added.
1321          *
1322          * @since 3.7.0
1323          *
1324          * @param array $emails     An array of email addresses to receive a comment notification.
1325          * @param int   $comment_id The comment ID.
1326          */
1327         $emails = apply_filters( 'comment_notification_recipients', $emails, $comment_id );
1328         $emails = array_filter( $emails );
1329
1330         // If there are no addresses to send the comment to, bail.
1331         if ( ! count( $emails ) ) {
1332                 return false;
1333         }
1334
1335         // Facilitate unsetting below without knowing the keys.
1336         $emails = array_flip( $emails );
1337
1338         /**
1339          * Filter whether to notify comment authors of their comments on their own posts.
1340          *
1341          * By default, comment authors aren't notified of their comments on their own
1342          * posts. This filter allows you to override that.
1343          *
1344          * @since 3.8.0
1345          *
1346          * @param bool $notify     Whether to notify the post author of their own comment.
1347          *                         Default false.
1348          * @param int  $comment_id The comment ID.
1349          */
1350         $notify_author = apply_filters( 'comment_notification_notify_author', false, $comment_id );
1351
1352         // The comment was left by the author
1353         if ( $author && ! $notify_author && $comment->user_id == $post->post_author ) {
1354                 unset( $emails[ $author->user_email ] );
1355         }
1356
1357         // The author moderated a comment on their own post
1358         if ( $author && ! $notify_author && $post->post_author == get_current_user_id() ) {
1359                 unset( $emails[ $author->user_email ] );
1360         }
1361
1362         // The post author is no longer a member of the blog
1363         if ( $author && ! $notify_author && ! user_can( $post->post_author, 'read_post', $post->ID ) ) {
1364                 unset( $emails[ $author->user_email ] );
1365         }
1366
1367         // If there's no email to send the comment to, bail, otherwise flip array back around for use below
1368         if ( ! count( $emails ) ) {
1369                 return false;
1370         } else {
1371                 $emails = array_flip( $emails );
1372         }
1373
1374         $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
1375
1376         // The blogname option is escaped with esc_html on the way into the database in sanitize_option
1377         // we want to reverse this for the plain text arena of emails.
1378         $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
1379
1380         switch ( $comment->comment_type ) {
1381                 case 'trackback':
1382                         $notify_message  = sprintf( __( 'New trackback on your post "%s"' ), $post->post_title ) . "\r\n";
1383                         /* translators: 1: website name, 2: author IP, 3: author domain */
1384                         $notify_message .= sprintf( __('Website: %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1385                         $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
1386                         $notify_message .= sprintf( __( 'Comment: %s' ), $comment->comment_content ) . "\r\n\r\n";
1387                         $notify_message .= __( 'You can see all trackbacks on this post here:' ) . "\r\n";
1388                         /* translators: 1: blog name, 2: post title */
1389                         $subject = sprintf( __('[%1$s] Trackback: "%2$s"'), $blogname, $post->post_title );
1390                         break;
1391                 case 'pingback':
1392                         $notify_message  = sprintf( __( 'New pingback on your post "%s"' ), $post->post_title ) . "\r\n";
1393                         /* translators: 1: comment author, 2: author IP, 3: author domain */
1394                         $notify_message .= sprintf( __('Website: %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1395                         $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
1396                         $notify_message .= sprintf( __( 'Comment: %s' ), $comment->comment_content ) . "\r\n\r\n";
1397                         $notify_message .= __( 'You can see all pingbacks on this post here:' ) . "\r\n";
1398                         /* translators: 1: blog name, 2: post title */
1399                         $subject = sprintf( __('[%1$s] Pingback: "%2$s"'), $blogname, $post->post_title );
1400                         break;
1401                 default: // Comments
1402                         $notify_message  = sprintf( __( 'New comment on your post "%s"' ), $post->post_title ) . "\r\n";
1403                         /* translators: 1: comment author, 2: author IP, 3: author domain */
1404                         $notify_message .= sprintf( __( 'Author: %1$s (IP: %2$s , %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1405                         $notify_message .= sprintf( __( 'E-mail: %s' ), $comment->comment_author_email ) . "\r\n";
1406                         $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
1407                         $notify_message .= sprintf( __( 'Whois: %s' ), "http://whois.arin.net/rest/ip/{$comment->comment_author_IP}" ) . "\r\n";
1408                         $notify_message .= sprintf( __('Comment: %s' ), $comment->comment_content ) . "\r\n\r\n";
1409                         $notify_message .= __( 'You can see all comments on this post here:' ) . "\r\n";
1410                         /* translators: 1: blog name, 2: post title */
1411                         $subject = sprintf( __('[%1$s] Comment: "%2$s"'), $blogname, $post->post_title );
1412                         break;
1413         }
1414         $notify_message .= get_permalink($comment->comment_post_ID) . "#comments\r\n\r\n";
1415         $notify_message .= sprintf( __('Permalink: %s'), get_comment_link( $comment_id ) ) . "\r\n";
1416
1417         if ( user_can( $post->post_author, 'edit_comment', $comment_id ) ) {
1418                 if ( EMPTY_TRASH_DAYS )
1419                         $notify_message .= sprintf( __('Trash it: %s'), admin_url("comment.php?action=trash&c=$comment_id") ) . "\r\n";
1420                 else
1421                         $notify_message .= sprintf( __('Delete it: %s'), admin_url("comment.php?action=delete&c=$comment_id") ) . "\r\n";
1422                 $notify_message .= sprintf( __('Spam it: %s'), admin_url("comment.php?action=spam&c=$comment_id") ) . "\r\n";
1423         }
1424
1425         $wp_email = 'wordpress@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME']));
1426
1427         if ( '' == $comment->comment_author ) {
1428                 $from = "From: \"$blogname\" <$wp_email>";
1429                 if ( '' != $comment->comment_author_email )
1430                         $reply_to = "Reply-To: $comment->comment_author_email";
1431         } else {
1432                 $from = "From: \"$comment->comment_author\" <$wp_email>";
1433                 if ( '' != $comment->comment_author_email )
1434                         $reply_to = "Reply-To: \"$comment->comment_author_email\" <$comment->comment_author_email>";
1435         }
1436
1437         $message_headers = "$from\n"
1438                 . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
1439
1440         if ( isset($reply_to) )
1441                 $message_headers .= $reply_to . "\n";
1442
1443         /**
1444          * Filter the comment notification email text.
1445          *
1446          * @since 1.5.2
1447          *
1448          * @param string $notify_message The comment notification email text.
1449          * @param int    $comment_id     Comment ID.
1450          */
1451         $notify_message = apply_filters( 'comment_notification_text', $notify_message, $comment_id );
1452
1453         /**
1454          * Filter the comment notification email subject.
1455          *
1456          * @since 1.5.2
1457          *
1458          * @param string $subject    The comment notification email subject.
1459          * @param int    $comment_id Comment ID.
1460          */
1461         $subject = apply_filters( 'comment_notification_subject', $subject, $comment_id );
1462
1463         /**
1464          * Filter the comment notification email headers.
1465          *
1466          * @since 1.5.2
1467          *
1468          * @param string $message_headers Headers for the comment notification email.
1469          * @param int    $comment_id      Comment ID.
1470          */
1471         $message_headers = apply_filters( 'comment_notification_headers', $message_headers, $comment_id );
1472
1473         foreach ( $emails as $email ) {
1474                 @wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
1475         }
1476
1477         return true;
1478 }
1479 endif;
1480
1481 if ( !function_exists('wp_notify_moderator') ) :
1482 /**
1483  * Notifies the moderator of the blog about a new comment that is awaiting approval.
1484  *
1485  * @since 1.0.0
1486  *
1487  * @global wpdb $wpdb WordPress database abstraction object.
1488  *
1489  * @param int $comment_id Comment ID
1490  * @return bool Always returns true
1491  */
1492 function wp_notify_moderator($comment_id) {
1493         global $wpdb;
1494
1495         if ( 0 == get_option( 'moderation_notify' ) )
1496                 return true;
1497
1498         $comment = get_comment($comment_id);
1499         $post = get_post($comment->comment_post_ID);
1500         $user = get_userdata( $post->post_author );
1501         // Send to the administration and to the post author if the author can modify the comment.
1502         $emails = array( get_option( 'admin_email' ) );
1503         if ( user_can( $user->ID, 'edit_comment', $comment_id ) && ! empty( $user->user_email ) ) {
1504                 if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) )
1505                         $emails[] = $user->user_email;
1506         }
1507
1508         $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
1509         $comments_waiting = $wpdb->get_var("SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'");
1510
1511         // The blogname option is escaped with esc_html on the way into the database in sanitize_option
1512         // we want to reverse this for the plain text arena of emails.
1513         $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
1514
1515         switch ( $comment->comment_type ) {
1516                 case 'trackback':
1517                         $notify_message  = sprintf( __('A new trackback on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
1518                         $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
1519                         $notify_message .= sprintf( __('Website : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1520                         $notify_message .= sprintf( __('URL    : %s'), $comment->comment_author_url ) . "\r\n";
1521                         $notify_message .= __('Trackback excerpt: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
1522                         break;
1523                 case 'pingback':
1524                         $notify_message  = sprintf( __('A new pingback on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
1525                         $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
1526                         $notify_message .= sprintf( __('Website : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1527                         $notify_message .= sprintf( __('URL    : %s'), $comment->comment_author_url ) . "\r\n";
1528                         $notify_message .= __('Pingback excerpt: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
1529                         break;
1530                 default: // Comments
1531                         $notify_message  = sprintf( __('A new comment on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
1532                         $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
1533                         $notify_message .= sprintf( __('Author : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1534                         $notify_message .= sprintf( __('E-mail : %s'), $comment->comment_author_email ) . "\r\n";
1535                         $notify_message .= sprintf( __('URL    : %s'), $comment->comment_author_url ) . "\r\n";
1536                         $notify_message .= sprintf( __('Whois  : http://whois.arin.net/rest/ip/%s'), $comment->comment_author_IP ) . "\r\n";
1537                         $notify_message .= __('Comment: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
1538                         break;
1539         }
1540
1541         $notify_message .= sprintf( __('Approve it: %s'),  admin_url("comment.php?action=approve&c=$comment_id") ) . "\r\n";
1542         if ( EMPTY_TRASH_DAYS )
1543                 $notify_message .= sprintf( __('Trash it: %s'), admin_url("comment.php?action=trash&c=$comment_id") ) . "\r\n";
1544         else
1545                 $notify_message .= sprintf( __('Delete it: %s'), admin_url("comment.php?action=delete&c=$comment_id") ) . "\r\n";
1546         $notify_message .= sprintf( __('Spam it: %s'), admin_url("comment.php?action=spam&c=$comment_id") ) . "\r\n";
1547
1548         $notify_message .= sprintf( _n('Currently %s comment is waiting for approval. Please visit the moderation panel:',
1549                 'Currently %s comments are waiting for approval. Please visit the moderation panel:', $comments_waiting), number_format_i18n($comments_waiting) ) . "\r\n";
1550         $notify_message .= admin_url("edit-comments.php?comment_status=moderated") . "\r\n";
1551
1552         $subject = sprintf( __('[%1$s] Please moderate: "%2$s"'), $blogname, $post->post_title );
1553         $message_headers = '';
1554
1555         /**
1556          * Filter the list of recipients for comment moderation emails.
1557          *
1558          * @since 3.7.0
1559          *
1560          * @param array $emails     List of email addresses to notify for comment moderation.
1561          * @param int   $comment_id Comment ID.
1562          */
1563         $emails = apply_filters( 'comment_moderation_recipients', $emails, $comment_id );
1564
1565         /**
1566          * Filter the comment moderation email text.
1567          *
1568          * @since 1.5.2
1569          *
1570          * @param string $notify_message Text of the comment moderation email.
1571          * @param int    $comment_id     Comment ID.
1572          */
1573         $notify_message = apply_filters( 'comment_moderation_text', $notify_message, $comment_id );
1574
1575         /**
1576          * Filter the comment moderation email subject.
1577          *
1578          * @since 1.5.2
1579          *
1580          * @param string $subject    Subject of the comment moderation email.
1581          * @param int    $comment_id Comment ID.
1582          */
1583         $subject = apply_filters( 'comment_moderation_subject', $subject, $comment_id );
1584
1585         /**
1586          * Filter the comment moderation email headers.
1587          *
1588          * @since 2.8.0
1589          *
1590          * @param string $message_headers Headers for the comment moderation email.
1591          * @param int    $comment_id      Comment ID.
1592          */
1593         $message_headers = apply_filters( 'comment_moderation_headers', $message_headers, $comment_id );
1594
1595         foreach ( $emails as $email ) {
1596                 @wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
1597         }
1598
1599         return true;
1600 }
1601 endif;
1602
1603 if ( !function_exists('wp_password_change_notification') ) :
1604 /**
1605  * Notify the blog admin of a user changing password, normally via email.
1606  *
1607  * @since 2.7.0
1608  *
1609  * @param object $user User Object
1610  */
1611 function wp_password_change_notification(&$user) {
1612         // send a copy of password change notification to the admin
1613         // but check to see if it's the admin whose password we're changing, and skip this
1614         if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) ) {
1615                 $message = sprintf(__('Password Lost and Changed for user: %s'), $user->user_login) . "\r\n";
1616                 // The blogname option is escaped with esc_html on the way into the database in sanitize_option
1617                 // we want to reverse this for the plain text arena of emails.
1618                 $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
1619                 wp_mail(get_option('admin_email'), sprintf(__('[%s] Password Lost/Changed'), $blogname), $message);
1620         }
1621 }
1622 endif;
1623
1624 if ( !function_exists('wp_new_user_notification') ) :
1625 /**
1626  * Email login credentials to a newly-registered user.
1627  *
1628  * A new user registration notification is also sent to admin email.
1629  *
1630  * @since 2.0.0
1631  *
1632  * @param int    $user_id        User ID.
1633  * @param string $plaintext_pass Optional. The user's plaintext password. Default empty.
1634  */
1635 function wp_new_user_notification($user_id, $plaintext_pass = '') {
1636         $user = get_userdata( $user_id );
1637
1638         // The blogname option is escaped with esc_html on the way into the database in sanitize_option
1639         // we want to reverse this for the plain text arena of emails.
1640         $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
1641
1642         $message  = sprintf(__('New user registration on your site %s:'), $blogname) . "\r\n\r\n";
1643         $message .= sprintf(__('Username: %s'), $user->user_login) . "\r\n\r\n";
1644         $message .= sprintf(__('E-mail: %s'), $user->user_email) . "\r\n";
1645
1646         @wp_mail(get_option('admin_email'), sprintf(__('[%s] New User Registration'), $blogname), $message);
1647
1648         if ( empty($plaintext_pass) )
1649                 return;
1650
1651         $message  = sprintf(__('Username: %s'), $user->user_login) . "\r\n";
1652         $message .= sprintf(__('Password: %s'), $plaintext_pass) . "\r\n";
1653         $message .= wp_login_url() . "\r\n";
1654
1655         wp_mail($user->user_email, sprintf(__('[%s] Your username and password'), $blogname), $message);
1656
1657 }
1658 endif;
1659
1660 if ( !function_exists('wp_nonce_tick') ) :
1661 /**
1662  * Get the time-dependent variable for nonce creation.
1663  *
1664  * A nonce has a lifespan of two ticks. Nonces in their second tick may be
1665  * updated, e.g. by autosave.
1666  *
1667  * @since 2.5.0
1668  *
1669  * @return float Float value rounded up to the next highest integer.
1670  */
1671 function wp_nonce_tick() {
1672         /**
1673          * Filter the lifespan of nonces in seconds.
1674          *
1675          * @since 2.5.0
1676          *
1677          * @param int $lifespan Lifespan of nonces in seconds. Default 86,400 seconds, or one day.
1678          */
1679         $nonce_life = apply_filters( 'nonce_life', DAY_IN_SECONDS );
1680
1681         return ceil(time() / ( $nonce_life / 2 ));
1682 }
1683 endif;
1684
1685 if ( !function_exists('wp_verify_nonce') ) :
1686 /**
1687  * Verify that correct nonce was used with time limit.
1688  *
1689  * The user is given an amount of time to use the token, so therefore, since the
1690  * UID and $action remain the same, the independent variable is the time.
1691  *
1692  * @since 2.0.3
1693  *
1694  * @param string     $nonce  Nonce that was used in the form to verify
1695  * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
1696  * @return bool Whether the nonce check passed or failed.
1697  */
1698 function wp_verify_nonce( $nonce, $action = -1 ) {
1699         $nonce = (string) $nonce;
1700         $user = wp_get_current_user();
1701         $uid = (int) $user->ID;
1702         if ( ! $uid ) {
1703                 /**
1704                  * Filter whether the user who generated the nonce is logged out.
1705                  *
1706                  * @since 3.5.0
1707                  *
1708                  * @param int    $uid    ID of the nonce-owning user.
1709                  * @param string $action The nonce action.
1710                  */
1711                 $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
1712         }
1713
1714         if ( empty( $nonce ) ) {
1715                 return false;
1716         }
1717
1718         $token = wp_get_session_token();
1719         $i = wp_nonce_tick();
1720
1721         // Nonce generated 0-12 hours ago
1722         $expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 );
1723         if ( hash_equals( $expected, $nonce ) ) {
1724                 return 1;
1725         }
1726
1727         // Nonce generated 12-24 hours ago
1728         $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
1729         if ( hash_equals( $expected, $nonce ) ) {
1730                 return 2;
1731         }
1732
1733         // Invalid nonce
1734         return false;
1735 }
1736 endif;
1737
1738 if ( !function_exists('wp_create_nonce') ) :
1739 /**
1740  * Creates a cryptographic token tied to a specific action, user, and window of time.
1741  *
1742  * @since 2.0.3
1743  *
1744  * @param string|int $action Scalar value to add context to the nonce.
1745  * @return string The token.
1746  */
1747 function wp_create_nonce($action = -1) {
1748         $user = wp_get_current_user();
1749         $uid = (int) $user->ID;
1750         if ( ! $uid ) {
1751                 /** This filter is documented in wp-includes/pluggable.php */
1752                 $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
1753         }
1754
1755         $token = wp_get_session_token();
1756         $i = wp_nonce_tick();
1757
1758         return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
1759 }
1760 endif;
1761
1762 if ( !function_exists('wp_salt') ) :
1763 /**
1764  * Get salt to add to hashes.
1765  *
1766  * Salts are created using secret keys. Secret keys are located in two places:
1767  * in the database and in the wp-config.php file. The secret key in the database
1768  * is randomly generated and will be appended to the secret keys in wp-config.php.
1769  *
1770  * The secret keys in wp-config.php should be updated to strong, random keys to maximize
1771  * security. Below is an example of how the secret key constants are defined.
1772  * Do not paste this example directly into wp-config.php. Instead, have a
1773  * {@link https://api.wordpress.org/secret-key/1.1/salt/ secret key created} just
1774  * for you.
1775  *
1776  *     define('AUTH_KEY',         ' Xakm<o xQy rw4EMsLKM-?!T+,PFF})H4lzcW57AF0U@N@< >M%G4Yt>f`z]MON');
1777  *     define('SECURE_AUTH_KEY',  'LzJ}op]mr|6+![P}Ak:uNdJCJZd>(Hx.-Mh#Tz)pCIU#uGEnfFz|f ;;eU%/U^O~');
1778  *     define('LOGGED_IN_KEY',    '|i|Ux`9<p-h$aFf(qnT:sDO:D1P^wZ$$/Ra@miTJi9G;ddp_<q}6H1)o|a +&JCM');
1779  *     define('NONCE_KEY',        '%:R{[P|,s.KuMltH5}cI;/k<Gx~j!f0I)m_sIyu+&NJZ)-iO>z7X>QYR0Z_XnZ@|');
1780  *     define('AUTH_SALT',        'eZyT)-Naw]F8CwA*VaW#q*|.)g@o}||wf~@C-YSt}(dh_r6EbI#A,y|nU2{B#JBW');
1781  *     define('SECURE_AUTH_SALT', '!=oLUTXh,QW=H `}`L|9/^4-3 STz},T(w}W<I`.JjPi)<Bmf1v,HpGe}T1:Xt7n');
1782  *     define('LOGGED_IN_SALT',   '+XSqHc;@Q*K_b|Z?NC[3H!!EONbh.n<+=uKR:>*c(u`g~EJBf#8u#R{mUEZrozmm');
1783  *     define('NONCE_SALT',       'h`GXHhD>SLWVfg1(1(N{;.V!MoE(SfbA_ksP@&`+AycHcAV$+?@3q+rxV{%^VyKT');
1784  *
1785  * Salting passwords helps against tools which has stored hashed values of
1786  * common dictionary strings. The added values makes it harder to crack.
1787  *
1788  * @since 2.5.0
1789  *
1790  * @link https://api.wordpress.org/secret-key/1.1/salt/ Create secrets for wp-config.php
1791  *
1792  * @param string $scheme Authentication scheme (auth, secure_auth, logged_in, nonce)
1793  * @return string Salt value
1794  */
1795 function wp_salt( $scheme = 'auth' ) {
1796         static $cached_salts = array();
1797         if ( isset( $cached_salts[ $scheme ] ) ) {
1798                 /**
1799                  * Filter the WordPress salt.
1800                  *
1801                  * @since 2.5.0
1802                  *
1803                  * @param string $cached_salt Cached salt for the given scheme.
1804                  * @param string $scheme      Authentication scheme. Values include 'auth',
1805                  *                            'secure_auth', 'logged_in', and 'nonce'.
1806                  */
1807                 return apply_filters( 'salt', $cached_salts[ $scheme ], $scheme );
1808         }
1809
1810         static $duplicated_keys;
1811         if ( null === $duplicated_keys ) {
1812                 $duplicated_keys = array( 'put your unique phrase here' => true );
1813                 foreach ( array( 'AUTH', 'SECURE_AUTH', 'LOGGED_IN', 'NONCE', 'SECRET' ) as $first ) {
1814                         foreach ( array( 'KEY', 'SALT' ) as $second ) {
1815                                 if ( ! defined( "{$first}_{$second}" ) ) {
1816                                         continue;
1817                                 }
1818                                 $value = constant( "{$first}_{$second}" );
1819                                 $duplicated_keys[ $value ] = isset( $duplicated_keys[ $value ] );
1820                         }
1821                 }
1822         }
1823
1824         $values = array(
1825                 'key' => '',
1826                 'salt' => ''
1827         );
1828         if ( defined( 'SECRET_KEY' ) && SECRET_KEY && empty( $duplicated_keys[ SECRET_KEY ] ) ) {
1829                 $values['key'] = SECRET_KEY;
1830         }
1831         if ( 'auth' == $scheme && defined( 'SECRET_SALT' ) && SECRET_SALT && empty( $duplicated_keys[ SECRET_SALT ] ) ) {
1832                 $values['salt'] = SECRET_SALT;
1833         }
1834
1835         if ( in_array( $scheme, array( 'auth', 'secure_auth', 'logged_in', 'nonce' ) ) ) {
1836                 foreach ( array( 'key', 'salt' ) as $type ) {
1837                         $const = strtoupper( "{$scheme}_{$type}" );
1838                         if ( defined( $const ) && constant( $const ) && empty( $duplicated_keys[ constant( $const ) ] ) ) {
1839                                 $values[ $type ] = constant( $const );
1840                         } elseif ( ! $values[ $type ] ) {
1841                                 $values[ $type ] = get_site_option( "{$scheme}_{$type}" );
1842                                 if ( ! $values[ $type ] ) {
1843                                         $values[ $type ] = wp_generate_password( 64, true, true );
1844                                         update_site_option( "{$scheme}_{$type}", $values[ $type ] );
1845                                 }
1846                         }
1847                 }
1848         } else {
1849                 if ( ! $values['key'] ) {
1850                         $values['key'] = get_site_option( 'secret_key' );
1851                         if ( ! $values['key'] ) {
1852                                 $values['key'] = wp_generate_password( 64, true, true );
1853                                 update_site_option( 'secret_key', $values['key'] );
1854                         }
1855                 }
1856                 $values['salt'] = hash_hmac( 'md5', $scheme, $values['key'] );
1857         }
1858
1859         $cached_salts[ $scheme ] = $values['key'] . $values['salt'];
1860
1861         /** This filter is documented in wp-includes/pluggable.php */
1862         return apply_filters( 'salt', $cached_salts[ $scheme ], $scheme );
1863 }
1864 endif;
1865
1866 if ( !function_exists('wp_hash') ) :
1867 /**
1868  * Get hash of given string.
1869  *
1870  * @since 2.0.3
1871  *
1872  * @param string $data Plain text to hash
1873  * @return string Hash of $data
1874  */
1875 function wp_hash($data, $scheme = 'auth') {
1876         $salt = wp_salt($scheme);
1877
1878         return hash_hmac('md5', $data, $salt);
1879 }
1880 endif;
1881
1882 if ( !function_exists('wp_hash_password') ) :
1883 /**
1884  * Create a hash (encrypt) of a plain text password.
1885  *
1886  * For integration with other applications, this function can be overwritten to
1887  * instead use the other package password checking algorithm.
1888  *
1889  * @since 2.5.0
1890  *
1891  * @global object $wp_hasher PHPass object
1892  * @uses PasswordHash::HashPassword
1893  *
1894  * @param string $password Plain text user password to hash
1895  * @return string The hash string of the password
1896  */
1897 function wp_hash_password($password) {
1898         global $wp_hasher;
1899
1900         if ( empty($wp_hasher) ) {
1901                 require_once( ABSPATH . WPINC . '/class-phpass.php');
1902                 // By default, use the portable hash from phpass
1903                 $wp_hasher = new PasswordHash(8, true);
1904         }
1905
1906         return $wp_hasher->HashPassword( trim( $password ) );
1907 }
1908 endif;
1909
1910 if ( !function_exists('wp_check_password') ) :
1911 /**
1912  * Checks the plaintext password against the encrypted Password.
1913  *
1914  * Maintains compatibility between old version and the new cookie authentication
1915  * protocol using PHPass library. The $hash parameter is the encrypted password
1916  * and the function compares the plain text password when encrypted similarly
1917  * against the already encrypted password to see if they match.
1918  *
1919  * For integration with other applications, this function can be overwritten to
1920  * instead use the other package password checking algorithm.
1921  *
1922  * @since 2.5.0
1923  *
1924  * @global object $wp_hasher PHPass object used for checking the password
1925  *      against the $hash + $password
1926  * @uses PasswordHash::CheckPassword
1927  *
1928  * @param string $password Plaintext user's password
1929  * @param string $hash Hash of the user's password to check against.
1930  * @return bool False, if the $password does not match the hashed password
1931  */
1932 function wp_check_password($password, $hash, $user_id = '') {
1933         global $wp_hasher;
1934
1935         // If the hash is still md5...
1936         if ( strlen($hash) <= 32 ) {
1937                 $check = hash_equals( $hash, md5( $password ) );
1938                 if ( $check && $user_id ) {
1939                         // Rehash using new hash.
1940                         wp_set_password($password, $user_id);
1941                         $hash = wp_hash_password($password);
1942                 }
1943
1944                 /**
1945                  * Filter whether the plaintext password matches the encrypted password.
1946                  *
1947                  * @since 2.5.0
1948                  *
1949                  * @param bool   $check    Whether the passwords match.
1950                  * @param string $password The plaintext password.
1951                  * @param string $hash     The hashed password.
1952                  * @param int    $user_id  User ID.
1953                  */
1954                 return apply_filters( 'check_password', $check, $password, $hash, $user_id );
1955         }
1956
1957         // If the stored hash is longer than an MD5, presume the
1958         // new style phpass portable hash.
1959         if ( empty($wp_hasher) ) {
1960                 require_once( ABSPATH . WPINC . '/class-phpass.php');
1961                 // By default, use the portable hash from phpass
1962                 $wp_hasher = new PasswordHash(8, true);
1963         }
1964
1965         $check = $wp_hasher->CheckPassword($password, $hash);
1966
1967         /** This filter is documented in wp-includes/pluggable.php */
1968         return apply_filters( 'check_password', $check, $password, $hash, $user_id );
1969 }
1970 endif;
1971
1972 if ( !function_exists('wp_generate_password') ) :
1973 /**
1974  * Generates a random password drawn from the defined set of characters.
1975  *
1976  * @since 2.5.0
1977  *
1978  * @param int  $length              Optional. The length of password to generate. Default 12.
1979  * @param bool $special_chars       Optional. Whether to include standard special characters.
1980  *                                  Default true.
1981  * @param bool $extra_special_chars Optional. Whether to include other special characters.
1982  *                                  Used when generating secret keys and salts. Default false.
1983  * @return string The random password.
1984  */
1985 function wp_generate_password( $length = 12, $special_chars = true, $extra_special_chars = false ) {
1986         $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
1987         if ( $special_chars )
1988                 $chars .= '!@#$%^&*()';
1989         if ( $extra_special_chars )
1990                 $chars .= '-_ []{}<>~`+=,.;:/?|';
1991
1992         $password = '';
1993         for ( $i = 0; $i < $length; $i++ ) {
1994                 $password .= substr($chars, wp_rand(0, strlen($chars) - 1), 1);
1995         }
1996
1997         /**
1998          * Filter the randomly-generated password.
1999          *
2000          * @since 3.0.0
2001          *
2002          * @param string $password The generated password.
2003          */
2004         return apply_filters( 'random_password', $password );
2005 }
2006 endif;
2007
2008 if ( !function_exists('wp_rand') ) :
2009 /**
2010  * Generates a random number
2011  *
2012  * @since 2.6.2
2013  *
2014  * @param int $min Lower limit for the generated number
2015  * @param int $max Upper limit for the generated number
2016  * @return int A random number between min and max
2017  */
2018 function wp_rand( $min = 0, $max = 0 ) {
2019         global $rnd_value;
2020
2021         // Reset $rnd_value after 14 uses
2022         // 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value
2023         if ( strlen($rnd_value) < 8 ) {
2024                 if ( defined( 'WP_SETUP_CONFIG' ) )
2025                         static $seed = '';
2026                 else
2027                         $seed = get_transient('random_seed');
2028                 $rnd_value = md5( uniqid(microtime() . mt_rand(), true ) . $seed );
2029                 $rnd_value .= sha1($rnd_value);
2030                 $rnd_value .= sha1($rnd_value . $seed);
2031                 $seed = md5($seed . $rnd_value);
2032                 if ( ! defined( 'WP_SETUP_CONFIG' ) )
2033                         set_transient('random_seed', $seed);
2034         }
2035
2036         // Take the first 8 digits for our value
2037         $value = substr($rnd_value, 0, 8);
2038
2039         // Strip the first eight, leaving the remainder for the next call to wp_rand().
2040         $rnd_value = substr($rnd_value, 8);
2041
2042         $value = abs(hexdec($value));
2043
2044         // Some misconfigured 32bit environments (Entropy PHP, for example) truncate integers larger than PHP_INT_MAX to PHP_INT_MAX rather than overflowing them to floats.
2045         $max_random_number = 3000000000 === 2147483647 ? (float) "4294967295" : 4294967295; // 4294967295 = 0xffffffff
2046
2047         // Reduce the value to be within the min - max range
2048         if ( $max != 0 )
2049                 $value = $min + ( $max - $min + 1 ) * $value / ( $max_random_number + 1 );
2050
2051         return abs(intval($value));
2052 }
2053 endif;
2054
2055 if ( !function_exists('wp_set_password') ) :
2056 /**
2057  * Updates the user's password with a new encrypted one.
2058  *
2059  * For integration with other applications, this function can be overwritten to
2060  * instead use the other package password checking algorithm.
2061  *
2062  * Please note: This function should be used sparingly and is really only meant for single-time
2063  * application. Leveraging this improperly in a plugin or theme could result in an endless loop
2064  * of password resets if precautions are not taken to ensure it does not execute on every page load.
2065  *
2066  * @since 2.5.0
2067  *
2068  * @global wpdb $wpdb WordPress database abstraction object.
2069  *
2070  * @param string $password The plaintext new user password
2071  * @param int $user_id User ID
2072  */
2073 function wp_set_password( $password, $user_id ) {
2074         global $wpdb;
2075
2076         $hash = wp_hash_password( $password );
2077         $wpdb->update($wpdb->users, array('user_pass' => $hash, 'user_activation_key' => ''), array('ID' => $user_id) );
2078
2079         wp_cache_delete($user_id, 'users');
2080 }
2081 endif;
2082
2083 if ( !function_exists( 'get_avatar' ) ) :
2084 /**
2085  * Retrieve the avatar for a user who provided a user ID or email address.
2086  *
2087  * @since 2.5.0
2088  *
2089  * @param int|string|object $id_or_email A user ID,  email address, or comment object
2090  * @param int $size Size of the avatar image
2091  * @param string $default URL to a default image to use if no avatar is available
2092  * @param string $alt Alternative text to use in image tag. Defaults to blank
2093  * @return false|string `<img>` tag for the user's avatar.
2094 */
2095 function get_avatar( $id_or_email, $size = '96', $default = '', $alt = false ) {
2096         if ( ! get_option('show_avatars') )
2097                 return false;
2098
2099         if ( false === $alt)
2100                 $safe_alt = '';
2101         else
2102                 $safe_alt = esc_attr( $alt );
2103
2104         if ( !is_numeric($size) )
2105                 $size = '96';
2106
2107         $email = '';
2108         if ( is_numeric($id_or_email) ) {
2109                 $id = (int) $id_or_email;
2110                 $user = get_userdata($id);
2111                 if ( $user )
2112                         $email = $user->user_email;
2113         } elseif ( is_object($id_or_email) ) {
2114                 // No avatar for pingbacks or trackbacks
2115
2116                 /**
2117                  * Filter the list of allowed comment types for retrieving avatars.
2118                  *
2119                  * @since 3.0.0
2120                  *
2121                  * @param array $types An array of content types. Default only contains 'comment'.
2122                  */
2123                 $allowed_comment_types = apply_filters( 'get_avatar_comment_types', array( 'comment' ) );
2124                 if ( ! empty( $id_or_email->comment_type ) && ! in_array( $id_or_email->comment_type, (array) $allowed_comment_types ) )
2125                         return false;
2126
2127                 if ( ! empty( $id_or_email->user_id ) ) {
2128                         $id = (int) $id_or_email->user_id;
2129                         $user = get_userdata($id);
2130                         if ( $user )
2131                                 $email = $user->user_email;
2132                 }
2133
2134                 if ( ! $email && ! empty( $id_or_email->comment_author_email ) )
2135                         $email = $id_or_email->comment_author_email;
2136         } else {
2137                 $email = $id_or_email;
2138         }
2139
2140         if ( empty($default) ) {
2141                 $avatar_default = get_option('avatar_default');
2142                 if ( empty($avatar_default) )
2143                         $default = 'mystery';
2144                 else
2145                         $default = $avatar_default;
2146         }
2147
2148         if ( !empty($email) )
2149                 $email_hash = md5( strtolower( trim( $email ) ) );
2150
2151         if ( is_ssl() ) {
2152                 $host = 'https://secure.gravatar.com';
2153         } else {
2154                 if ( !empty($email) )
2155                         $host = sprintf( "http://%d.gravatar.com", ( hexdec( $email_hash[0] ) % 2 ) );
2156                 else
2157                         $host = 'http://0.gravatar.com';
2158         }
2159
2160         if ( 'mystery' == $default )
2161                 $default = "$host/avatar/ad516503a11cd5ca435acc9bb6523536?s={$size}"; // ad516503a11cd5ca435acc9bb6523536 == md5('unknown@gravatar.com')
2162         elseif ( 'blank' == $default )
2163                 $default = $email ? 'blank' : includes_url( 'images/blank.gif' );
2164         elseif ( !empty($email) && 'gravatar_default' == $default )
2165                 $default = '';
2166         elseif ( 'gravatar_default' == $default )
2167                 $default = "$host/avatar/?s={$size}";
2168         elseif ( empty($email) )
2169                 $default = "$host/avatar/?d=$default&amp;s={$size}";
2170         elseif ( strpos($default, 'http://') === 0 )
2171                 $default = add_query_arg( 's', $size, $default );
2172
2173         if ( !empty($email) ) {
2174                 $out = "$host/avatar/";
2175                 $out .= $email_hash;
2176                 $out .= '?s='.$size;
2177                 $out .= '&amp;d=' . urlencode( $default );
2178
2179                 $rating = get_option('avatar_rating');
2180                 if ( !empty( $rating ) )
2181                         $out .= "&amp;r={$rating}";
2182
2183                 $out = str_replace( '&#038;', '&amp;', esc_url( $out ) );
2184                 $avatar = "<img alt='{$safe_alt}' src='{$out}' class='avatar avatar-{$size} photo' height='{$size}' width='{$size}' />";
2185         } else {
2186                 $out = esc_url( $default );
2187                 $avatar = "<img alt='{$safe_alt}' src='{$out}' class='avatar avatar-{$size} photo avatar-default' height='{$size}' width='{$size}' />";
2188         }
2189
2190         /**
2191          * Filter the avatar to retrieve.
2192          *
2193          * @since 2.5.0
2194          *
2195          * @param string            $avatar      Image tag for the user's avatar.
2196          * @param int|object|string $id_or_email A user ID, email address, or comment object.
2197          * @param int               $size        Square avatar width and height in pixels to retrieve.
2198          * @param string            $alt         Alternative text to use in the avatar image tag.
2199          *                                       Default empty.
2200          */
2201         return apply_filters( 'get_avatar', $avatar, $id_or_email, $size, $default, $alt );
2202 }
2203 endif;
2204
2205 if ( !function_exists( 'wp_text_diff' ) ) :
2206 /**
2207  * Displays a human readable HTML representation of the difference between two strings.
2208  *
2209  * The Diff is available for getting the changes between versions. The output is
2210  * HTML, so the primary use is for displaying the changes. If the two strings
2211  * are equivalent, then an empty string will be returned.
2212  *
2213  * The arguments supported and can be changed are listed below.
2214  *
2215  * 'title' : Default is an empty string. Titles the diff in a manner compatible
2216  *              with the output.
2217  * 'title_left' : Default is an empty string. Change the HTML to the left of the
2218  *              title.
2219  * 'title_right' : Default is an empty string. Change the HTML to the right of
2220  *              the title.
2221  *
2222  * @since 2.6.0
2223  *
2224  * @see wp_parse_args() Used to change defaults to user defined settings.
2225  * @uses Text_Diff
2226  * @uses WP_Text_Diff_Renderer_Table
2227  *
2228  * @param string $left_string "old" (left) version of string
2229  * @param string $right_string "new" (right) version of string
2230  * @param string|array $args Optional. Change 'title', 'title_left', and 'title_right' defaults.
2231  * @return string Empty string if strings are equivalent or HTML with differences.
2232  */
2233 function wp_text_diff( $left_string, $right_string, $args = null ) {
2234         $defaults = array( 'title' => '', 'title_left' => '', 'title_right' => '' );
2235         $args = wp_parse_args( $args, $defaults );
2236
2237         if ( !class_exists( 'WP_Text_Diff_Renderer_Table' ) )
2238                 require( ABSPATH . WPINC . '/wp-diff.php' );
2239
2240         $left_string  = normalize_whitespace($left_string);
2241         $right_string = normalize_whitespace($right_string);
2242
2243         $left_lines  = explode("\n", $left_string);
2244         $right_lines = explode("\n", $right_string);
2245         $text_diff = new Text_Diff($left_lines, $right_lines);
2246         $renderer  = new WP_Text_Diff_Renderer_Table( $args );
2247         $diff = $renderer->render($text_diff);
2248
2249         if ( !$diff )
2250                 return '';
2251
2252         $r  = "<table class='diff'>\n";
2253
2254         if ( ! empty( $args[ 'show_split_view' ] ) ) {
2255                 $r .= "<col class='content diffsplit left' /><col class='content diffsplit middle' /><col class='content diffsplit right' />";
2256         } else {
2257                 $r .= "<col class='content' />";
2258         }
2259
2260         if ( $args['title'] || $args['title_left'] || $args['title_right'] )
2261                 $r .= "<thead>";
2262         if ( $args['title'] )
2263                 $r .= "<tr class='diff-title'><th colspan='4'>$args[title]</th></tr>\n";
2264         if ( $args['title_left'] || $args['title_right'] ) {
2265                 $r .= "<tr class='diff-sub-title'>\n";
2266                 $r .= "\t<td></td><th>$args[title_left]</th>\n";
2267                 $r .= "\t<td></td><th>$args[title_right]</th>\n";
2268                 $r .= "</tr>\n";
2269         }
2270         if ( $args['title'] || $args['title_left'] || $args['title_right'] )
2271                 $r .= "</thead>\n";
2272
2273         $r .= "<tbody>\n$diff\n</tbody>\n";
2274         $r .= "</table>";
2275
2276         return $r;
2277 }
2278 endif;
2279