324 lines
14 KiB
PHP
324 lines
14 KiB
PHP
<?php
|
||
/**
|
||
* User profile/password/email AJAX handlers
|
||
*
|
||
* @package AKSRT
|
||
*/
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
// ============================================================
|
||
add_action('wp_ajax_aksrt_save_profile', function () {
|
||
if (!isset($_POST['_profile_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_profile_nonce'])), 'aksrt_profile_save')) {
|
||
wp_send_json_error(['message' => __('安全验证失败,请刷新页面重试', 'aksrt')]);
|
||
}
|
||
|
||
$user_id = isset($_POST['user_id']) ? (int) $_POST['user_id'] : 0;
|
||
$result = function_exists('aksrt_save_user_center_profile')
|
||
? aksrt_save_user_center_profile($user_id, $_POST)
|
||
: new WP_Error('aksrt_profile_unavailable', __('保存失败', 'aksrt'));
|
||
|
||
if (is_wp_error($result)) {
|
||
wp_send_json_error(['message' => $result->get_error_message()]);
|
||
}
|
||
|
||
wp_send_json_success(['message' => __('保存成功!', 'aksrt')]);
|
||
});
|
||
|
||
// ============================================================
|
||
// AJAX: 发送邮箱验证码(修改密码/更改邮箱通用)
|
||
// ============================================================
|
||
|
||
if (!function_exists('aksrt_get_email_code_key')) :
|
||
function aksrt_get_email_code_key(int $user_id, string $scene): string {
|
||
return 'aksrt_email_code_' . $scene . '_' . $user_id;
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_get_email_code_rate_key')) :
|
||
function aksrt_get_email_code_rate_key(int $user_id, string $scene, string $target = ''): string {
|
||
$suffix = $target !== '' ? '_' . md5(strtolower($target)) : '';
|
||
return 'aksrt_email_code_rate_' . $scene . '_' . $user_id . $suffix;
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_store_email_code')) :
|
||
function aksrt_store_email_code(int $user_id, string $scene, string $code, string $target = ''): void {
|
||
set_transient(
|
||
aksrt_get_email_code_key($user_id, $scene),
|
||
[
|
||
'hash' => wp_hash_password($code),
|
||
'target' => $target,
|
||
'issued_at' => time(),
|
||
],
|
||
5 * MINUTE_IN_SECONDS
|
||
);
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_consume_email_code')) :
|
||
function aksrt_consume_email_code(int $user_id, string $scene, string $code, string $target = ''): bool {
|
||
$key = aksrt_get_email_code_key($user_id, $scene);
|
||
$stored = get_transient($key);
|
||
if (!is_array($stored) || empty($stored['hash']) || !wp_check_password($code, $stored['hash'])) {
|
||
return false;
|
||
}
|
||
if ($target !== '' && strtolower((string) ($stored['target'] ?? '')) !== strtolower($target)) {
|
||
return false;
|
||
}
|
||
|
||
delete_transient($key);
|
||
return true;
|
||
}
|
||
|
||
endif;
|
||
|
||
add_action('wp_ajax_aksrt_send_email_code', function () {
|
||
if ( ! isset( $_POST['_settings_nonce'] ) || ! wp_verify_nonce( $_POST['_settings_nonce'], 'aksrt_account_settings' ) ) {
|
||
wp_send_json_error( array( 'message' => __( '安全验证失败,请刷新页面重试', 'aksrt' ) ) );
|
||
}
|
||
|
||
if ( ! is_user_logged_in() ) {
|
||
wp_send_json_error( array( 'message' => __( '请先登录', 'aksrt' ) ) );
|
||
}
|
||
|
||
$scene = isset( $_POST['scene'] ) ? sanitize_key( (string) $_POST['scene'] ) : '';
|
||
if ( ! in_array( $scene, array( 'change_password', 'change_email' ), true ) ) {
|
||
wp_send_json_error( array( 'message' => __( '无效的验证场景', 'aksrt' ) ) );
|
||
}
|
||
|
||
if ( function_exists( 'aksrt_require_captcha' ) ) {
|
||
$captcha_result = aksrt_require_captcha( $scene, wp_unslash( $_POST ) );
|
||
if ( $captcha_result !== true ) {
|
||
wp_send_json_error( array( 'message' => $captcha_result ) );
|
||
}
|
||
}
|
||
|
||
$current_user = wp_get_current_user();
|
||
$target_email = '';
|
||
$success_message = '';
|
||
|
||
if ( $scene === 'change_password' ) {
|
||
$target_email = $current_user->user_email;
|
||
if ( empty( $target_email ) || ! is_email( $target_email ) ) {
|
||
wp_send_json_error( array( 'message' => __( '当前账号未绑定有效邮箱', 'aksrt' ) ) );
|
||
}
|
||
$success_message = __( '验证码已发送到您的注册邮箱', 'aksrt' );
|
||
} else {
|
||
$new_email = isset( $_POST['new_email'] ) ? trim( wp_unslash( $_POST['new_email'] ) ) : '';
|
||
$current_password = isset( $_POST['current_password'] ) ? trim( wp_unslash( $_POST['current_password'] ) ) : '';
|
||
|
||
if ( empty( $current_password ) || ! wp_check_password( $current_password, $current_user->user_pass, $current_user->ID ) ) {
|
||
wp_send_json_error( array( 'message' => __( '当前密码不正确', 'aksrt' ) ) );
|
||
}
|
||
if ( empty( $new_email ) || ! is_email( $new_email ) ) {
|
||
wp_send_json_error( array( 'message' => __( '请输入有效的新邮箱地址', 'aksrt' ) ) );
|
||
}
|
||
if ( strtolower( $new_email ) === strtolower( $current_user->user_email ) ) {
|
||
wp_send_json_error( array( 'message' => __( '新邮箱与当前邮箱相同', 'aksrt' ) ) );
|
||
}
|
||
if ( email_exists( $new_email ) ) {
|
||
wp_send_json_error( array( 'message' => __( '该邮箱已被其他账号使用', 'aksrt' ) ) );
|
||
}
|
||
|
||
$target_email = $new_email;
|
||
$success_message = __( '验证码已发送到新邮箱,请完成验证后再提交', 'aksrt' );
|
||
}
|
||
|
||
// 频率限制:60秒内不能重复发送
|
||
$rate_key = aksrt_get_email_code_rate_key( $current_user->ID, $scene, $target_email );
|
||
if ( get_transient( $rate_key ) ) {
|
||
wp_send_json_error( array( 'message' => __( '操作过于频繁,请稍后再试', 'aksrt' ) ) );
|
||
}
|
||
set_transient( $rate_key, true, 60 );
|
||
|
||
// 生成验证码并同步发送,只有真正发信成功后才写入验证码缓存。
|
||
$code = str_pad( (string) random_int( 0, 999999 ), 6, '0', STR_PAD_LEFT );
|
||
|
||
$site_name = get_bloginfo( 'name' );
|
||
$default_subject = '[' . $site_name . '] ' . __( '邮箱验证码', 'aksrt' );
|
||
$default_content = sprintf(
|
||
__( "您好 %s,\n\n您正在进行敏感操作验证,验证码为:\n\n【%s】\n\n验证码有效期为 5 分钟。如非本人操作,请忽略此邮件。", 'aksrt' ),
|
||
$current_user->display_name,
|
||
$code
|
||
);
|
||
$sent = class_exists( '\AKSRT\Settings\Settings' )
|
||
? \AKSRT\Settings\Settings::send_event_email(
|
||
'change_code', $target_email, $default_subject, $default_content,
|
||
[ '{username}' => $current_user->display_name, '{site_name}' => $site_name, '{code}' => $code ]
|
||
)
|
||
: wp_mail( $target_email, $default_subject, $default_content, [ 'Content-Type: text/plain; charset=UTF-8' ] );
|
||
|
||
if ( ! $sent ) {
|
||
delete_transient( $rate_key );
|
||
error_log( '[AKSRT] 验证码邮件发送失败 user_id=' . $current_user->ID . ' email=' . $target_email . ' scene=' . $scene );
|
||
wp_send_json_error( array( 'message' => __( '验证码邮件发送失败,请稍后重试', 'aksrt' ) ) );
|
||
}
|
||
|
||
aksrt_store_email_code( $current_user->ID, $scene, $code, $target_email );
|
||
|
||
wp_send_json_success( array( 'message' => $success_message ) );
|
||
});
|
||
|
||
// ============================================================
|
||
// AJAX: 修改密码
|
||
// ============================================================
|
||
add_action('wp_ajax_aksrt_change_password', function () {
|
||
if ( ! isset( $_POST['_settings_nonce'] ) || ! wp_verify_nonce( $_POST['_settings_nonce'], 'aksrt_account_settings' ) ) {
|
||
wp_send_json_error( array( 'message' => __( '安全验证失败,请刷新页面重试', 'aksrt' ) ) );
|
||
}
|
||
|
||
$user_id = get_current_user_id();
|
||
if ( ! $user_id ) {
|
||
wp_send_json_error( array( 'message' => __( '请先登录', 'aksrt' ) ) );
|
||
}
|
||
|
||
$old_password = isset( $_POST['old_password'] ) ? trim( wp_unslash( $_POST['old_password'] ) ) : '';
|
||
$new_password = isset( $_POST['new_password'] ) ? trim( wp_unslash( $_POST['new_password'] ) ) : '';
|
||
$new_password_confirm = isset( $_POST['new_password_confirm'] ) ? trim( wp_unslash( $_POST['new_password_confirm'] ) ) : '';
|
||
$email_code = isset( $_POST['email_code'] ) ? sanitize_text_field( $_POST['email_code'] ) : '';
|
||
|
||
// 验证原密码
|
||
$user = get_userdata( $user_id );
|
||
if ( ! $user || ! wp_check_password( $old_password, $user->data->user_pass, $user_id ) ) {
|
||
wp_send_json_error( array( 'message' => __( '原密码不正确', 'aksrt' ) ) );
|
||
}
|
||
|
||
// 验证新密码强度
|
||
if ( mb_strlen( $new_password ) < 6 ) {
|
||
wp_send_json_error( array( 'message' => __( '新密码长度至少6位', 'aksrt' ) ) );
|
||
}
|
||
if ( mb_strlen( $new_password ) > 128 ) {
|
||
wp_send_json_error( array( 'message' => __( '新密码过长', 'aksrt' ) ) );
|
||
}
|
||
if ( $new_password !== $new_password_confirm ) {
|
||
wp_send_json_error( array( 'message' => __( '两次输入的新密码不一致', 'aksrt' ) ) );
|
||
}
|
||
|
||
// 人机验证
|
||
if ( function_exists( 'aksrt_require_captcha' ) ) {
|
||
$captcha_result = aksrt_require_captcha( 'change_password', wp_unslash( $_POST ) );
|
||
if ( $captcha_result !== true ) {
|
||
wp_send_json_error( array( 'message' => $captcha_result ) );
|
||
}
|
||
}
|
||
|
||
// 验证邮箱验证码
|
||
if ( ! aksrt_consume_email_code( $user_id, 'change_password', $email_code, $user->user_email ) ) {
|
||
wp_send_json_error( array( 'message' => __( '邮箱验证码错误或已过期', 'aksrt' ) ) );
|
||
}
|
||
|
||
// 设置新密码
|
||
wp_set_password( $new_password, $user_id );
|
||
|
||
if ( class_exists( 'WP_Session_Tokens' ) ) {
|
||
WP_Session_Tokens::get_instance( $user_id )->destroy_all();
|
||
}
|
||
|
||
// 清除登录态
|
||
wp_clear_auth_cookie();
|
||
|
||
wp_send_json_success( array(
|
||
'message' => __( '密码修改成功,即将跳转到登录页…', 'aksrt' ),
|
||
'redirect_to' => aksrt_get_login_url(),
|
||
));
|
||
});
|
||
|
||
// ============================================================
|
||
// AJAX: 更改邮箱
|
||
// ============================================================
|
||
add_action('wp_ajax_aksrt_change_email', function () {
|
||
if ( ! isset( $_POST['_settings_nonce'] ) || ! wp_verify_nonce( $_POST['_settings_nonce'], 'aksrt_account_settings' ) ) {
|
||
wp_send_json_error( array( 'message' => __( '安全验证失败,请刷新页面重试', 'aksrt' ) ) );
|
||
}
|
||
|
||
$user_id = get_current_user_id();
|
||
if ( ! $user_id ) {
|
||
wp_send_json_error( array( 'message' => __( '请先登录', 'aksrt' ) ) );
|
||
}
|
||
|
||
$current_password = isset( $_POST['current_password'] ) ? trim( wp_unslash( $_POST['current_password'] ) ) : '';
|
||
$new_email = isset( $_POST['new_email'] ) ? trim( wp_unslash( $_POST['new_email'] ) ) : '';
|
||
$email_code = isset( $_POST['email_code'] ) ? sanitize_text_field( $_POST['email_code'] ) : '';
|
||
|
||
$current_user = wp_get_current_user();
|
||
if ( empty( $current_password ) || ! wp_check_password( $current_password, $current_user->user_pass, $current_user->ID ) ) {
|
||
wp_send_json_error( array( 'message' => __( '当前密码不正确', 'aksrt' ) ) );
|
||
}
|
||
|
||
// 验证新邮箱格式
|
||
if ( empty( $new_email ) || ! is_email( $new_email ) ) {
|
||
wp_send_json_error( array( 'message' => __( '请输入有效的邮箱地址', 'aksrt' ) ) );
|
||
}
|
||
|
||
if ( strtolower( $new_email ) === strtolower( $current_user->user_email ) ) {
|
||
wp_send_json_error( array( 'message' => __( '新邮箱与当前邮箱相同', 'aksrt' ) ) );
|
||
}
|
||
|
||
// 检查邮箱是否已被使用
|
||
if ( email_exists( $new_email ) ) {
|
||
wp_send_json_error( array( 'message' => __( '该邮箱已被其他账号使用', 'aksrt' ) ) );
|
||
}
|
||
|
||
// 人机验证
|
||
if ( function_exists( 'aksrt_require_captcha' ) ) {
|
||
$captcha_result = aksrt_require_captcha( 'change_email', wp_unslash( $_POST ) );
|
||
if ( $captcha_result !== true ) {
|
||
wp_send_json_error( array( 'message' => $captcha_result ) );
|
||
}
|
||
}
|
||
|
||
// 验证邮箱验证码
|
||
if ( ! aksrt_consume_email_code( $user_id, 'change_email', $email_code, $new_email ) ) {
|
||
wp_send_json_error( array( 'message' => __( '邮箱验证码错误或已过期', 'aksrt' ) ) );
|
||
}
|
||
|
||
// 更新邮箱
|
||
$old_email = $current_user->user_email;
|
||
$update_result = wp_update_user( [
|
||
'ID' => $user_id,
|
||
'user_email' => $new_email,
|
||
] );
|
||
|
||
if ( is_wp_error( $update_result ) ) {
|
||
wp_send_json_error( array( 'message' => $update_result->get_error_message() ?: __( '邮箱更新失败,请稍后重试', 'aksrt' ) ) );
|
||
}
|
||
|
||
if ( is_email( $old_email ) ) {
|
||
$site_name = get_bloginfo( 'name' );
|
||
$default_subject = '[' . $site_name . '] ' . __( '账号邮箱已变更', 'aksrt' );
|
||
$default_content = sprintf(
|
||
__( "您好 %s,\n\n您的账号邮箱已成功修改为:%s\n\n如果这不是您的操作,请立即联系站点管理员。", 'aksrt' ),
|
||
$current_user->display_name,
|
||
$new_email
|
||
);
|
||
if ( class_exists( '\AKSRT\Settings\Settings' ) ) {
|
||
\AKSRT\Settings\Settings::send_event_email(
|
||
'change_notice', $old_email, $default_subject, $default_content,
|
||
[ '{username}' => $current_user->display_name, '{site_name}' => $site_name, '{new_email}' => $new_email ]
|
||
);
|
||
} else {
|
||
wp_mail( $old_email, $default_subject, $default_content, [ 'Content-Type: text/plain; charset=UTF-8' ] );
|
||
}
|
||
}
|
||
|
||
$verify_url = '';
|
||
$verify_message = '';
|
||
update_user_meta( $user_id, 'aksrt_email_verified', 1 );
|
||
|
||
if ( class_exists( 'WP_Session_Tokens' ) ) {
|
||
WP_Session_Tokens::get_instance( $user_id )->destroy_all();
|
||
}
|
||
|
||
// 清除登录态
|
||
wp_clear_auth_cookie();
|
||
|
||
wp_send_json_success( array(
|
||
'message' => $verify_message !== ''
|
||
? __( '邮箱修改成功,请前往新邮箱完成验证后重新登录…', 'aksrt' )
|
||
: __( '邮箱修改成功,即将跳转到登录页…', 'aksrt' ),
|
||
'redirect_to' => $verify_url !== '' ? $verify_url : aksrt_get_login_url(),
|
||
'verify_url' => $verify_url,
|
||
));
|
||
});
|