setAttributes(array( 'class' => 'standard', 'id' => 'change_password', 'action' => multisite('change_password.php') )); $form->addHiddenInputs(array( 'action' => 'change_password', 'target_url' => $target_url )); $fieldset = new ElementFieldset(); $fieldset->addLegend(get_vocab('change_password')); // 顶部提示 / 错误消息 $field = new FieldDiv(); $p = new ElementP(); if (isset($error)) { switch ($error) { case 'old_pwd_invalid': $p->setText(get_vocab('old_pwd_invalid')); break; case 'pwd_not_match': $p->setText(get_vocab('passwords_not_eq')); break; case 'pwd_same': $p->setText(get_vocab('pwd_same_as_old')); break; case 'pwd_invalid': $p->setText(get_vocab('password_invalid')); break; default: $p->setText(get_vocab('unknown_user')); break; } $p->setAttribute('class', 'error'); $field->addControlElement($p); // 策略不满足时列出具体规则 if (($error == 'pwd_invalid') && isset($pwd_policy)) { $ul = new Element('ul'); $ul->setAttribute('class', 'error'); foreach ($pwd_policy as $rule => $value) { if ($value != 0) { $li = new Element('li'); $li->setText(get_vocab('policy_' . $rule, $value)); $ul->addElement($li); } } $field->addControlElement($ul); } } else { // 提示(强制改密或常规自助修改) $p->setText(get_vocab('pwd_expired_msg')); $field->addControlElement($p); } $fieldset->addElement($field); // 当前密码 $field = new FieldInputPassword(); $field->setLabel(get_vocab('current_password')) ->setControlAttributes(array('id' => 'password_old', 'name' => 'password_old', 'autocomplete' => 'current-password', 'required' => true, 'autofocus' => true)); $fieldset->addElement($field); // 新密码(输入两次) $labels = array(get_vocab('new_password'), get_vocab('confirm_password')); for ($i = 0; $i < 2; $i++) { $field = new FieldInputPassword(); $field->setLabel($labels[$i]) ->setControlAttributes(array('id' => "password$i", 'name' => "password$i", 'autocomplete' => 'new-password', 'required' => true)); $fieldset->addElement($field); } // 口令策略说明 if (isset($pwd_policy)) { $field = new FieldDiv(); $p = new ElementP(); $p->setText(get_vocab('pwd_must_contain')); $field->addControlElement($p); $ul = new Element('ul'); $ul->setAttribute('id', 'pwd_policy'); foreach ($pwd_policy as $rule => $value) { if ($value != 0) { $li = new Element('li'); $li->setText(get_vocab('policy_' . $rule, $value)); $ul->addElement($li); } } $field->addControlElement($ul); $fieldset->addElement($field); } $form->addElement($fieldset); // 提交按钮 $fieldset = new ElementFieldset(); $field = new FieldInputSubmit(); $field->setControlAttributes(array('value' => get_vocab('change_password'))); $fieldset->addElement($field); $form->addElement($fieldset); $form->render(); } function generate_change_password_success(string $target_url) : void { echo "

" . get_vocab('change_password') . "

\n"; echo "

" . get_vocab('password_changed') . "

\n"; echo '

' . get_vocab('back') . "

\n"; } // ===== 主流程 ===== // 必须是已登录用户 $mrbs_user = session()->getCurrentUser(); if (!isset($mrbs_user)) { // 未登录:引导到登录页,登录成功后回到本页 session()->authGet(null, 'change_password.php'); exit; } // 跳转目标(仅允许站内相对 URL) $target_url = get_form_var('target_url', 'url_local', null, INPUT_GET); if (!isset($target_url) || ($target_url == '')) { $target_url = 'index.php'; } // 防止把改密页自身作为跳转目标(避免循环) if ($target_url == 'change_password.php') { $target_url = 'index.php'; } // 处理提交(action 只从 POST 读取,且必须通过 CSRF 校验) $action = get_form_var('action', 'string', null, INPUT_POST); if (isset($action) && ($action == 'change_password')) { Form::checkToken(); $old_password = get_form_var('password_old', 'string', null, INPUT_POST); $password0 = get_form_var('password0', 'string', null, INPUT_POST); $password1 = get_form_var('password1', 'string', null, INPUT_POST); $post_target = get_form_var('target_url', 'url_local', null, INPUT_POST); if (isset($post_target) && ($post_target != '')) { $target_url = $post_target; } $error = null; // 1. 校验当前密码 // (注意:validateUser 失败会计入失败次数;连续 5 次错误当前账号将被临时锁定, // 与登录通道行为一致,属预期安全设计) if (($old_password === null) || ($old_password === '') || !auth()->validateUser($mrbs_user->username, $old_password)) { $error = 'old_pwd_invalid'; Audit::log('PWD_CHANGE_FAIL', $mrbs_user->username, 'old password incorrect'); } // 2. 两次输入一致 elseif ($password0 !== $password1) { $error = 'pwd_not_match'; } // 3. 符合复杂度策略 elseif (($password0 === null) || ($password0 === '') || !auth()->validatePassword($password0)) { $error = 'pwd_invalid'; } // 4. 新旧密码不同 elseif ($password0 === $old_password) { $error = 'pwd_same'; } else { // 成功:更新口令并记录修改时间 auth()->updatePassword($mrbs_user->username, $password0); Audit::log('PWD_CHANGE', $mrbs_user->username, 'self-service change'); // 清除“强制改密”标记(须在 session_write_close 前完成) unset($_SESSION['mrbs_force_pwd_change']); session_write_close(); location_header('change_password.php?result=ok&target_url=' . urlencode($target_url)); exit; } // 校验失败:回到表单显示错误(PRG 模式,防止表单重复提交) location_header('change_password.php?error=' . urlencode($error) . '&target_url=' . urlencode($target_url)); exit; } // ===== 渲染页面 ===== $context = array( 'view' => $view, 'view_all' => $view_all, 'year' => $year, 'month' => $month, 'day' => $day, 'area' => isset($area) ? $area : null, 'room' => isset($room) ? $room : null ); print_header($context); $result = get_form_var('result', 'string', null, INPUT_GET); $error = get_form_var('error', 'string', null, INPUT_GET); echo "
\n"; if (isset($result) && ($result == 'ok')) { generate_change_password_success($target_url); } else { generate_change_password_form($error, $target_url); } echo "
\n"; print_footer();