432 lines
17 KiB
PHP
432 lines
17 KiB
PHP
|
|
<?php
|
|||
|
|
// 强制显示所有错误(仅用于调试)
|
|||
|
|
ini_set('display_errors', 1);
|
|||
|
|
ini_set('display_startup_errors', 1);
|
|||
|
|
error_reporting(E_ALL);
|
|||
|
|
|
|||
|
|
// 记录错误到日志文件
|
|||
|
|
ini_set('log_errors', 1);
|
|||
|
|
ini_set('error_log', 'error_log.txt');
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 启动会话
|
|||
|
|
session_start();
|
|||
|
|
|
|||
|
|
// 检查用户是否已登录,如果已登录则重定向到首页
|
|||
|
|
if (isset($_SESSION['user_logged_in']) && $_SESSION['user_logged_in'] === true) {
|
|||
|
|
header('Location: index.php');
|
|||
|
|
exit;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// --- 配置区 ---
|
|||
|
|
// 数据库连接配置
|
|||
|
|
$servername = "localhost";
|
|||
|
|
$dbusername = "a1sax1m9i";
|
|||
|
|
$dbpassword = "a1sax1m9i";
|
|||
|
|
$dbname = "a1sax1m9i";
|
|||
|
|
|
|||
|
|
// QQ邮箱配置 - 请修改为你的信息
|
|||
|
|
$smtpHost = 'smtp.qq.com'; // QQ邮箱SMTP服务器
|
|||
|
|
$smtpPort = 465; // QQ邮箱SMTP端口(SSL)
|
|||
|
|
$smtpUsername = 'luoriguodu@qq.com'; // 你的QQ邮箱地址
|
|||
|
|
$smtpPassword = 'awjoclnnhqpybiie'; // QQ邮箱授权码(不是登录密码)
|
|||
|
|
$fromName = "音乐分享网站"; // 发件人名称
|
|||
|
|
|
|||
|
|
// 初始化消息变量
|
|||
|
|
$message = "";
|
|||
|
|
$messageType = ""; // success 或 error
|
|||
|
|
|
|||
|
|
// 确保密码重置表存在
|
|||
|
|
function ensurePasswordResetTableExists($conn) {
|
|||
|
|
$sql = "CREATE TABLE IF NOT EXISTS password_reset_tokens (
|
|||
|
|
user_id INT NOT NULL,
|
|||
|
|
token VARCHAR(255) NOT NULL,
|
|||
|
|
expiry DATETIME NOT NULL,
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
PRIMARY KEY (user_id)
|
|||
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
|
|||
|
|
|
|||
|
|
if (!$conn->query($sql)) {
|
|||
|
|
return "创建密码重置表失败: " . $conn->error;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成随机令牌
|
|||
|
|
function generateToken() {
|
|||
|
|
return bin2hex(random_bytes(32));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 使用QQ SMTP发送密码重置邮件
|
|||
|
|
function sendResetEmailViaQQSMTP($toEmail, $resetLink, $smtpHost, $smtpPort, $smtpUsername, $smtpPassword, $fromName) {
|
|||
|
|
// 邮件主题
|
|||
|
|
$subject = "=?UTF-8?B?" . base64_encode("密码重置请求 - 音乐分享网站") . "?=";
|
|||
|
|
|
|||
|
|
// 邮件内容
|
|||
|
|
$message = '
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>密码重置请求 - 音乐分享网站</title>
|
|||
|
|
<!-- 基础样式重置,适配不同邮箱客户端 -->
|
|||
|
|
<style type="text/css">
|
|||
|
|
/* 清除默认边距和内边距 */
|
|||
|
|
* {
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
font-family: "Microsoft YaHei", "Arial", sans-serif;
|
|||
|
|
}
|
|||
|
|
/* 响应式图片 */
|
|||
|
|
img {
|
|||
|
|
max-width: 100%;
|
|||
|
|
height: auto;
|
|||
|
|
border: none;
|
|||
|
|
}
|
|||
|
|
/* 链接样式统一 */
|
|||
|
|
a {
|
|||
|
|
text-decoration: none;
|
|||
|
|
transition: all 0.3s ease;
|
|||
|
|
}
|
|||
|
|
/* 按钮基础样式 */
|
|||
|
|
.btn {
|
|||
|
|
display: inline-block;
|
|||
|
|
padding: 12px 24px;
|
|||
|
|
background-color: #2c3e50;
|
|||
|
|
color: #ffffff !important;
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: 500;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
text-align: center;
|
|||
|
|
min-width: 180px;
|
|||
|
|
}
|
|||
|
|
.btn:hover {
|
|||
|
|
background-color: #34495e;
|
|||
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
|||
|
|
}
|
|||
|
|
/* 内容容器样式 */
|
|||
|
|
.email-container {
|
|||
|
|
max-width: 600px;
|
|||
|
|
margin: 0 auto;
|
|||
|
|
padding: 20px 15px;
|
|||
|
|
background-color: #f9fafb;
|
|||
|
|
}
|
|||
|
|
/* 邮件头部样式 */
|
|||
|
|
.email-header {
|
|||
|
|
padding: 15px 0;
|
|||
|
|
margin-bottom: 25px;
|
|||
|
|
border-bottom: 1px solid #eee;
|
|||
|
|
}
|
|||
|
|
.header-logo {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 10px;
|
|||
|
|
color: #2c3e50;
|
|||
|
|
}
|
|||
|
|
.logo-icon {
|
|||
|
|
font-size: 28px;
|
|||
|
|
color: #2c3e50;
|
|||
|
|
}
|
|||
|
|
.logo-text {
|
|||
|
|
font-size: 20px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
/* 邮件主体样式 */
|
|||
|
|
.email-body {
|
|||
|
|
padding: 30px;
|
|||
|
|
background-color: #ffffff;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
box-shadow: 0 2px 12px rgba(0,0,0,0.05);
|
|||
|
|
}
|
|||
|
|
.body-title {
|
|||
|
|
font-size: 22px;
|
|||
|
|
color: #2c3e50;
|
|||
|
|
margin-bottom: 18px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
.body-desc {
|
|||
|
|
font-size: 15px;
|
|||
|
|
color: #666666;
|
|||
|
|
line-height: 1.6;
|
|||
|
|
margin-bottom: 25px;
|
|||
|
|
}
|
|||
|
|
.body-desc p {
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
}
|
|||
|
|
/* 按钮容器,确保居中 */
|
|||
|
|
.btn-container {
|
|||
|
|
margin: 30px 0;
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
/* 邮件底部样式 */
|
|||
|
|
.email-footer {
|
|||
|
|
margin-top: 25px;
|
|||
|
|
padding-top: 15px;
|
|||
|
|
border-top: 1px solid #eee;
|
|||
|
|
font-size: 13px;
|
|||
|
|
color: #999999;
|
|||
|
|
text-align: center;
|
|||
|
|
line-height: 1.5;
|
|||
|
|
}
|
|||
|
|
.footer-note {
|
|||
|
|
margin-top: 8px;
|
|||
|
|
}
|
|||
|
|
/* 适配移动设备 */
|
|||
|
|
@media (max-width: 480px) {
|
|||
|
|
.email-body {
|
|||
|
|
padding: 20px 15px;
|
|||
|
|
}
|
|||
|
|
.body-title {
|
|||
|
|
font-size: 19px;
|
|||
|
|
}
|
|||
|
|
.body-desc {
|
|||
|
|
font-size: 14px;
|
|||
|
|
}
|
|||
|
|
.btn {
|
|||
|
|
padding: 10px 20px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
min-width: 150px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
<!-- 引入Font Awesome图标(若邮箱客户端支持),增强视觉效果 -->
|
|||
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<!-- 邮件整体容器,控制最大宽度和背景 -->
|
|||
|
|
<div class="email-container">
|
|||
|
|
<!-- 邮件头部:显示网站标识 -->
|
|||
|
|
<div class="email-header">
|
|||
|
|
<div class="header-logo">
|
|||
|
|
<i class="fas fa-music logo-icon"></i>
|
|||
|
|
<span class="logo-text">音乐分享网站</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 邮件主体:核心内容区域 -->
|
|||
|
|
<div class="email-body">
|
|||
|
|
<h1 class="body-title">您请求重置密码</h1>
|
|||
|
|
<div class="body-desc">
|
|||
|
|
<p>您好!我们收到了您的密码重置请求,若此操作非您本人发起,请忽略此邮件。</p>
|
|||
|
|
<p>请点击下方按钮重置您的密码(链接有效期为1小时,过期后需重新申请):</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 重置按钮:居中显示,突出引导 -->
|
|||
|
|
<div class="btn-container">
|
|||
|
|
<a href="' . htmlspecialchars($resetLink) . '" class="btn">
|
|||
|
|
<i class="fas fa-key mr-2"></i>立即重置密码
|
|||
|
|
</a>
|
|||
|
|
</div>
|
|||
|
|
<div class="btn-container">
|
|||
|
|
<a href="mailto:luoriguodu@foxmail.com" class="btn">
|
|||
|
|
<i class="fas fa-key mr-2"></i>反馈问题
|
|||
|
|
</a>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 备用链接:防止按钮失效时用户仍能操作 -->
|
|||
|
|
<div class="body-desc">
|
|||
|
|
<p>若按钮无法点击,可将下方链接复制到浏览器地址栏访问:</p>
|
|||
|
|
<p style="word-break: break-all; color: #3498db;">
|
|||
|
|
' . htmlspecialchars($resetLink) . '
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 邮件底部:补充说明和版权信息 -->
|
|||
|
|
<div class="email-footer">
|
|||
|
|
<p>此邮件为系统自动发送,请勿直接回复</p>
|
|||
|
|
<p class="footer-note">© 2024 音乐分享网站 版权所有 | 如有疑问,请联系客服</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</body>
|
|||
|
|
</html>
|
|||
|
|
';
|
|||
|
|
|
|||
|
|
// 创建邮件头部
|
|||
|
|
$headers = [
|
|||
|
|
'From' => $fromName . " <" . $smtpUsername . ">",
|
|||
|
|
'Reply-To' => $smtpUsername,
|
|||
|
|
'X-Mailer' => 'PHP/' . phpversion(),
|
|||
|
|
'MIME-Version' => '1.0',
|
|||
|
|
'Content-Type' => 'text/html; charset=UTF-8'
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 组装头部字符串
|
|||
|
|
$headerString = "";
|
|||
|
|
foreach ($headers as $key => $value) {
|
|||
|
|
$headerString .= $key . ": " . $value . "\r\n";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 使用stream_socket_client发送邮件
|
|||
|
|
$socket = stream_socket_client(
|
|||
|
|
'ssl://' . $smtpHost . ':' . $smtpPort,
|
|||
|
|
$errorNumber,
|
|||
|
|
$errorMessage,
|
|||
|
|
30,
|
|||
|
|
STREAM_CLIENT_CONNECT
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
if (!$socket) {
|
|||
|
|
throw new Exception("无法连接到SMTP服务器: $errorMessage ($errorNumber)");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 发送SMTP命令
|
|||
|
|
fwrite($socket, "EHLO " . gethostname() . "\r\n");
|
|||
|
|
fread($socket, 1024);
|
|||
|
|
|
|||
|
|
fwrite($socket, "AUTH LOGIN\r\n");
|
|||
|
|
fread($socket, 1024);
|
|||
|
|
|
|||
|
|
fwrite($socket, base64_encode($smtpUsername) . "\r\n");
|
|||
|
|
fread($socket, 1024);
|
|||
|
|
|
|||
|
|
fwrite($socket, base64_encode($smtpPassword) . "\r\n");
|
|||
|
|
fread($socket, 1024);
|
|||
|
|
|
|||
|
|
fwrite($socket, "MAIL FROM: <" . $smtpUsername . ">\r\n");
|
|||
|
|
fread($socket, 1024);
|
|||
|
|
|
|||
|
|
fwrite($socket, "RCPT TO: <" . $toEmail . ">\r\n");
|
|||
|
|
fread($socket, 1024);
|
|||
|
|
|
|||
|
|
fwrite($socket, "DATA\r\n");
|
|||
|
|
fread($socket, 1024);
|
|||
|
|
|
|||
|
|
fwrite($socket, "Subject: " . $subject . "\r\n");
|
|||
|
|
fwrite($socket, $headerString . "\r\n");
|
|||
|
|
fwrite($socket, $message . "\r\n");
|
|||
|
|
fwrite($socket, ".\r\n");
|
|||
|
|
fread($socket, 1024);
|
|||
|
|
|
|||
|
|
fwrite($socket, "QUIT\r\n");
|
|||
|
|
fread($socket, 1024);
|
|||
|
|
fclose($socket);
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理表单提交
|
|||
|
|
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
|||
|
|
$email = trim($_POST['email'] ?? '');
|
|||
|
|
|
|||
|
|
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
|||
|
|
$message = "请输入有效的邮箱地址";
|
|||
|
|
$messageType = "error";
|
|||
|
|
} else {
|
|||
|
|
$conn = new mysqli($servername, $dbusername, $dbpassword, $dbname);
|
|||
|
|
if ($conn->connect_error) {
|
|||
|
|
throw new Exception("数据库连接失败: " . $conn->connect_error);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$tableCheck = ensurePasswordResetTableExists($conn);
|
|||
|
|
if ($tableCheck !== true) {
|
|||
|
|
throw new Exception($tableCheck);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$stmt = $conn->prepare("SELECT id FROM users WHERE email = ?");
|
|||
|
|
if (!$stmt) {
|
|||
|
|
throw new Exception("准备查询语句失败: " . $conn->error);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$stmt->bind_param("s", $email);
|
|||
|
|
$stmt->execute();
|
|||
|
|
$stmt->store_result();
|
|||
|
|
|
|||
|
|
if ($stmt->num_rows == 1) {
|
|||
|
|
$stmt->bind_result($userId);
|
|||
|
|
$stmt->fetch();
|
|||
|
|
$token = generateToken();
|
|||
|
|
$expiry = date('Y-m-d H:i:s', strtotime('+1 hour'));
|
|||
|
|
|
|||
|
|
$updateStmt = $conn->prepare("INSERT INTO password_reset_tokens (user_id, token, expiry) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE token = ?, expiry = ?");
|
|||
|
|
if (!$updateStmt) {
|
|||
|
|
throw new Exception("准备更新语句失败: " . $conn->error);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$updateStmt->bind_param("issss", $userId, $token, $expiry, $token, $expiry);
|
|||
|
|
$updateStmt->execute();
|
|||
|
|
|
|||
|
|
// 生成重置链接
|
|||
|
|
$resetLink = "http://" . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . "/reset_password.php?token=" . $token;
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 发送重置邮件
|
|||
|
|
sendResetEmailViaQQSMTP(
|
|||
|
|
$email,
|
|||
|
|
$resetLink,
|
|||
|
|
$smtpHost,
|
|||
|
|
$smtpPort,
|
|||
|
|
$smtpUsername,
|
|||
|
|
$smtpPassword,
|
|||
|
|
$fromName
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
$message = "密码重置链接已发送到您的邮箱,请查收(1小时内有效)";
|
|||
|
|
$messageType = "success";
|
|||
|
|
} catch (Exception $e) {
|
|||
|
|
$message = "邮件发送失败: " . $e->getMessage();
|
|||
|
|
$messageType = "error";
|
|||
|
|
error_log("邮件发送错误: " . $e->getMessage());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$updateStmt->close();
|
|||
|
|
} else {
|
|||
|
|
// 安全考虑,无论邮箱是否存在,都显示相同的成功消息
|
|||
|
|
$message = "如果该邮箱已注册,密码重置链接将发送";
|
|||
|
|
$messageType = "success";
|
|||
|
|
}
|
|||
|
|
$stmt->close();
|
|||
|
|
$conn->close();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} catch (Exception $e) {
|
|||
|
|
$message = "系统错误: " . $e->getMessage();
|
|||
|
|
$messageType = "error";
|
|||
|
|
error_log("Forgot Password Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
|
|||
|
|
}
|
|||
|
|
?>
|
|||
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>忘记密码 - 音乐分享网站</title>
|
|||
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|||
|
|
<style>
|
|||
|
|
body { font-family: 'Arial', sans-serif; max-width: 500px; margin: 2rem auto; padding: 0 1rem; background-color: #f5f5f7; }
|
|||
|
|
.container { background-color: white; padding: 2rem; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
|||
|
|
h1 { text-align: center; color: #2c3e50; }
|
|||
|
|
.form-group { margin-bottom: 1.5rem; }
|
|||
|
|
label { display: block; margin-bottom: 0.5rem; color: #333; }
|
|||
|
|
input { width: 100%; padding: 0.8rem; border: 1px solid #ddd; border-radius: 5px; box-sizing: border-box; font-size: 1rem; }
|
|||
|
|
button { width: 100%; padding: 0.8rem; background-color: #2c3e50; color: white; border: none; border-radius: 5px; font-size: 1rem; cursor: pointer; }
|
|||
|
|
.message { padding: 1rem; border-radius: 5px; margin-bottom: 1.5rem; }
|
|||
|
|
.error-message { background-color: #f8d7da; color: #721c24; }
|
|||
|
|
.success-message { background-color: #d4edda; color: #155724; }
|
|||
|
|
.back-link { text-align: center; margin-top: 1.5rem; }
|
|||
|
|
.back-link a { color: #2c3e50; text-decoration: none; }
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<div class="container">
|
|||
|
|
<h1><i class="fas fa-key"></i> 忘记密码</h1>
|
|||
|
|
<?php if (!empty($message)): ?>
|
|||
|
|
<div class="message <?php echo $messageType === 'error' ? 'error-message' : 'success-message'; ?>">
|
|||
|
|
<?php echo $message; ?>
|
|||
|
|
</div>
|
|||
|
|
<?php endif; ?>
|
|||
|
|
<form method="post" action="">
|
|||
|
|
<div class="form-group">
|
|||
|
|
<label for="email">请输入您注册时使用的邮箱</label>
|
|||
|
|
<input type="email" id="email" name="email" value="<?php echo htmlspecialchars($_POST['email'] ?? ''); ?>" required>
|
|||
|
|
</div>
|
|||
|
|
<button type="submit">获取重置链接</button>
|
|||
|
|
</form>
|
|||
|
|
<div class="back-link">
|
|||
|
|
<a href="login.php"><i class="fas fa-arrow-left"></i> 返回登录</a>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</body>
|
|||
|
|
</html>
|
|||
|
|
|