133 lines
6.5 KiB
PHP
133 lines
6.5 KiB
PHP
<?php
|
|
// 登录 / 注册
|
|
require __DIR__ . '/includes/init.php';
|
|
$pageTitle = __('login.title');
|
|
|
|
$next = $_GET['next'] ?? '';
|
|
$mode = $_GET['mode'] ?? 'login';
|
|
$invite = trim($_GET['inv'] ?? '');
|
|
$err = '';
|
|
$ok = '';
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
verifyCsrf();
|
|
|
|
if (isset($_POST['login'])) {
|
|
$u = trim($_POST['username'] ?? '');
|
|
$pw = $_POST['password'] ?? '';
|
|
$stmt = db()->prepare('SELECT * FROM ' . tn('users') . ' WHERE username = ?');
|
|
$stmt->execute([$u]);
|
|
$row = $stmt->fetch();
|
|
if ($row && password_verify($pw, $row['password'])) {
|
|
$_SESSION['user_id'] = $row['id'];
|
|
unset($_SESSION['csrf']);
|
|
redirect($next ?: 'index.php');
|
|
}
|
|
$err = __('login.err_login_failed');
|
|
}
|
|
|
|
if (isset($_POST['register'])) {
|
|
$u = trim($_POST['username'] ?? '');
|
|
$pw = $_POST['password'] ?? '';
|
|
$pw2 = $_POST['password2'] ?? '';
|
|
$em = trim($_POST['email'] ?? '');
|
|
$cap = strtoupper(trim($_POST['captcha'] ?? ''));
|
|
// 邀请码:优先使用表单填写,其次使用 URL 参数
|
|
$postInvite = isset($_POST['invite_code']) ? trim($_POST['invite_code']) : null;
|
|
$invite = $postInvite !== null ? $postInvite : trim($_GET['inv'] ?? '');
|
|
|
|
// 自研图形验证码:一次性校验后清空
|
|
$sessCap = isset($_SESSION['captcha']) ? strtoupper($_SESSION['captcha']) : '';
|
|
unset($_SESSION['captcha']);
|
|
if ($cap === '' || $cap !== $sessCap) {
|
|
$err = __('login.err_captcha_wrong');
|
|
}
|
|
elseif (strlen($u) < 3) $err = __('login.err_username_short');
|
|
elseif (strlen($pw) < 6) $err = __('login.err_password_short');
|
|
elseif ($pw !== $pw2) $err = __('login.err_password_mismatch');
|
|
elseif (!filter_var($em, FILTER_VALIDATE_EMAIL)) $err = __('login.err_email_invalid');
|
|
// 若用户在表单里手动填写了邀请码,则必须校验通过
|
|
elseif ($postInvite !== null && $postInvite !== '' && getInviterIdByCode($postInvite) === 0) {
|
|
$err = __('login.err_invite_invalid');
|
|
}
|
|
|
|
// 单 IP 每日最多注册 2 个账号
|
|
if ($err === '') {
|
|
$ip = getClientIp();
|
|
if (regCountToday($ip) >= 2) {
|
|
$err = __('login.err_ip_limit');
|
|
}
|
|
}
|
|
|
|
if ($err === '') {
|
|
$chk = db()->prepare('SELECT id FROM ' . tn('users') . ' WHERE username = ?');
|
|
$chk->execute([$u]);
|
|
if ($chk->fetch()) {
|
|
$err = __('login.err_username_exists');
|
|
} else {
|
|
$hash = password_hash($pw, PASSWORD_DEFAULT);
|
|
$myCode = genInviteCode();
|
|
db()->prepare('INSERT INTO ' . tn('users') . ' (username,password,email,reg_ip,invite_code,verified,created_at) VALUES (?,?,?,?,?,0,NOW())')
|
|
->execute([$u, $hash, $em, $ip, $myCode]);
|
|
$id = db()->lastInsertId();
|
|
// 邀请奖励:通过他人邀请码注册,给邀请人加积分
|
|
if ($invite !== '') {
|
|
$invId = getInviterIdByCode($invite);
|
|
if ($invId > 0 && $invId != $id) {
|
|
db()->prepare('UPDATE ' . tn('users') . ' SET invited_by = ? WHERE id = ?')
|
|
->execute([$invId, $id]);
|
|
$invPts = max(0, (int) getSetting('points_invite', '20'));
|
|
if ($invPts > 0) {
|
|
addPoints($invId, 'invite', $invPts, '邀请好友 ' . $u . ' 注册成功');
|
|
}
|
|
}
|
|
}
|
|
$_SESSION['user_id'] = $id;
|
|
// 发送邮箱验证邮件(不阻塞注册:失败也可正常使用)
|
|
$sendRes = sendVerifyMail($id);
|
|
$_SESSION['verify_notice'] = $sendRes['ok'] ? 'sent' : 'fail';
|
|
unset($_SESSION['csrf']);
|
|
redirect($next ?: 'index.php');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
require 'includes/header.php';
|
|
?>
|
|
<section class="section auth-section">
|
|
<div class="auth-card">
|
|
<div class="auth-tabs">
|
|
<a href="login.php?mode=login" class="<?= $mode==='login'?'active':'' ?>"><?= __('login.tab_login') ?></a>
|
|
<a href="login.php?mode=register" class="<?= $mode==='register'?'active':'' ?>"><?= __('login.tab_register') ?></a>
|
|
</div>
|
|
|
|
<?php if ($err): ?><p class="form-err"><?= h($err) ?></p><?php endif; ?>
|
|
|
|
<?php if ($mode === 'login'): ?>
|
|
<form method="post" action="" class="auth-form">
|
|
<?= csrfField() ?>
|
|
<label><?= __('auth.username') ?><input type="text" name="username" required></label>
|
|
<label><?= __('auth.password') ?><input type="password" name="password" required></label>
|
|
<button type="submit" name="login" class="btn btn-primary"><?= __('login.btn_login') ?></button>
|
|
</form>
|
|
<?php else: ?>
|
|
<form method="post" action="" class="auth-form">
|
|
<?= csrfField() ?>
|
|
<label><?= __('auth.username') ?><input type="text" name="username" placeholder="<?= __('login.username_placeholder') ?>" required></label>
|
|
<label><?= __('login.label_email') ?> *<input type="email" name="email" placeholder="<?= __('login.email_placeholder') ?>" required></label>
|
|
<div class="captcha-box">
|
|
<img src="captcha.php" alt="CAPTCHA" class="captcha-img" onclick="this.src='captcha.php?'+Date.now()" title="<?= __('login.captcha_hint') ?>">
|
|
<label><?= __('login.label_captcha') ?><input type="text" name="captcha" maxlength="4" autocomplete="off" placeholder="<?= __('login.captcha_placeholder') ?>" required></label>
|
|
</div>
|
|
<label><?= __('auth.password') ?><input type="password" name="password" placeholder="<?= __('login.pwd_placeholder') ?>" required></label>
|
|
<label><?= __('auth.confirm_password') ?><input type="password" name="password2" required></label>
|
|
<label><?= __('login.label_invite') ?><input type="text" name="invite_code" placeholder="<?= __('login.invite_placeholder') ?>" value="<?= h($invite) ?>"></label>
|
|
<button type="submit" name="register" class="btn btn-primary"><?= __('login.btn_register') ?></button>
|
|
<p class="form-tip"><?= __('login.register_tip') ?></p>
|
|
</form>
|
|
<?php endif; ?>
|
|
</div>
|
|
</section>
|
|
<?php require 'includes/footer.php'; ?>
|