__('安全验证失败,请刷新页面重试', '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: 上传打赏收款码 // ============================================================ add_action('wp_ajax_aksrt_upload_reward_qr', 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 = get_current_user_id(); if ($user_id <= 0) { wp_send_json_error(['message' => __('请先登录', 'aksrt')]); } if (function_exists('aksrt_rewards_enabled') && !aksrt_rewards_enabled()) { wp_send_json_error(['message' => __('打赏功能未启用', 'aksrt')]); } $kind = isset($_POST['kind']) ? sanitize_key((string) $_POST['kind']) : ''; if (!in_array($kind, ['weixin', 'alipay'], true)) { wp_send_json_error(['message' => __('无效类型', 'aksrt')]); } if (empty($_FILES['file']['name'])) { wp_send_json_error(['message' => __('请选择图片', 'aksrt')]); } require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/image.php'; $file = $_FILES['file']; $check = wp_check_filetype_and_ext($file['tmp_name'], $file['name']); $allowed = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']; $mime = (string) ($check['type'] ?? $file['type'] ?? ''); if ($mime === '' || !in_array($mime, $allowed, true)) { wp_send_json_error(['message' => __('仅支持 JPG/PNG/GIF/WebP 图片', 'aksrt')]); } if (!empty($file['size']) && (int) $file['size'] > 2 * 1024 * 1024) { wp_send_json_error(['message' => __('图片不能超过 2MB', 'aksrt')]); } $attachment_id = media_handle_upload('file', 0); if (is_wp_error($attachment_id)) { wp_send_json_error(['message' => $attachment_id->get_error_message()]); } $meta = $kind === 'weixin' ? 'aksrt_rewards_weixin' : 'aksrt_rewards_alipay'; update_user_meta($user_id, $meta, (int) $attachment_id); $url = wp_get_attachment_image_url((int) $attachment_id, 'full'); wp_send_json_success([ 'message' => __('上传成功', 'aksrt'), 'id' => (int) $attachment_id, 'url' => is_string($url) ? $url : '', 'kind' => $kind, ]); }); // ============================================================ // 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' ] ); } } // ====== 邮箱变更后重置验证状态(阶段 5)====== // 1. 写入 14 天回滚窗口 meta(管理员可在此期内还原旧邮箱) // 2. 把 aksrt_email_verified 重置为 0 // 3. 若功能启用 → 立即给新邮箱发送验证邮件 update_user_meta( $user_id, 'aksrt_email_previous', $old_email ); update_user_meta( $user_id, 'aksrt_email_changed_at', time() ); $verify_url = ''; $verify_message = ''; if ( class_exists( '\AKSRT\Settings\Settings' ) && class_exists( '\AKSRT\Auth\Service' ) && \AKSRT\Settings\Settings::registration_requires_email_verification() ) { update_user_meta( $user_id, 'aksrt_email_verified', 0 ); // 用户对自身的 edit_user 权限映射到 'read',因此 admin_send_verification 会通过权限校验。 $verify_result = \AKSRT\Auth\Service::admin_send_verification( $user_id, $user_id ); if ( ! empty( $verify_result['success'] ) ) { $verify_url = function_exists('aksrt_get_verify_email_url') ? aksrt_get_verify_email_url( $user_id ) : ''; $verify_message = __( '请前往新邮箱完成验证,否则下次登录将被拦截。', 'aksrt' ); } } 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, )); });