'invalid', 'user' => null, 'error' => __('旧的重置密码链接已失效,请重新申请重置密码。', 'aksrt'), 'token' => '', 'user_id'=> 0, ]; } $token = sanitize_text_field($query['token'] ?? ''); $user_id = isset($query['uid']) ? absint($query['uid']) : 0; if ($token === '' || $user_id <= 0) { return [ 'mode' => 'request', 'user' => null, 'error' => '', 'token' => '', 'user_id'=> 0, ]; } $user = self::validate_reset_token($user_id, $token); if (is_wp_error($user)) { return [ 'mode' => 'invalid', 'user' => null, 'error' => $user->get_error_message(), 'token' => $token, 'user_id'=> $user_id, ]; } return [ 'mode' => 'reset', 'user' => $user, 'error' => '', 'token' => $token, 'user_id'=> $user_id, ]; } public static function request_password_reset(array $post): array { if (!wp_verify_nonce($post['_reset_nonce'] ?? '', 'aksrt_reset_password')) { return ['success' => false, 'error' => __('安全验证失败,请刷新页面重试', 'aksrt')]; } if (function_exists('aksrt_require_captcha')) { $captcha_result = aksrt_require_captcha('lostpassword', $post); if ($captcha_result !== true) { return ['success' => false, 'error' => $captcha_result]; } } $raw_login = trim((string) ($post['user_login'] ?? '')); if ($raw_login === '') { return ['success' => false, 'error' => __('请输入邮箱地址或用户名', 'aksrt')]; } $user = null; if (is_email($raw_login)) { $user = get_user_by('email', $raw_login); } else { $user = get_user_by('login', sanitize_user($raw_login, true)); } if (!$user || is_wp_error($user)) { return ['success' => true, 'message' => __('如果该账号存在,重置邮件已发送到注册邮箱', 'aksrt')]; } $token = self::create_reset_token($user->ID); $sent = self::send_password_reset_email($user, $token); if (!$sent) { return ['success' => false, 'error' => __('重置邮件发送失败,请稍后再试', 'aksrt')]; } return ['success' => true, 'message' => __('如果该账号存在,重置邮件已发送到注册邮箱', 'aksrt')]; } public static function reset_password_with_token(array $post): array { if (!wp_verify_nonce($post['_setpw_nonce'] ?? '', 'aksrt_set_password')) { return ['success' => false, 'error' => __('安全验证失败,请刷新页面重试', 'aksrt')]; } $token = sanitize_text_field($post['reset_token'] ?? ''); $user_id = isset($post['reset_uid']) ? absint($post['reset_uid']) : 0; $pass1 = (string) ($post['pass1'] ?? ''); $pass2 = (string) ($post['pass2'] ?? ''); $user = self::validate_reset_token($user_id, $token); if (is_wp_error($user)) { return ['success' => false, 'error' => $user->get_error_message(), 'mode' => 'invalid']; } $password_check = self::validate_password($pass1, $pass2); if ($password_check !== true) { return ['success' => false, 'error' => $password_check, 'mode' => 'reset']; } wp_set_password($pass1, $user_id); self::clear_reset_token($user_id); return ['success' => true, 'message' => __('密码已设置成功!', 'aksrt')]; } private static function create_reset_token(int $user_id): string { $token = wp_generate_password(48, false, false); update_user_meta($user_id, self::RESET_TOKEN_HASH_META, hash('sha256', $token)); update_user_meta($user_id, self::RESET_TOKEN_EXPIRES_META, time() + self::RESET_TOKEN_TTL); update_user_meta($user_id, self::RESET_TOKEN_REQUESTED_AT, time()); return $token; } private static function validate_reset_token(int $user_id, string $token) { if ($user_id <= 0 || $token === '') { return new \WP_Error('invalid_reset_token', __('重置链接无效或已过期', 'aksrt')); } $user = get_userdata($user_id); if (!$user || is_wp_error($user)) { return new \WP_Error('invalid_reset_token', __('重置链接无效或已过期', 'aksrt')); } $stored_hash = (string) get_user_meta($user_id, self::RESET_TOKEN_HASH_META, true); $expires_at = (int) get_user_meta($user_id, self::RESET_TOKEN_EXPIRES_META, true); $token_hash = hash('sha256', $token); if ($stored_hash === '' || $expires_at <= time() || !hash_equals($stored_hash, $token_hash)) { return new \WP_Error('invalid_reset_token', __('重置链接无效或已过期', 'aksrt')); } return $user; } private static function clear_reset_token(int $user_id): void { delete_user_meta($user_id, self::RESET_TOKEN_HASH_META); delete_user_meta($user_id, self::RESET_TOKEN_EXPIRES_META); delete_user_meta($user_id, self::RESET_TOKEN_REQUESTED_AT); } private static function send_password_reset_email(\WP_User $user, string $token): bool { $reset_url = aksrt_get_reset_password_url($token, $user->ID); $site_name = get_bloginfo('name'); $default_subject = '[' . $site_name . '] ' . __('重置密码', 'aksrt'); $default_content = sprintf( __("您好 %s,\n\n有人请求重置您在 %s 的密码。\n\n请点击以下链接设置新密码:\n\n%s\n\n如果这不是您本人的操作,请忽略此邮件,您的密码不会被更改。", 'aksrt'), $user->user_login, $site_name, $reset_url ); return \AKSRT\Settings\Settings::send_event_email( 'password_reset', $user->user_email, $default_subject, $default_content, ['{username}' => $user->user_login, '{site_name}' => $site_name, '{url}' => $reset_url] ); } /* ================================================================= * 手机号认证(注册 / 登录 / 绑定) * 对齐 zibll 的 signup_captcha / signin_captcha / bind_phone_captcha * ================================================================= */ /** * 手机号注册 * * @param array $post POST 数据 (phone, code, password, ref) * @return array{success: bool, user_id?: int, error?: string, redirect?: string} */ public static function register_by_phone(array $post): array { $phone = sanitize_text_field((string) ($post['phone'] ?? '')); $code = sanitize_text_field((string) ($post['code'] ?? '')); $pass = (string) ($post['password'] ?? ''); if (!preg_match('/^1[3-9]\d{9}$/', $phone)) { return ['success' => false, 'error' => __('手机号格式不正确', 'aksrt')]; } if (empty($code)) { return ['success' => false, 'error' => __('请输入验证码', 'aksrt')]; } if (strlen($pass) < 6) { return ['success' => false, 'error' => __('密码至少 6 位', 'aksrt')]; } if (function_exists('aksrt_require_captcha')) { $captcha_result = aksrt_require_captcha('register', $post); if ($captcha_result !== true) { return ['success' => false, 'error' => $captcha_result]; } } // 验证 SMS 验证码 if (class_exists('\AKSRT\Sms\SMS')) { $verify_result = \AKSRT\Sms\SMS::get_instance()->verify_code($phone, $code); if (empty($verify_result['success'])) { return ['success' => false, 'error' => $verify_result['message'] ?? __('验证码不正确', 'aksrt')]; } } else { return ['success' => false, 'error' => __('短信服务不可用', 'aksrt')]; } // 检查手机号是否已注册 $existing_user = self::get_user_by_phone($phone); if ($existing_user) { return ['success' => false, 'error' => __('该手机号已注册', 'aksrt')]; } // 生成用户名(phone_ + 后4位) $username = 'phone_' . substr($phone, -4); $suffix = 1; $base = $username; while (username_exists($username)) { $username = $base . '_' . $suffix; $suffix++; } $ref_service = class_exists('\AKSRT\Payment\ReferralAttribution') ? \AKSRT\Payment\ReferralAttribution::get_instance() : null; if ($ref_service) { $ref_service->clear_registration_context(); } $registration = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_referral_registration_settings() : ['enabled' => false, 'register_field' => 'hidden', 'reject_invalid' => true]; $submitted_ref = sanitize_key((string) ($post['ref'] ?? '')); $field_mode = !empty($registration['enabled']) ? (string) ($registration['register_field'] ?? 'hidden') : 'hidden'; $accept_submitted = !empty($registration['enabled']) && $field_mode !== 'hidden'; $ref_context = $ref_service ? $ref_service->prepare_registration($accept_submitted ? $submitted_ref : '') : ['valid' => false, 'submitted_valid' => false, 'conflict' => false, 'source' => 'none']; if ($field_mode === 'required' && empty($ref_context['valid'])) { if ($submitted_ref === '') { if ($ref_service) { $ref_service->clear_registration_context(); } return ['success' => false, 'error' => __('请填写推广码', 'aksrt')]; } if (!empty($registration['reject_invalid'])) { if ($ref_service) { $ref_service->clear_registration_context(); } return ['success' => false, 'error' => __('推广码无效,请检查后重试', 'aksrt')]; } } // 创建用户 $user_id = wp_create_user($username, $pass, $phone . '@sms.aksrt.local'); if (is_wp_error($user_id)) { if ($ref_service) { $ref_service->clear_registration_context(); } return ['success' => false, 'error' => $user_id->get_error_message()]; } // 绑定手机号 update_user_meta($user_id, 'aksrt_phone', $phone); update_user_meta($user_id, 'aksrt_phone_verified', '1'); // 邮箱标记为已验证(手机注册等同于已验证) update_user_meta($user_id, 'aksrt_email_verified', '1'); if ($ref_service) { $ref_service->reward_registered_user((int) $user_id); } // 自动登录 wp_set_current_user($user_id); wp_set_auth_cookie($user_id, true); $redirect = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url() : home_url('/'); return [ 'success' => true, 'user_id' => $user_id, 'redirect' => $redirect, 'message' => __('注册成功', 'aksrt'), 'notice' => $ref_service ? $ref_service->take_registration_notice() : '', ]; } /** * 手机号登录(密码登录) * * @param array $post (phone, password) * @return array */ public static function login_by_phone_password(array $post): array { $phone = sanitize_text_field((string) ($post['phone'] ?? '')); $pass = (string) ($post['password'] ?? ''); if (!preg_match('/^1[3-9]\d{9}$/', $phone)) { return ['success' => false, 'error' => __('手机号格式不正确', 'aksrt')]; } if (function_exists('aksrt_require_captcha')) { $captcha_result = aksrt_require_captcha('login', $post); if ($captcha_result !== true) { return ['success' => false, 'error' => $captcha_result]; } } $user = self::get_user_by_phone($phone); if (!$user) { return ['success' => false, 'error' => __('该手机号未注册', 'aksrt')]; } // 验证密码 if (!wp_check_password($pass, $user->data->user_pass, $user->ID)) { return ['success' => false, 'error' => __('密码不正确', 'aksrt')]; } wp_set_current_user($user->ID); wp_set_auth_cookie($user->ID, true); $redirect = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url() : home_url('/'); return [ 'success' => true, 'user_id' => $user->ID, 'redirect' => $redirect, ]; } /** * 手机号免密登录(SMS 验证码登录) * * @param array $post (phone, code) * @return array */ public static function login_by_phone_code(array $post): array { $phone = sanitize_text_field((string) ($post['phone'] ?? '')); $code = sanitize_text_field((string) ($post['code'] ?? '')); if (!preg_match('/^1[3-9]\d{9}$/', $phone)) { return ['success' => false, 'error' => __('手机号格式不正确', 'aksrt')]; } if (function_exists('aksrt_require_captcha')) { $captcha_result = aksrt_require_captcha('login', $post); if ($captcha_result !== true) { return ['success' => false, 'error' => $captcha_result]; } } // 验证 SMS 验证码 if (class_exists('\AKSRT\Sms\SMS')) { $verify_result = \AKSRT\Sms\SMS::get_instance()->verify_code($phone, $code); if (empty($verify_result['success'])) { return ['success' => false, 'error' => $verify_result['message'] ?? __('验证码不正确', 'aksrt')]; } } else { return ['success' => false, 'error' => __('短信服务不可用', 'aksrt')]; } $user = self::get_user_by_phone($phone); if (!$user) { return ['success' => false, 'error' => __('该手机号未注册', 'aksrt')]; } wp_set_current_user($user->ID); wp_set_auth_cookie($user->ID, true); $redirect = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url() : home_url('/'); return [ 'success' => true, 'user_id' => $user->ID, 'redirect' => $redirect, ]; } /** * 绑定手机号到当前用户 * * @param array $post (phone, code) * @return array */ public static function bind_phone(array $post): array { if (!is_user_logged_in()) { return ['success' => false, 'error' => __('请先登录', 'aksrt')]; } $phone = sanitize_text_field((string) ($post['phone'] ?? '')); $code = sanitize_text_field((string) ($post['code'] ?? '')); if (!preg_match('/^1[3-9]\d{9}$/', $phone)) { return ['success' => false, 'error' => __('手机号格式不正确', 'aksrt')]; } if (function_exists('aksrt_require_captcha')) { $captcha_result = aksrt_require_captcha('bind_phone', $post); if ($captcha_result !== true) { return ['success' => false, 'error' => $captcha_result]; } } // 验证 SMS 验证码 if (class_exists('\AKSRT\Sms\SMS')) { $verify_result = \AKSRT\Sms\SMS::get_instance()->verify_code($phone, $code); if (empty($verify_result['success'])) { return ['success' => false, 'error' => $verify_result['message'] ?? __('验证码不正确', 'aksrt')]; } } else { return ['success' => false, 'error' => __('短信服务不可用', 'aksrt')]; } // 检查手机号是否已被其他用户绑定 $existing = self::get_user_by_phone($phone); if ($existing && (int) $existing->ID !== get_current_user_id()) { return ['success' => false, 'error' => __('该手机号已被其他账号绑定', 'aksrt')]; } $user_id = get_current_user_id(); update_user_meta($user_id, 'aksrt_phone', $phone); update_user_meta($user_id, 'aksrt_phone_verified', '1'); return [ 'success' => true, 'message' => __('手机号绑定成功', 'aksrt'), ]; } /** * 根据手机号查找用户 */ private static function get_user_by_phone(string $phone): ?\WP_User { $users = get_users([ 'meta_key' => 'aksrt_phone', 'meta_value' => $phone, 'number' => 1, 'fields' => 'all', ]); return !empty($users) ? $users[0] : null; } }