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