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