46 'user_login' => '', |
46 'user_login' => '', |
47 'user_password' => '', |
47 'user_password' => '', |
48 'remember' => false, |
48 'remember' => false, |
49 ); |
49 ); |
50 |
50 |
51 if ( ! empty( $_POST['log'] ) ) { |
51 if ( ! empty( $_POST['log'] ) && is_string( $_POST['log'] ) ) { |
52 $credentials['user_login'] = wp_unslash( $_POST['log'] ); |
52 $credentials['user_login'] = wp_unslash( $_POST['log'] ); |
53 } |
53 } |
54 if ( ! empty( $_POST['pwd'] ) ) { |
54 if ( ! empty( $_POST['pwd'] ) && is_string( $_POST['pwd'] ) ) { |
55 $credentials['user_password'] = $_POST['pwd']; |
55 $credentials['user_password'] = $_POST['pwd']; |
56 } |
56 } |
57 if ( ! empty( $_POST['rememberme'] ) ) { |
57 if ( ! empty( $_POST['rememberme'] ) ) { |
58 $credentials['remember'] = $_POST['rememberme']; |
58 $credentials['remember'] = $_POST['rememberme']; |
59 } |
59 } |
148 * @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null. |
148 * @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null. |
149 * @param string $username Username for authentication. |
149 * @param string $username Username for authentication. |
150 * @param string $password Password for authentication. |
150 * @param string $password Password for authentication. |
151 * @return WP_User|WP_Error WP_User on success, WP_Error on failure. |
151 * @return WP_User|WP_Error WP_User on success, WP_Error on failure. |
152 */ |
152 */ |
153 function wp_authenticate_username_password( $user, $username, $password ) { |
153 function wp_authenticate_username_password( |
|
154 $user, |
|
155 $username, |
|
156 #[\SensitiveParameter] |
|
157 $password |
|
158 ) { |
154 if ( $user instanceof WP_User ) { |
159 if ( $user instanceof WP_User ) { |
155 return $user; |
160 return $user; |
156 } |
161 } |
157 |
162 |
158 if ( empty( $username ) || empty( $password ) ) { |
163 if ( empty( $username ) || empty( $password ) ) { |
198 $user = apply_filters( 'wp_authenticate_user', $user, $password ); |
203 $user = apply_filters( 'wp_authenticate_user', $user, $password ); |
199 if ( is_wp_error( $user ) ) { |
204 if ( is_wp_error( $user ) ) { |
200 return $user; |
205 return $user; |
201 } |
206 } |
202 |
207 |
203 if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) { |
208 $valid = wp_check_password( $password, $user->user_pass, $user->ID ); |
|
209 |
|
210 if ( ! $valid ) { |
204 return new WP_Error( |
211 return new WP_Error( |
205 'incorrect_password', |
212 'incorrect_password', |
206 sprintf( |
213 sprintf( |
207 /* translators: %s: User name. */ |
214 /* translators: %s: User name. */ |
208 __( '<strong>Error:</strong> The password you entered for the username %s is incorrect.' ), |
215 __( '<strong>Error:</strong> The password you entered for the username %s is incorrect.' ), |
226 * callback failed authentication. |
237 * callback failed authentication. |
227 * @param string $email Email address for authentication. |
238 * @param string $email Email address for authentication. |
228 * @param string $password Password for authentication. |
239 * @param string $password Password for authentication. |
229 * @return WP_User|WP_Error WP_User on success, WP_Error on failure. |
240 * @return WP_User|WP_Error WP_User on success, WP_Error on failure. |
230 */ |
241 */ |
231 function wp_authenticate_email_password( $user, $email, $password ) { |
242 function wp_authenticate_email_password( |
|
243 $user, |
|
244 $email, |
|
245 #[\SensitiveParameter] |
|
246 $password |
|
247 ) { |
232 if ( $user instanceof WP_User ) { |
248 if ( $user instanceof WP_User ) { |
233 return $user; |
249 return $user; |
234 } |
250 } |
235 |
251 |
236 if ( empty( $email ) || empty( $password ) ) { |
252 if ( empty( $email ) || empty( $password ) ) { |
270 |
286 |
271 if ( is_wp_error( $user ) ) { |
287 if ( is_wp_error( $user ) ) { |
272 return $user; |
288 return $user; |
273 } |
289 } |
274 |
290 |
275 if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) { |
291 $valid = wp_check_password( $password, $user->user_pass, $user->ID ); |
|
292 |
|
293 if ( ! $valid ) { |
276 return new WP_Error( |
294 return new WP_Error( |
277 'incorrect_password', |
295 'incorrect_password', |
278 sprintf( |
296 sprintf( |
279 /* translators: %s: Email address. */ |
297 /* translators: %s: Email address. */ |
280 __( '<strong>Error:</strong> The password you entered for the email address %s is incorrect.' ), |
298 __( '<strong>Error:</strong> The password you entered for the email address %s is incorrect.' ), |
299 * @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null. |
321 * @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null. |
300 * @param string $username Username. If not empty, cancels the cookie authentication. |
322 * @param string $username Username. If not empty, cancels the cookie authentication. |
301 * @param string $password Password. If not empty, cancels the cookie authentication. |
323 * @param string $password Password. If not empty, cancels the cookie authentication. |
302 * @return WP_User|WP_Error WP_User on success, WP_Error on failure. |
324 * @return WP_User|WP_Error WP_User on success, WP_Error on failure. |
303 */ |
325 */ |
304 function wp_authenticate_cookie( $user, $username, $password ) { |
326 function wp_authenticate_cookie( |
|
327 $user, |
|
328 $username, |
|
329 #[\SensitiveParameter] |
|
330 $password |
|
331 ) { |
305 global $auth_secure_cookie; |
332 global $auth_secure_cookie; |
306 |
333 |
307 if ( $user instanceof WP_User ) { |
334 if ( $user instanceof WP_User ) { |
308 return $user; |
335 return $user; |
309 } |
336 } |
340 * @param string $username Username for authentication. |
367 * @param string $username Username for authentication. |
341 * @param string $password Password for authentication. |
368 * @param string $password Password for authentication. |
342 * @return WP_User|WP_Error|null WP_User on success, WP_Error on failure, null if |
369 * @return WP_User|WP_Error|null WP_User on success, WP_Error on failure, null if |
343 * null is passed in and this isn't an API request. |
370 * null is passed in and this isn't an API request. |
344 */ |
371 */ |
345 function wp_authenticate_application_password( $input_user, $username, $password ) { |
372 function wp_authenticate_application_password( |
|
373 $input_user, |
|
374 $username, |
|
375 #[\SensitiveParameter] |
|
376 $password |
|
377 ) { |
346 if ( $input_user instanceof WP_User ) { |
378 if ( $input_user instanceof WP_User ) { |
347 return $input_user; |
379 return $input_user; |
348 } |
380 } |
349 |
381 |
350 if ( ! WP_Application_Passwords::is_in_use() ) { |
382 if ( ! WP_Application_Passwords::is_in_use() ) { |
423 $password = preg_replace( '/[^a-z\d]/i', '', $password ); |
455 $password = preg_replace( '/[^a-z\d]/i', '', $password ); |
424 |
456 |
425 $hashed_passwords = WP_Application_Passwords::get_user_application_passwords( $user->ID ); |
457 $hashed_passwords = WP_Application_Passwords::get_user_application_passwords( $user->ID ); |
426 |
458 |
427 foreach ( $hashed_passwords as $key => $item ) { |
459 foreach ( $hashed_passwords as $key => $item ) { |
428 if ( ! wp_check_password( $password, $item['password'], $user->ID ) ) { |
460 if ( ! WP_Application_Passwords::check_password( $password, $item['password'] ) ) { |
429 continue; |
461 continue; |
430 } |
462 } |
431 |
463 |
432 $error = new WP_Error(); |
464 $error = new WP_Error(); |
433 |
465 |
582 * @return string Number of posts the user has written in this post type. |
614 * @return string Number of posts the user has written in this post type. |
583 */ |
615 */ |
584 function count_user_posts( $userid, $post_type = 'post', $public_only = false ) { |
616 function count_user_posts( $userid, $post_type = 'post', $public_only = false ) { |
585 global $wpdb; |
617 global $wpdb; |
586 |
618 |
|
619 $post_type = array_unique( (array) $post_type ); |
|
620 sort( $post_type ); |
|
621 |
587 $where = get_posts_by_author_sql( $post_type, true, $userid, $public_only ); |
622 $where = get_posts_by_author_sql( $post_type, true, $userid, $public_only ); |
588 |
623 $query = "SELECT COUNT(*) FROM $wpdb->posts $where"; |
589 $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" ); |
624 |
|
625 $last_changed = wp_cache_get_last_changed( 'posts' ); |
|
626 $cache_key = 'count_user_posts:' . md5( $query ) . ':' . $last_changed; |
|
627 $count = wp_cache_get( $cache_key, 'post-queries' ); |
|
628 if ( false === $count ) { |
|
629 $count = $wpdb->get_var( $query ); |
|
630 wp_cache_set( $cache_key, $count, 'post-queries' ); |
|
631 } |
590 |
632 |
591 /** |
633 /** |
592 * Filters the number of posts a user has written. |
634 * Filters the number of posts a user has written. |
593 * |
635 * |
594 * @since 2.7.0 |
636 * @since 2.7.0 |
616 * @return string[] Amount of posts each user has written, as strings, keyed by user ID. |
658 * @return string[] Amount of posts each user has written, as strings, keyed by user ID. |
617 */ |
659 */ |
618 function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) { |
660 function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) { |
619 global $wpdb; |
661 global $wpdb; |
620 |
662 |
621 $count = array(); |
|
622 if ( empty( $users ) || ! is_array( $users ) ) { |
663 if ( empty( $users ) || ! is_array( $users ) ) { |
623 return $count; |
664 return array(); |
|
665 } |
|
666 |
|
667 /** |
|
668 * Filters whether to short-circuit performing the post counts. |
|
669 * |
|
670 * When filtering, return an array of posts counts as strings, keyed |
|
671 * by the user ID. |
|
672 * |
|
673 * @since 6.8.0 |
|
674 * |
|
675 * @param string[]|null $count The post counts. Return a non-null value to short-circuit. |
|
676 * @param int[] $users Array of user IDs. |
|
677 * @param string|string[] $post_type Single post type or array of post types to check. |
|
678 * @param bool $public_only Whether to only return counts for public posts. |
|
679 */ |
|
680 $pre = apply_filters( 'pre_count_many_users_posts', null, $users, $post_type, $public_only ); |
|
681 if ( null !== $pre ) { |
|
682 return $pre; |
624 } |
683 } |
625 |
684 |
626 $userlist = implode( ',', array_map( 'absint', $users ) ); |
685 $userlist = implode( ',', array_map( 'absint', $users ) ); |
627 $where = get_posts_by_author_sql( $post_type, true, null, $public_only ); |
686 $where = get_posts_by_author_sql( $post_type, true, null, $public_only ); |
628 |
687 |
629 $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N ); |
688 $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N ); |
|
689 |
|
690 $count = array_fill_keys( $users, 0 ); |
630 foreach ( $result as $row ) { |
691 foreach ( $result as $row ) { |
631 $count[ $row[0] ] = $row[1]; |
692 $count[ $row[0] ] = $row[1]; |
632 } |
|
633 |
|
634 foreach ( $users as $id ) { |
|
635 if ( ! isset( $count[ $id ] ) ) { |
|
636 $count[ $id ] = 0; |
|
637 } |
|
638 } |
693 } |
639 |
694 |
640 return $count; |
695 return $count; |
641 } |
696 } |
642 |
697 |
771 if ( ! $is_global ) { |
826 if ( ! $is_global ) { |
772 $option_name = $wpdb->get_blog_prefix() . $option_name; |
827 $option_name = $wpdb->get_blog_prefix() . $option_name; |
773 } |
828 } |
774 |
829 |
775 return delete_user_meta( $user_id, $option_name ); |
830 return delete_user_meta( $user_id, $option_name ); |
|
831 } |
|
832 |
|
833 /** |
|
834 * Retrieves user info by user ID. |
|
835 * |
|
836 * @since 6.7.0 |
|
837 * |
|
838 * @param int $user_id User ID. |
|
839 * |
|
840 * @return WP_User|false WP_User object on success, false on failure. |
|
841 */ |
|
842 function get_user( $user_id ) { |
|
843 return get_user_by( 'id', $user_id ); |
776 } |
844 } |
777 |
845 |
778 /** |
846 /** |
779 * Retrieves list of users matching criteria. |
847 * Retrieves list of users matching criteria. |
780 * |
848 * |
1136 * |
1204 * |
1137 * @since 3.0.0 |
1205 * @since 3.0.0 |
1138 * |
1206 * |
1139 * @param int $user_id User ID. |
1207 * @param int $user_id User ID. |
1140 * @param string $meta_key Metadata name. |
1208 * @param string $meta_key Metadata name. |
1141 * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. |
1209 * @param mixed $meta_value Metadata value. Arrays and objects are stored as serialized data and |
|
1210 * will be returned as the same type when retrieved. Other data types will |
|
1211 * be stored as strings in the database: |
|
1212 * - false is stored and retrieved as an empty string ('') |
|
1213 * - true is stored and retrieved as '1' |
|
1214 * - numbers (both integer and float) are stored and retrieved as strings |
|
1215 * Must be serializable if non-scalar. |
1142 * @param bool $unique Optional. Whether the same key should not be added. |
1216 * @param bool $unique Optional. Whether the same key should not be added. |
1143 * Default false. |
1217 * Default false. |
1144 * @return int|false Meta ID on success, false on failure. |
1218 * @return int|false Meta ID on success, false on failure. |
1145 */ |
1219 */ |
1146 function add_user_meta( $user_id, $meta_key, $meta_value, $unique = false ) { |
1220 function add_user_meta( $user_id, $meta_key, $meta_value, $unique = false ) { |
1183 * This parameter has no effect if `$key` is not specified. |
1257 * This parameter has no effect if `$key` is not specified. |
1184 * Default false. |
1258 * Default false. |
1185 * @return mixed An array of values if `$single` is false. |
1259 * @return mixed An array of values if `$single` is false. |
1186 * The value of meta data field if `$single` is true. |
1260 * The value of meta data field if `$single` is true. |
1187 * False for an invalid `$user_id` (non-numeric, zero, or negative value). |
1261 * False for an invalid `$user_id` (non-numeric, zero, or negative value). |
1188 * An empty string if a valid but non-existing user ID is passed. |
1262 * An empty array if a valid but non-existing user ID is passed and `$single` is false. |
|
1263 * An empty string if a valid but non-existing user ID is passed and `$single` is true. |
|
1264 * Note: Non-serialized values are returned as strings: |
|
1265 * - false values are returned as empty strings ('') |
|
1266 * - true values are returned as '1' |
|
1267 * - numbers (both integer and float) are returned as strings |
|
1268 * Arrays and objects retain their original type. |
1189 */ |
1269 */ |
1190 function get_user_meta( $user_id, $key = '', $single = false ) { |
1270 function get_user_meta( $user_id, $key = '', $single = false ) { |
1191 return get_metadata( 'user', $user_id, $key, $single ); |
1271 return get_metadata( 'user', $user_id, $key, $single ); |
1192 } |
1272 } |
1193 |
1273 |
1547 } |
1627 } |
1548 |
1628 |
1549 /** |
1629 /** |
1550 * Creates dropdown HTML content of users. |
1630 * Creates dropdown HTML content of users. |
1551 * |
1631 * |
1552 * The content can either be displayed, which it is by default or retrieved by |
1632 * The content can either be displayed, which it is by default, or retrieved by |
1553 * setting the 'echo' argument. The 'include' and 'exclude' arguments do not |
1633 * setting the 'echo' argument to false. The 'include' and 'exclude' arguments |
1554 * need to be used; all users will be displayed in that case. Only one can be |
1634 * are optional; if they are not specified, all users will be displayed. Only one |
1555 * used, either 'include' or 'exclude', but not both. |
1635 * can be used in a single call, either 'include' or 'exclude', but not both. |
1556 * |
|
1557 * The available arguments are as follows: |
|
1558 * |
1636 * |
1559 * @since 2.3.0 |
1637 * @since 2.3.0 |
1560 * @since 4.5.0 Added the 'display_name_with_login' value for 'show'. |
1638 * @since 4.5.0 Added the 'display_name_with_login' value for 'show'. |
1561 * @since 4.7.0 Added the 'role', 'role__in', and 'role__not_in' parameters. |
1639 * @since 4.7.0 Added the 'role', 'role__in', and 'role__not_in' parameters. |
1562 * @since 5.9.0 Added the 'capability', 'capability__in', and 'capability__not_in' parameters. |
1640 * @since 5.9.0 Added the 'capability', 'capability__in', and 'capability__not_in' parameters. |
2352 $meta['comment_shortcuts'] = empty( $userdata['comment_shortcuts'] ) || 'false' === $userdata['comment_shortcuts'] ? 'false' : 'true'; |
2430 $meta['comment_shortcuts'] = empty( $userdata['comment_shortcuts'] ) || 'false' === $userdata['comment_shortcuts'] ? 'false' : 'true'; |
2353 |
2431 |
2354 $admin_color = empty( $userdata['admin_color'] ) ? 'fresh' : $userdata['admin_color']; |
2432 $admin_color = empty( $userdata['admin_color'] ) ? 'fresh' : $userdata['admin_color']; |
2355 $meta['admin_color'] = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $admin_color ); |
2433 $meta['admin_color'] = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $admin_color ); |
2356 |
2434 |
2357 $meta['use_ssl'] = empty( $userdata['use_ssl'] ) ? 0 : (bool) $userdata['use_ssl']; |
2435 $meta['use_ssl'] = empty( $userdata['use_ssl'] ) ? '0' : '1'; |
2358 |
2436 |
2359 $meta['show_admin_bar_front'] = empty( $userdata['show_admin_bar_front'] ) ? 'true' : $userdata['show_admin_bar_front']; |
2437 $meta['show_admin_bar_front'] = empty( $userdata['show_admin_bar_front'] ) ? 'true' : $userdata['show_admin_bar_front']; |
2360 |
2438 |
2361 $meta['locale'] = isset( $userdata['locale'] ) ? $userdata['locale'] : ''; |
2439 $meta['locale'] = isset( $userdata['locale'] ) ? $userdata['locale'] : ''; |
2362 |
2440 |
2376 * |
2454 * |
2377 * It only includes data in the users table, not any user metadata. |
2455 * It only includes data in the users table, not any user metadata. |
2378 * |
2456 * |
2379 * @since 4.9.0 |
2457 * @since 4.9.0 |
2380 * @since 5.8.0 The `$userdata` parameter was added. |
2458 * @since 5.8.0 The `$userdata` parameter was added. |
|
2459 * @since 6.8.0 The user's password is now hashed using bcrypt by default instead of phpass. |
2381 * |
2460 * |
2382 * @param array $data { |
2461 * @param array $data { |
2383 * Values and keys for the user. |
2462 * Values and keys for the user. |
2384 * |
2463 * |
2385 * @type string $user_login The user's login. Only included if $update == false |
2464 * @type string $user_login The user's login. Only included if $update == false |
2386 * @type string $user_pass The user's password. |
2465 * @type string $user_pass The user's password. |
2387 * @type string $user_email The user's email. |
2466 * @type string $user_email The user's email. |
2388 * @type string $user_url The user's url. |
2467 * @type string $user_url The user's url. |
2389 * @type string $user_nicename The user's nice name. Defaults to a URL-safe version of user's login |
2468 * @type string $user_nicename The user's nice name. Defaults to a URL-safe version of user's login. |
2390 * @type string $display_name The user's display name. |
2469 * @type string $display_name The user's display name. |
2391 * @type string $user_registered MySQL timestamp describing the moment when the user registered. Defaults to |
2470 * @type string $user_registered MySQL timestamp describing the moment when the user registered. Defaults to |
2392 * the current UTC timestamp. |
2471 * the current UTC timestamp. |
2393 * } |
2472 * } |
2394 * @param bool $update Whether the user is being updated rather than created. |
2473 * @param bool $update Whether the user is being updated rather than created. |
2766 |
2845 |
2767 // Update the cookies if the password changed. |
2846 // Update the cookies if the password changed. |
2768 $current_user = wp_get_current_user(); |
2847 $current_user = wp_get_current_user(); |
2769 if ( $current_user->ID === $user_id ) { |
2848 if ( $current_user->ID === $user_id ) { |
2770 if ( isset( $plaintext_pass ) ) { |
2849 if ( isset( $plaintext_pass ) ) { |
2771 wp_clear_auth_cookie(); |
|
2772 |
|
2773 /* |
2850 /* |
2774 * Here we calculate the expiration length of the current auth cookie and compare it to the default expiration. |
2851 * Here we calculate the expiration length of the current auth cookie and compare it to the default expiration. |
2775 * If it's greater than this, then we know the user checked 'Remember Me' when they logged in. |
2852 * If it's greater than this, then we know the user checked 'Remember Me' when they logged in. |
2776 */ |
2853 */ |
2777 $logged_in_cookie = wp_parse_auth_cookie( '', 'logged_in' ); |
2854 $logged_in_cookie = wp_parse_auth_cookie( '', 'logged_in' ); |
2778 /** This filter is documented in wp-includes/pluggable.php */ |
2855 /** This filter is documented in wp-includes/pluggable.php */ |
2779 $default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $user_id, false ); |
2856 $default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $user_id, false ); |
2780 |
2857 |
|
2858 wp_clear_auth_cookie(); |
|
2859 |
2781 $remember = false; |
2860 $remember = false; |
2782 |
2861 $token = ''; |
2783 if ( false !== $logged_in_cookie && ( $logged_in_cookie['expiration'] - time() ) > $default_cookie_life ) { |
2862 |
|
2863 if ( false !== $logged_in_cookie ) { |
|
2864 $token = $logged_in_cookie['token']; |
|
2865 } |
|
2866 |
|
2867 if ( false !== $logged_in_cookie && ( (int) $logged_in_cookie['expiration'] - time() ) > $default_cookie_life ) { |
2784 $remember = true; |
2868 $remember = true; |
2785 } |
2869 } |
2786 |
2870 |
2787 wp_set_auth_cookie( $user_id, $remember ); |
2871 wp_set_auth_cookie( $user_id, $remember, '', $token ); |
2788 } |
2872 } |
2789 } |
2873 } |
2790 |
2874 |
2791 /** |
2875 /** |
2792 * Fires after the user has been updated and emails have been sent. |
2876 * Fires after the user has been updated and emails have been sent. |
2816 * @param string $password The user's password. |
2900 * @param string $password The user's password. |
2817 * @param string $email Optional. The user's email. Default empty. |
2901 * @param string $email Optional. The user's email. Default empty. |
2818 * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not |
2902 * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not |
2819 * be created. |
2903 * be created. |
2820 */ |
2904 */ |
2821 function wp_create_user( $username, $password, $email = '' ) { |
2905 function wp_create_user( |
|
2906 $username, |
|
2907 #[\SensitiveParameter] |
|
2908 $password, |
|
2909 $email = '' |
|
2910 ) { |
2822 $user_login = wp_slash( $username ); |
2911 $user_login = wp_slash( $username ); |
2823 $user_email = wp_slash( $email ); |
2912 $user_email = wp_slash( $email ); |
2824 $user_pass = $password; |
2913 $user_pass = $password; |
2825 |
2914 |
2826 $userdata = compact( 'user_login', 'user_email', 'user_pass' ); |
2915 $userdata = compact( 'user_login', 'user_email', 'user_pass' ); |
2913 /** |
3002 /** |
2914 * Creates, stores, then returns a password reset key for user. |
3003 * Creates, stores, then returns a password reset key for user. |
2915 * |
3004 * |
2916 * @since 4.4.0 |
3005 * @since 4.4.0 |
2917 * |
3006 * |
2918 * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance. |
|
2919 * |
|
2920 * @param WP_User $user User to retrieve password reset key for. |
3007 * @param WP_User $user User to retrieve password reset key for. |
2921 * @return string|WP_Error Password reset key on success. WP_Error on error. |
3008 * @return string|WP_Error Password reset key on success. WP_Error on error. |
2922 */ |
3009 */ |
2923 function get_password_reset_key( $user ) { |
3010 function get_password_reset_key( $user ) { |
2924 global $wp_hasher; |
|
2925 |
|
2926 if ( ! ( $user instanceof WP_User ) ) { |
3011 if ( ! ( $user instanceof WP_User ) ) { |
2927 return new WP_Error( 'invalidcombo', __( '<strong>Error:</strong> There is no account with that username or email address.' ) ); |
3012 return new WP_Error( 'invalidcombo', __( '<strong>Error:</strong> There is no account with that username or email address.' ) ); |
2928 } |
3013 } |
2929 |
3014 |
2930 /** |
3015 /** |
2966 * @param string $user_login The username for the user. |
3051 * @param string $user_login The username for the user. |
2967 * @param string $key The generated password reset key. |
3052 * @param string $key The generated password reset key. |
2968 */ |
3053 */ |
2969 do_action( 'retrieve_password_key', $user->user_login, $key ); |
3054 do_action( 'retrieve_password_key', $user->user_login, $key ); |
2970 |
3055 |
2971 // Now insert the key, hashed, into the DB. |
3056 $hashed = time() . ':' . wp_fast_hash( $key ); |
2972 if ( empty( $wp_hasher ) ) { |
|
2973 require_once ABSPATH . WPINC . '/class-phpass.php'; |
|
2974 $wp_hasher = new PasswordHash( 8, true ); |
|
2975 } |
|
2976 |
|
2977 $hashed = time() . ':' . $wp_hasher->HashPassword( $key ); |
|
2978 |
3057 |
2979 $key_saved = wp_update_user( |
3058 $key_saved = wp_update_user( |
2980 array( |
3059 array( |
2981 'ID' => $user->ID, |
3060 'ID' => $user->ID, |
2982 'user_activation_key' => $hashed, |
3061 'user_activation_key' => $hashed, |
2998 * hashing process. This field is now hashed; old values are no longer accepted |
3077 * hashing process. This field is now hashed; old values are no longer accepted |
2999 * but have a different WP_Error code so good user feedback can be provided. |
3078 * but have a different WP_Error code so good user feedback can be provided. |
3000 * |
3079 * |
3001 * @since 3.1.0 |
3080 * @since 3.1.0 |
3002 * |
3081 * |
3003 * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance. |
3082 * @param string $key The password reset key. |
3004 * |
|
3005 * @param string $key Hash to validate sending user's password. |
|
3006 * @param string $login The user login. |
3083 * @param string $login The user login. |
3007 * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys. |
3084 * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys. |
3008 */ |
3085 */ |
3009 function check_password_reset_key( $key, $login ) { |
3086 function check_password_reset_key( |
3010 global $wp_hasher; |
3087 #[\SensitiveParameter] |
3011 |
3088 $key, |
|
3089 $login |
|
3090 ) { |
3012 $key = preg_replace( '/[^a-z0-9]/i', '', $key ); |
3091 $key = preg_replace( '/[^a-z0-9]/i', '', $key ); |
3013 |
3092 |
3014 if ( empty( $key ) || ! is_string( $key ) ) { |
3093 if ( empty( $key ) || ! is_string( $key ) ) { |
3015 return new WP_Error( 'invalid_key', __( 'Invalid key.' ) ); |
3094 return new WP_Error( 'invalid_key', __( 'Invalid key.' ) ); |
3016 } |
3095 } |
3021 |
3100 |
3022 $user = get_user_by( 'login', $login ); |
3101 $user = get_user_by( 'login', $login ); |
3023 |
3102 |
3024 if ( ! $user ) { |
3103 if ( ! $user ) { |
3025 return new WP_Error( 'invalid_key', __( 'Invalid key.' ) ); |
3104 return new WP_Error( 'invalid_key', __( 'Invalid key.' ) ); |
3026 } |
|
3027 |
|
3028 if ( empty( $wp_hasher ) ) { |
|
3029 require_once ABSPATH . WPINC . '/class-phpass.php'; |
|
3030 $wp_hasher = new PasswordHash( 8, true ); |
|
3031 } |
3105 } |
3032 |
3106 |
3033 /** |
3107 /** |
3034 * Filters the expiration time of password reset keys. |
3108 * Filters the expiration time of password reset keys. |
3035 * |
3109 * |
3049 |
3123 |
3050 if ( ! $pass_key ) { |
3124 if ( ! $pass_key ) { |
3051 return new WP_Error( 'invalid_key', __( 'Invalid key.' ) ); |
3125 return new WP_Error( 'invalid_key', __( 'Invalid key.' ) ); |
3052 } |
3126 } |
3053 |
3127 |
3054 $hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key ); |
3128 $hash_is_correct = wp_verify_fast_hash( $key, $pass_key ); |
3055 |
3129 |
3056 if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) { |
3130 if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) { |
3057 return $user; |
3131 return $user; |
3058 } elseif ( $hash_is_correct && $expiration_time ) { |
3132 } elseif ( $hash_is_correct && $expiration_time ) { |
3059 // Key has an expiration time that's passed. |
3133 // Key has an expiration time that's passed. |
3064 $return = new WP_Error( 'expired_key', __( 'Invalid key.' ) ); |
3138 $return = new WP_Error( 'expired_key', __( 'Invalid key.' ) ); |
3065 $user_id = $user->ID; |
3139 $user_id = $user->ID; |
3066 |
3140 |
3067 /** |
3141 /** |
3068 * Filters the return value of check_password_reset_key() when an |
3142 * Filters the return value of check_password_reset_key() when an |
3069 * old-style key is used. |
3143 * old-style key or an expired key is used. |
3070 * |
3144 * |
3071 * @since 3.7.0 Previously plain-text keys were stored in the database. |
3145 * @since 3.7.0 Previously plain-text keys were stored in the database. |
3072 * @since 4.3.0 Previously key hashes were stored without an expiration time. |
3146 * @since 4.3.0 Previously key hashes were stored without an expiration time. |
3073 * |
3147 * |
3074 * @param WP_Error $return A WP_Error object denoting an expired key. |
3148 * @param WP_Error $return A WP_Error object denoting an expired key. |
3085 * Handles sending a password retrieval email to a user. |
3159 * Handles sending a password retrieval email to a user. |
3086 * |
3160 * |
3087 * @since 2.5.0 |
3161 * @since 2.5.0 |
3088 * @since 5.7.0 Added `$user_login` parameter. |
3162 * @since 5.7.0 Added `$user_login` parameter. |
3089 * |
3163 * |
3090 * @global wpdb $wpdb WordPress database abstraction object. |
3164 * @global wpdb $wpdb WordPress database abstraction object. |
3091 * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance. |
|
3092 * |
3165 * |
3093 * @param string $user_login Optional. Username to send a password retrieval email for. |
3166 * @param string $user_login Optional. Username to send a password retrieval email for. |
3094 * Defaults to `$_POST['user_login']` if not set. |
3167 * Defaults to `$_POST['user_login']` if not set. |
3095 * @return true|WP_Error True when finished, WP_Error object on error. |
3168 * @return true|WP_Error True when finished, WP_Error object on error. |
3096 */ |
3169 */ |
3097 function retrieve_password( $user_login = null ) { |
3170 function retrieve_password( $user_login = '' ) { |
3098 $errors = new WP_Error(); |
3171 $errors = new WP_Error(); |
3099 $user_data = false; |
3172 $user_data = false; |
3100 |
3173 |
3101 // Use the passed $user_login if available, otherwise use $_POST['user_login']. |
3174 // Use the passed $user_login if available, otherwise use $_POST['user_login']. |
3102 if ( ! $user_login && ! empty( $_POST['user_login'] ) ) { |
3175 if ( ! $user_login && ! empty( $_POST['user_login'] ) ) { |
3217 $message .= sprintf( __( 'Site Name: %s' ), $site_name ) . "\r\n\r\n"; |
3290 $message .= sprintf( __( 'Site Name: %s' ), $site_name ) . "\r\n\r\n"; |
3218 /* translators: %s: User login. */ |
3291 /* translators: %s: User login. */ |
3219 $message .= sprintf( __( 'Username: %s' ), $user_login ) . "\r\n\r\n"; |
3292 $message .= sprintf( __( 'Username: %s' ), $user_login ) . "\r\n\r\n"; |
3220 $message .= __( 'If this was a mistake, ignore this email and nothing will happen.' ) . "\r\n\r\n"; |
3293 $message .= __( 'If this was a mistake, ignore this email and nothing will happen.' ) . "\r\n\r\n"; |
3221 $message .= __( 'To reset your password, visit the following address:' ) . "\r\n\r\n"; |
3294 $message .= __( 'To reset your password, visit the following address:' ) . "\r\n\r\n"; |
3222 $message .= network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' ) . '&wp_lang=' . $locale . "\r\n\r\n"; |
3295 |
|
3296 /* |
|
3297 * Since some user login names end in a period, this could produce ambiguous URLs that |
|
3298 * end in a period. To avoid the ambiguity, ensure that the login is not the last query |
|
3299 * arg in the URL. If moving it to the end, a trailing period will need to be escaped. |
|
3300 * |
|
3301 * @see https://core.trac.wordpress.org/tickets/42957 |
|
3302 */ |
|
3303 $message .= network_site_url( 'wp-login.php?login=' . rawurlencode( $user_login ) . "&key=$key&action=rp", 'login' ) . '&wp_lang=' . $locale . "\r\n\r\n"; |
3223 |
3304 |
3224 if ( ! is_user_logged_in() ) { |
3305 if ( ! is_user_logged_in() ) { |
3225 $requester_ip = $_SERVER['REMOTE_ADDR']; |
3306 $requester_ip = $_SERVER['REMOTE_ADDR']; |
3226 if ( $requester_ip ) { |
3307 if ( $requester_ip ) { |
3227 $message .= sprintf( |
3308 $message .= sprintf( |
4146 * @param string $sitename The name of the site. |
4231 * @param string $sitename The name of the site. |
4147 * @param array $email_data { |
4232 * @param array $email_data { |
4148 * Data relating to the account action email. |
4233 * Data relating to the account action email. |
4149 * |
4234 * |
4150 * @type WP_User_Request $request User request object. |
4235 * @type WP_User_Request $request User request object. |
4151 * @type string $user_email The email address confirming a request |
4236 * @type string $user_email The email address confirming a request. |
4152 * @type string $description Description of the action being performed so the user knows what the email is for. |
4237 * @type string $description Description of the action being performed so the user knows what the email is for. |
4153 * @type string $manage_url The link to click manage privacy requests of this type. |
4238 * @type string $manage_url The link to click manage privacy requests of this type. |
4154 * @type string $sitename The site name sending the mail. |
4239 * @type string $sitename The site name sending the mail. |
4155 * @type string $siteurl The site URL sending the mail. |
4240 * @type string $siteurl The site URL sending the mail. |
4156 * @type string $admin_email The administrator email receiving the mail. |
4241 * @type string $admin_email The administrator email receiving the mail. |
4197 * @param string $content The email content. |
4282 * @param string $content The email content. |
4198 * @param array $email_data { |
4283 * @param array $email_data { |
4199 * Data relating to the account action email. |
4284 * Data relating to the account action email. |
4200 * |
4285 * |
4201 * @type WP_User_Request $request User request object. |
4286 * @type WP_User_Request $request User request object. |
4202 * @type string $user_email The email address confirming a request |
4287 * @type string $user_email The email address confirming a request. |
4203 * @type string $description Description of the action being performed |
4288 * @type string $description Description of the action being performed |
4204 * so the user knows what the email is for. |
4289 * so the user knows what the email is for. |
4205 * @type string $manage_url The link to click manage privacy requests of this type. |
4290 * @type string $manage_url The link to click manage privacy requests of this type. |
4206 * @type string $sitename The site name sending the mail. |
4291 * @type string $sitename The site name sending the mail. |
4207 * @type string $siteurl The site URL sending the mail. |
4292 * @type string $siteurl The site URL sending the mail. |
4237 * @param string $content The email content. |
4322 * @param string $content The email content. |
4238 * @param array $email_data { |
4323 * @param array $email_data { |
4239 * Data relating to the account action email. |
4324 * Data relating to the account action email. |
4240 * |
4325 * |
4241 * @type WP_User_Request $request User request object. |
4326 * @type WP_User_Request $request User request object. |
4242 * @type string $user_email The email address confirming a request |
4327 * @type string $user_email The email address confirming a request. |
4243 * @type string $description Description of the action being performed so the user knows what the email is for. |
4328 * @type string $description Description of the action being performed so the user knows what the email is for. |
4244 * @type string $manage_url The link to click manage privacy requests of this type. |
4329 * @type string $manage_url The link to click manage privacy requests of this type. |
4245 * @type string $sitename The site name sending the mail. |
4330 * @type string $sitename The site name sending the mail. |
4246 * @type string $siteurl The site URL sending the mail. |
4331 * @type string $siteurl The site URL sending the mail. |
4247 * @type string $admin_email The administrator email receiving the mail. |
4332 * @type string $admin_email The administrator email receiving the mail. |
4268 * @param int $request_id The request ID. |
4353 * @param int $request_id The request ID. |
4269 * @param array $email_data { |
4354 * @param array $email_data { |
4270 * Data relating to the account action email. |
4355 * Data relating to the account action email. |
4271 * |
4356 * |
4272 * @type WP_User_Request $request User request object. |
4357 * @type WP_User_Request $request User request object. |
4273 * @type string $user_email The email address confirming a request |
4358 * @type string $user_email The email address confirming a request. |
4274 * @type string $description Description of the action being performed so the user knows what the email is for. |
4359 * @type string $description Description of the action being performed so the user knows what the email is for. |
4275 * @type string $manage_url The link to click manage privacy requests of this type. |
4360 * @type string $manage_url The link to click manage privacy requests of this type. |
4276 * @type string $sitename The site name sending the mail. |
4361 * @type string $sitename The site name sending the mail. |
4277 * @type string $siteurl The site URL sending the mail. |
4362 * @type string $siteurl The site URL sending the mail. |
4278 * @type string $admin_email The administrator email receiving the mail. |
4363 * @type string $admin_email The administrator email receiving the mail. |
4855 /** |
4940 /** |
4856 * Returns a confirmation key for a user action and stores the hashed version for future comparison. |
4941 * Returns a confirmation key for a user action and stores the hashed version for future comparison. |
4857 * |
4942 * |
4858 * @since 4.9.6 |
4943 * @since 4.9.6 |
4859 * |
4944 * |
4860 * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance. |
|
4861 * |
|
4862 * @param int $request_id Request ID. |
4945 * @param int $request_id Request ID. |
4863 * @return string Confirmation key. |
4946 * @return string Confirmation key. |
4864 */ |
4947 */ |
4865 function wp_generate_user_request_key( $request_id ) { |
4948 function wp_generate_user_request_key( $request_id ) { |
4866 global $wp_hasher; |
|
4867 |
|
4868 // Generate something random for a confirmation key. |
4949 // Generate something random for a confirmation key. |
4869 $key = wp_generate_password( 20, false ); |
4950 $key = wp_generate_password( 20, false ); |
4870 |
4951 |
4871 // Return the key, hashed. |
4952 // Save the key, hashed. |
4872 if ( empty( $wp_hasher ) ) { |
|
4873 require_once ABSPATH . WPINC . '/class-phpass.php'; |
|
4874 $wp_hasher = new PasswordHash( 8, true ); |
|
4875 } |
|
4876 |
|
4877 wp_update_post( |
4953 wp_update_post( |
4878 array( |
4954 array( |
4879 'ID' => $request_id, |
4955 'ID' => $request_id, |
4880 'post_status' => 'request-pending', |
4956 'post_status' => 'request-pending', |
4881 'post_password' => $wp_hasher->HashPassword( $key ), |
4957 'post_password' => wp_fast_hash( $key ), |
4882 ) |
4958 ) |
4883 ); |
4959 ); |
4884 |
4960 |
4885 return $key; |
4961 return $key; |
4886 } |
4962 } |
4887 |
4963 |
4888 /** |
4964 /** |
4889 * Validates a user request by comparing the key with the request's key. |
4965 * Validates a user request by comparing the key with the request's key. |
4890 * |
4966 * |
4891 * @since 4.9.6 |
4967 * @since 4.9.6 |
4892 * |
|
4893 * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance. |
|
4894 * |
4968 * |
4895 * @param string $request_id ID of the request being confirmed. |
4969 * @param string $request_id ID of the request being confirmed. |
4896 * @param string $key Provided key to validate. |
4970 * @param string $key Provided key to validate. |
4897 * @return true|WP_Error True on success, WP_Error on failure. |
4971 * @return true|WP_Error True on success, WP_Error on failure. |
4898 */ |
4972 */ |
4899 function wp_validate_user_request_key( $request_id, $key ) { |
4973 function wp_validate_user_request_key( |
4900 global $wp_hasher; |
4974 $request_id, |
4901 |
4975 #[\SensitiveParameter] |
|
4976 $key |
|
4977 ) { |
4902 $request_id = absint( $request_id ); |
4978 $request_id = absint( $request_id ); |
4903 $request = wp_get_user_request( $request_id ); |
4979 $request = wp_get_user_request( $request_id ); |
4904 $saved_key = $request->confirm_key; |
4980 $saved_key = $request->confirm_key; |
4905 $key_request_time = $request->modified_timestamp; |
4981 $key_request_time = $request->modified_timestamp; |
4906 |
4982 |
4914 |
4990 |
4915 if ( empty( $key ) ) { |
4991 if ( empty( $key ) ) { |
4916 return new WP_Error( 'missing_key', __( 'The confirmation key is missing from this personal data request.' ) ); |
4992 return new WP_Error( 'missing_key', __( 'The confirmation key is missing from this personal data request.' ) ); |
4917 } |
4993 } |
4918 |
4994 |
4919 if ( empty( $wp_hasher ) ) { |
|
4920 require_once ABSPATH . WPINC . '/class-phpass.php'; |
|
4921 $wp_hasher = new PasswordHash( 8, true ); |
|
4922 } |
|
4923 |
|
4924 /** |
4995 /** |
4925 * Filters the expiration time of confirm keys. |
4996 * Filters the expiration time of confirm keys. |
4926 * |
4997 * |
4927 * @since 4.9.6 |
4998 * @since 4.9.6 |
4928 * |
4999 * |
4929 * @param int $expiration The expiration time in seconds. |
5000 * @param int $expiration The expiration time in seconds. |
4930 */ |
5001 */ |
4931 $expiration_duration = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS ); |
5002 $expiration_duration = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS ); |
4932 $expiration_time = $key_request_time + $expiration_duration; |
5003 $expiration_time = $key_request_time + $expiration_duration; |
4933 |
5004 |
4934 if ( ! $wp_hasher->CheckPassword( $key, $saved_key ) ) { |
5005 if ( ! wp_verify_fast_hash( $key, $saved_key ) ) { |
4935 return new WP_Error( 'invalid_key', __( 'The confirmation key is invalid for this personal data request.' ) ); |
5006 return new WP_Error( 'invalid_key', __( 'The confirmation key is invalid for this personal data request.' ) ); |
4936 } |
5007 } |
4937 |
5008 |
4938 if ( ! $expiration_time || time() > $expiration_time ) { |
5009 if ( ! $expiration_time || time() > $expiration_time ) { |
4939 return new WP_Error( 'expired_key', __( 'The confirmation key has expired for this personal data request.' ) ); |
5010 return new WP_Error( 'expired_key', __( 'The confirmation key has expired for this personal data request.' ) ); |